diff options
Diffstat (limited to 'meta-openbmc-mods')
357 files changed, 51375 insertions, 0 deletions
diff --git a/meta-openbmc-mods/COPYING.MIT b/meta-openbmc-mods/COPYING.MIT new file mode 100644 index 000000000..89de35479 --- /dev/null +++ b/meta-openbmc-mods/COPYING.MIT @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/meta-openbmc-mods/COPYING.apache-2.0 b/meta-openbmc-mods/COPYING.apache-2.0 new file mode 100644 index 000000000..67db85882 --- /dev/null +++ b/meta-openbmc-mods/COPYING.apache-2.0 @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/meta-openbmc-mods/README b/meta-openbmc-mods/README new file mode 100644 index 000000000..3d883acb2 --- /dev/null +++ b/meta-openbmc-mods/README @@ -0,0 +1,64 @@ +This README file contains information on the contents of the +intel layer. + +Please see the corresponding sections below for details. + + +Dependencies +============ + +This layer depends on: + + URI: git://git.openembedded.org/bitbake + branch: master + + URI: git://git.openembedded.org/openembedded-core + layers: meta + branch: master + + URI: git://git.yoctoproject.org/xxxx + layers: xxxx + branch: master + + +Patches +======= + +Please submit any patches against the intel layer to the +xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer: + +Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com> + + +Table of Contents +================= + + I. Adding the intel layer to your build + II. Misc + + +I. Adding the intel layer to your build +================================================= + +--- replace with specific instructions for the intel layer --- + +In order to use this layer, you need to make the build system aware of +it. + +Assuming the intel layer exists at the top-level of your +yocto build tree, you can add it to the build system by adding the +location of the intel layer to bblayers.conf, along with any +other layers needed. e.g.: + + BBLAYERS ?= " \ + /path/to/yocto/meta \ + /path/to/yocto/meta-poky \ + /path/to/yocto/meta-yocto-bsp \ + /path/to/yocto/meta-intel \ + " + + +II. Misc +======== + +--- replace with specific information about the intel layer --- diff --git a/meta-openbmc-mods/conf/layer.conf b/meta-openbmc-mods/conf/layer.conf new file mode 100644 index 000000000..35c801089 --- /dev/null +++ b/meta-openbmc-mods/conf/layer.conf @@ -0,0 +1,22 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "intel-openbmc" +BBFILE_PATTERN_intel-openbmc = "^${LAYERDIR}/" +BBFILE_PRIORITY_intel-openbmc = "5" +LAYERSERIES_COMPAT_intel-openbmc = "warrior" + +IMAGE_FEATURES[validitems] += "tools-sdk tools-debug" + +# static userid assignments +USERADDEXTENSION = "useradd-staticids" +USERADD_UID_TABLES = "files/passwd" +USERADD_GID_TABLES = "files/group" + +LAYER_CONF_VERSION = "10" + +INTELBASE = '${@os.path.normpath("${LAYERDIR}/")}' diff --git a/meta-openbmc-mods/conf/machine/include/intel.inc b/meta-openbmc-mods/conf/machine/include/intel.inc new file mode 100644 index 000000000..70297bab8 --- /dev/null +++ b/meta-openbmc-mods/conf/machine/include/intel.inc @@ -0,0 +1,27 @@ +OBMC_MACHINE_FEATURES += "\ + obmc-phosphor-fan-mgmt \ + obmc-phosphor-chassis-mgmt \ + obmc-phosphor-flash-mgmt \ + obmc-host-ipmi \ + obmc-host-state-mgmt \ + obmc-chassis-state-mgmt \ + obmc-bmc-state-mgmt \ + " + +VIRTUAL-RUNTIME_skeleton_workbook = "${MACHINE}-config" +VIRTUAL-RUNTIME_obmc-inventory-manager = "entity-manager" +VIRTUAL-RUNTIME_obmc-led-monitor = "" +VIRTUAL-RUNTIME_obmc-host-state-manager = "intel-chassis-control" +VIRTUAL-RUNTIME_obmc-chassis-state-manager = "intel-chassis-control" +VIRTUAL-RUNTIME_obmc-discover-system-state = "intel-chassis-control" +VIRTUAL-RUNTIME_obmc-settings-mgmt = "settings" + +PREFERRED_PROVIDER_virtual/obmc-host-ipmi-hw = "phosphor-ipmi-kcs" +PREFERRED_PROVIDER_virtual/obmc-chassis-mgmt = "packagegroup-intel-apps" +PREFERRED_PROVIDER_virtual/obmc-fan-mgmt = "packagegroup-intel-apps" +PREFERRED_PROVIDER_virtual/obmc-flash-mgmt = "packagegroup-intel-apps" +PREFERRED_PROVIDER_virtual/obmc-system-mgmt = "packagegroup-intel-apps" +PREFERRED_PROVIDER_virtual/obmc-host-ctl ?= "" +PREFERRED_PROVIDER_virtual/obmc-inventory-data = "entity-manager" +PREFERRED_PROVIDER_virtual/phosphor-led-manager-config-native ?= "intel-led-manager-config-native" +#PREFERRED_PROVIDER_virtual/obmc-gpio-monitor ?= "phosphor-gpio-monitor" diff --git a/meta-openbmc-mods/files/group b/meta-openbmc-mods/files/group new file mode 100644 index 000000000..8f8c8e325 --- /dev/null +++ b/meta-openbmc-mods/files/group @@ -0,0 +1,12 @@ +bmcweb:x:443: +ipmid:x:197: +lock:x:198: +netdev:x:208: +avahi:x:200: +messagebus:x:201 +systemd-journal:x:202: +systemd-network:x:203: +systemd-timesync:x:204: +systemd-coredump:x:205: +systemd-bus-proxy:x:206: +systemd-resolve:!:207: diff --git a/meta-openbmc-mods/files/passwd b/meta-openbmc-mods/files/passwd new file mode 100644 index 000000000..ae48cfb46 --- /dev/null +++ b/meta-openbmc-mods/files/passwd @@ -0,0 +1,10 @@ +bmcweb:x:443:443::/home/bmcweb:/bin/false +hostipmid:x:196:197::/:/bin/false +netipmid:x:197:197::/:/bin/false +avahi:x:200:200::/var/run/avahi-daemon:/bin/false +messagebus:x:201:201::/var/lib/dbus:/bin/false +systemd-network:x:203:203::/:/bin/false +systemd-timesync:x:204:204::/:/bin/false +systemd-coredump:x:205:205::/:/bin/false +systemd-bus-proxy:x:206:206::/:/bin/false +systemd-resolve:!:207:207::/:/bin/nologin diff --git a/meta-openbmc-mods/meta-ast2500/conf/layer.conf b/meta-openbmc-mods/meta-ast2500/conf/layer.conf new file mode 100644 index 000000000..99ca15d28 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/conf/layer.conf @@ -0,0 +1,21 @@ +LOCALCONF_VERSION = "3" +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "ast2500" +BBFILE_PATTERN_ast2500 = "" +BBFILE_PRIORITY_ast2500 = "6" +LAYERSERIES_COMPAT_ast2500 = "warrior" + +INHERIT += "extrausers" +#INHERIT += " cve-check" + +EXTRA_USERS_PARAMS_append_pn-intel-platforms = " \ + usermod -p '\$1\$UGMqyqdG\$FZiylVFmRRfl9Z0Ue8G7e/' root; \ + " + +hostname_pn-base-files = "intel-obmc" diff --git a/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc b/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc new file mode 100644 index 000000000..1bbd64381 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/conf/machine/include/intel-ast2500.inc @@ -0,0 +1,13 @@ +KMACHINE = "aspeed" +KERNEL_DEVICETREE = "${KMACHINE}-bmc-intel-purley.dtb" + +require conf/machine/include/ast2500.inc +require conf/machine/include/obmc-bsp-si-common.inc +require conf/machine/include/intel.inc +require conf/distro/include/phosphor-tiny.inc + +UBOOT_MACHINE = "ast_g5_phy_config" + +VIRTUAL-RUNTIME_skeleton_workbook = "${MACHINE}-config" + +IMAGE_CLASSES += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'image_types_intel_pfr', '', d)}" diff --git a/meta-openbmc-mods/meta-ast2500/conf/machine/include/obmc-bsp-si-common.inc b/meta-openbmc-mods/meta-ast2500/conf/machine/include/obmc-bsp-si-common.inc new file mode 100644 index 000000000..f4f8a7b9f --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/conf/machine/include/obmc-bsp-si-common.inc @@ -0,0 +1,40 @@ +#@TYPE: Machine +#@NAME: OpenBMC +#@DESCRIPTION: Common machine configuration for OpenBMC chips + +MACHINE_EXTRA_RRECOMMENDS = " kernel-modules" +EXTRA_IMAGEDEPENDS += "u-boot" + +IMAGE_FSTYPES += "squashfs-xz" +IMAGE_FSTYPES += "mtd-auto" +INITRAMFS_FSTYPES = "squashfs-xz" +EXTRA_IMAGECMD_squashfs-xz_append = "-processors ${BB_NUMBER_THREADS} -b 262144 -Xdict-size 100% -Xbcj arm" + +KERNEL_CLASSES ?= "kernel-fitimage" +KERNEL_IMAGETYPES ?= "fitImage" +KERNEL_EXTRA_ARGS += "LOADADDR=${UBOOT_ENTRYPOINT}" + +UBOOT_SUFFIX ?= "bin" + +MACHINEOVERRIDES =. "openbmc:" + +OBMC_PHOSPHOR_IMAGE_OVERLAY= "1" +OBMC_IMAGE_EXTRA_INSTALL_append = " u-boot-fw-utils-aspeed" + +IMAGE_CLASSES += "image_types image_types_phosphor_auto qemuboot" + +INITRAMFS_CTYPE ?= "lzma" +INITRAMFS_IMAGE = "obmc-phosphor-initramfs" + +MACHINE_FEATURES_BACKFILL_CONSIDERED = "qemu-usermode" + +KERNEL_IMAGETYPES += "zImage" + +# runqemu +QB_SYSTEM_NAME = "qemu-system-arm" +QB_DEFAULT_FSTYPE = "mtd" +QB_ROOTFS_OPT = "-drive file=@ROOTFS@,format=raw,if=mtd" +QB_MACHINE = "-M intel-ast2500" +QB_OPT_APPEND += " -nographic" +QB_NETWORK_DEVICE = "-net nic,macaddr=C0:FF:EE:00:00:02,model=ftgmac100" +QB_DEFAULT_KERNEL = "none" diff --git a/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-Report-link-statistics-for-the-NCSI-channel.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-Report-link-statistics-for-the-NCSI-channel.patch new file mode 100644 index 000000000..a79457962 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-Report-link-statistics-for-the-NCSI-channel.patch @@ -0,0 +1,54 @@ +From 39ea8eb8a221646ce019bbb176e58be47f4ca03a Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Thu, 1 Aug 2019 11:29:41 -0700 +Subject: [PATCH] Report link statistics for the NCSI channel + +The ftgmac driver does not report the link statistics for the NCSI +channel used for the shared NICs attached to the BMC. Report a fixed +value for the NSCI interface. + +Change-Id: Idb65ca1ce07f06a883417ee44df30ea2c8483107 +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 055f77c70fa3..974ea44e9195 100644 +--- a/drivers/net/ethernet/faraday/ftgmac100.c ++++ b/drivers/net/ethernet/faraday/ftgmac100.c +@@ -1215,10 +1215,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 = SPEED_100; ++ cmd->base.duplex = DUPLEX_FULL; ++ 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.20.1 + diff --git a/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch new file mode 100644 index 000000000..782e5e795 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch @@ -0,0 +1,466 @@ +From 219406610ce816c56fa7cb5952bbec72fd94a3a9 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 platforms + +Add the DTS file for Intel 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> +--- + arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 437 ++++++++++++++++++++++++++ + 1 file changed, 436 insertions(+) + create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-purley.dts + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +new file mode 100644 +index 0000000..9f8192f +--- /dev/null ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +@@ -0,0 +1,437 @@ ++/dts-v1/; ++ ++#include "aspeed-g5.dtsi" ++#include <dt-bindings/gpio/aspeed-gpio.h> ++#include <dt-bindings/i2c/i2c.h> ++ ++/ { ++ model = "Purley BMC"; ++ compatible = "intel,purley-bmc", "aspeed,ast2500"; ++ ++ aliases { ++ serial4 = &uart5; ++ }; ++ ++ chosen { ++ stdout-path = &uart5; ++ bootargs = "console=ttyS4,115200 earlyprintk"; ++ }; ++ ++ memory@80000000 { ++ reg = <0x80000000 0x20000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ vga_memory: framebuffer@7f000000 { ++ no-map; ++ reg = <0x7f000000 0x01000000>; ++ }; ++ ++ gfx_memory: framebuffer { ++ size = <0x01000000>; ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ video_engine_memory: jpegbuffer { ++ size = <0x02000000>; /* 32M */ ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ }; ++ ++ vga-shared-memory { ++ compatible = "aspeed,ast2500-vga-sharedmem"; ++ reg = <0x9ff00000 0x100000>; ++ }; ++ ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, ++ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, ++ <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>, ++ <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ identify { ++ default-state = "off"; ++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_amber { ++ default-state = "off"; ++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_green { ++ default-state = "keep"; ++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ beeper { ++ compatible = "pwm-beeper"; ++ pwms = <&timer 5 1000000 0>; ++ }; ++}; ++ ++&fmc { ++ status = "okay"; ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++#include "openbmc-flash-layout-intel-64MB.dtsi" ++ }; ++}; ++ ++&espi { ++ status = "okay"; ++}; ++ ++&jtag { ++ status = "okay"; ++}; ++ ++&peci0 { ++ status = "okay"; ++ gpios = <&gpio ASPEED_GPIO(F, 6) 0>; ++}; ++ ++&syscon { ++ uart-clock-high-speed; ++ status = "okay"; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&gpio { ++ status = "okay"; ++ gpio-line-names = ++ /*A0-A7*/ "","","","","","","","", ++ /*B0-B7*/ "","","","","","","","", ++ /*C0-C7*/ "","","","","","","","", ++ /*D0-D7*/ "","","","","","","","", ++ /*E0-E7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","","","","", ++ /*F0-F7*/ "NMI_OUT","","","","CPU_ERR0","CPU_ERR1","","", ++ /*G0-G7*/ "CPU_ERR2","CPU_CATERR","PCH_BMC_THERMTRIP","","","","","", ++ /*H0-H7*/ "","","","","","","","", ++ /*I0-I7*/ "","","","","","","","", ++ /*J0-J7*/ "","","","","","","","", ++ /*K0-K7*/ "","","","","","","","", ++ /*L0-L7*/ "","","","","","","","", ++ /*M0-M7*/ "","","","","","","","", ++ /*N0-N7*/ "","","","","","","","", ++ /*O0-O7*/ "","","","","","","","", ++ /*P0-P7*/ "","","","","","","","", ++ /*Q0-Q7*/ "","","","","","","","", ++ /*R0-R7*/ "","","","","","","","", ++ /*S0-S7*/ "","","","","","","","", ++ /*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","","","","","","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","","","","","","","", ++ /*IB0-IB7*/ "","","CPU2_PRESENCE","","","","","", ++ /*IC0-IC7*/ "","","","","","","","", ++ /*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"; ++}; ++ ++/** ++ * 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"; ++ ++ hsbp0@10 { ++ compatible = "slave-mqueue"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; ++ ++&i2c5 { ++ bus-frequency = <1000000>; ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++ ++ smlink0@10 { ++ compatible = "slave-mqueue"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; ++ ++&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 = <5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_timer5_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-ast2500/recipes-kernel/linux/linux-aspeed/0001-aspeed-pwm-tacho-change-default-fan-speed.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-aspeed-pwm-tacho-change-default-fan-speed.patch new file mode 100644 index 000000000..40afce9be --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0001-aspeed-pwm-tacho-change-default-fan-speed.patch @@ -0,0 +1,28 @@ +From 80795ca1de706c4111ac7e8874e1490e7ebf8100 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.17.1 + diff --git a/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch new file mode 100644 index 000000000..0ce4163dd --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch @@ -0,0 +1,121 @@ +From 56faf4c5a3957012f3a3a8467b3dfde760093784 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 | 1 + + drivers/pinctrl/aspeed/pinctrl-aspeed.c | 60 ++++++++++++++++++++++++++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed.h | 3 ++ + 3 files changed, 64 insertions(+) + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index e20e2a259141..fbc9a68bd88c 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -2605,6 +2605,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_gpio_disable_free, + .strict = true, + }; + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +index 18f46177b4af..6feea140b438 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +@@ -356,6 +356,66 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, + return aspeed_sig_expr_enable(&pdata->pinmux, expr); + } + ++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset) ++{ ++ const 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 we're freeing GPIOE1 (33) or GPIOE3 (35) then re-enable the ++ * pass-through mux setting; otherwise, do nothing. ++ */ ++ if (offset != 33 && offset != 35) ++ return; ++ ++ dev_dbg(pctldev->dev, ++ "Freeing pass-through pin %s (%d). Re-enabling pass-through.\n", ++ pdesc->name, offset); ++ ++ if (!pdesc) ++ return; ++ ++ 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 11cc0eb6666b..735162ebb855 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h +@@ -64,6 +64,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-ast2500/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch new file mode 100644 index 000000000..c38134b8c --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch @@ -0,0 +1,70 @@ +From 7513371d16158cb638dd97e81b402bbef7ed3156 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-purley.dts | 4 ++++ + drivers/gpio/gpio-aspeed.c | 10 ++++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +index b049f816bf67..4815104459f1 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +@@ -116,6 +116,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*/ "","","","","","","","", +diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c +index 13d80bfbc3b6..e426452a28f7 100644 +--- a/drivers/gpio/gpio-aspeed.c ++++ b/drivers/gpio/gpio-aspeed.c +@@ -1152,6 +1152,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; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); +@@ -1199,6 +1200,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 E0 and E2. 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 (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-ast2500/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch new file mode 100644 index 000000000..14b7154bf --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/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-purley.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +index 4815104459f1..df02bb1aaf36 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.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-ast2500/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch new file mode 100644 index 000000000..c1207055d --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch @@ -0,0 +1,80 @@ +From 029cf5d5ff436ea14ab2d33da32238910be0a8b2 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 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index fbc9a68bd88c..6f151e7c8d81 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -272,7 +272,7 @@ FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21); + + #define B20 32 + SIG_EXPR_LIST_DECL_SINGLE(NCTS3, NCTS3, SIG_DESC_SET(SCU80, 16)); +-SIG_EXPR_DECL(GPIE0IN, GPIE0, GPIE0_DESC); ++SIG_EXPR_DECL(GPIE0IN, GPIE0); + SIG_EXPR_DECL(GPIE0IN, GPIE, GPIE_DESC); + SIG_EXPR_LIST_DECL_DUAL(GPIE0IN, GPIE0, GPIE); + MS_PIN_DECL(B20, GPIOE0, NCTS3, GPIE0IN); +@@ -292,7 +292,7 @@ FUNC_GROUP_DECL(GPIE0, B20, C20); + + #define F18 34 + SIG_EXPR_LIST_DECL_SINGLE(NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18)); +-SIG_EXPR_DECL(GPIE2IN, GPIE2, GPIE2_DESC); ++SIG_EXPR_DECL(GPIE2IN, GPIE2); + SIG_EXPR_DECL(GPIE2IN, GPIE, GPIE_DESC); + SIG_EXPR_LIST_DECL_DUAL(GPIE2IN, GPIE2, GPIE); + MS_PIN_DECL(F18, GPIOE2, NDSR3, GPIE2IN); +@@ -1371,7 +1371,7 @@ FUNC_GROUP_DECL(ADC15, H4); + + #define R22 192 + SIG_EXPR_DECL(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8)); +-SIG_EXPR_DECL(SIOS3, ACPI, ACPI_DESC); ++SIG_EXPR_DECL(SIOS3, ACPI); + SIG_EXPR_LIST_DECL_DUAL(SIOS3, SIOS3, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(DASHR22, DASHR22, SIG_DESC_SET(SCU94, 10)); + MS_PIN_DECL(R22, GPIOY0, SIOS3, DASHR22); +@@ -1379,7 +1379,7 @@ FUNC_GROUP_DECL(SIOS3, R22); + + #define R21 193 + SIG_EXPR_DECL(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9)); +-SIG_EXPR_DECL(SIOS5, ACPI, ACPI_DESC); ++SIG_EXPR_DECL(SIOS5, ACPI); + SIG_EXPR_LIST_DECL_DUAL(SIOS5, SIOS5, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(DASHR21, DASHR21, SIG_DESC_SET(SCU94, 10)); + MS_PIN_DECL(R21, GPIOY1, SIOS5, DASHR21); +@@ -1395,7 +1395,7 @@ FUNC_GROUP_DECL(SIOPWREQ, P22); + + #define P21 195 + SIG_EXPR_DECL(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11)); +-SIG_EXPR_DECL(SIOONCTRL, ACPI, ACPI_DESC); ++SIG_EXPR_DECL(SIOONCTRL, ACPI); + SIG_EXPR_LIST_DECL_DUAL(SIOONCTRL, SIOONCTRL, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(DASHP21, DASHP21, SIG_DESC_SET(SCU94, 11)); + MS_PIN_DECL(P21, GPIOY3, SIOONCTRL, DASHP21); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/intel-ast2500.cfg b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/intel-ast2500.cfg new file mode 100644 index 000000000..9860a2815 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/intel-ast2500.cfg @@ -0,0 +1,68 @@ +CONFIG_HWMON=y +CONFIG_SENSORS_ASPEED=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_IIO=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_ASPEED_ADC=y +CONFIG_SGPIO_ASPEED=y +CONFIG_CRC8=y +CONFIG_PECI=y +CONFIG_PECI_CHARDEV=y +CONFIG_PECI_ASPEED=y +CONFIG_SENSORS_PECI_CPUTEMP=y +CONFIG_SENSORS_PECI_DIMMTEMP=y +CONFIG_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_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 + diff --git a/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed_%.bbappend new file mode 100644 index 000000000..909e7cccc --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -0,0 +1,10 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/linux-aspeed:" +SRC_URI += "file://intel-ast2500.cfg \ + file://0001-arm-dts-add-DTS-for-Intel-platforms.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://0001-aspeed-pwm-tacho-change-default-fan-speed.patch \ + file://0001-Report-link-statistics-for-the-NCSI-channel.patch \ + " +SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}" diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CYP-baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CYP-baseboard.json new file mode 100755 index 000000000..42e313568 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/CYP-baseboard.json @@ -0,0 +1,1435 @@ +{ + "Exposes": [ + { + "Index": 0, + "Name": "P12V_PSU_RIGHT", + "PowerState": "On", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 1, + "Name": "P3V3", + "PowerState": "On", + "ScaleFactor": 0.4107, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.647 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.541 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 3.066 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.974 + } + ], + "Type": "ADC" + }, + { + "Index": 2, + "Name": "PVNN_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.081 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.049 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.807 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.783 + } + ], + "Type": "ADC" + }, + { + "Index": 3, + "Name": "P105_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.139 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.106 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.995 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.966 + } + ], + "Type": "ADC" + }, + { + "Index": 4, + "Name": "P12V_PSU_LEFT", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 5, + "Name": "P12V_AUX", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 6, + "Name": "P1V8_PCH", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.961 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.904 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.699 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.648 + } + ], + "Type": "ADC" + }, + { + "BridgeGpio": [ + { + "Name": "P3VBAT_BRIDGE_EN", + "Polarity": "High" + } + ], + "Index": 7, + "Name": "P3VBAT", + "ScaleFactor": 0.3333, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.296 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 2.457 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.138 + } + ], + "Type": "ADC" + }, + { + "Index": 8, + "Name": "PVCCIN_CPU0", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 9, + "Name": "PVCCIN_CPU2", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 10, + "Name": "PVDQ_ABCD_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 11, + "Name": "PVDQ_EFGH_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 12, + "Name": "PVDQ_ABCD_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 13, + "Name": "PVDQ_EFGH_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 14, + "Name": "PVCCIO_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 15, + "Name": "PVCCIO_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "BindGpioIntrusion": "Chassis Intrusion GPIO", + "Class": "Gpio", + "Name": "Chassis Intrusion Sensor", + "Type": "ChassisIntrusionSensor" + }, + { + "Direction": "In", + "Index": 0, + "Name": "Board REV ID0", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 3, + "Name": "Board REV ID1", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 8, + "Name": "Board SKU ID0", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 9, + "Name": "Board SKU ID1", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 10, + "Name": "Board SKU ID2", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 11, + "Name": "Board SKU ID3", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 12, + "Name": "Board SKU ID4", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 18, + "Name": "OCP3 PRSNTB0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 19, + "Name": "OCP3 PRSNTB1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 20, + "Name": "OCP3 PRSNTB2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 21, + "Name": "OCP3 PRSNTB3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 24, + "Name": "Force BMC Update", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 26, + "Name": "OCP PWRGD Aux", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 42, + "Name": "CPU1 Memhot", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 43, + "Name": "CPU2 Memhot", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 44, + "Name": "Cpu Err0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 45, + "Name": "Cpu Err1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 46, + "Name": "Platform Reset", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 47, + "Name": "CPU PRDY", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 50, + "Name": "PCH Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 51, + "Name": "Board REV ID2", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 52, + "Name": "NMI Event", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 53, + "Name": "Board SKU ID5", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 56, + "Name": "Rise1 PWRGD", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 57, + "Name": "Rise2 PWRGD", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 61, + "Name": "Rise3 PWRGD", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "In", + "Index": 62, + "Name": "Rise4 PWRGD", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 63, + "Name": "240VA OC", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 64, + "Name": "SYS FAN0 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 65, + "Name": "SYS FAN1 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 66, + "Name": "SYS FAN2 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 67, + "Name": "SYS FAN3 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 68, + "Name": "SASM ROC ID0", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 69, + "Name": "SASM ROC ID1", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 70, + "Name": "Midplane Switch ID0", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 71, + "Name": "Midplane Switch ID1", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 137, + "Name": "PCA9555 Intr", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 138, + "Name": "SYS FAN4 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 139, + "Name": "SYS FAN5 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 140, + "Name": "SYS FAN6 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 141, + "Name": "SYS FAN7 PRSNT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 143, + "Name": "Chassis Intrusion GPIO", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 144, + "Name": "Remote Debug Enable", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 146, + "Name": "RSMRST", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 214, + "Name": "SMI Active", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 218, + "Name": "ID Button", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 232, + "Name": "CPU1 Present", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 233, + "Name": "CPU1 Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 234, + "Name": "CPU1 VR Hot", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 235, + "Name": "CPU1 FIVR Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 236, + "Name": "CPU1 Mem VR Hot1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 237, + "Name": "CPU1 Mem VR Hot2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 238, + "Name": "CPU1 ID0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 239, + "Name": "CPU1 ID1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 240, + "Name": "CPU1 Mismatch", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 241, + "Name": "CPU1 DIMM Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 242, + "Name": "CPU2 Present", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 243, + "Name": "CPU2 Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 244, + "Name": "CPU2 VR Hot", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 245, + "Name": "CPU2 FIVR Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 246, + "Name": "CPU2 Mem VR Hot1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 247, + "Name": "CPU1 Mem VR Hot2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 248, + "Name": "CPU2 ID0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 249, + "Name": "CPU2 ID1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 250, + "Name": "CPU2 Mismatch", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 251, + "Name": "CPU2 DIMM Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 272, + "Name": "PLD Minor Revison Bit 0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 273, + "Name": "PLD Minor Revison Bit 1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 274, + "Name": "PLD Minor Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 275, + "Name": "PLD Minor Revison Bit 3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 276, + "Name": "PLD Minor Revison Bit 4", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 277, + "Name": "PLD Minor Revison Bit 5", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 278, + "Name": "PLD Minor Revison Bit 6", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 279, + "Name": "PLD Minor Revison Bit 7", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 280, + "Name": "Main PLD Major Revison Bit 0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 281, + "Name": "Main PLD Major Revison Bit 1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 282, + "Name": "Main PLD Major Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 283, + "Name": "Main PLD Major Revison Bit 3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 284, + "Name": "Main PLD Major Revison Bit 4", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 285, + "Name": "Main PLD Major Revison Bit 5", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 286, + "Name": "Main PLD Major Revison Bit 6", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 287, + "Name": "Main PLD Major Revison Bit 7", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 289, + "Name": "Memory Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 290, + "Name": "CPU Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 291, + "Name": "P3V3 Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 292, + "Name": "PSU Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 295, + "Name": "PCH Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Address": "0x71", + "Bus": 2, + "ChannelNames": [ + "M2_Slot1", + "M2_Slot2", + "", + "" + ], + "Name": "M.2 Mux", + "Type": "PCA9543Mux" + }, + { + "Address": "0x70", + "Bus": 4, + "ChannelNames": [ + "U2_Slot1", + "U2_Slot2", + "U2_Slot3", + "U2_Slot4" + ], + "Name": "HSBP 1 Mux", + "Type": "PCA9546Mux" + }, + { + "Address": "0x74", + "Bus": 4, + "ChannelNames": [ + "U2_Slot5", + "U2_Slot6", + "U2_Slot7", + "U2_Slot8" + ], + "Name": "HSBP 1 Mux2", + "Type": "PCA9546Mux" + }, + { + "Address": "0x77", + "Bus": 4, + "ChannelNames": [ + "U2_Slot1", + "U2_Slot2", + "U2_Slot3", + "U2_Slot4" + ], + "Name": "HSBP 2 Mux", + "Type": "PCA9546Mux" + }, + { + "Address": "0x73", + "Bus": 4, + "ChannelNames": [ + "U2_Slot5", + "U2_Slot6", + "U2_Slot7", + "U2_Slot8" + ], + "Name": "HSBP 2 Mux2", + "Type": "PCA9546Mux" + }, + { + "Address": "0x76", + "Bus": 4, + "ChannelNames": [ + "U2_Slot1", + "U2_Slot2", + "U2_Slot3", + "U2_Slot4" + ], + "Name": "HSBP 3 Mux", + "Type": "PCA9546Mux" + }, + { + "Address": "0x72", + "Bus": 4, + "ChannelNames": [ + "U2_Slot5", + "U2_Slot6", + "U2_Slot7", + "U2_Slot8" + ], + "Name": "HSBP 3 Mux2", + "Type": "PCA9546Mux" + }, + { + "Address": "0x4D", + "Bus": 6, + "Name": "CPU0 VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP421" + }, + { + "Address": "0x4F", + "Bus": 6, + "Name": "CPU1 Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP421" + }, + { + "Address": "0x4A", + "Bus": 6, + "Name": "BMC Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4B", + "Bus": 6, + "Name": "RightRear Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4E", + "Bus": 6, + "Name": "LeftRear Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4C", + "Bus": 6, + "Name": "PCH DS Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + } + ], + "Name": "CYP Baseboard", + "Probe": [ + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': 'M50CYP2SB2U'})", + "OR", + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*CYP'})" + ], + "ProductId": 152, + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$PRODUCT_MANUFACTURER", + "Model": "$PRODUCT_PRODUCT_NAME", + "PartNumber": "$PRODUCT_PART_NUMBER", + "SerialNumber": "$PRODUCT_SERIAL_NUMBER" + } +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json new file mode 100644 index 000000000..84ff6f12f --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json @@ -0,0 +1,91 @@ +[ + { + "Exposes": [ + { + "Address": "$address", + "Bus": "$bus", + "Name": "FCXXPDBASSMBL Fru", + "Type": "24C01" + }, + { + "Address": "0x18", + "Bus": "$bus", + "Name": "Multi Node Presence Detector", + "Type": "MultiNodePresence" + }, + { + "Address": "0x48", + "Bus": "$bus", + "Name": "PDB Temp1", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 80 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 75 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x49", + "Bus": "$bus", + "Name": "PDB Temp2", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 80 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 75 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + } + ], + "Name": "FCXXPDBASSMBL PDB", + "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'FCXXPDBASSMBL', 'ADDRESS' : 85})", + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$BOARD_MANUFACTURER", + "Model": "$BOARD_PRODUCT_NAME", + "PartNumber": "$BOARD_PART_NUMBER", + "SerialNumber": "$BOARD_SERIAL_NUMBER" + } + } +]
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/MIDPLANE-2U2X12SWITCH.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/MIDPLANE-2U2X12SWITCH.json new file mode 100644 index 000000000..53edbfe87 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/MIDPLANE-2U2X12SWITCH.json @@ -0,0 +1,104 @@ +[ + { + "Exposes": [ + { + "Address": "$address", + "Bus": "$bus", + "Name": "Midplane 1 Fru", + "Type": "EEPROM" + }, + { + "Address": "0x4E", + "Bus": "$bus", + "Name": "Midplane 1 Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 80 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 75 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + } + ], + "Name": "Midplane 1", + "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U2X12SWITCH', 'ADDRESS' : 86})", + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$BOARD_MANUFACTURER", + "Model": "$BOARD_PRODUCT_NAME", + "PartNumber": "$BOARD_PART_NUMBER", + "SerialNumber": "$BOARD_SERIAL_NUMBER" + } + }, + { + "Exposes": [ + { + "Address": "$address", + "Bus": "$bus", + "Name": "Midplane 2 Fru", + "Type": "EEPROM" + }, + { + "Address": "0x4F", + "Bus": "$bus", + "Name": "Midplane 2 Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 80 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 75 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + } + ], + "Name": "Midplane 2", + "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'F2U2X12SWITCH', 'ADDRESS' : 87})", + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$BOARD_MANUFACTURER", + "Model": "$BOARD_PRODUCT_NAME", + "PartNumber": "$BOARD_PART_NUMBER", + "SerialNumber": "$BOARD_SERIAL_NUMBER" + } + } +]
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json new file mode 100644 index 000000000..a81329787 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json @@ -0,0 +1,49 @@ +{ + "Exposes": [ + { + "Address": "0x56", + "Bus": 9, + "Class": "MCUTemp", + "Name": "PDB MCU Temp", + "Reg": "0x22", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "MCUTempSensor" + } + ], + "Name": "OPB2RH Chassis", + "Probe": [ + "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'FCXXPDBASSMBL'})" + ], + "Type": "Chassis", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "Intel Corporation", + "Model": "OPB2RH", + "PartNumber": "R1234", + "SerialNumber": "12345" + } +} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json new file mode 100644 index 000000000..0e1848dd2 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json @@ -0,0 +1,1822 @@ +{ + "Exposes": [ + { + "Index": 0, + "Name": "Baseboard 12 Volt", + "PowerState": "On", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 4, + "Name": "P0V83_LAN_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 0.901 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 0.875 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.786 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.763 + } + ], + "Type": "ADC" + }, + { + "Index": 3, + "Name": "P105_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.139 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.106 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.995 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.966 + } + ], + "Type": "ADC" + }, + { + "Index": 5, + "Name": "P12V_AUX", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 6, + "Name": "P1V8_PCH", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.961 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.904 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.699 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.648 + } + ], + "Type": "ADC" + }, + { + "Index": 1, + "Name": "P3V3", + "PowerState": "On", + "ScaleFactor": 0.4107, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.647 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.541 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 3.066 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.974 + } + ], + "Type": "ADC" + }, + { + "BridgeGpio": [ + { + "Name": "P3VBAT_BRIDGE_EN", + "Polarity": "High" + } + ], + "Index": 7, + "Name": "P3VBAT", + "ScaleFactor": 0.3333, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.296 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 2.457 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.138 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 8, + "Name": "PVCCIN_CPU1", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 9, + "Name": "PVCCIN_CPU2", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 14, + "Name": "PVCCIO_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 15, + "Name": "PVCCIO_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 10, + "Name": "PVDQ_ABCD_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 12, + "Name": "PVDQ_ABCD_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 11, + "Name": "PVDQ_EFGH_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 13, + "Name": "PVDQ_EFGH_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "Index": 2, + "Name": "PVNN_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.081 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.049 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.807 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.783 + } + ], + "Type": "ADC" + }, + { + "Direction": "Input", + "Index": 40, + "Name": "NMI Out", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 50, + "Name": "PCH Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 51, + "Name": "Lcp Enter Button", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 52, + "Name": "Lcp Left Button", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 53, + "Name": "Lcp Right Button", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 63, + "Name": "PU 240VA Status", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 214, + "Name": "Nmi Button", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 218, + "Name": "ID Button", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 232, + "Name": "Post Complete led0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 233, + "Name": "Post Complete led1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 233, + "Name": "CPU1 Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 234, + "Name": "Post Complete led2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 234, + "Name": "CPU1 VR Hot", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 235, + "Name": "Post Complete led3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 236, + "Name": "Post Complete led4", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 236, + "Name": "CPU1 Mem VR Hot1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 237, + "Name": "Post Complete led5", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 237, + "Name": "CPU1 Mem VR Hot2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 238, + "Name": "Post Complete led6", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 239, + "Name": "Post Complete led7", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 232, + "Name": "CPU1 Present", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 235, + "Name": "CPU1 FIVR Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 238, + "Name": "CPU1 ID0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 240, + "Name": "CPU1 CH1 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 240, + "Name": "CPU1 Mismatch", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 241, + "Name": "CPU1 CH1 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 241, + "Name": "CPU1 DIMM Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 242, + "Name": "CPU1 CH2 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 242, + "Name": "CPU2 Present", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 243, + "Name": "CPU1 CH2 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 243, + "Name": "CPU2 Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 244, + "Name": "CPU1 CH3 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 244, + "Name": "CPU2 VR Hot", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 245, + "Name": "CPU1 CH3 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 245, + "Name": "CPU2 FIVR Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 246, + "Name": "CPU1 CH4 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 246, + "Name": "CPU2 Mem VR Hot1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 247, + "Name": "CPU1 CH4 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 247, + "Name": "CPU1 Mem VR Hot2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 248, + "Name": "CPU1 CH5 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 248, + "Name": "CPU2 ID0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 249, + "Name": "CPU1 CH5 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 250, + "Name": "CPU1 CH6 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 250, + "Name": "CPU2 Mismatch", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 251, + "Name": "CPU1 CH6 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 251, + "Name": "CPU2 DIMM Thermaltrip", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 252, + "Name": "Fan1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 253, + "Name": "Fan2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 254, + "Name": "Fan3 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 255, + "Name": "Fan4 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 256, + "Name": "Fan5 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 257, + "Name": "Fan6 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 258, + "Name": "Fan7 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 259, + "Name": "Fan8 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 260, + "Name": "CPU2 CH1 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 261, + "Name": "CPU2 CH1 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 262, + "Name": "CPU2 CH2 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 263, + "Name": "CPU2 CH2 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 264, + "Name": "CPU2 CH3 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 265, + "Name": "CPU2 CH3 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 266, + "Name": "CPU2 CH4 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 267, + "Name": "CPU2 CH4 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 268, + "Name": "CPU2 CH5 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 269, + "Name": "CPU2 CH5 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 270, + "Name": "CPU2 CH6 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 271, + "Name": "CPU2 CH6 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 272, + "Name": "CPU3 CH1 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 272, + "Name": "PLD Minor Revison Bit 0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 273, + "Name": "CPU3 CH1 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 273, + "Name": "PLD Minor Revison Bit 1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 274, + "Name": "CPU3 CH2 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 274, + "Name": "PLD Minor Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 275, + "Name": "CPU3 CH2 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 275, + "Name": "PLD Minor Revison Bit 3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 276, + "Name": "CPU3 CH3 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 276, + "Name": "PLD Major Revison Bit 0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 277, + "Name": "CPU3 CH3 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 277, + "Name": "PLD Major Revison Bit 1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 278, + "Name": "CPU3 CH4 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 278, + "Name": "PLD Major Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 279, + "Name": "CPU3 CH4 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 279, + "Name": "PLD Major Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 280, + "Name": "CPU3 CH5 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 280, + "Name": "Main PLD Minor Revison Bit 0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 281, + "Name": "CPU3 CH5 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 281, + "Name": "Main PLD Minor Revison Bit 1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 282, + "Name": "CPU3 CH6 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 282, + "Name": "Main PLD Minor Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 283, + "Name": "CPU3 CH6 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 283, + "Name": "Main PLD Minor Revison Bit 3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 284, + "Name": "CPU4 CH1 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 284, + "Name": "Main PLD Major Revison Bit 0", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 285, + "Name": "CPU4 CH1 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 285, + "Name": "Main PLD Major Revison Bit 1", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 286, + "Name": "CPU4 CH2 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 286, + "Name": "Main PLD Major Revison Bit 2", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 287, + "Name": "CPU4 CH2 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 287, + "Name": "Main PLD Major Revison Bit 3", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 288, + "Name": "CPU4 CH3 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 289, + "Name": "CPU4 CH3 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 289, + "Name": "Memory Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 290, + "Name": "CPU4 CH4 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 290, + "Name": "CPU Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 291, + "Name": "CPU4 CH4 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 291, + "Name": "P5V P3V3 Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 292, + "Name": "CPU4 CH5 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 292, + "Name": "PSU Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 293, + "Name": "CPU4 CH5 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 293, + "Name": "SAS Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 294, + "Name": "CPU4 CH6 DIMM1 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 294, + "Name": "Lan Aux Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Out", + "Index": 295, + "Name": "CPU4 CH6 DIMM2 FAULT", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 295, + "Name": "PCH Pwr Fault", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 27, + "Name": "Node ID GPIO 0", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 26, + "Name": "Node ID GPIO 1", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Name": "CPU 1 Fan Connector", + "Pwm": 7, + "Status": "disabled", + "Tachs": [ + 13 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "CPU 2 Fan Connector", + "Pwm": 8, + "Status": "disabled", + "Tachs": [ + 14 + ], + "Type": "IntelFanConnector" + }, + { + "Address": "0x8", + "Class": "METemp", + "Name": "SSB Temp", + "PowerState": "BiosPost", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 103 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 98 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x7c", + "Class": "PxeBridgeTemp", + "Name": "CPU1 P12V PVCCIO VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x70", + "Class": "PxeBridgeTemp", + "Name": "CPU1 P12V PVCCIN VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x74", + "Class": "PxeBridgeTemp", + "Name": "CPU1 VR Mem ABC Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x78", + "Class": "PxeBridgeTemp", + "Name": "CPU1 VR Mem DEF Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x9c", + "Class": "PxeBridgeTemp", + "Name": "CPU2 P12V PVCCIO VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x50", + "Class": "PxeBridgeTemp", + "Name": "CPU2 P12V PVCCIN VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x94", + "Class": "PxeBridgeTemp", + "Name": "CPU2 VR Mem ABC Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x98", + "Class": "PxeBridgeTemp", + "Name": "CPU2 VR Mem DEF Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xAC", + "Class": "PxeBridgeTemp", + "Name": "VR P1V05 Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x20", + "Bus": 10, + "Class": "NodePower", + "Name": "Node Power", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 255 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 250 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "MP5920" + }, + { + "GpioPins": [ + 27, + 26 + ], + "Name": "Multi Node ID", + "Type": "MultiNodeID" + }, + { + "Address": "0x71", + "Bus": 2, + "ChannelNames": [ + "M2_Slot1", + "M2_Slot2", + "", + "" + ], + "Name": "M.2 Mux", + "Type": "PCA9543Mux" + }, + { + "Address": "0x4E", + "Bus": 6, + "Name": "Exit Air Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4B", + "Bus": 6, + "Name": "Inlet Air Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x30", + "Bus": 0, + "CpuID": 1, + "Name": "CPU 1", + "Type": "XeonCPU", + "UseWA": 1 + }, + { + "Address": "0x31", + "Bus": 0, + "CpuID": 2, + "Name": "CPU 2", + "Type": "XeonCPU", + "UseWA": 1 + } + ], + "Name": "TNP Baseboard", + "Probe": [ + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': 'D50TNP1SB'})", + "OR", + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*TNP'})" + ], + "ProductId": 153, + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$PRODUCT_MANUFACTURER", + "Model": "$PRODUCT_PRODUCT_NAME", + "PartNumber": "$PRODUCT_PART_NUMBER", + "SerialNumber": "$PRODUCT_SERIAL_NUMBER" + } +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json new file mode 100644 index 000000000..5dcd316c3 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json @@ -0,0 +1,2024 @@ +{ + "Exposes": [ + { + "Index": 0, + "Name": "A_P12V_PSU_SCALED", + "PowerState": "On", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 3, + "Name": "P105_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.139 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.106 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.995 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.966 + } + ], + "Type": "ADC" + }, + { + "Index": 5, + "Name": "P12V_AUX", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 6, + "Name": "P1V8_PCH", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.961 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.904 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.699 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.648 + } + ], + "Type": "ADC" + }, + { + "Index": 1, + "Name": "P3V3", + "PowerState": "On", + "ScaleFactor": 0.4107, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.647 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.541 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 3.066 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.974 + } + ], + "Type": "ADC" + }, + { + "BridgeGpio": [ + { + "Name": "P3VBAT_BRIDGE_EN", + "Polarity": "High" + } + ], + "Index": 7, + "Name": "P3VBAT", + "ScaleFactor": 0.3333, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.296 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 2.457 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.138 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 8, + "Name": "PVCCIN_CPU1", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 9, + "Name": "PVCCIN_CPU2", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 14, + "Name": "PVCCIO_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 15, + "Name": "PVCCIO_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 10, + "Name": "PVDQ_ABC_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 12, + "Name": "PVDQ_ABC_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 11, + "Name": "PVDQ_DEF_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 13, + "Name": "PVDQ_DEF_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "Index": 2, + "Name": "PVNN_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.081 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.049 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.807 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.783 + } + ], + "Type": "ADC" + }, + { + "BindConnector": "System Fan connector 1", + "Index": 0, + "Name": "Fan 1a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 1", + "Index": 1, + "Name": "Fan 1b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 2", + "Index": 2, + "Name": "Fan 2a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 2", + "Index": 3, + "Name": "Fan 2b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 3", + "Index": 4, + "Name": "Fan 3a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 3", + "Index": 5, + "Name": "Fan 3b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 4", + "Index": 6, + "Name": "Fan 4a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 4", + "Index": 7, + "Name": "Fan 4b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 5", + "Index": 8, + "Name": "Fan 5a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 5", + "Index": 9, + "Name": "Fan 5b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 6", + "Index": 10, + "Name": "Fan 6a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 6", + "Index": 11, + "Name": "Fan 6b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 7", + "Index": 12, + "Name": "Fan 7a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 7", + "Index": 13, + "Name": "Fan 7b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 8", + "Index": 14, + "Name": "Fan 8a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 8", + "Index": 15, + "Name": "Fan 8b", + "Type": "AspeedFan" + }, + { + "C1": 92.16, + "C2": 107.52, + "MaxCFM": 17.5, + "Name": "System Airflow", + "TachMaxPercent": 100, + "TachMinPercent": 20, + "Tachs": [ + "Fan 1a", + "Fan 1b", + "Fan 2a", + "Fan 2b", + "Fan 3a", + "Fan 3b", + "Fan 4a", + "Fan 4b", + "Fan 5a", + "Fan 5b", + "Fan 6a", + "Fan 6b", + "Fan 7a", + "Fan 7b", + "Fan 8a", + "Fan 8b" + ], + "Type": "CFMSensor" + }, + { + "AlphaF": 4.352, + "AlphaS": 0.512, + "Name": "Exit Air Temp", + "PowerFactorMax": 1.0, + "PowerFactorMin": 0.4, + "QMax": 88, + "QMin": 15, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 85 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 80 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "ExitAirTempSensor" + }, + { + "AllowedFailures": 1, + "Name": "FanRedundancy", + "Type": "FanRedundancy" + }, + { + "Direction": "Input", + "Index": 40, + "Name": "NMI Input", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 214, + "Name": "SMI Input", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 218, + "Name": "ID Button", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Name": "System Fan connector 1", + "Pwm": 0, + "Tachs": [ + 0, + 1 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 2", + "Pwm": 1, + "Tachs": [ + 2, + 3 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 3", + "Pwm": 2, + "Tachs": [ + 4, + 5 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 4", + "Pwm": 3, + "Tachs": [ + 6, + 7 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 5", + "Pwm": 4, + "Tachs": [ + 8, + 9 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 6", + "Pwm": 5, + "Tachs": [ + 10, + 11 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 7", + "Pwm": 6, + "Tachs": [ + 12, + 13 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 8", + "Pwm": 7, + "Tachs": [ + 14, + 15 + ], + "Type": "IntelFanConnector" + }, + { + "Address": "0x8", + "Class": "METemp", + "Name": "SSB Temp", + "PowerState": "BiosPost", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 103 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 98 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xC4", + "Class": "MpsBridgeTemp", + "Name": "CPU1 P12V PVCCIN VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xB4", + "Class": "PxeBridgeTemp", + "Name": "CPU1 P12V PVCCIO VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xDC", + "Class": "PxeBridgeTemp", + "Name": "CPU1 VR Mem ABCD Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xDC", + "Class": "PxeBridgeTemp", + "Name": "CPU1 VR Mem EFGH Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x4A", + "Class": "IRBridgeTemp", + "Name": "CPU1 VR P1V8", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xCC", + "Class": "MpsBridgeTemp", + "Name": "CPU2 P12V PVCCIN VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xD4", + "Class": "PxeBridgeTemp", + "Name": "CPU2 P12V PVCCIO VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xB0", + "Class": "PxeBridgeTemp", + "Name": "CPU2 VR Mem ABCD Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xEC", + "Class": "PxeBridgeTemp", + "Name": "CPU2 VR Mem EFGH Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x4C", + "Class": "IRBridgeTemp", + "Name": "CPU2 VR P1V8", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x71", + "Bus": 2, + "ChannelNames": [ + "M2Slot1", + "M2Slot2" + ], + "Name": "M2 Mux", + "Type": "PCA9543Mux" + }, + { + "Address": "0x72", + "Bus": 2, + "ChannelNames": [ + "Pcie_Slot_1", + "Pcie_Slot_2", + "", + "FruChannel" + ], + "Name": "Riser 1 Mux", + "Type": "PCA9545Mux" + }, + { + "Address": "0x73", + "Bus": 2, + "ChannelNames": [ + "Pcie_Slot_1", + "Pcie_Slot_2", + "", + "FruChannel" + ], + "Name": "Riser 2 Mux", + "Type": "PCA9545Mux" + }, + { + "Address": "0x73", + "Bus": 9, + "ChannelNames": [ + "MemoryChannel1", + "MemoryChannel2", + "MemoryChannel3", + "MemoryChannel4" + ], + "Name": "Memory Mux", + "Type": "PCA9545Mux" + }, + { + "Address": "0x74", + "Bus": 2, + "ChannelNames": [ + "Pcie_Slot_1", + "Pcie_Slot_2", + "Pcie_Slot_3", + "Pcie_Slot_4" + ], + "Name": "PCIE Mux", + "Type": "PCA9546Mux" + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "Exit Air Temp" + ], + "Name": "Exit Air Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 65.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 1a", + "Fan 1b" + ], + "Name": "Fan 1", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 1" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 2a", + "Fan 2b" + ], + "Name": "Fan 2", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 2" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 3a", + "Fan 3b" + ], + "Name": "Fan 3", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 3" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 4a", + "Fan 4b" + ], + "Name": "Fan 4", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 4" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 5a", + "Fan 5b" + ], + "Name": "Fan 5", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 5" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 6a", + "Fan 6b" + ], + "Name": "Fan 6", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 6" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 7a", + "Fan 7b" + ], + "Name": "Fan 7", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 7" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 8a", + "Fan 8b" + ], + "Name": "Fan 8", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 8" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "BMC Temp" + ], + "Name": "BMC Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [ABC]\\d+ CPU1" + ], + "Name": "CPU1 DIMM ABC", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [DEF]\\d+ CPU1" + ], + "Name": "CPU1 DIMM DEF", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [ABC]\\d+ CPU2" + ], + "Name": "CPU2 DIMM ABC", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right", + "PSU" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [DEF]\\d+ CPU2" + ], + "Name": "CPU2 DIMM DEF", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DTS CPU1" + ], + "Name": "DTS CPU1", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DTS CPU2" + ], + "Name": "DTS CPU2", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right", + "PSU" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "Left Rear Temp" + ], + "Name": "Left Rear Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 60.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "Right Rear Board" + ], + "Name": "Right Rear Board", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 60.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "SSB Temp" + ], + "Name": "SSB Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 75.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "CPU1 VR Mem ABCD Temp", + "CPU1 VR Mem ABCD Temp", + "CPU1 VR P1V8" + ], + "Name": "CPU 1 VR Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 85.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "CPU2 VR Mem ABCD Temp", + "CPU2 VR Mem ABCD Temp", + "CPU2 VR P1V8" + ], + "Name": "CPU 2 VR Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 85.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right", + "PSU" + ] + }, + { + "FailSafePercent": 100, + "MinThermalOutput": 30, + "Name": "Left", + "Type": "Pid.Zone" + }, + { + "FailSafePercent": 100, + "MinThermalOutput": 30, + "Name": "Right", + "Type": "Pid.Zone" + }, + { + "FailSafePercent": 100, + "MinThermalOutput": 30, + "Name": "PSU", + "Type": "Pid.Zone" + }, + { + "Class": "Ceiling", + "Inputs": [ + "Front Panel Temp" + ], + "Name": "Front Panel UCC", + "NegativeHysteresis": 2, + "Output": [ + 70.0, + 80.0 + ], + "PositiveHysteresis": 0, + "Profiles": [ + "Acoustic" + ], + "Reading": [ + 22.0, + 32.0 + ], + "Type": "Stepwise", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "Floor", + "Inputs": [ + "Front Panel Temp" + ], + "Name": "Front Panel LCC", + "NegativeHysteresis": 2, + "Output": [ + 50.0, + 60.0 + ], + "PositiveHysteresis": 0, + "Reading": [ + 20.0, + 30.0 + ], + "Type": "Stepwise", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Address": "0x4A", + "Bus": 6, + "Name": "BMC Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4B", + "Bus": 6, + "Name": "Right Rear Board Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x49", + "Bus": 6, + "Name": "Left Rear Board Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x48", + "Bus": 6, + "Name": "PCH M.2 Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4f", + "Bus": 6, + "Name": "Inlet BRD Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4D", + "Bus": "0x1", + "Name": "Front Panel Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 55 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 50 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x30", + "Bus": 0, + "CpuID": 1, + "Name": "CPU 1", + "PresenceGpio": [ + { + "Name": "CPU1_PRESENCE", + "Polarity": "Low" + } + ], + "Type": "XeonCPU", + "UseWA": 1 + }, + { + "Address": "0x31", + "Bus": 0, + "CpuID": 2, + "Name": "CPU 2", + "PresenceGpio": [ + { + "Name": "CPU2_PRESENCE", + "Polarity": "Low" + } + ], + "Type": "XeonCPU", + "UseWA": 1 + } + ], + "Name": "WC Baseboard", + "Probe": [ + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': 'WilsonCity'})", + "OR", + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*WC'})" + ], + "ProductId": 145, + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$PRODUCT_MANUFACTURER", + "Model": "$PRODUCT_PRODUCT_NAME", + "PartNumber": "$PRODUCT_PART_NUMBER", + "SerialNumber": "$PRODUCT_SERIAL_NUMBER" + }, + "xyz.openbmc_project.Inventory.Decorator.AssetTag": { + "AssetTag": "$PRODUCT_ASSET_TAG" + }, + "xyz.openbmc_project.Inventory.Item.System": {} +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json new file mode 100644 index 000000000..71a5540da --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json @@ -0,0 +1,2017 @@ +{ + "Exposes": [ + { + "Index": 0, + "Name": "A_P12V_PSU_SCALED", + "PowerState": "On", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 3, + "Name": "P105_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.139 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.106 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.995 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.966 + } + ], + "Type": "ADC" + }, + { + "Index": 5, + "Name": "P12V_AUX", + "ScaleFactor": 0.1124, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 13.494 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 13.101 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 10.945 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 10.616 + } + ], + "Type": "ADC" + }, + { + "Index": 6, + "Name": "P1V8_PCH", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.961 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.904 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.699 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.648 + } + ], + "Type": "ADC" + }, + { + "Index": 1, + "Name": "P3V3", + "PowerState": "On", + "ScaleFactor": 0.4107, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.647 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.541 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 3.066 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.974 + } + ], + "Type": "ADC" + }, + { + "BridgeGpio": [ + { + "Name": "P3VBAT_BRIDGE_EN", + "Polarity": "High" + } + ], + "Index": 7, + "Name": "P3VBAT", + "ScaleFactor": 0.3333, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 3.296 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 3.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 2.457 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 2.138 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 8, + "Name": "PVCCIN_CPU1", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 9, + "Name": "PVCCIN_CPU2", + "PowerState": "On", + "ScaleFactor": 0.7505, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 2.151 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 2.088 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.418 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.376 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 14, + "Name": "PVCCIO_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 15, + "Name": "PVCCIO_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.19 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.155 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.752 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.729 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 10, + "Name": "PVDQ_ABC_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 12, + "Name": "PVDQ_ABC_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 1, + "Index": 11, + "Name": "PVDQ_DEF_CPU1", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "CPURequired": 2, + "Index": 13, + "Name": "PVDQ_DEF_CPU2", + "PowerState": "On", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.301 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.263 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 1.138 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 1.104 + } + ], + "Type": "ADC" + }, + { + "Index": 2, + "Name": "PVNN_PCH_AUX", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 1.081 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 1.049 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 0.807 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0.783 + } + ], + "Type": "ADC" + }, + { + "BindConnector": "System Fan connector 1", + "Index": 0, + "Name": "Fan 1a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 1", + "Index": 1, + "Name": "Fan 1b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 2", + "Index": 2, + "Name": "Fan 2a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 2", + "Index": 3, + "Name": "Fan 2b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 3", + "Index": 4, + "Name": "Fan 3a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 3", + "Index": 5, + "Name": "Fan 3b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 4", + "Index": 6, + "Name": "Fan 4a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 4", + "Index": 7, + "Name": "Fan 4b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 5", + "Index": 8, + "Name": "Fan 5a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 5", + "Index": 9, + "Name": "Fan 5b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 6", + "Index": 10, + "Name": "Fan 6a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 6", + "Index": 11, + "Name": "Fan 6b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 7", + "Index": 12, + "Name": "Fan 7a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 7", + "Index": 13, + "Name": "Fan 7b", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 8", + "Index": 14, + "Name": "Fan 8a", + "Type": "AspeedFan" + }, + { + "BindConnector": "System Fan connector 8", + "Index": 15, + "Name": "Fan 8b", + "Type": "AspeedFan" + }, + { + "C1": 92.16, + "C2": 107.52, + "MaxCFM": 17.5, + "Name": "System Airflow", + "TachMaxPercent": 100, + "TachMinPercent": 20, + "Tachs": [ + "Fan 1a", + "Fan 1b", + "Fan 2a", + "Fan 2b", + "Fan 3a", + "Fan 3b", + "Fan 4a", + "Fan 4b", + "Fan 5a", + "Fan 5b", + "Fan 6a", + "Fan 6b", + "Fan 7a", + "Fan 7b", + "Fan 8a", + "Fan 8b" + ], + "Type": "CFMSensor" + }, + { + "AlphaF": 4.352, + "AlphaS": 0.512, + "Name": "Exit Air Temp", + "PowerFactorMax": 1.0, + "PowerFactorMin": 0.4, + "QMax": 88, + "QMin": 15, + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 85 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 80 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "ExitAirTempSensor" + }, + { + "AllowedFailures": 1, + "Name": "FanRedundancy", + "Type": "FanRedundancy" + }, + { + "Direction": "Input", + "Index": 214, + "Name": "SMI Input", + "Polarity": "High", + "Type": "Gpio" + }, + { + "Direction": "Input", + "Index": 218, + "Name": "ID Button", + "Polarity": "Low", + "Type": "Gpio" + }, + { + "Name": "System Fan connector 1", + "Pwm": 0, + "Tachs": [ + 0, + 1 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 2", + "Pwm": 1, + "Tachs": [ + 2, + 3 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 3", + "Pwm": 2, + "Tachs": [ + 4, + 5 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 4", + "Pwm": 3, + "Tachs": [ + 6, + 7 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 5", + "Pwm": 4, + "Tachs": [ + 8, + 9 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 6", + "Pwm": 5, + "Tachs": [ + 10, + 11 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 7", + "Pwm": 6, + "Tachs": [ + 12, + 13 + ], + "Type": "IntelFanConnector" + }, + { + "Name": "System Fan connector 8", + "Pwm": 7, + "Tachs": [ + 14, + 15 + ], + "Type": "IntelFanConnector" + }, + { + "Address": "0x8", + "Class": "METemp", + "Name": "SSB Temp", + "PowerState": "BiosPost", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 103 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 98 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xC4", + "Class": "MpsBridgeTemp", + "Name": "CPU1 P12V PVCCIN VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xB4", + "Class": "PxeBridgeTemp", + "Name": "CPU1 P12V PVCCIO VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xDC", + "Class": "PxeBridgeTemp", + "Name": "CPU1 VR Mem ABCD Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xDC", + "Class": "PxeBridgeTemp", + "Name": "CPU1 VR Mem EFGH Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x4A", + "Class": "IRBridgeTemp", + "Name": "CPU1 VR P1V8", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xCC", + "Class": "MpsBridgeTemp", + "Name": "CPU2 P12V PVCCIN VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xD4", + "Class": "PxeBridgeTemp", + "Name": "CPU2 P12V PVCCIO VR Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xB0", + "Class": "PxeBridgeTemp", + "Name": "CPU2 VR Mem ABCD Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0xEC", + "Class": "PxeBridgeTemp", + "Name": "CPU2 VR Mem EFGH Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x4C", + "Class": "IRBridgeTemp", + "Name": "CPU2 VR P1V8", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "IpmbSensor" + }, + { + "Address": "0x71", + "Bus": 2, + "ChannelNames": [ + "M2Slot1", + "M2Slot2" + ], + "Name": "M2 Mux", + "Type": "PCA9543Mux" + }, + { + "Address": "0x72", + "Bus": 2, + "ChannelNames": [ + "Pcie_Slot_1", + "Pcie_Slot_2", + "", + "FruChannel" + ], + "Name": "Riser 1 Mux", + "Type": "PCA9545Mux" + }, + { + "Address": "0x73", + "Bus": 2, + "ChannelNames": [ + "Pcie_Slot_1", + "Pcie_Slot_2", + "", + "FruChannel" + ], + "Name": "Riser 2 Mux", + "Type": "PCA9545Mux" + }, + { + "Address": "0x73", + "Bus": 9, + "ChannelNames": [ + "MemoryChannel1", + "MemoryChannel2", + "MemoryChannel3", + "MemoryChannel4" + ], + "Name": "Memory Mux", + "Type": "PCA9545Mux" + }, + { + "Address": "0x74", + "Bus": 2, + "ChannelNames": [ + "Pcie_Slot_1", + "Pcie_Slot_2", + "Pcie_Slot_3", + "Pcie_Slot_4" + ], + "Name": "PCIE Mux", + "Type": "PCA9546Mux" + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "Exit Air Temp" + ], + "Name": "Exit Air Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 65.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 1a", + "Fan 1b" + ], + "Name": "Fan 1", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 1" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 2a", + "Fan 2b" + ], + "Name": "Fan 2", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 2" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 3a", + "Fan 3b" + ], + "Name": "Fan 3", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 3" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 4a", + "Fan 4b" + ], + "Name": "Fan 4", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 4" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 5a", + "Fan 5b" + ], + "Name": "Fan 5", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 5" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 6a", + "Fan 6b" + ], + "Name": "Fan 6", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 6" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 7a", + "Fan 7b" + ], + "Name": "Fan 7", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 7" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "fan", + "FFGainCoefficient": 1.0, + "FFOffCoefficient": 0.0, + "ICoefficient": 0.0, + "ILimitMax": 0.0, + "ILimitMin": 0.0, + "Inputs": [ + "Fan 8a", + "Fan 8b" + ], + "Name": "Fan 8", + "NegativeHysteresis": 0.0, + "OutLimitMax": 100.0, + "OutLimitMin": 30.0, + "Outputs": [ + "Pwm 8" + ], + "PCoefficient": 0.0, + "PositiveHysteresis": 0.0, + "SlewNeg": 0.0, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "BMC Temp" + ], + "Name": "BMC Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [ABC]\\d+ CPU1" + ], + "Name": "CPU1 DIMM ABC", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [DEF]\\d+ CPU1" + ], + "Name": "CPU1 DIMM DEF", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [ABC]\\d+ CPU2" + ], + "Name": "CPU2 DIMM ABC", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right", + "PSU" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DIMM [DEF]\\d+ CPU2" + ], + "Name": "CPU2 DIMM DEF", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DTS CPU1" + ], + "Name": "DTS CPU1", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "DTS CPU2" + ], + "Name": "DTS CPU2", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 80.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right", + "PSU" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "Left Rear Temp" + ], + "Name": "Left Rear Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 60.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "Right Rear Board" + ], + "Name": "Right Rear Board", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 60.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "SSB Temp" + ], + "Name": "SSB Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 75.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "CPU1 VR Mem ABCD Temp", + "CPU1 VR Mem ABCD Temp", + "CPU1 VR P1V8" + ], + "Name": "CPU 1 VR Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 85.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Left" + ] + }, + { + "Class": "temp", + "FFGainCoefficient": 0.0, + "FFOffCoefficient": 0.0, + "ICoefficient": -1.0, + "ILimitMax": 100, + "ILimitMin": 30, + "Inputs": [ + "CPU2 VR Mem ABCD Temp", + "CPU2 VR Mem ABCD Temp", + "CPU2 VR P1V8" + ], + "Name": "CPU 2 VR Temp", + "NegativeHysteresis": 5.0, + "OutLimitMax": 100, + "OutLimitMin": 30, + "Outputs": [], + "PCoefficient": -0.15, + "PositiveHysteresis": 0.0, + "SetPoint": 85.0, + "SlewNeg": -1, + "SlewPos": 0.0, + "Type": "Pid", + "Zones": [ + "Right", + "PSU" + ] + }, + { + "FailSafePercent": 100, + "MinThermalOutput": 30, + "Name": "Left", + "Type": "Pid.Zone" + }, + { + "FailSafePercent": 100, + "MinThermalOutput": 30, + "Name": "Right", + "Type": "Pid.Zone" + }, + { + "FailSafePercent": 100, + "MinThermalOutput": 30, + "Name": "PSU", + "Type": "Pid.Zone" + }, + { + "Class": "Ceiling", + "Inputs": [ + "Front Panel Temp" + ], + "Name": "Front Panel UCC", + "NegativeHysteresis": 2, + "Output": [ + 70.0, + 80.0 + ], + "PositiveHysteresis": 0, + "Profiles": [ + "Acoustic" + ], + "Reading": [ + 22.0, + 32.0 + ], + "Type": "Stepwise", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Class": "Floor", + "Inputs": [ + "Front Panel Temp" + ], + "Name": "Front Panel LCC", + "NegativeHysteresis": 2, + "Output": [ + 50.0, + 60.0 + ], + "PositiveHysteresis": 0, + "Reading": [ + 20.0, + 30.0 + ], + "Type": "Stepwise", + "Zones": [ + "Left", + "Right" + ] + }, + { + "Address": "0x4A", + "Bus": 6, + "Name": "BMC Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4B", + "Bus": 6, + "Name": "Right Rear Board Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x49", + "Bus": 6, + "Name": "Left Rear Board Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x48", + "Bus": 6, + "Name": "PCH M.2 Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4f", + "Bus": 6, + "Name": "Inlet BRD Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 115 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 110 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x4D", + "Bus": "0x1", + "Name": "Front Panel Temp", + "Thresholds": [ + { + "Direction": "greater than", + "Name": "upper critical", + "Severity": 1, + "Value": 55 + }, + { + "Direction": "greater than", + "Name": "upper non critical", + "Severity": 0, + "Value": 50 + }, + { + "Direction": "less than", + "Name": "lower non critical", + "Severity": 0, + "Value": 5 + }, + { + "Direction": "less than", + "Name": "lower critical", + "Severity": 1, + "Value": 0 + } + ], + "Type": "TMP75" + }, + { + "Address": "0x30", + "Bus": 0, + "CpuID": 1, + "Name": "CPU 1", + "PresenceGpio": [ + { + "Name": "CPU1_PRESENCE", + "Polarity": "Low" + } + ], + "Type": "XeonCPU", + "UseWA": 1 + }, + { + "Address": "0x31", + "Bus": 0, + "CpuID": 2, + "Name": "CPU 2", + "PresenceGpio": [ + { + "Name": "CPU2_PRESENCE", + "Polarity": "Low" + } + ], + "Type": "XeonCPU", + "UseWA": 1 + } + ], + "Name": "WP Baseboard", + "Probe": [ + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': 'WilsonPoint'})", + "OR", + "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*WP'})" + ], + "ProductId": 154, + "Type": "Board", + "xyz.openbmc_project.Inventory.Decorator.Asset": { + "Manufacturer": "$PRODUCT_MANUFACTURER", + "Model": "$PRODUCT_PRODUCT_NAME", + "PartNumber": "$PRODUCT_PART_NUMBER", + "SerialNumber": "$PRODUCT_SERIAL_NUMBER" + }, + "xyz.openbmc_project.Inventory.Decorator.AssetTag": { + "AssetTag": "$PRODUCT_ASSET_TAG" + }, + "xyz.openbmc_project.Inventory.Item.System": {} +} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager_%.bbappend new file mode 100644 index 000000000..b8b38ecff --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/configuration/entity-manager_%.bbappend @@ -0,0 +1,15 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" +SRC_URI_append = " file://WC-Baseboard.json \ + file://WP-Baseboard.json \ + file://TNP-baseboard.json \ + file://FCXXPDBASSMBL_PDB.json \ + file://OPB2RH-Chassis.json \ + file://CYP-baseboard.json \ + file://MIDPLANE-2U2X12SWITCH.json" + +RDEPENDS_${PN} += " default-fru" + +do_install_append(){ + install -d ${D}/usr/share/entity-manager/configurations + install -m 0444 ${WORKDIR}/*.json ${D}/usr/share/entity-manager/configurations +} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/obmc-console.conf b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/obmc-console.conf new file mode 100644 index 000000000..1d332e2a2 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/obmc-console.conf @@ -0,0 +1,3 @@ +baud = 921600 +local-tty = ttyS3 +local-tty-baud = 921600 diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/obmc-console@.service b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/obmc-console@.service new file mode 100644 index 000000000..7fb8f79d3 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/obmc-console@.service @@ -0,0 +1,21 @@ +[Unit] +Description=Phosphor Console Muxer listening on device /dev/%I +BindsTo=dev-%i.device +After=dev-%i.device + +[Service] +ExecStartPre=/usr/bin/sol-option-check.sh +ExecStartPre=/bin/sh -c 'echo -n "uart3" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart1' +ExecStartPre=/bin/sh -c 'echo -n "uart1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart3' +ExecStartPre=/bin/sh -c 'echo -n "io1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart4' +ExecStartPre=/bin/sh -c 'echo -n "uart4" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/io1' +ExecStart=/usr/bin/env obmc-console-server --config {sysconfdir}/obmc-console.conf %i +ExecStopPost=/bin/sh -c 'echo -n "io1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart1' +ExecStopPost=/bin/sh -c 'echo -n "io3" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart3' +ExecStopPost=/bin/sh -c 'echo -n "io4" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart4' +ExecStopPost=/bin/sh -c 'echo -n "uart1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/io1' +SyslogIdentifier=obmc-console-server +Restart=always + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/sol-option-check.sh b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/sol-option-check.sh new file mode 100755 index 000000000..ef32fcb9a --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console/sol-option-check.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# Copyright 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +if [ $(grep 192000000 /sys/class/tty/ttyS0/uartclk | wc -l) != 0 ]; then + echo "hs-uart" + sed -i -e 's/115200/921600/g' /etc/obmc-console.conf +else + echo "normal uart" + sed -i -e 's/921600/115200/g' /etc/obmc-console.conf +fi diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console_%.bbappend b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console_%.bbappend new file mode 100644 index 000000000..e808e4929 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/console/obmc-console_%.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend_intel-ast2500 := "${THISDIR}/${PN}:" +OBMC_CONSOLE_HOST_TTY = "ttyS2" +SRC_URI += "file://sol-option-check.sh" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/sol-option-check.sh ${D}${bindir} +} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru.bb new file mode 100644 index 000000000..b8b8f7524 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru.bb @@ -0,0 +1,39 @@ +SUMMARY = "Default Fru" +DESCRIPTION = "Installs a default fru file to image" + +inherit systemd + +SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service" + +S = "${WORKDIR}" +SRC_URI = "file://checkFru.sh \ + file://SetBaseboardFru.service \ + file://create_fru.py" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +RDEPENDS_${PN} = "bash" + +python do_compile() { + import sys + workdir = d.getVar('WORKDIR', True) + sys.path.insert(0, workdir) + from create_fru import create_fru + create_fru('S2600WFT') + create_fru('WilsonCity') + create_fru('WilsonPoint') + create_fru('M50CYP2SB2U') + create_fru('D50TNP1SB') +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh + + install -d ${D}${sysconfdir}/fru + cp ${S}/*.fru.bin ${D}/${sysconfdir}/fru + + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/SetBaseboardFru.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/SetBaseboardFru.service new file mode 100644 index 000000000..dec53725e --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/SetBaseboardFru.service @@ -0,0 +1,9 @@ +[Unit] +Description=Reads GPIO and Loads the FRU + +[Service] +ExecStart=/usr/bin/checkFru.sh +Type=oneshot + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/checkFru.sh new file mode 100755 index 000000000..4b7910198 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/checkFru.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# this script checks the gpio id and loads the correct baseboard fru +fruFile="/etc/fru/baseboard.fru.bin" +idGpio=( 8 9 10 11 12 53) +result=0 +idx=0 + +if [ -f $fruFile ]; then + exit 0 +fi + +cd /etc/fru +for gpio in "${idGpio[@]}" +do + echo $gpio > /sys/class/gpio/export + typeset -i value=$(cat /sys/class/gpio/gpio$gpio/value) + value=$((value << idx)) + result=$((result | value)) + idx=$((idx+1)) +done + +# wp +if (($result == 62)); then + cat WilsonPoint.fru.bin > $fruFile +# wc +elif (($result == 45)); then + cat WilsonCity.fru.bin > $fruFile +# cyp +elif (($result == 60)); then + cat M50CYP2SB2U.fru.bin > $fruFile +# tnp +elif (($result == 12)); then + cat D50TNP1SB.fru.bin > $fruFile +# default to wft +else + cat S2600WFT.fru.bin > $fruFile +fi diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/create_fru.py b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/create_fru.py new file mode 100755 index 000000000..7f11cbf2d --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/fru/default-fru/create_fru.py @@ -0,0 +1,154 @@ +#!/usr/bin/python3 + +""" +This script generates a default baseboard fru file. +""" + + +def create_fru(name): + if len(name) > 16: + raise Exception('Product Name Too Large: {}'.format(name)) + + fill_char = ord('.') + eof = 0xC1 + + filename = '{}.fru.bin'.format(name) + name = name.encode('ascii') + + name_len = (0x3 << 6) | len(name) + + # internal area + internal = [0x01] + ([0] * 6) + [0x01] + + # chassis area + chassis = [0x01, # Chassis Info Area Format Version Bit Fields + 0xFF, # Chassis Info Area Length (in multiples of 8 bytes) + 0x17] # Chassis Type (Main Server Chassis) + + fill_len = 18 + + # Chassis Part Number + chassis += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) + + # Chassis Serial Number + chassis += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) + + fill_len = 31 + chassis += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) # Info AM1 + chassis += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) # Info AM2 + + chassis.append(eof) + + chassis.append(0) # need room for checksum + + while len(chassis) % 8: # pad + chassis.append(0) + + chassis[1] = int(len(chassis) / 8) # populate length + chassis[-1] = (256 - sum(chassis)) & 0xFF # populate checksum + + # board area + board = [0x1, # Board Info Area Format Version Bit Fields + 0xFF, # Board Info Area Length (in multiples of 8 bytes) + 0x0, # Language Code + 0x0, # Mfg. Date/Time + 0x0, # Mfg. Date/Time + 0x0, # Mfg. Date/Time + 0xD1] # Product Manufacturer Name Len + + corp = b'Intel Corporation' + board += bytearray(corp) # Manufacturer Name + + board.append(name_len) + board += bytearray(name) # Board Product Name + + fill_len = 12 + board += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) # board SN + + fill_len = 10 + board += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) # board PN + + version = b'FRU Ver 0.01' + + board += [0x3 << 6 | len(version)] # FRU File version ID string + board += bytearray(version) + + board.append(eof) + + board.append(0) # need room for checksum + + while len(board) % 8: + board.append(0) + + board[1] = int(len(board) / 8) # populate length + board[-1] = (256 - sum(board)) & 0xFF # populate checksum + + # product area + product = [1, # Product Info Area Format Version Bit Fields + 0xFF, # Product Info Area Length (in multiples of 8 bytes) + 0x0, # Language Code + 0xD1] # Product Manufacturer Name Len + + product += bytearray(corp) # Manufacturer Name + + product.append(name_len) # Product Name Len + product += bytearray(name) # Product Name + + fill_len = 10 + + # Product Part Number + product += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) + + # Product Version + fill_len = 20 + product += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) + + # Product Serial Number + fill_len = 12 + product += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) + + # Asset Tag + fill_len = 20 + product += [0x3 << 6 | fill_len] + ([fill_char] * fill_len) + + product.append(0xC0) # FRU File ID (Not used) + product.append(eof) + + product.append(0) # need room for checksum + + while len(product) % 8: + product.append(0) + + product[1] = int(len(product) / 8) + product[-1] = (256 - sum(product)) & 0xFF + + header = [0x1] + length = 1 # internal + header.append(length) + length += int(len(internal) / 8) + header.append(length) + length += int(len(chassis) / 8) + header.append(length) + length += int(len(board) / 8) + header.append(length) + header.append(0) + header.append(0) + header.append((256 - sum(header)) & 0xFF) + + result = header + internal + chassis + board + product + + while len(result) < 0x1FF: + result.append(0) + + result = bytearray(result) + + # print(result) + + with open(filename, 'wb') as out: + out.write(result) + + +if __name__ == '__main__': + product_name = input('Enter Product Name: ') + create_fru(product_name) + diff --git a/meta-openbmc-mods/meta-ast2500/recipes-phosphor/workbook/wolfpass-config.bb b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/workbook/wolfpass-config.bb new file mode 100644 index 000000000..c91053536 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes-phosphor/workbook/wolfpass-config.bb @@ -0,0 +1,10 @@ +SUMMARY = "Wolfpass board wiring" +DESCRIPTION = "Board wiring information for the Wolfpass system." +PR = "r1" + +inherit config-in-skeleton + +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRCREV = "946064239016e38cd1cc346047b1d26960c06cdb" +SKELETON_URI = "git://git@github.com/Intel-BMC/skeleton.git;protocol=ssh;branch=intel" diff --git a/meta-openbmc-mods/meta-ast2500/recipes.txt b/meta-openbmc-mods/meta-ast2500/recipes.txt new file mode 100644 index 000000000..3ec3f4a42 --- /dev/null +++ b/meta-openbmc-mods/meta-ast2500/recipes.txt @@ -0,0 +1,2 @@ +recipes-kernel - The kernel and generic applications/libraries with strong kernel dependencies +recipes-phosphor - Phosphor OpenBMC applications and configuration diff --git a/meta-openbmc-mods/meta-common-small/conf/layer.conf b/meta-openbmc-mods/meta-common-small/conf/layer.conf new file mode 100644 index 000000000..666ddbcab --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/conf/layer.conf @@ -0,0 +1,11 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "common-small" +BBFILE_PATTERN_common-small = "^${LAYERDIR}/" +BBFILE_PRIORITY_common-small = "10" +LAYERSERIES_COMPAT_common-small = "warrior" diff --git a/meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend b/meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend new file mode 100644 index 000000000..12cb9fd48 --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend @@ -0,0 +1,14 @@ +# add some configuration overrides for systemd default /usr/lib/tmpfiles.d/ + +LICENSE = "GPL-2.0" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# Disable udev hwdb +RRECOMMENDS_${PN}_remove += "udev-hwdb" +PACKAGES_remove += "udev-hwdb" + +do_install_append() { + rm -rf ${D}${rootlibexecdir}/udev/hwdb.d + rm -f ${D}${sysconfdir}/udev/hwdb.bin +} diff --git a/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/files/0001-hw-arm-aspeed-Add-an-intel-ast2500-machine-type.patch b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/files/0001-hw-arm-aspeed-Add-an-intel-ast2500-machine-type.patch new file mode 100644 index 000000000..cca6c838b --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/files/0001-hw-arm-aspeed-Add-an-intel-ast2500-machine-type.patch @@ -0,0 +1,83 @@ +From 2ad1d60c39a2a9a08bcd29188362efba4e92e546 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Tue, 9 Apr 2019 16:18:07 -0700 +Subject: [PATCH] hw/arm/aspeed: Add an intel-ast2500 machine type + +Include the HW strap setting and some I2C temperature sensors. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + hw/arm/aspeed.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c +index 465e65f323..80e8466aa9 100644 +--- a/hw/arm/aspeed.c ++++ b/hw/arm/aspeed.c +@@ -60,6 +60,21 @@ struct AspeedBoardState { + SCU_HW_STRAP_MAC0_RGMII) & \ + ~SCU_HW_STRAP_2ND_BOOT_WDT) + ++/* intel ast2500 hardware value: 0xF3CCC286 */ ++#define INTEL_AST2500_BMC_HW_STRAP1 (( \ ++ AST2500_HW_STRAP1_DEFAULTS | \ ++ SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ ++ SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ ++ SCU_AST2500_HW_STRAP_UART_DEBUG | \ ++ SCU_AST2500_HW_STRAP_ESPI_ENABLE | \ ++ SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ ++ SCU_HW_STRAP_GPIOE_PT_EN | \ ++ SCU_AST2400_HW_STRAP_ACPI_DIS | \ ++ SCU_HW_STRAP_CLK_48M_IN | \ ++ SCU_HW_STRAP_VGA_CLASS_CODE | \ ++ SCU_HW_STRAP_MAC1_RGMII) & \ ++ ~SCU_HW_STRAP_2ND_BOOT_WDT) ++ + /* Romulus hardware value: 0xF10AD206 */ + #define ROMULUS_BMC_HW_STRAP1 ( \ + AST2500_HW_STRAP1_DEFAULTS | \ +@@ -281,6 +296,24 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc) + i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32); + } + ++static void intel_ast2500_i2c_init(AspeedBoardState *bmc) ++{ ++ AspeedSoCState *soc = &bmc->soc; ++ DeviceState *dev; ++ ++ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp421", 0x4d); ++ object_property_set_int(OBJECT(dev), 50000, "temperature0", &error_abort); ++ /* The s2600wf expects a TMP75 but a TMP105 is compatible */ ++ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x48); ++ object_property_set_int(OBJECT(dev), 50000, "temperature", &error_abort); ++ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x49); ++ object_property_set_int(OBJECT(dev), 50000, "temperature", &error_abort); ++ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x4a); ++ object_property_set_int(OBJECT(dev), 50000, "temperature", &error_abort); ++ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 6), "tmp105", 0x4b); ++ object_property_set_int(OBJECT(dev), 50000, "temperature", &error_abort); ++} ++ + static void romulus_bmc_i2c_init(AspeedBoardState *bmc) + { + AspeedSoCState *soc = &bmc->soc; +@@ -390,6 +423,15 @@ static const AspeedBoardConfig aspeed_boards[] = { + .spi_model = "mx25l25635e", + .num_cs = 1, + .i2c_init = ast2500_evb_i2c_init, ++ }, { ++ .name = MACHINE_TYPE_NAME("intel-ast2500"), ++ .desc = "Intel AST2500 BMC (ARM1176)", ++ .soc_name = "ast2500-a1", ++ .hw_strap1 = INTEL_AST2500_BMC_HW_STRAP1, ++ .fmc_model = "n25q512a", ++ .spi_model = "n25q512a", ++ .num_cs = 1, ++ .i2c_init = intel_ast2500_i2c_init, + }, { + .name = MACHINE_TYPE_NAME("romulus-bmc"), + .desc = "OpenPOWER Romulus BMC (ARM1176)", +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/files/0002-Turn-Off-FFWUPD-Jumper.patch b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/files/0002-Turn-Off-FFWUPD-Jumper.patch new file mode 100644 index 000000000..2f81895d0 --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/files/0002-Turn-Off-FFWUPD-Jumper.patch @@ -0,0 +1,32 @@ +From db99abbddc9fe958353e47fcd91c741bd7a93066 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Wed, 19 Jun 2019 14:15:07 -0700 +Subject: [PATCH] Turn Off FFWUPD Jumper + +This disabled the jumper so we don't get stuck during +boot. + +TODO: Do this the "right way", if there is one. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + hw/gpio/aspeed_gpio.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c +index 12d8a49666..ca6f8dd0dd 100644 +--- a/hw/gpio/aspeed_gpio.c ++++ b/hw/gpio/aspeed_gpio.c +@@ -29,6 +29,9 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr addr, + val = s->regs[addr]; + } + ++ if (addr == 0x0){ ++ val |= 1 << 0x18; // ffupd jumper ++ } + return val; + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu-native_%.bbappend b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu-native_%.bbappend new file mode 100644 index 000000000..4b4630d7c --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu-native_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI = "git://github.com/openbmc/qemu.git \ + file://0001-hw-arm-aspeed-Add-an-intel-ast2500-machine-type.patch \ + file://0002-Turn-Off-FFWUPD-Jumper.patch" + +QEMU_TARGETS = "arm" + +S = "${WORKDIR}/git" +SRCREV = "5dca85cb0b85ac309d131f9db1fb57af282d67cc" diff --git a/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu-system-native_%.bbappend b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu-system-native_%.bbappend new file mode 100644 index 000000000..fb0a749bb --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu-system-native_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI = "git://github.com/openbmc/qemu.git \ + file://powerpc_rom.bin \ + file://run-ptest \ + file://0001-hw-arm-aspeed-Add-an-intel-ast2500-machine-type.patch \ + file://0002-Turn-Off-FFWUPD-Jumper.patch" + +QEMU_TARGETS = "arm" + +S = "${WORKDIR}/git" +SRCREV = "5dca85cb0b85ac309d131f9db1fb57af282d67cc" diff --git a/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu_%.bbappend b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu_%.bbappend new file mode 100644 index 000000000..b25c0f2e8 --- /dev/null +++ b/meta-openbmc-mods/meta-common-small/recipes-devtools/qemu/qemu_%.bbappend @@ -0,0 +1,7 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI = "git://github.com/openbmc/qemu.git \ + file://0001-hw-arm-aspeed-Add-an-intel-ast2500-machine-type.patch \ + file://0002-Turn-Off-FFWUPD-Jumper.patch" + +S = "${WORKDIR}/git" +SRCREV = "5dca85cb0b85ac309d131f9db1fb57af282d67cc" 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..9962e7df6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass @@ -0,0 +1,113 @@ +
+
+inherit obmc-phosphor-full-fitimage
+DEPENDS += "obmc-intel-pfr-image-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 macros
+# directory where PFR scripts and key are copied
+PFR_STAGING_DIR = "${STAGING_DIR}/intel-pfr-files"
+# PFR images directory
+PFR_IMAGES_DIR = "${DEPLOY_DIR_IMAGE}/pfr_images"
+
+# 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.
+ python ${PFR_STAGING_DIR}/pfr_image.py ${PFR_STAGING_DIR}/pfr_manifest.json ${DEPLOY_DIR_IMAGE}/image-mtd ${build_version} ${build_number} ${build_hash}
+
+ # sign the PFM region
+ ${PFR_STAGING_DIR}/blocksign -c ${PFR_STAGING_DIR}/pfm_config.xml -o ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm.bin
+
+ # 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_STAGING_DIR}/blocksign -c ${PFR_STAGING_DIR}/bmc_config.xml -o ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin
+
+ # 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}
+}
+
+do_image_pfr[vardepsexclude] += "DATETIME"
+do_image_pfr[vardeps] += "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16"
+
+python() {
+ 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..6a3ad73d7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass @@ -0,0 +1,42 @@ +inherit obmc-phosphor-image +inherit systemd-watchdog + +IMAGE_INSTALL_append = " \ + bmcweb \ + dbus-broker \ + dtc \ + dtoverlay \ + entity-manager \ + ipmitool \ + intel-ipmi-oem \ + phosphor-ipmi-ipmb \ + phosphor-node-manager-proxy \ + dbus-sensors \ + phosphor-webui \ + rest-dbus-static \ + phosphor-pid-control \ + phosphor-host-postd \ + smbios-mdrv1 \ + phosphor-certificate-manager \ + 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 \ + beepcode-mgr \ + " + +# this package was flagged as a security risk +IMAGE_INSTALL_remove += " lrzsz" + diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass new file mode 100644 index 000000000..6a1ac3f14 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass @@ -0,0 +1,7 @@ +IMAGE_INSTALL_append = " \ + mtd-util \ + io-app \ + intel-fw-update \ + lpc-cmds \ + beeper-test \ + " diff --git a/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass new file mode 100644 index 000000000..4cc3845c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass @@ -0,0 +1,27 @@ +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 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..03226a8ed --- /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" diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch new file mode 100644 index 000000000..73ab78a65 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch @@ -0,0 +1,424 @@ +Index: u-boot/arch/arm/mach-aspeed/flash.c +=================================================================== +--- u-boot.orig/arch/arm/mach-aspeed/flash.c ++++ u-boot/arch/arm/mach-aspeed/flash.c +@@ -28,6 +28,7 @@ + #include <common.h> + #include <asm/processor.h> + #include <asm/byteorder.h> ++#include <asm/io.h> + #include <environment.h> + + #include <asm/arch/ast_scu.h> +@@ -199,7 +200,7 @@ static void reset_flash (flash_info_t * + if (info->dualport) + ulCtrlData |= 0x08; + #endif +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } + +@@ -228,28 +229,22 @@ static void enable_write (flash_info_t * + + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x06); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x06, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x02)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } + +@@ -280,30 +275,23 @@ static void write_status_register (flash + + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x01); +- udelay(10); +- *(uchar *) (base) = (uchar) (data); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x01, base); ++ writeb(data, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (jReg & 0x01); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + } + + static void enable4b (flash_info_t * info) +@@ -330,13 +318,11 @@ static void enable4b (flash_info_t * inf + + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0xb7); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0xb7, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } /* enable4b */ + +@@ -366,29 +352,23 @@ static void enable4b_spansion (flash_inf + /* Enable 4B: BAR0 D[7] = 1 */ + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x17); +- udelay(10); +- *(uchar *) (base) = (uchar) (0x80); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x17, base); ++ writeb(0x80, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x16); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x16, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x80)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } /* enable4b_spansion */ + +@@ -420,14 +400,11 @@ static void enable4b_numonyx (flash_info + /* Enable 4B: CMD:0xB7 */ + ulCtrlData = (info->tCK_Write << 8); + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0xB7); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0xB7, base); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + } /* enable4b_numonyx */ + +@@ -463,63 +440,49 @@ static void flash_write_buffer (flash_in + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x02); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x02, base); + if (info->address32) + { +- *(uchar *) (base) = (uchar) ((offset & 0xff000000) >> 24); +- udelay(10); ++ writeb((uchar) ((offset & 0xff000000) >> 24), base); + } +- *(uchar *) (base) = (uchar) ((offset & 0xff0000) >> 16); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x00ff00) >> 8); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x0000ff)); +- udelay(10); ++ writeb((uchar) ((offset & 0xff0000) >> 16), base); ++ writeb((uchar) ((offset & 0x00ff00) >> 8), base); ++ writeb((uchar) ((offset & 0x0000ff)), base); + + for (j=0; j<len; j++) + { +- *(uchar *) (base) = *(uchar *) (src++); +- udelay(10); ++ writeb(*src++, base); + } + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while ((jReg & 0x01)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + /* RFSR */ + if (info->specificspi == SpecificSPI_N25Q512) + { + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x70); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x70, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x80)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + } + } + +@@ -603,57 +566,44 @@ int flash_erase (flash_info_t * info, in + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0xd8); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0xd8, base); + if (info->address32) + { +- *(uchar *) (base) = (uchar) ((offset & 0xff000000) >> 24); +- udelay(10); ++ writeb((uchar) ((offset & 0xff000000) >> 24), base); + } +- *(uchar *) (base) = (uchar) ((offset & 0xff0000) >> 16); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x00ff00) >> 8); +- udelay(10); +- *(uchar *) (base) = (uchar) ((offset & 0x0000ff)); +- udelay(10); ++ writeb((uchar) ((offset & 0xff0000) >> 16), base); ++ writeb((uchar) ((offset & 0x00ff00) >> 8), base); ++ writeb((uchar) ((offset & 0x0000ff)), base); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x05); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x05, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while ((jReg & 0x01)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + + /* RFSR */ + if (info->specificspi == SpecificSPI_N25Q512) + { + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (base) = (uchar) (0x70); +- udelay(10); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x70, base); + do { +- jReg = *(volatile uchar *) (base); ++ jReg = readb(base); + } while (!(jReg & 0x80)); + ulCtrlData &= CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + } + + putc ('.'); +@@ -764,22 +714,16 @@ static ulong flash_get_size (ulong base, + } + + /* Get Flash ID */ +- ulCtrlData = *(ulong *) (info->reg_base + CtrlOffset) & CMD_MASK; ++ ulCtrlData = readl(info->reg_base + CtrlOffset) & CMD_MASK; + ulCtrlData |= CE_LOW | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); +- *(uchar *) (vbase) = (uchar) (0x9F); +- udelay(10); +- ch[0] = *(volatile uchar *)(vbase); +- udelay(10); +- ch[1] = *(volatile uchar *)(vbase); +- udelay(10); +- ch[2] = *(volatile uchar *)(vbase); +- udelay(10); +- ulCtrlData = *(ulong *) (info->reg_base + CtrlOffset) & CMD_MASK; ++ writel(ulCtrlData, info->reg_base + CtrlOffset); ++ writeb(0x9F, vbase); ++ ch[0] = readb(vbase); ++ ch[1] = readb(vbase); ++ ch[2] = readb(vbase); ++ ulCtrlData = readl(info->reg_base + CtrlOffset) & CMD_MASK; + ulCtrlData |= CE_HIGH | USERMODE; +- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData; +- udelay(200); ++ writel(ulCtrlData, info->reg_base + CtrlOffset); + ulID = ((ulong)ch[0]) | ((ulong)ch[1] << 8) | ((ulong)ch[2] << 16) ; + info->flash_id = ulID; + +@@ -1294,13 +1238,13 @@ static ulong flash_get_size (ulong base, + + if (info->address32) { + #ifndef AST_SOC_G5 +- reg = *((volatile ulong*) 0x1e6e2070); /* set H/W Trappings */ ++ reg = readl(0x1e6e2070); /* set H/W Trappings */ + reg |= 0x10; +- *((volatile ulong*) 0x1e6e2070) = reg; ++ writel(reg, 0x1e6e2070); + #endif +- reg = *((volatile ulong*) (info->reg_base + 0x4)); /* enable 32b control bit*/ ++ reg = readl(info->reg_base + 0x4); /* enable 32b control bit*/ + reg |= (0x01 << info->CE); +- *((volatile ulong*) (info->reg_base + 0x4)) = reg; ++ writel(reg, info->reg_base + 0x4); + + /* set flash chips to 32bits addressing mode */ + if ((info->flash_id & 0xFF) == 0x01) /* Spansion */ +@@ -1322,7 +1266,7 @@ unsigned long flash_init (void) + unsigned long size = 0; + int i; + +- *((volatile ulong*) AST_FMC_BASE) |= 0x800f0000; /* enable Flash Write */ ++ writel(readl(AST_FMC_BASE) | 0x800f0000, AST_FMC_BASE); /* enable Flash Write */ + + /* Init: FMC */ + /* BANK 0 : FMC CS0 , 1: FMC CS1, */ +@@ -1352,7 +1296,7 @@ unsigned long flash_init (void) + #ifdef CONFIG_SPI0_CS + //pin switch by trap[13:12] -- [0:1] Enable SPI Master + ast_scu_spi_master(1); /* enable SPI master */ +- *((volatile ulong*) AST_FMC_SPI0_BASE) |= 0x10000; /* enable Flash Write */ ++ writel(readl(AST_FMC_SPI0_BASE) | 0x10000, AST_FMC_SPI0_BASE); /* enable Flash Write */ + flash_info[CONFIG_FMC_CS].sysspi = 1; + flash_info[CONFIG_FMC_CS].reg_base = AST_FMC_SPI0_BASE; + flash_info[CONFIG_FMC_CS].flash_id = FLASH_UNKNOWN; +@@ -1403,21 +1347,24 @@ void memmove_dma(void * dest,const void + poll_time = 100; /* set 100 us as default */ + + /* force end of burst read */ +- *(volatile ulong *) (AST_FMC_BASE + CS0_CTRL) |= CE_HIGH; +- *(volatile ulong *) (AST_FMC_BASE + CS0_CTRL) &= ~CE_HIGH; +- +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_CONTROL) = (ulong) (~FLASH_DMA_ENABLE); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_FLASH_BASE) = (ulong) (src); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_DRAM_BASE) = (ulong) (dest); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_LENGTH) = (ulong) (count_align); +- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_CONTROL) = (ulong) (FLASH_DMA_ENABLE); ++ data = readl(AST_FMC_BASE + CS0_CTRL); ++ writel(data | CE_HIGH, AST_FMC_BASE + CS0_CTRL); ++ writel(data & ~CE_HIGH, AST_FMC_BASE + CS0_CTRL); ++ ++ writel(~FLASH_DMA_ENABLE, AST_FMC_BASE + REG_FLASH_DMA_CONTROL); ++ writel((ulong)src, AST_FMC_BASE + REG_FLASH_DMA_FLASH_BASE); ++ writel((ulong)dest, AST_FMC_BASE + REG_FLASH_DMA_DRAM_BASE); ++ writel(count_align, AST_FMC_BASE + REG_FLASH_DMA_LENGTH); ++ writel(FLASH_DMA_ENABLE, AST_FMC_BASE + REG_FLASH_DMA_CONTROL); + + /* wait poll */ + do { + udelay(poll_time); +- data = *(ulong *) (AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); ++ data = readl(AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); + } while (!(data & FLASH_STATUS_DMA_READY)); + + /* clear status */ +- *(ulong *) (AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS) |= FLASH_STATUS_DMA_CLEAR; ++ data = readl(AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); ++ writel(data | FLASH_STATUS_DMA_CLEAR, ++ AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS); + } diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch new file mode 100644 index 000000000..8937047c5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch @@ -0,0 +1,51 @@ +From 7979a73fba832747ed3c037c0b47c9e67dcf283e Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Mon, 30 Apr 2018 10:52:37 -0700 + +--- + common/board_r.c | 8 ++++++-- + include/configs/ast-common.h | 9 ++++++--- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/common/board_r.c b/common/board_r.c +index d959ad3..74797ed 100644 +--- a/common/board_r.c ++++ b/common/board_r.c +@@ -494,10 +494,14 @@ static int should_load_env(void) + static int initr_env(void) + { + /* initialize environment */ +- if (should_load_env()) ++ if (should_load_env()) { ++ /* try again, in case the environment failed to load the first time */ ++ if (!gd->env_valid) ++ env_init(); + env_relocate(); +- else ++ } else { + set_default_env(NULL); ++ } + #ifdef CONFIG_OF_CONTROL + setenv_addr("fdtcontroladdr", gd->fdt_blob); + #endif +diff --git a/include/configs/ast-common.h b/include/configs/ast-common.h +index eff6d2b..b7d7192 100644 +--- a/include/configs/ast-common.h ++++ b/include/configs/ast-common.h +@@ -103,10 +103,13 @@ + #define CONFIG_SYS_MAX_FLASH_BANKS (CONFIG_FMC_CS) + #define CONFIG_SYS_MAX_FLASH_SECT (8192) /* max number of sectors on one chip */ + #define CONFIG_ENV_IS_IN_FLASH 1 +-#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + 0x60000) ++#define CONFIG_ENV_OFFSET 0x2400000 /* environment starts here */ ++#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET) ++#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ + +-#define CONFIG_ENV_OFFSET 0x60000 /* environment starts here */ +-#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ ++#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) ++#define CONFIG_ENV_ADDR_REDUND (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET_REDUND) ++#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE + + #define CONFIG_BOOTCOMMAND "bootm 20080000" + #define CONFIG_ENV_OVERWRITE diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch new file mode 100644 index 000000000..e7e6c56d7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch @@ -0,0 +1,73 @@ +From 954e7dd9ff9c5d1159f0896afa34c673061b82ea Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 11 Sep 2018 16:24:06 +0800 +Subject: [PATCH] Make sure debug uart is using 24MHz clock source + +u-boot defines the uart5(debug console) as 24MHz, +set the SCU14[28] to 0, to make sure the clock source is 24M + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> + +--- + arch/arm/include/asm/arch-aspeed/ast_scu.h | 2 ++ + arch/arm/include/asm/arch-aspeed/platform.h | 1 + + arch/arm/mach-aspeed/ast-scu.c | 6 ++++++ + board/aspeed/ast-g5/ast-g5.c | 8 ++++++++ + 4 files changed, 17 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h +index dcbc673..06825ce 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h +@@ -46,4 +46,6 @@ extern void ast_scu_init_eth(u8 num); + extern void ast_scu_multi_func_eth(u8 num); + extern void ast_scu_multi_func_romcs(u8 num); + ++void ast_config_uart5_clk(void); ++ + #endif +diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h +index 1c02914..92ea33b 100644 +--- a/arch/arm/include/asm/arch-aspeed/platform.h ++++ b/arch/arm/include/asm/arch-aspeed/platform.h +@@ -27,6 +27,7 @@ + #include <asm/arch/ast2400_platform.h> + #elif defined(AST_SOC_G5) + #include <asm/arch/ast_g5_platform.h> ++#define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ + #else + #err "No define for platform.h" + #endif +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 12de9b8..fff02dc 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -538,3 +538,9 @@ void ast_scu_get_who_init_dram(void) + break; + } + } ++ ++void ast_config_uart5_clk(void) ++{ ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & ++ ~(1 << 28), AST_SCU_MISC2_CTRL); ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index e67a4bf..5a1fade 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -16,6 +16,14 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++int board_early_init_f(void) ++{ ++ /* make sure uart5 is using 24MHz clock */ ++ ast_config_uart5_clk(); ++ ++ return 0; ++} ++ + int board_init(void) + { + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch new file mode 100644 index 000000000..6bd063e39 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch @@ -0,0 +1,53 @@ +From 7e11461d6b65969005605f13677269eb91d39643 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Wed, 7 Nov 2018 13:57:57 +0800 +Subject: [PATCH] enable passthrough in uboot + +--- + arch/arm/mach-aspeed/ast-scu.c | 22 ++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5.c | 2 ++ + 2 files changed, 24 insertions(+) + +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index fff02dc..d27f3d3 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -544,3 +544,25 @@ void ast_config_uart5_clk(void) + ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & + ~(1 << 28), AST_SCU_MISC2_CTRL); + } ++ ++ ++void ast_enable_pass_through(void) ++{ ++ //Enable GPIOE pin mode, SCU80[16:23] = 00 */ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & (~0x00FF0000), ++ AST_SCU_FUN_PIN_CTRL1); ++ ++ //Enable all pass through pins by setting SCU8C[15:12] = 0x3. ++ //Pass-through pins set: ++ //GPIOE0 -> GPIOE1 ++ //GPIOE2 -> GPIOE3 ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL4) | (0x3000), ++ AST_SCU_FUN_PIN_CTRL4); ++ ++ //Disable HWStrap for GPIOE pass-through mode ++ //The write operation to SCU70(0x1e6e2070) only can set to '1'. ++ //To clear to '0', it must write '1' to 0x1e6e207c ++ if (ast_scu_read(AST_SCU_HW_STRAP1) & (0x1 << 22)){ ++ ast_scu_write((0x1 << 22), AST_SCU_REVISION_ID); ++ } ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index 5a1fade..b492003 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -20,6 +20,8 @@ int board_early_init_f(void) + { + /* make sure uart5 is using 24MHz clock */ + ast_config_uart5_clk(); ++ /*enable pass through*/ ++ ast_enable_pass_through(); + + return 0; + } diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch new file mode 100644 index 000000000..4f90d6dfe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch @@ -0,0 +1,387 @@ +From e782f6a90468fee35877b78e248a17f39f67c94c Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 10:21:40 -0800 +Subject: [PATCH] Add Aspeed g5 interrupt support + +This adds a few new files to the board g5 directory. Several Intel +features require interrupts running in U-Boot, so this adds basic +interrupt registration and handling support. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0 + +--- + Kconfig | 13 +++ + arch/arm/lib/interrupts.c | 11 +++ + board/aspeed/ast-g5/Makefile | 3 +- + board/aspeed/ast-g5/ast-g5-irq.c | 176 ++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-irq.h | 39 ++++++++ + board/aspeed/ast-g5/ast-g5.c | 3 + + board/aspeed/ast-g5/ast-g5.h | 7 ++ + cmd/Kconfig | 5 + + configs/ast_g5_ncsi_2boot_defconfig | 1 + + configs/ast_g5_ncsi_defconfig | 1 + + configs/ast_g5_phy_defconfig | 1 + + 11 files changed, 259 insertions(+), 1 deletion(-) + create mode 100644 board/aspeed/ast-g5/ast-g5-irq.c + create mode 100644 board/aspeed/ast-g5/ast-g5-irq.h + create mode 100644 board/aspeed/ast-g5/ast-g5.h + +diff --git a/Kconfig b/Kconfig +index 3ceff25..d6439d0 100644 +--- a/Kconfig ++++ b/Kconfig +@@ -115,6 +115,19 @@ if EXPERT + When disabling this, please check if malloc calls, maybe + should be replaced by calloc - if one expects zeroed memory. + endif ++ ++config USE_IRQ ++ bool "Use interrupts" ++ default n ++ ++config STACKSIZE_IRQ ++ int "Size for IRQ stack (only if USE_IRQ enabled)" ++ default 16384 ++ ++config STACKSIZE_FIQ ++ int "Size for FIQ stack (only if USE_IRQ enabled)" ++ default 16384 ++ + endmenu # General setup + + menu "Boot images" +diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c +index ed83043..a96b3aa 100644 +--- a/arch/arm/lib/interrupts.c ++++ b/arch/arm/lib/interrupts.c +@@ -94,6 +94,17 @@ int disable_interrupts (void) + : "memory"); + return (old & 0x80) == 0; + } ++ ++int global_interrupts_enabled(void) ++{ ++ unsigned long old; ++ __asm__ __volatile__("mrs %0, cpsr\n" ++ : "=r" (old) ++ : ++ : "memory"); ++ return (old & 0x80) == 0; ++} ++ + #else + int interrupt_init (void) + { +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index d1d7f85..df4e639 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -1 +1,2 @@ +-obj-y = ast-g5.o ++obj-y += ast-g5.o ++obj-y += ast-g5-irq.o +diff --git a/board/aspeed/ast-g5/ast-g5-irq.c b/board/aspeed/ast-g5/ast-g5-irq.c +new file mode 100644 +index 0000000..860f16c +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-irq.c +@@ -0,0 +1,176 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <netdev.h> ++ ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/ast-sdmc.h> ++#include <asm/io.h> ++ ++#include "ast-g5.h" ++#include "ast-g5-irq.h" ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#ifdef CONFIG_USE_IRQ ++ ++#define VIC_STATUS_L 0x80 ++#define VIC_STATUS_H 0x84 ++#define VIC_IRQ_SELECTION_L 0x98 ++#define VIC_IRQ_SELECTION_H 0x9C ++#define VIC_ENABLE_L 0xA0 ++#define VIC_ENABLE_H 0xA4 ++#define VIC_ENABLE_CLEAR_L 0xA8 ++#define VIC_ENABLE_CLEAR_H 0xAC ++#define VIC_INTERRUPT_CLEAR_L 0xD8 ++#define VIC_INTERRUPT_CLEAR_H 0xDC ++ ++#define VIC_CLEAR_ALL (~0) ++ ++int arch_interrupt_init_early(void) ++{ ++ writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_L); ++ writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_H); ++ return 0; ++} ++int arch_interrupt_init(void) ++{ ++ return 0; ++} ++ ++#define AST_IRQ_START_L 0 ++#define AST_IRQ_END_L 31 ++#define AST_IRQ_START_H 32 ++#define AST_IRQ_END_H 63 ++#define AST_IRQ_COUNT 64 ++static interrupt_handler_t *handlers[AST_IRQ_COUNT] = {NULL}; ++static unsigned long irq_total = 0; ++static unsigned long irq_counts[AST_IRQ_COUNT] = {0}; ++ ++int request_irq(int irq, interrupt_handler_t *handler) ++{ ++ if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) { ++ printf("irq %d out of range\n", irq); ++ return -1; ++ } ++ if (handlers[irq]) { ++ printf("irq %d already in use (%p)\n", irq, handlers[irq]); ++ return -1; ++ } ++ handlers[irq] = handler; ++ if (irq < AST_IRQ_START_H) { ++ writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_L); ++ } else { ++ writel((1 << (irq - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_H); ++ } ++ return 0; ++} ++ ++int release_irq(int irq) ++{ ++ if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) { ++ return -1; ++ } ++ if (handlers[irq]) { ++ handlers[irq] = NULL; ++ if (irq < AST_IRQ_START_H) { ++ writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_CLEAR_L); ++ } else { ++ writel((1 << (irq - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_CLEAR_H); ++ } ++ } ++ return 0; ++} ++ ++extern int global_interrupts_enabled(void); ++int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int i; ++ int enabled = global_interrupts_enabled(); ++ unsigned long long irqs_enabled = ++ ((unsigned long long)readl(AST_VIC_BASE + VIC_ENABLE_H)) ++ << AST_IRQ_START_H ++ | readl(AST_VIC_BASE + VIC_ENABLE_L); ++ printf("interrupts %sabled\n", (enabled ? "en" : "dis")); ++ for (i = AST_IRQ_START_L; i < AST_IRQ_COUNT; i++) { ++ printf("% 2i (% 3s): %lu\n", i, ++ ((irqs_enabled & 1) ? "on" : "off"), irq_counts[i]); ++ irqs_enabled >>= 1; ++ } ++ printf("total: %lu\n", irq_total); ++ return 0; ++} ++ ++void do_irq(struct pt_regs *pt_regs) ++{ ++ uint32_t irq = readl(AST_VIC_BASE + VIC_STATUS_L); ++ int i; ++ irq_total++; ++ if (irq) { ++ // handler irq0-31 ++ for (i = AST_IRQ_START_L; i <= AST_IRQ_END_L; i++) { ++ if (irq & (1 << i)) { ++ irq_counts[i]++; ++ /* mask */ ++ writel((1 << i), ++ AST_VIC_BASE + VIC_ENABLE_CLEAR_L); ++ if (handlers[i]) { ++ handlers[i](pt_regs); ++ /* clear */ ++ writel((1 << i), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_L); ++ /* unmask */ ++ writel((1 << i), ++ AST_VIC_BASE + VIC_ENABLE_L); ++ } else { ++ printf("unexpected interrupt %i; masking\n", ++ i); ++ /* clear; do not unmask */ ++ writel((1 << i), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_L); ++ } ++ } ++ } ++ } ++ irq = readl(AST_VIC_BASE + VIC_STATUS_H); ++ if (irq) { ++ // handler irq32-63 ++ for (i = AST_IRQ_START_H; i <= AST_IRQ_END_H; i++) { ++ if (irq & (1 << (i - AST_IRQ_START_H))) { ++ irq_counts[i]++; ++ /* mask */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_CLEAR_H); ++ if (handlers[i]) { ++ handlers[i](pt_regs); ++ /* clear */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_H); ++ /* unmask */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE + VIC_ENABLE_H); ++ } else { ++ printf("unexpected interrupt %i; masking\n", ++ i); ++ /* clear; do not unmask */ ++ writel((1 << (i - AST_IRQ_START_H)), ++ AST_VIC_BASE ++ + VIC_INTERRUPT_CLEAR_H); ++ } ++ } ++ } ++ } ++} ++#endif +diff --git a/board/aspeed/ast-g5/ast-g5-irq.h b/board/aspeed/ast-g5/ast-g5-irq.h +new file mode 100644 +index 0000000..703eeab +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-irq.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifndef __AST_G5_IRQ_H__ ++#define __AST_G5_IRQ_H__ ++ ++#include <common.h> ++ ++#ifdef CONFIG_USE_IRQ ++ ++int arch_interrupt_init_early(void); ++ ++int request_irq(int irq, interrupt_handler_t *handler); ++ ++int release_irq(int irq); ++ ++#else /* CONFIG_USE_IRQ */ ++ ++int arch_interrupt_init_early(void) { ++ return 0; ++} ++ ++int request_irq(int irq, interrupt_handler_t *handler) { ++ return -1; ++} ++ ++int release_irq(int irq) { ++ return -1; ++} ++ ++#endif /* CONFIG_USE_IRQ */ ++ ++#endif /* __AST_G5_IRQ_H__ */ +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index b492003..2472aa3 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -14,6 +14,8 @@ + #include <asm/arch/ast-sdmc.h> + #include <asm/io.h> + ++#include "ast-g5.h" ++ + DECLARE_GLOBAL_DATA_PTR; + + int board_early_init_f(void) +@@ -22,6 +24,7 @@ int board_early_init_f(void) + ast_config_uart5_clk(); + /*enable pass through*/ + ast_enable_pass_through(); ++ arch_interrupt_init_early(); + + return 0; + } +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +new file mode 100644 +index 0000000..9fd10ec +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -0,0 +1,7 @@ ++#ifndef _AST_G5_H_ ++#define _AST_G5_H_ ++ ++#include <common.h> ++#include "ast-g5-irq.h" ++ ++#endif /* _AST_G5_H_ */ +diff --git a/cmd/Kconfig b/cmd/Kconfig +index d69b817..33be240 100644 +--- a/cmd/Kconfig ++++ b/cmd/Kconfig +@@ -313,6 +313,11 @@ endmenu + + menu "Device access commands" + ++config CMD_IRQ ++ bool "interrupts - enable/disable interrupts" ++ depends on USE_IRQ ++ default y ++ + config CMD_DM + bool "dm - Access to driver model information" + depends on DM +diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig +index 2d28c86..d5b7894 100644 +--- a/configs/ast_g5_ncsi_2boot_defconfig ++++ b/configs/ast_g5_ncsi_2boot_defconfig +@@ -33,3 +33,4 @@ CONFIG_CMD_CRC32=y + CONFIG_LOOPW=y + CONFIG_CMD_MEMTEST=y + CONFIG_CMD_MX_CYCLIC=y ++CONFIG_USE_IRQ=y +diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig +index 74029ed..9481e5f 100644 +--- a/configs/ast_g5_ncsi_defconfig ++++ b/configs/ast_g5_ncsi_defconfig +@@ -11,3 +11,4 @@ CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y + CONFIG_SYS_NS16550=y ++CONFIG_USE_IRQ=y +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 767f3af..4aefcf4 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -12,3 +12,4 @@ CONFIG_HUSH_PARSER=y + CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y + CONFIG_SYS_NS16550=y ++CONFIG_USE_IRQ=y diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch new file mode 100644 index 000000000..b37aee7e6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch @@ -0,0 +1,328 @@ +From c46cb2dd703f55ca63ed9c5cf2a97868a7e6c209 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 10:21:40 -0800 +Subject: [PATCH] Add espi support + +This adds basic eSPI support for U-Boot. The eSPI driver works best with +interrupts because the timing of the initialization with the PCH is not +trivial. + +The espi driver is currently just a bare-minimum driver allowing the +host to boot. In the future it may be expanded to have further +functions. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0 + +--- + arch/arm/include/asm/arch-aspeed/regs-scu.h | 2 + + board/aspeed/ast-g5/Makefile | 2 + + board/aspeed/ast-g5/ast-g5-espi.c | 231 ++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 16 ++ + board/aspeed/ast-g5/ast-g5.c | 3 + + 5 files changed, 254 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-espi.c + create mode 100644 board/aspeed/ast-g5/ast-g5-intel.c + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h +index b714fa9..10b983a 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -552,6 +552,8 @@ + + #define CLK_25M_IN (0x1 << 23) + ++#define SCU_HW_STRAP_FAST_RESET (1 << 27) ++#define SCU_HW_STRAP_ESPI_ENABLED (1 << 25) + #define SCU_HW_STRAP_2ND_BOOT_WDT (0x1 << 17) + #define SCU_HW_STRAP_SUPER_IO_CONFIG (0x1 << 16) + #define SCU_HW_STRAP_VGA_CLASS_CODE (0x1 << 15) +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index df4e639..58e0c64 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -1,2 +1,4 @@ + obj-y += ast-g5.o ++obj-y += ast-g5-intel.o ++obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o +diff --git a/board/aspeed/ast-g5/ast-g5-espi.c b/board/aspeed/ast-g5/ast-g5-espi.c +new file mode 100644 +index 0000000..79ef253 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-espi.c +@@ -0,0 +1,231 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++ ++#define DEBUG_ESPI_ENABLED 1 ++#ifdef DEBUG_ESPI_ENABLED ++#define DBG_ESPI debug ++#else ++#define DBG_ESPI(...) ++#endif ++/* eSPI controller registers */ ++#define ESPI000 0x000 /* Engine Control. */ ++#define ESPI004 0x004 /* Engine Status. */ ++#define ESPI008 0x008 /* Interrupt Status. */ ++#define ESPI00C 0x00C /* Interrupt Enable. */ ++#define ESPI010 0x010 /* DMA Addr of Peripheral Channel Posted Rx pkt */ ++#define ESPI014 0x014 /* Control of Peripheral Channel Posted Rx pkt. */ ++#define ESPI018 0x018 /* Data port of Peripheral Channel Posted Rx pkt. */ ++#define ESPI020 0x020 /* DMA Addr of Peripheral Channel Posted Tx pkt. */ ++#define ESPI024 0x024 /* Control of Peripheral Channel Posted Tx pkt. */ ++#define ESPI028 0x028 /* Data port of Peripheral Channel Posted Tx pkt. */ ++#define ESPI030 0x030 /* DMA Addr of Peripheral Channel Non-Posted Tx pkt. */ ++#define ESPI034 0x034 /* Control of Peripheral Channel Non-Posted Tx pkt. */ ++#define ESPI038 0x038 /* Data port of Peripheral Channel Non-Posted Tx pkt. */ ++#define ESPI040 0x040 /* DMA Addr of OOB Channel Rx pkt. */ ++#define ESPI044 0x044 /* Control of OOB Channel Rx pkt. */ ++#define ESPI048 0x048 /* Data port of OOB Channel Rx pkt. */ ++#define ESPI050 0x050 /* DMA Addr of OOB Channel Tx pkt. */ ++#define ESPI054 0x054 /* Control of OOB Channel Tx pkt. */ ++#define ESPI058 0x058 /* Data port of OOB Channel Tx pkt. */ ++#define ESPI060 0x060 /* DMA Addr of Flash Channel Rx pkt. */ ++#define ESPI064 0x064 /* Control of Flash Channel Rx pkt. */ ++#define ESPI068 0x068 /* Data port of Flash Channel Rx pkt. */ ++#define ESPI070 0x070 /* DMA Addr of Flash Channel Tx pkt. */ ++#define ESPI074 0x074 /* Control of Flash Channel Tx pkt. */ ++#define ESPI078 0x078 /* Data port of Flash Channel Tx pkt. */ ++#define ESPI084 0x084 /* Mapping Src Addr of Peripheral Channel Rx pkt. */ ++#define ESPI088 0x088 /* Mapping Tgt Addr of Peripheral Channel Rx pkt. */ ++#define ESPI08C 0x08C /* Mapping Addr Mask of Peripheral Channel Rx pkt. */ ++#define ESPI090 0x090 /* Mapping Target Addr and Mask of Flash Channel. */ ++#define ESPI094 0x094 /* Interrupt enable of System Event from Master. */ ++#define ESPI098 0x098 /* System Event from and to Master. */ ++#define ESPI09C 0x09C /* GPIO through Virtual Wire Channel. */ ++#define ESPI0A0 0x0A0 /* General Capabilities and Configurations. */ ++#define ESPI0A4 0x0A4 /* Channel 0 Capabilities and Configurations. */ ++#define ESPI0A8 0x0A8 /* Channel 1 Capabilities and Configurations. */ ++#define ESPI0AC 0x0AC /* Channel 2 Capabilities and Configurations. */ ++#define ESPI0B0 0x0B0 /* Channel 3 Capabilities and Configurations. */ ++#define ESPI0B4 0x0B4 /* GPIO Direction of Virtual Wire Channel. */ ++#define ESPI0B8 0x0B8 /* GPIO Selection of Virtual Wire Channel. */ ++#define ESPI0BC 0x0BC /* GPIO Reset Selection of Virtual Wire Channel. */ ++#define ESPI100 0x100 /* Interrupt enable of System Event 1 from Master. */ ++#define ESPI104 0x104 /* System Event 1 from and to Master. */ ++#define ESPI110 0x110 /* Interrupt type 0 of System Event from Master. */ ++#define ESPI114 0x114 /* Interrupt type 1 of System Event from Master. */ ++#define ESPI118 0x118 /* Interrupt type 2 of System Event from Master. */ ++#define ESPI11C 0x11C /* Interrupt status of System Event from Master. */ ++#define ESPI120 0x120 /* Interrupt type 0 of System Event 1 from Master. */ ++#define ESPI124 0x124 /* Interrupt type 1 of System Event 1 from Master. */ ++#define ESPI128 0x128 /* Interrupt type 2 of System Event 1 from Master. */ ++#define ESPI12C 0x12C /* Interrupt status of System Event 1 from Master. */ ++#define ESPICFG004 0x004 /* Device Identification. */ ++#define ESPICFG008 0x008 /* General Capabilities and Configurations. */ ++#define ESPICFG010 0x010 /* Channel 0 Capabilities and Configurations. */ ++#define ESPICFG020 0x020 /* Channel 1 Capabilities and Configurations. */ ++#define ESPICFG030 0x030 /* Channel 2 Capabilities and Configurations. */ ++#define ESPICFG040 0x040 /* Channel 3 Capabilities and Configurations. */ ++#define ESPICFG044 0x044 /* Channel 3 Capabilities and Configurations 2. */ ++#define ESPICFG800 0x800 /* GPIO Direction of Virtual Wire Channel. */ ++#define ESPICFG804 0x804 /* GPIO Selection of Virtual Wire Channel. */ ++#define ESPICFG808 0x808 /* GPIO Reset Selection of Virtual Wire Channel. */ ++#define ESPICFG810 0x810 /* Mapping Src Addr of Peripheral Channel Rx pkt */ ++#define ESPICFG814 0x814 /* Mapping Tgt Addr of Peripheral Channel Rx pkt */ ++#define ESPICFG818 0x818 /* Mapping Addr Mask of Peripheral Channel Rx pkt */ ++ ++/* ESPI000 bits */ ++#define AST_ESPI_OOB_CHRDY (1 << 4) ++#define AST_ESPI_FLASH_SW_CHRDY (0x1 << 7) ++#define AST_ESPI_FLASH_SW_READ (0x1 << 10) ++ ++/* ESPI00C bits (Interrupt Enable) */ ++#define AST_ESPI_IEN_SYS_EV (1 << 8) ++#define AST_ESPI_IEN_GPIO_EV (1 << 9) ++ ++/* ESPI008 bits ISR */ ++#define AST_ESPI_VW_SYS_EVT (1 << 8) ++#define AST_ESPI_VW_SYS_EV1 (1 << 22) ++ ++/* ESPI098 and ESPI11C bits */ ++#define AST_ESPI_OOB_RST_WARN (1 << 6) ++#define AST_ESPI_HOST_RST_WARN (1 << 8) ++#define AST_ESPI_OOB_RST_ACK (1 << 16) ++#define AST_ESPI_SL_BT_DONE (1 << 20) ++#define AST_ESPI_SL_BT_STATUS (1 << 23) ++#define AST_ESPI_HOST_RST_ACK (1 << 27) ++ ++/* ESPI104 bits */ ++#define AST_ESPI_SUS_WARN (1 << 0) ++#define AST_ESPI_SUS_ACK (1 << 20) ++ ++/* LPC chip ID */ ++#define SCR0SIO 0x170 ++#define IRQ_SRC_ESPI 23 /* IRQ 23 */ ++ ++static int espi_irq_handler(struct pt_regs *regs) ++{ ++ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008); ++ ++ DBG_ESPI("ISR irq_status : 0x%08X\n", irq_status); ++ ++ if (irq_status & AST_ESPI_VW_SYS_EVT) { ++ uint32_t sys_status = readl(AST_ESPI_BASE + ESPI11C); ++ uint32_t sys_event = readl(AST_ESPI_BASE + ESPI098); ++ ++ DBG_ESPI("sys_status : 0x%08X\n", sys_status); ++ if (sys_status & AST_ESPI_HOST_RST_WARN) { ++ DBG_ESPI("HOST_RST_WARN ev: %08X\n", sys_event); ++ if (sys_event & AST_ESPI_HOST_RST_WARN) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) ++ | AST_ESPI_HOST_RST_ACK; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ } ++ } ++ if (sys_status & AST_ESPI_OOB_RST_WARN) { ++ DBG_ESPI("OOB_RST_WARN ev: %08X\n", sys_event); ++ if (sys_event & AST_ESPI_OOB_RST_WARN) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) ++ | AST_ESPI_OOB_RST_ACK; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ } ++ } ++ writel(sys_status, AST_ESPI_BASE + ESPI11C); // clear status ++ } ++ ++ if (irq_status & AST_ESPI_VW_SYS_EV1) { ++ uint32_t sys1_status = readl(AST_ESPI_BASE + ESPI12C); ++ uint32_t sys1_event = readl(AST_ESPI_BASE + ESPI104); ++ ++ DBG_ESPI("sys1_status : 0x%08X\n", sys1_status); ++ if (sys1_status & AST_ESPI_SUS_WARN) { ++ DBG_ESPI("SUS WARN ev: %08X\n", sys1_event); ++ if (sys1_event & AST_ESPI_SUS_WARN) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI104) ++ | AST_ESPI_SUS_ACK; ++ writel(v, AST_ESPI_BASE + ESPI104); ++ } ++ } ++ writel(sys1_status, AST_ESPI_BASE + ESPI12C); // clear status ++ } ++ writel(irq_status, AST_ESPI_BASE + ESPI008); // clear irq_status ++ return 0; ++} ++ ++static void espi_handshake_ack(void) ++{ ++ // IRQ only serviced if strapped, so no strap check ++ if (!(readl(AST_ESPI_BASE + ESPI098) & AST_ESPI_SL_BT_STATUS)) { ++ DBG_ESPI("Setting espi slave boot done\n"); ++ uint32_t v = readl(AST_ESPI_BASE + ESPI098) ++ | AST_ESPI_SL_BT_STATUS | AST_ESPI_SL_BT_DONE; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ } ++ ++ if (readl(AST_ESPI_BASE + ESPI104) & AST_ESPI_SUS_WARN) { ++ DBG_ESPI("Boot SUS WARN set %08x\n", ++ readl(AST_ESPI_BASE + ESPI104)); ++ uint32_t v = readl(AST_ESPI_BASE + ESPI104) | AST_ESPI_SUS_ACK; ++ writel(v, AST_ESPI_BASE + ESPI104); ++ } ++} ++ ++void espi_init(void) ++{ ++ if (readl(AST_SCU_BASE + AST_SCU_HW_STRAP1) ++ & SCU_HW_STRAP_ESPI_ENABLED) { ++ uint32_t v; ++ DBG_ESPI("espi_init\n"); ++ ++ /* Block flash access from Host */ ++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_FLASH_SW_CHRDY; ++ v |= AST_ESPI_FLASH_SW_READ | AST_ESPI_OOB_CHRDY; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ /* Set SIO register 0x28 to 0xa8 as a faked ASPEED ChipID for ++ * BIOS using in eSPI mode */ ++ v = readl(AST_LPC_BASE + SCR0SIO) & ~0x000000ff; ++ writel(v, AST_LPC_BASE + SCR0SIO); ++ v = readl(AST_LPC_BASE + SCR0SIO) | 0xa8; ++ writel(v, AST_LPC_BASE + SCR0SIO); ++ ++ v = readl(AST_ESPI_BASE + ESPI000) | AST_ESPI_OOB_CHRDY; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ writel(0, AST_ESPI_BASE + ESPI110); ++ writel(0, AST_ESPI_BASE + ESPI114); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN, ++ AST_ESPI_BASE + ESPI118); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN, ++ AST_ESPI_BASE + ESPI094); ++ ++ writel(AST_ESPI_SUS_WARN, ++ AST_ESPI_BASE + ESPI120); // int type 0 susp warn ++ writel(0, AST_ESPI_BASE + ESPI124); ++ writel(0, AST_ESPI_BASE + ESPI128); ++ writel(AST_ESPI_SUS_WARN, ++ AST_ESPI_BASE ++ + ESPI100); // Enable sysev1 ints for susp warn ++ ++ writel(AST_ESPI_IEN_SYS_EV, ++ AST_ESPI_BASE + ESPI00C); // Enable only sys events ++ ++ espi_handshake_ack(); ++ ++ request_irq(IRQ_SRC_ESPI, espi_irq_handler); ++ } else { ++ DBG_ESPI("No espi strap\n"); ++ } ++} +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +new file mode 100644 +index 0000000..e79235c +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -0,0 +1,16 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++ ++extern void espi_init(void); ++void ast_g5_intel(void) ++{ ++ espi_init(); ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index 2472aa3..d41ef9c 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -18,6 +18,8 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++extern void ast_g5_intel(void); ++ + int board_early_init_f(void) + { + /* make sure uart5 is using 24MHz clock */ +@@ -34,6 +36,7 @@ int board_init(void) + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + gd->flags = 0; + ++ ast_g5_intel(); + return 0; + } + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch new file mode 100644 index 000000000..5fa4bffa1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch @@ -0,0 +1,158 @@ +From 40e02e4ffa13c0128db555a3a3982a7cdc0ebf60 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 12:09:52 -0800 +Subject: [PATCH] add sgio support for port80 snoop post LEDs + +This ties together the port 80 snooping to the SGPIO output that +ultimately drives the POST code LEDs. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Iaa1b91cd40f4b6323dba0598da373cb631459e66 + +--- + arch/arm/include/asm/arch-aspeed/ast_scu.h | 1 + + arch/arm/mach-aspeed/ast-scu.c | 8 +++ + board/aspeed/ast-g5/ast-g5-intel.c | 96 ++++++++++++++++++++++++++++++ + 3 files changed, 105 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h +index 06825ce..369c4e3 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h +@@ -45,6 +45,7 @@ extern u32 ast_scu_get_vga_memsize(void); + extern void ast_scu_init_eth(u8 num); + extern void ast_scu_multi_func_eth(u8 num); + extern void ast_scu_multi_func_romcs(u8 num); ++extern void ast_scu_multi_func_sgpio(void); + + void ast_config_uart5_clk(void); + +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index d27f3d3..3a9ba05 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -449,6 +449,14 @@ void ast_scu_multi_func_romcs(u8 num) + SCU_FUN_PIN_ROMCS(num), AST_SCU_FUN_PIN_CTRL3); + } + ++void ast_scu_multi_func_sgpio(void) ++{ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL2) | ++ SCU_FUN_PIN_SGPMI | SCU_FUN_PIN_SGPMO | ++ SCU_FUN_PIN_SGPMLD | SCU_FUN_PIN_SGPMCK, ++ AST_SCU_FUN_PIN_CTRL2); ++} ++ + u32 ast_scu_revision_id(void) + { + int i; +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e79235c..c2a8b33 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -8,9 +8,105 @@ + */ + + #include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++ ++#define LPC_SNOOP_ADDR 0x80 ++#define HICR5 0x080 /* Host Interface Control Register 5 */ ++#define HICR6 0x084 /* Host Interface Control Register 6 */ ++#define HICR7 0x088 /* Host Interface Control Register 7 */ ++#define HICR8 0x08c /* Host Interface Control Register 8 */ ++#define SNPWADR 0x090 /* LPC Snoop Address Register */ ++#define SNPWDR 0x094 /* LPC Snoop Data Register */ ++#define HICR9 0x098 /* Host Interface Control Register 9 */ ++#define HICRA 0x09c /* Host Interface Control Register A */ ++#define LHCR0 0x0a0 /* LPC Host Control Register 0 */ ++#define LHCR1 0x0a4 /* LPC Host Control Register 1 */ ++#define LHCR2 0x0a8 /* LPC Host Control Register 2 */ ++#define LHCR3 0x0ac /* LPC Host Control Register 3 */ ++#define LHCR4 0x0b0 /* LPC Host Control Register 4 */ ++#define LHCR5 0x0b4 /* LPC Host Control Register 5 */ ++#define LHCR6 0x0b8 /* LPC Host Control Register 6 */ ++#define LHCR7 0x0bc /* LPC Host Control Register 7 */ ++#define LHCR8 0x0c0 /* LPC Host Control Register 8 */ ++#define PCCR6 0x0c4 /* Post Code Control Register 6 */ ++#define LHCRA 0x0c8 /* LPC Host Control Register A */ ++#define LHCRB 0x0cc /* LPC Host Control Register B */ ++#define PCCR4 0x0d0 /* Post Code Control Register 4 */ ++#define PCCR5 0x0d4 /* Post Code Control Register 5 */ ++#define HICRB 0x100 /* Host Interface Control Register B */ ++#define HICRC 0x104 /* Host Interface Control Register C */ ++/* HICR5 Bits */ ++#define HICR5_EN_SIOGIO (1 << 31) /* Enable SIOGIO */ ++#define HICR5_EN80HGIO (1 << 30) /* Enable 80hGIO */ ++#define HICR5_SEL80HGIO (0x1f << 24) /* Select 80hGIO */ ++#define SET_SEL80HGIO(x) ((x & 0x1f) << 24) /* Select 80hGIO Offset */ ++#define HICR5_UNKVAL_MASK 0x1FFF0000 /* Bits with unknown values on reset */ ++#define HICR5_ENINT_SNP0W (1 << 1) /* Enable Snooping address 0 */ ++#define HICR5_EN_SNP0W (1 << 0) /* Enable Snooping address 0 */ ++ ++/* HRCR6 Bits */ ++#define HICR6_STR_SNP0W (1 << 0) /* Interrupt Status Snoop address 0 */ ++#define HICR6_STR_SNP1W (1 << 1) /* Interrupt Status Snoop address 1 */ ++ ++/* HICRB Bits */ ++#define HICRB_EN80HSGIO (1 << 13) /* Enable 80hSGIO */ ++ ++#define SGPIO_CLK_DIV(N) ((N) << 16) ++#define SGPIO_BYTES(N) ((N) << 6) ++#define SGPIO_ENABLE 1 ++#define GPIO254 0x254 ++ ++static void sgpio_init(void) ++{ ++ uint32_t value; ++ /* ++ 33.4.2 ++ LPC port80h direct to SGPIO ++ In AST2500 SGPIO, it supports output data from 80h. It always uses SGPIOA. ++ 1. Configure LPC snoop function. ++ (a) Set SNPWADR(0x1e789090)[15:0] to 0x80. ++ (b) Set HICR5(0x1e789080)[0] to 1 to enable snoop. ++ 2. Configure SGPIO ++ (a) Set GPIO254[9:6] to larger than or equal to 0x1. ++ (b) Set GPIO254[0] to 1 to enable SGPIO. ++ 3. Set SuperIO ++ (a) Set SIOR7 30h to 0x40. ++ */ ++ /* make sure multi-pin stuff goes in our favor */ ++ ast_scu_multi_func_sgpio(); ++ ++ /* set lpc snoop #0 to port 0x80 */ ++ value = readl(AST_LPC_BASE + SNPWADR) & 0xffff0000; ++ writel(value | LPC_SNOOP_ADDR, AST_LPC_BASE + SNPWADR); ++ ++ /* clear interrupt status */ ++ value = readl(AST_LPC_BASE + HICR6); ++ value |= HICR6_STR_SNP0W | HICR6_STR_SNP1W; ++ writel(value, AST_LPC_BASE + HICR6); ++ ++ /* enable lpc snoop #0 and SIOGIO */ ++ value = readl(AST_LPC_BASE + HICR5) & ~(HICR5_UNKVAL_MASK); ++ value |= HICR5_EN_SIOGIO | HICR5_EN_SNP0W; ++ writel(value, AST_LPC_BASE + HICR5); ++ ++ ++ /* enable port80h snoop on SGPIO */ ++ value = readl(AST_LPC_BASE + HICRB) | HICRB_EN80HSGIO; ++ writel(value, AST_LPC_BASE + HICRB); ++ ++ /* set the gpio clock to pclk/(2*(5+1)) or ~2 MHz */ ++ value = SGPIO_CLK_DIV(256) | SGPIO_BYTES(10) | SGPIO_ENABLE; ++ writel(value, AST_GPIO_BASE + GPIO254); ++} + + extern void espi_init(void); + void ast_g5_intel(void) + { + espi_init(); ++ sgpio_init(); + } diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch new file mode 100644 index 000000000..f7dd80504 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch @@ -0,0 +1,412 @@ +From 0fbd5fe6fa08f709b64bdbad6440ea77b422fc4b Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 09:58:01 -0800 +Subject: [PATCH] Add basic GPIO support + +Add a table of well-known gpios (such as FP LEDs and FF UPD jumper) and +initialize them at boot. + +Add a mechanism to get/set well known gpios from command line. + +Change-Id: I4136a5ccb048b3604f13b17ea0c18a4bc596c249 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-gpio.c | 195 +++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-gpio.h | 102 +++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 42 ++++++++ + board/aspeed/ast-g5/ast-g5.h | 1 + + 5 files changed, 341 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.c + create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 58e0c64..2970ae5 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -2,3 +2,4 @@ obj-y += ast-g5.o + obj-y += ast-g5-intel.o + obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o ++obj-y += ast-g5-gpio.o +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.c b/board/aspeed/ast-g5/ast-g5-gpio.c +new file mode 100644 +index 0000000..d596c15 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-gpio.c +@@ -0,0 +1,195 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++#include "ast-g5-gpio.h" ++ ++typedef struct _gpio_bases { ++ uint32_t u32ddr; /* data and direction registers */ ++ uint32_t u32intcfg; /* interrupt config */ ++ uint32_t u32debounce; /* debounce config */ ++ uint32_t u32cmdsrc; /* command source config */ ++} sGPIO_BASES; ++ ++static const sGPIO_BASES GPIO_BASES[] = { ++ /* ABCD */ ++ {AST_GPIO_BASE + 0x0000, AST_GPIO_BASE + 0x0008, ++ AST_GPIO_BASE + 0x0040, AST_GPIO_BASE + 0x0060}, ++ /* EFGH */ ++ {AST_GPIO_BASE + 0x0020, AST_GPIO_BASE + 0x0028, ++ AST_GPIO_BASE + 0x0048, AST_GPIO_BASE + 0x0068}, ++ /* IJKL */ ++ {AST_GPIO_BASE + 0x0070, AST_GPIO_BASE + 0x0098, ++ AST_GPIO_BASE + 0x00b0, AST_GPIO_BASE + 0x0090}, ++ /* MNOP */ ++ {AST_GPIO_BASE + 0x0078, AST_GPIO_BASE + 0x00e8, ++ AST_GPIO_BASE + 0x0100, AST_GPIO_BASE + 0x00e0}, ++ /* QRST */ ++ {AST_GPIO_BASE + 0x0080, AST_GPIO_BASE + 0x0118, ++ AST_GPIO_BASE + 0x0130, AST_GPIO_BASE + 0x0110}, ++ /* UVWX */ ++ {AST_GPIO_BASE + 0x0088, AST_GPIO_BASE + 0x0148, ++ AST_GPIO_BASE + 0x0160, AST_GPIO_BASE + 0x0140}, ++ /* YZAB */ ++ {AST_GPIO_BASE + 0x01e0, AST_GPIO_BASE + 0x0178, ++ AST_GPIO_BASE + 0x0190, AST_GPIO_BASE + 0x0170}, ++ /* AC__ */ ++ {AST_GPIO_BASE + 0x01e8, AST_GPIO_BASE + 0x01a8, ++ AST_GPIO_BASE + 0x01c0, AST_GPIO_BASE + 0x01a0}, ++}; ++ ++static size_t gpio_max = 0; ++static const GPIOValue * gpio_table = NULL; ++ ++void gpio_set_value(int n, int asserted) ++{ ++ uint8_t port; ++ uint8_t pin; ++ uint32_t base; ++ uint8_t shift; ++ uint8_t assert; ++ uint32_t gpio_value; ++ ++ if (n >= gpio_max || !gpio_table) { ++ return; ++ } ++ port = GPIO_PORT(gpio_table[n].u8PortPin); ++ assert = GPIO_PORT(gpio_table[n].u8Value); ++ pin = GPIO_PIN(gpio_table[n].u8PortPin); ++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr; ++ shift = GPIO_SHIFT(port, pin); ++ ++ gpio_value = readl(base + GPIO_DATA_VALUE); ++ if ((assert &&asserted) || !(assert || asserted)) { ++ // set the bit ++ gpio_value |= (1 << shift); ++ } else { ++ // clear the bit ++ gpio_value &= ~(1 << shift); ++ } ++ writel(gpio_value, base + GPIO_DATA_VALUE); ++} ++ ++int gpio_get_value(int n) ++{ ++ uint8_t port; ++ uint8_t pin; ++ uint32_t base; ++ uint8_t shift; ++ uint8_t assert; ++ uint32_t gpio_value; ++ ++ if (n >= gpio_max || !gpio_table) { ++ return -1; ++ } ++ port = GPIO_PORT(gpio_table[n].u8PortPin); ++ assert = GPIO_PORT(gpio_table[n].u8Value); ++ pin = GPIO_PIN(gpio_table[n].u8PortPin); ++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr; ++ shift = GPIO_SHIFT(port, pin); ++ ++ gpio_value = readl(base + GPIO_DATA_VALUE); ++ gpio_value >>= shift; ++ gpio_value &= 1; ++ gpio_value ^= assert; ++ return !gpio_value; ++} ++ ++void gpio_init(const GPIOValue* table, size_t count) ++{ ++ uint32_t pclk, value; ++ int i; ++ ++ gpio_table = table; ++ gpio_max = count; ++ /* set up the debounce timers (in units of PCLK cycles) */ ++ pclk = ast_get_ahbclk(); ++ /* GPIO_DEBOUNCE_120us */ ++ writel((pclk / 1000000) * 120, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_0); ++ /* GPIO_DEBOUNCE_8ms */ ++ writel((pclk / 1000000) * 8000, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_1); ++ /* GPIO_DEBOUNCE_16ms */ ++ writel((pclk / 1000000) * 16000, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_2); ++ ++ for (i = 0; i < gpio_max; i++) { ++ uint8_t port; ++ uint8_t pin; ++ uint32_t base; ++ uint8_t shift; ++ ++ port = GPIO_PORT(gpio_table[i].u8PortPin); ++ pin = GPIO_PIN(gpio_table[i].u8PortPin); ++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr; ++ shift = GPIO_SHIFT(port, pin); ++ ++ /* set direction */ ++ value = readl(base + GPIO_DIRECTION); ++ if (gpio_table[i].u8PinCFG & GPCFG_OUTPUT_EN) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DIRECTION); ++ ++ /* set data value */ ++ value = readl(base + GPIO_DATA_VALUE); ++ if (gpio_table[i].u8Value) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DATA_VALUE); ++ ++ /* set debounce */ ++ base = GPIO_BASES[GPIO_GROUP(port)].u32debounce; ++ value = readl(base + GPIO_DEBOUNCE_SEL_0); ++ if (gpio_table[i].u8Debounce & 0x01) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DEBOUNCE_SEL_0); ++ value = readl(base + GPIO_DEBOUNCE_SEL_1); ++ if (gpio_table[i].u8Debounce & 0x02) ++ value |= (1 << shift); ++ else ++ value &= ~(1 << shift); ++ writel(value, base + GPIO_DEBOUNCE_SEL_1); ++ } ++} ++ ++int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int n; ++ if (argc < 3) { ++ return 1; ++ } ++ n = simple_strtoul(argv[2], NULL, 16); ++ if (argv[1][0] == 'g') { ++ printf("%d\n", gpio_get_value(n)); ++ return 0; ++ } ++ if (argc < 4) { ++ return 1; ++ } ++ if (argv[1][0] == 's') { ++ int value; ++ value = simple_strtoul(argv[3], NULL, 16); ++ gpio_set_value(n, value); ++ return 0; ++ } ++ ++ return 1; ++} ++U_BOOT_CMD(gpio, 4, 0, do_gpio, ++ "do stuff with gpios <set|get> [n] [value]", ++ ""); +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h +new file mode 100644 +index 0000000..a820c0f +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -0,0 +1,102 @@ ++#ifndef __HW_GPIO_H__ ++#define __HW_GPIO_H__ ++ ++#define GPIO_PORT_A 0 ++#define GPIO_PORT_B 1 ++#define GPIO_PORT_C 2 ++#define GPIO_PORT_D 3 ++#define GPIO_PORT_E 4 ++#define GPIO_PORT_F 5 ++#define GPIO_PORT_G 6 ++#define GPIO_PORT_H 7 ++#define GPIO_PORT_I 8 ++#define GPIO_PORT_J 9 ++#define GPIO_PORT_K 10 ++#define GPIO_PORT_L 11 ++#define GPIO_PORT_M 12 ++#define GPIO_PORT_N 13 ++#define GPIO_PORT_O 14 ++#define GPIO_PORT_P 15 ++#define GPIO_PORT_Q 16 ++#define GPIO_PORT_R 17 ++#define GPIO_PORT_S 18 ++#define GPIO_PORT_T 19 ++#define GPIO_PORT_U 20 ++#define GPIO_PORT_V 21 ++#define GPIO_PORT_W 22 ++#define GPIO_PORT_X 23 ++#define GPIO_PORT_Y 24 ++#define GPIO_PORT_Z 25 ++#define GPIO_PORT_AA 26 ++#define GPIO_PORT_AB 27 ++#define GPIO_PORT_AC 28 ++ ++#define GPIO_PIN_0 0 ++#define GPIO_PIN_1 1 ++#define GPIO_PIN_2 2 ++#define GPIO_PIN_3 3 ++#define GPIO_PIN_4 4 ++#define GPIO_PIN_5 5 ++#define GPIO_PIN_6 6 ++#define GPIO_PIN_7 7 ++ ++#define GPIO_DEBOUNCE_TIMER_0 0x50 ++#define GPIO_DEBOUNCE_TIMER_1 0x54 ++#define GPIO_DEBOUNCE_TIMER_2 0x58 ++ ++/* relative to u32ddr base */ ++#define GPIO_DATA_VALUE 0x00 ++#define GPIO_DIRECTION 0x04 ++/* relative to u32intcfg base */ ++#define GPIO_INT_ENABLE 0x00 ++#define GPIO_INT_SENSE0 0x04 ++#define GPIO_INT_SENSE1 0x18 ++#define GPIO_INT_SENSE2 0x1c ++#define GPIO_INT_STATUS 0x20 ++#define GPIO_RESET_TOL 0x24 ++/* relative to u32debounce base */ ++#define GPIO_DEBOUNCE_SEL_0 0 ++#define GPIO_DEBOUNCE_SEL_1 4 ++/* relative to u32cmdsrc base */ ++#define GPIO_CMD_SRC_0 0 ++#define GPIO_CMD_SRC_1 4 ++ ++#define PORT_PIN(PORT, PIN) (((PORT) << 3) | ((PIN)&0x07)) ++#define GPIO_PIN(N) (N & 0x07) ++#define GPIO_PORT(N) (N >> 3) ++#define GPIO_SHIFT(PORT, PIN) ((PIN) + (((PORT) % 4) * 8)) ++#define GPIO_GROUP(PORT) ((PORT) / 4) ++ ++#define ID_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_6) ++#define GRN_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_4) ++#define AMB_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_5) ++#define FORCE_BMC_UPDATE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_0) ++#define TPM_EN_PULSE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_6) ++ ++ ++// GPIO Configuration Register bits ++#define GPCFG_EVENT_TO_SMI (1 << 7) // 1 == enabled ++#define GPCFG_EVENT_TO_IRQ (1 << 6) // 1 == enabled ++#define GPCFG_DEBOUNCE_EN (1 << 5) // 1 == input debounce, 0 == pulse output ++#define GPCFG_ACTIVE_HIGH (1 << 4) // 1 == Active high ++#define GPCFG_LEVEL_TRIG (1 << 3) // 1 == level (default), 0 == edge ++#define GPCFG_OUTPUT_EN (1 << 0) // 1 == Output enabled ++ ++// GPIO Debounce and Blink Configuration Register bits ++#define GPIO_DEBOUNCE_NONE 0x00 ++#define GPIO_DEBOUNCE_60US 0x01 ++#define GPIO_DEBOUNCE_8MS 0x02 ++#define GPIO_DEBOUNCE_16MS 0x03 ++ ++typedef struct { ++ uint8_t u8PortPin; ++ uint8_t u8PinCFG; ++ uint8_t u8Value; ++ uint8_t u8Debounce; ++} GPIOValue; ++ ++void gpio_init(const GPIOValue* table, size_t count); ++void gpio_set_value(int n, int asserted); ++int gpio_get_value(int n); ++ ++#endif /* __HW_GPIO_H__ */ +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index c2a8b33..069e7a3 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -14,6 +14,47 @@ + #include <asm/arch/aspeed.h> + + #include "ast-g5.h" ++#include "ast-g5-gpio.h" ++ ++/* Names to match the GPIOs */ ++enum gpio_names { ++ GPIO_ID_LED = 0, ++ GPIO_GREEN_LED, ++ GPIO_AMBER_LED, ++ GPIO_FF_UPD_JUMPER, ++ GPIO_ENABLE_TPM_PULSE, ++}; ++ ++#define GPIO_CFG_DEFAULT (GPCFG_ACTIVE_HIGH | GPCFG_LEVEL_TRIG) ++// Active High, Level, Output Disabled ++ ++#define GPIO_CFG_FP_LED (GPCFG_OUTPUT_EN) ++// Active High, Pull-up, Level, Output Disabled ++ ++// Format is: ++// GPIO PORT, GPIO PIN Number, GPIO PIN Configuration, GPIO PIN Value, GPIO ++// Debounce/Blink Setting ++static const GPIOValue gpio_table[] = { ++ /* ID LED pin S6 - low asserted, 0=on */ ++ [GPIO_ID_LED] = {ID_LED_PORT_PIN, GPIO_CFG_FP_LED, 0, ++ GPIO_DEBOUNCE_NONE}, ++ ++ /* Green LED pin S4 - high asserted, 0=off */ ++ [GPIO_GREEN_LED] = {GRN_LED_PORT_PIN, GPIO_CFG_FP_LED, 1, ++ GPIO_DEBOUNCE_NONE}, ++ ++ /* Amber LED pin S5 - high asserted, 0=off */ ++ [GPIO_AMBER_LED] = {AMB_LED_PORT_PIN, GPIO_CFG_FP_LED, 1, ++ GPIO_DEBOUNCE_NONE}, ++ ++ /* Force Update Jumper -- pin D0 */ ++ [GPIO_FF_UPD_JUMPER] = {FORCE_BMC_UPDATE_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ ++ /* Enable Pulse -- pin D6 */ ++ [GPIO_ENABLE_TPM_PULSE] = {PORT_PIN(GPIO_PORT_D, GPIO_PIN_6), ++ GPIO_CFG_DEFAULT, 0, GPIO_DEBOUNCE_8MS}, ++}; + + #define LPC_SNOOP_ADDR 0x80 + #define HICR5 0x080 /* Host Interface Control Register 5 */ +@@ -107,6 +148,7 @@ static void sgpio_init(void) + extern void espi_init(void); + void ast_g5_intel(void) + { ++ gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); + } +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +index 9fd10ec..908db14 100644 +--- a/board/aspeed/ast-g5/ast-g5.h ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -3,5 +3,6 @@ + + #include <common.h> + #include "ast-g5-irq.h" ++#include "ast-g5-gpio.h" + + #endif /* _AST_G5_H_ */ diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch new file mode 100644 index 000000000..c6ee49f57 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch @@ -0,0 +1,96 @@ +From d08d22af794eed7b928ab96030a103cfb7bf6ce1 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 14:59:04 -0800 +Subject: [PATCH] Update Force Firmware Update Jumper to use new gpio API + +Add a function that allows easy reading of the FFUJ from other +functions, such as autoboot. + +Change-Id: I8ead931e9dd828522095a0ef386875be652ec885 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +--- + arch/arm/include/asm/arch-aspeed/ast-g5-intel.h | 19 +++++++++++++++++++ + arch/arm/include/asm/arch-aspeed/platform.h | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 5 +++++ + common/autoboot.c | 6 ++++++ + 4 files changed, 31 insertions(+) + create mode 100644 arch/arm/include/asm/arch-aspeed/ast-g5-intel.h + +diff --git a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +new file mode 100644 +index 0000000..cd9a099 +--- /dev/null ++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifndef __AST_INTEL_G5_H__ ++#define __AST_INTEL_G5_H__ ++ ++#define AST_G5_INTEL 1 ++ ++#ifndef __ASSEMBLY__ ++int intel_force_firmware_jumper_enabled(void); ++#endif ++ ++#endif /* __AST_INTEL_G5_H__ */ +diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h +index 92ea33b..3b06e52 100644 +--- a/arch/arm/include/asm/arch-aspeed/platform.h ++++ b/arch/arm/include/asm/arch-aspeed/platform.h +@@ -27,6 +27,7 @@ + #include <asm/arch/ast2400_platform.h> + #elif defined(AST_SOC_G5) + #include <asm/arch/ast_g5_platform.h> ++#include <asm/arch/ast-g5-intel.h> + #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ + #else + #err "No define for platform.h" +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 069e7a3..144765a 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -145,6 +145,11 @@ static void sgpio_init(void) + writel(value, AST_GPIO_BASE + GPIO254); + } + ++int intel_force_firmware_jumper_enabled(void) ++{ ++ return gpio_get_value(GPIO_FF_UPD_JUMPER); ++} ++ + extern void espi_init(void); + void ast_g5_intel(void) + { +diff --git a/common/autoboot.c b/common/autoboot.c +index c52bad8..d66c0fa 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -14,6 +14,7 @@ + #include <menu.h> + #include <post.h> + #include <u-boot/sha256.h> ++#include <asm/arch/platform.h> + + DECLARE_GLOBAL_DATA_PTR; + +@@ -259,6 +260,11 @@ static int abortboot(int bootdelay) + { + int abort = 0; + ++# ifdef AST_G5_INTEL ++ if (intel_force_firmware_jumper_enabled()) ++ return 1; ++# endif ++ + if (bootdelay >= 0) + abort = __abortboot(bootdelay); + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch new file mode 100644 index 000000000..26b4c4fc9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch @@ -0,0 +1,158 @@ +From 320cf189fd017e3578b6949ff640213d7bddb20c Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 14:44:49 -0800 +Subject: [PATCH] Add basic timer support for Aspeed g5 in U-Boot + +Timers will be used for timing events and making blinky LEDs. This just +adds the API and infrastructure. + +Change-Id: I8ff03b26070b43a47fb970ddf6124d6c3f29b058 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 1 + + board/aspeed/ast-g5/ast-g5-timer.c | 66 ++++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-timer.h | 27 ++++++++++++++++ + board/aspeed/ast-g5/ast-g5.h | 1 + + 5 files changed, 96 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-timer.c + create mode 100644 board/aspeed/ast-g5/ast-g5-timer.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 2970ae5..9022433 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -3,3 +3,4 @@ obj-y += ast-g5-intel.o + obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o + obj-y += ast-g5-gpio.o ++obj-y += ast-g5-timer.o +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 144765a..6e45cb4 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -15,6 +15,7 @@ + + #include "ast-g5.h" + #include "ast-g5-gpio.h" ++#include "ast-g5-timer.h" + + /* Names to match the GPIOs */ + enum gpio_names { +diff --git a/board/aspeed/ast-g5/ast-g5-timer.c b/board/aspeed/ast-g5/ast-g5-timer.c +new file mode 100644 +index 0000000..5615722 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-timer.c +@@ -0,0 +1,66 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++#include <asm/io.h> ++#include <asm/arch/regs-scu.h> ++#include <asm/arch/ast_scu.h> ++#include <asm/arch/aspeed.h> ++ ++#include "ast-g5.h" ++#include "ast-g5-timer.h" ++#include "ast-g5-irq.h" ++ ++static const int timer_irqs[] = {16, 17, 18, 35, 37, 37, 38, 39}; ++/* offsets from AST_TIMER_BASE for each timer */ ++static const uint32_t timer_bases[] = {0, 0x10, 0x20, 0x40, ++ 0x50, 0x60, 0x70, 0x80}; ++#define TIMER_1MHZ_CLK_COUNT 1000000u ++#define TIMER_ENABLE 1 ++#define TIMER_1MHZ_CLK_SEL 2 ++#define TIMER_ENABLE_IRQ 4 ++#define TIMER_ENABLE_PULSE 8 ++#define TIMER_CONTROL 0x30 ++#define TIMER_RELOAD 0x04 ++ ++void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler) ++{ ++ if (n < 0 || n > 7) { ++ return; ++ } ++ uint32_t tctrl = readl(AST_TIMER_BASE + TIMER_CONTROL); ++ writel(tctrl & ~(0x0f << (n * 4)), AST_TIMER_BASE + TIMER_CONTROL); ++ ++ // figure out best base for requested frequency ++ // (this will give 1MHz clock preference if period is within 1ms of ++ // requested) ++ uint32_t v = TIMER_1MHZ_CLK_COUNT / freq; ++ if (v > 1000 || v * freq == TIMER_1MHZ_CLK_COUNT) { ++ tctrl |= (TIMER_1MHZ_CLK_SEL << (n * 4)); ++ } else { ++ uint32_t pclk = ast_get_ahbclk(); ++ v = pclk / freq; ++ } ++ writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD); ++ if (handler) { ++ request_irq(timer_irqs[n], handler); ++ tctrl |= (TIMER_ENABLE_IRQ << (n * 4)); ++ } ++ tctrl |= (TIMER_ENABLE << (n * 4)); ++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL); ++} ++ ++void timer_disable(int n) ++{ ++ if (n < 0 || n > 7) { ++ return; ++ } ++ uint32_t tctrl = readl(AST_TIMER_BASE + TIMER_CONTROL); ++ writel(tctrl & ~(0x0f << (n * 4)), AST_TIMER_BASE + TIMER_CONTROL); ++} +diff --git a/board/aspeed/ast-g5/ast-g5-timer.h b/board/aspeed/ast-g5/ast-g5-timer.h +new file mode 100644 +index 0000000..4b1ac28 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-timer.h +@@ -0,0 +1,27 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifndef __AST_G5_TIMER_H__ ++#define __AST_G5_TIMER_H__ ++ ++#include <common.h> ++ ++#define TIMER_1 0 ++#define TIMER_2 1 ++#define TIMER_3 2 ++#define TIMER_4 3 ++#define TIMER_5 4 ++#define TIMER_6 5 ++#define TIMER_7 6 ++#define TIMER_8 7 ++ ++void timer_enable(int n, uint32_t freq, interrupt_handler_t handler); ++void timer_disable(int n); ++ ++#endif /* __AST_G5_TIMER_H__ */ +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +index 908db14..28fe5ea 100644 +--- a/board/aspeed/ast-g5/ast-g5.h ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -4,5 +4,6 @@ + #include <common.h> + #include "ast-g5-irq.h" + #include "ast-g5-gpio.h" ++#include "ast-g5-timer.h" + + #endif /* _AST_G5_H_ */ diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch new file mode 100644 index 000000000..16eb31250 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch @@ -0,0 +1,142 @@ +From bc6ea87d8213ecdc5ab7cced8b2fc4284fdef019 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 12:16:53 -0800 +Subject: [PATCH] Add status and ID LED support + +Add status (amber and green) and ID (blue) LED support. In the +bootloader phase, the LEDs should be blinking. When booting linux, they +should turn to a fixed state. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Change-Id: Ic9595621b21000ef465ff57ed2047855296e2714 + +--- + board/aspeed/ast-g5/ast-g5-intel.c | 110 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 110 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 6e45cb4..e53f5eb 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -146,6 +146,110 @@ static void sgpio_init(void) + writel(value, AST_GPIO_BASE + GPIO254); + } + ++/* running the timer at 48 hertz will easily give a 24Hz blink */ ++#define TICK_HZ 48 ++#define BLINK_DELAY(HZ) ((int)((TICK_HZ / (HZ)) / 2) - 1) ++typedef enum { ++ /* ++ * Identifies the control request for the ID LED. ++ */ ++ EIDLED_Initialize = 0, ++ EIDLED_Tick, ++ EIDLED_Toggle, ++ EIDLED_Off, ++ EIDLED_On, ++ EIDLED_Blink, ++ EIDLED_Blink_24HZ = EIDLED_Blink + BLINK_DELAY(24), ++ EIDLED_Blink_12HZ = EIDLED_Blink + BLINK_DELAY(12), ++ EIDLED_Blink_6HZ = EIDLED_Blink + BLINK_DELAY(6), ++ EIDLED_Blink_3HZ = EIDLED_Blink + BLINK_DELAY(3), ++ EIDLED_Blink_1HZ = EIDLED_Blink + BLINK_DELAY(1), ++ EIDLED_Blink_0_5HZ = EIDLED_Blink + BLINK_DELAY(0.5), ++} EIDLEDControl; ++ ++struct led_info { ++ int gpio; ++ EIDLEDControl mode; ++ int count; ++ int state; ++}; ++ ++static struct led_info s_led_info[] = { ++ [GPIO_ID_LED] = {GPIO_ID_LED, EIDLED_Blink_3HZ, 1, 0}, ++ [GPIO_GREEN_LED] = {GPIO_GREEN_LED, EIDLED_Off, 0, 0}, ++ [GPIO_AMBER_LED] = {GPIO_AMBER_LED, EIDLED_Off, 0, 0}, ++}; ++ ++extern void gpio_set_value(int n, int asserted); ++void id_led_control(int id, int action) ++{ ++ if (id >= ARRAY_SIZE(s_led_info)) { ++ return; ++ } ++ /* don't bother with LEDs that are not initialized */ ++ if (EIDLED_Initialize == s_led_info[id].mode) { ++ return; ++ } ++ ++ /* check for a blinker action */ ++ if (EIDLED_Tick == action) { ++ if (s_led_info[id].mode < EIDLED_Blink) { ++ return; ++ } ++ /* check countdown for blink */ ++ if (s_led_info[id].count == 0) { ++ s_led_info[id].count = ++ s_led_info[id].mode - EIDLED_Blink; ++ s_led_info[id].state = !s_led_info[id].state; ++ } else { ++ s_led_info[id].count--; ++ return; ++ } ++ } else if (EIDLED_Toggle == action) { ++ s_led_info[id].state = !s_led_info[id].state; ++ s_led_info[id].mode = ++ s_led_info[id].state ? EIDLED_On : EIDLED_Off; ++ } else if (action > EIDLED_Toggle) { ++ s_led_info[id].mode = action; ++ if (EIDLED_Off == action) { ++ s_led_info[id].state = 0; ++ } else if (EIDLED_On == action) { ++ s_led_info[id].state = 1; ++ } else if (action >= EIDLED_Blink) { ++ s_led_info[id].count = action - EIDLED_Blink; ++ /* wait for the next tick */ ++ return; ++ } ++ } else if (EIDLED_Initialize == action) { ++ if (s_led_info[id].mode >= EIDLED_Blink) { ++ s_led_info[id].count = ++ s_led_info[id].mode - EIDLED_Blink; ++ } ++ } ++ gpio_set_value(s_led_info[id].gpio, s_led_info[id].state); ++} ++ ++static void timer8_irq_handler(void *regs) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(s_led_info); i++) { ++ id_led_control(i, EIDLED_Tick); ++ } ++} ++ ++void timer8_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(s_led_info); i++) { ++ id_led_control(i, EIDLED_Initialize); ++ } ++ ++ /* set up the timer to fire at TICK_HZ HZ */ ++ timer_enable(TIMER_8, TICK_HZ, timer8_irq_handler); ++} ++ + int intel_force_firmware_jumper_enabled(void) + { + return gpio_get_value(GPIO_FF_UPD_JUMPER); +@@ -157,4 +261,10 @@ void ast_g5_intel(void) + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); ++ timer8_init(); ++ if (intel_force_firmware_jumper_enabled()) { ++ id_led_control(GPIO_AMBER_LED, EIDLED_On); ++ } else { ++ id_led_control(GPIO_GREEN_LED, EIDLED_On); ++ } + } diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch new file mode 100644 index 000000000..10a45fa23 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch @@ -0,0 +1,130 @@ +From 34ccbd14d8f5caa66523a762e2030b6f105206cb Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 15:57:57 -0800 +Subject: [PATCH] aspeed: add Pwm Driver + +Change-Id: Ia8b80212f7c70aafcc6a71782936ec95cf9b7f38 + +--- + board/aspeed/ast-g5/ast-g5-intel.c | 105 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 105 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e53f5eb..c7ae566 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -255,9 +255,114 @@ int intel_force_firmware_jumper_enabled(void) + return gpio_get_value(GPIO_FF_UPD_JUMPER); + } + ++/* PWM offsets */ ++ ++#define PWM_BASE_ADDR 0x1E786000 ++#define PWM_CONTROL 0x00 ++#define PWM_CLOCK_SELECTION 0x04 ++#define PWM_DUTY_CYCLE 0x08 ++#define PWM_M0 0x10 ++#define PWM_M1 0x14 ++#define PWM_N0 0x18 ++#define PWM_N1 0x1c ++#define PWM_CONTROL_EXT 0x40 ++#define PWM_CLOCK_SEL_EXT 0x44 ++#define PWM_O0 0x50 ++#define PWM_O1 0x54 ++#define PWM_CHANNEL_COUNT 8 ++ ++#define PWM_CLK_ENABLE BIT(0) ++#define PWM_DUTY(PCT) (((PCT) * 128) / 100) ++#define PWM_DUTY_VALUE PWM_DUTY(57) ++ ++ ++static inline uint32_t ast_scu_read(uint32_t reg) ++{ ++ uint32_t val = readl(AST_SCU_BASE + reg); ++ ++ debug("ast_scu_read : reg = 0x%08x, val = 0x%08x\n", reg, val); ++ return val; ++} ++ ++static inline void ast_scu_write(uint32_t val, uint32_t reg) ++{ ++ debug("ast_scu_write : reg = 0x%08x, val = 0x%08x\n", reg, val); ++ ++ writel(SCU_PROTECT_UNLOCK, AST_SCU_BASE); ++ writel(val, AST_SCU_BASE + reg); ++#ifdef CONFIG_AST_SCU_LOCK ++ writel(0xaa, AST_SCU_BASE); ++#endif ++} ++ ++static void pwm_init(void) ++{ ++ uint32_t val; ++ uint32_t chan; ++ ++ /* select pwm 0-7 */ ++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL3); ++ val |= (SCU_FUN_PIN_VPIG7 | SCU_FUN_PIN_VPIG6 | SCU_FUN_PIN_VPIG5 ++ | SCU_FUN_PIN_VPIG4 | SCU_FUN_PIN_VPIG3 | SCU_FUN_PIN_VPIG2 ++ | SCU_FUN_PIN_VPIG1 | SCU_FUN_PIN_VPIG0); ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL3); ++ ++ /* disable video output mux */ ++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL5); ++ val &= 0xffffffcf; ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL5); ++ val = readl(AST_SCU_FUN_PIN_CTRL6); ++ val &= 0xfffffffc; ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL6); ++ ++ /* SCU reset of PWM module */ ++ val = ast_scu_read(AST_SCU_RESET); ++ val |= SCU_RESET_PWM; ++ ast_scu_write(val, AST_SCU_RESET); ++ val &= ~SCU_RESET_PWM; ++ ast_scu_write(val, AST_SCU_RESET); ++ ++ /* set M, N, and 0 clock regs to 0 */ ++ writel(0, PWM_BASE_ADDR + PWM_M0); ++ writel(0, PWM_BASE_ADDR + PWM_N0); ++ writel(0, PWM_BASE_ADDR + PWM_O0); ++ ++ /* disable fans and tachos, set M type control */ ++ writel(0x1, PWM_BASE_ADDR + PWM_CONTROL); ++ writel(0x1, PWM_BASE_ADDR + PWM_CONTROL_EXT); ++ ++ /* enable pwm channels */ ++ for (chan = 0; chan < PWM_CHANNEL_COUNT; chan++) { ++ uint32_t base = chan < 4 ? PWM_BASE_ADDR : PWM_BASE_ADDR + 0x40; ++ uint8_t ch_duty_shift = 16 * (chan & 0x1); ++ uint8_t ch_pair = (chan & 0x3) / 2; ++ ++ /* enable pwm for the channel */ ++ val = readl(base); ++ val |= ((1 << (chan & 0x3)) << 8); ++ writel(val, base); ++ ++ /* set duty cycle */ ++ val = readl(base + PWM_DUTY_CYCLE + ch_pair * 4); ++ val &= ~(0xffff << ch_duty_shift); ++ val |= (((uint32_t)PWM_DUTY_VALUE) << 8) << ch_duty_shift; ++ writel(val, base + PWM_DUTY_CYCLE + ch_pair * 4); ++ } ++ ++ /* set up clock type M: period = 127 units at 24MHz/8 (resulting ~23kHz period) */ ++ writel(0x7f30, PWM_BASE_ADDR + PWM_CLOCK_SELECTION); ++ ++ /* enable pwm-tacho */ ++ ++ val = readl(PWM_BASE_ADDR + PWM_CONTROL); ++ val |= PWM_CLK_ENABLE; ++ writel(val, PWM_BASE_ADDR + PWM_CONTROL); ++} ++ + extern void espi_init(void); + void ast_g5_intel(void) + { ++ pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch new file mode 100644 index 000000000..22191f07a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch @@ -0,0 +1,89 @@ +From 040c9c13778076403198ce93f43c4aa3a1ed3907 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Sat, 17 Nov 2018 14:17:27 -0800 +Subject: [PATCH] Keep interrupts enabled until last second + +The U-Boot bootm command disabled interrupts almost first thing. This +would prevent a person hitting the power button on the host immediatly +after AC on because the BMC would fail to respond to the espi interrupts +and the host would power off. + +Change-Id: I6c0fb5cca1be6c326da4c9a3d3dfbab89dac9928 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +--- + board/aspeed/ast-g5/ast-g5-intel.c | 8 ++++++++ + common/bootm.c | 7 ------- + common/bootm_os.c | 1 + + 3 files changed, 9 insertions(+), 7 deletions(-) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index c7ae566..01f8a13 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -255,6 +255,14 @@ int intel_force_firmware_jumper_enabled(void) + return gpio_get_value(GPIO_FF_UPD_JUMPER); + } + ++void arch_preboot_os(void) ++{ ++ // last second before booting... set the LEDs ++ id_led_control(GPIO_ID_LED, EIDLED_On); ++ id_led_control(GPIO_GREEN_LED, EIDLED_On); ++ id_led_control(GPIO_AMBER_LED, EIDLED_Off); ++} ++ + /* PWM offsets */ + + #define PWM_BASE_ADDR 0x1E786000 +diff --git a/common/bootm.c b/common/bootm.c +index 2431019..46909ec 100644 +--- a/common/bootm.c ++++ b/common/bootm.c +@@ -602,7 +602,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int states, bootm_headers_t *images, int boot_progress) + { + boot_os_fn *boot_fn; +- ulong iflag = 0; + int ret = 0, need_boot_fn; + + images->state |= states; +@@ -626,7 +625,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + if (!ret && (states & BOOTM_STATE_LOADOS)) { + ulong load_end; + +- iflag = bootm_disable_interrupts(); + ret = bootm_load_os(images, &load_end, 0); + if (ret == 0) + lmb_reserve(&images->lmb, images->os.load, +@@ -670,8 +668,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | + BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); + if (boot_fn == NULL && need_boot_fn) { +- if (iflag) +- enable_interrupts(); + printf("ERROR: booting os '%s' (%d) is not supported\n", + genimg_get_os_name(images->os.os), images->os.os); + bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); +@@ -711,9 +707,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + + /* Deal with any fallout */ + err: +- if (iflag) +- enable_interrupts(); +- + if (ret == BOOTM_ERR_UNIMPLEMENTED) + bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); + else if (ret == BOOTM_ERR_RESET) +diff --git a/common/bootm_os.c b/common/bootm_os.c +index 9ec84bd..b56eb39 100644 +--- a/common/bootm_os.c ++++ b/common/bootm_os.c +@@ -476,6 +476,7 @@ __weak void arch_preboot_os(void) + int boot_selected_os(int argc, char * const argv[], int state, + bootm_headers_t *images, boot_os_fn *boot_fn) + { ++ disable_interrupts(); + arch_preboot_os(); + boot_fn(state, argc, argv, images); + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch new file mode 100644 index 000000000..d93d9c4a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch @@ -0,0 +1,112 @@ +From 711c7bc5a07b62e8369bc76a9db265c960bacef8 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Mon, 19 Nov 2018 11:04:02 -0800 +Subject: [PATCH] Rewrite memmove to optimize on word transfers + +Reading from the flash at boot time was using byte-sized transfers, +which ultimately turns into four word transfers over spi for every real +word read. This change breaks memmove down into a header, body, and +trailer, where the body is all done with word-sized transfers. + +Change-Id: Ie0a1f3261e507fb34a908571883d9bf04a1059ee +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +--- + lib/string.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 64 insertions(+), 13 deletions(-) + +diff --git a/lib/string.c b/lib/string.c +index 67d5f6a..0bf472f 100644 +--- a/lib/string.c ++++ b/lib/string.c +@@ -505,26 +505,77 @@ void * memcpy(void *dest, const void *src, size_t count) + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +-void * memmove(void * dest,const void *src,size_t count) ++void *memmove(void *dest, const void *src, size_t count) + { +- char *tmp, *s; +- +- if (src == dest) ++ unsigned char *bdst = (unsigned char *)dest; ++ const unsigned char *bsrc = (const unsigned char *)src; ++ unsigned long *ldst; ++ const unsigned long *lsrc; ++ size_t unaligned_header = 0, unaligned_trailer = 0; ++ size_t unaligned_src = ++ (sizeof(*ldst) - (size_t)src) & (sizeof(*ldst) - 1); ++ size_t unaligned_dst = ++ (sizeof(*ldst) - (size_t)dest) & (sizeof(*ldst) - 1); ++ ++ if (src == dest || !count) + return dest; + ++ if (unaligned_src || unaligned_dst) { ++ if (unaligned_dst != unaligned_src) { ++ unaligned_header = count; ++ } else { ++ unaligned_header = unaligned_src; ++ if (unaligned_header > count) { ++ unaligned_header = count; ++ } ++ } ++ count -= unaligned_header; ++ } ++ if (count & (sizeof(*ldst) - 1)) { ++ unaligned_trailer = count & (sizeof(*ldst) - 1); ++ count -= unaligned_trailer; ++ } ++ + if (dest <= src) { +- tmp = (char *) dest; +- s = (char *) src; +- while (count--) +- *tmp++ = *s++; ++ /* possible un-aligned bytes */ ++ while (unaligned_header--) ++ *bdst++ = *bsrc++; ++ ++ /* aligned words */ ++ ldst = (unsigned long *)bdst; ++ lsrc = (const unsigned long *)bsrc; ++ while (count >= sizeof(*ldst)) { ++ count -= sizeof(*ldst); ++ *ldst++ = *lsrc++; + } +- else { +- tmp = (char *) dest + count; +- s = (char *) src + count; +- while (count--) +- *--tmp = *--s; ++ ++ /* possibly un-aligned bytes */ ++ bdst = (unsigned char *)ldst; ++ bsrc = (const unsigned char *)lsrc; ++ while (unaligned_trailer--) ++ *bdst++ = *bsrc++; ++ } else { ++ bdst += unaligned_header + count + unaligned_trailer; ++ bsrc += unaligned_header + count + unaligned_trailer; ++ ++ /* possibly un-aligned bytes */ ++ while (unaligned_trailer--) ++ *--bdst = *--bsrc; ++ ++ /* aligned words */ ++ ldst = (unsigned long *)bdst; ++ lsrc = (unsigned long *)bsrc; ++ while (count >= sizeof(*ldst)) { ++ count -= sizeof(*ldst); ++ *--ldst = *--lsrc; + } + ++ /* possibly un-aligned bytes */ ++ bdst = (unsigned char *)ldst; ++ bsrc = (const unsigned char *)lsrc; ++ while (unaligned_header--) ++ *--bdst = *--bsrc; ++ } + return dest; + } + #endif diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch new file mode 100644 index 000000000..8a63edbb7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch @@ -0,0 +1,46 @@ +From 9b05a276af65dd436f30b1b2680a09821c5a81aa Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Mon, 17 Dec 2018 20:37:23 -0800 +Subject: [PATCH] u-boot: full platform reset + espi oob-ready + +If the platform is strapped for fast reset, have platform-g5.S do a full +reset and then immediately set oob-ready so the espi master controller +can initiate communication. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +--- + arch/arm/mach-aspeed/platform_g5.S | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-aspeed/platform_g5.S b/arch/arm/mach-aspeed/platform_g5.S +index 2ac1ca4..66427b6 100644 +--- a/arch/arm/mach-aspeed/platform_g5.S ++++ b/arch/arm/mach-aspeed/platform_g5.S +@@ -139,7 +139,7 @@ + But if FW has other initial code executed before platform.S, then it should use WDT_SOC mode. + Use WDT_Full may clear the initial result of prior initial code. + ******************************************************************************/ +-//#define ASTMMC_INIT_RESET_MODE_FULL ++#define ASTMMC_INIT_RESET_MODE_FULL + + /****************************************************************************** + There is a compatibility issue for Hynix DDR4 SDRAM. +@@ -563,6 +563,17 @@ wait_first_reset: + *******************************************/ + + bypass_first_reset: ++ /* Timing from ESPI master requires OOB channel ready bit be set early */ ++ ldr r0, =0x1e6e2070 @ check strapping for eSPI mode ++ tst r0, #0x02000000 @ Test for bit 25 - eSPI Mode ++ beq espi_early_init_done @ if bit 25 clear, dont set OOB ready ++ ++ ldr r0, =0x1e6ee000 ++ ldr r1, [r0] @ ESPI000: ESPI Engine Control Reg ++ orr r1, r1, #0x00000010 @ Set OOB Channel Ready bit ++ str r1, [r0] ++espi_early_init_done: ++ + /* Enable Timer separate clear mode */ + ldr r0, =0x1e782038 + mov r1, #0xAE diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch new file mode 100644 index 000000000..afdd610b3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch @@ -0,0 +1,164 @@ +From 54616ade08517374200a332e50f68ee9d0fbf5c5 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 9 Apr 2019 14:42:05 +0800 +Subject: [PATCH] Add system reset status support + +Will display the reset reasons and other CPU information in u-boot, +and save the reset reasons into kernel command line, +for applications to query. + +Change-Id: I87ada3ecf14368519e4d09035bb1e09fdc05469b +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + arch/arm/include/asm/arch-aspeed/platform.h | 2 + + arch/arm/mach-aspeed/ast-scu.c | 4 ++ + board/aspeed/ast-g5/ast-g5-intel.c | 73 +++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5.c | 7 +++ + 4 files changed, 86 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h +index 3b06e52..4e4140d 100644 +--- a/arch/arm/include/asm/arch-aspeed/platform.h ++++ b/arch/arm/include/asm/arch-aspeed/platform.h +@@ -29,6 +29,8 @@ + #include <asm/arch/ast_g5_platform.h> + #include <asm/arch/ast-g5-intel.h> + #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ ++#define CONFIG_BOARD_LATE_INIT 1 /* Call board_late_init */ ++#define CONFIG_DISPLAY_CPUINFO 1 + #else + #err "No define for platform.h" + #endif +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 3a9ba05..976c59b 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -494,6 +494,9 @@ void ast_scu_sys_rest_info(void) + { + u32 rest = ast_scu_read(AST_SCU_SYS_CTRL); + ++#ifdef AST_SOC_G5 ++ printf("RST : 0x%02x\n", rest); ++#else + if (rest & SCU_SYS_EXT_RESET_FLAG) { + printf("RST : External\n"); + ast_scu_write(SCU_SYS_EXT_RESET_FLAG, AST_SCU_SYS_CTRL); +@@ -506,6 +509,7 @@ void ast_scu_sys_rest_info(void) + } else { + printf("RST : CLK en\n"); + } ++#endif + } + + u32 ast_scu_get_vga_memsize(void) +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 01f8a13..e0bf9ee 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -303,6 +303,79 @@ static inline void ast_scu_write(uint32_t val, uint32_t reg) + #endif + } + ++ ++static void update_bootargs_cmd(const char *key, const char *value) ++{ ++ int buf_len; ++ char *buf; ++ char *cmdline; ++ char comp_key[128]; ++ ++ if (!key || (key[0] == '\0')) { ++ printf("%s - Empty key not allowed\n", __func__); ++ return; ++ } ++ ++ cmdline = getenv("bootargs"); ++ ++ /* Allocate space for maximum possible new command line */ ++ if (value) ++ buf_len = strlen(cmdline) + strlen(key) + 3 + strlen(value); ++ else ++ buf_len = strlen(cmdline) + strlen(key) + 3; ++ ++ buf = malloc(buf_len); ++ if (!buf) { ++ printf("%s: out of memory\n", __func__); ++ return; ++ } ++ memset(buf, 0, buf_len); ++ ++ if (!cmdline) { ++ /* lets add key-value, though bootargs are empty */ ++ snprintf(buf, buf_len, "%s=%s", key, (value ? value : "")); ++ setenv("bootargs", buf); ++ free(buf); ++ return; ++ } ++ ++ snprintf(comp_key, sizeof(comp_key), "%s=", key); ++ char *start = strstr(cmdline, comp_key); ++ ++ /* Check for full word match. Match should be start of cmdline ++ * or there should be space before match */ ++ if (start && ((start == cmdline) || (*(start-1) == ' '))) { ++ char *end = strchr(start, ' '); ++ strncpy(buf, cmdline, (start - cmdline)); ++ ++ if (end) ++ snprintf(buf, buf_len, "%s%s=%s %s", buf, key, ++ (value ? value : ""), end+1); ++ else ++ snprintf(buf, buf_len, "%s%s=%s", buf, key, ++ (value ? value : "")); ++ } else { ++ snprintf(buf, buf_len, "%s %s=%s", cmdline, key, ++ (value ? value : "")); ++ } ++ ++ setenv("bootargs", buf); ++ free(buf); ++} ++ ++void ast_g5_intel_late_init(void) ++{ ++ char value[32]; ++ u32 reset_reason = 0; ++ ++ /* save and clear reset status */ ++ reset_reason = ast_scu_read(AST_SCU_SYS_CTRL); ++ snprintf(value, sizeof(value), "0x%x", reset_reason); ++ ast_scu_write(0, AST_SCU_SYS_CTRL); ++ ++ update_bootargs_cmd("resetreason", value); ++} ++ + static void pwm_init(void) + { + uint32_t val; +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index d41ef9c..0953677 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -19,6 +19,7 @@ + DECLARE_GLOBAL_DATA_PTR; + + extern void ast_g5_intel(void); ++extern void ast_g5_intel_late_init(void); + + int board_early_init_f(void) + { +@@ -40,6 +41,12 @@ int board_init(void) + return 0; + } + ++int board_late_init(void) ++{ ++ ast_g5_intel_late_init(); ++ return 0; ++} ++ + int dram_init(void) + { + u32 vga = ast_scu_get_vga_memsize(); diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch new file mode 100644 index 000000000..6949856db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch @@ -0,0 +1,36 @@ +From 647cc2538ed6b64054c742b4668386fda9394221 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 8 Jan 2019 13:33:15 -0800 +Subject: [PATCH] Enable PCIe L1 support + +This commit enables PCIe L1 support using magic registers. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> + +--- + arch/arm/mach-aspeed/platform_g5.S | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm/mach-aspeed/platform_g5.S b/arch/arm/mach-aspeed/platform_g5.S +index 66427b6..b404353 100644 +--- a/arch/arm/mach-aspeed/platform_g5.S ++++ b/arch/arm/mach-aspeed/platform_g5.S +@@ -2432,6 +2432,18 @@ spi_cbr_end: + bic r1, r1, #0x00400000 + str r1, [r0] + ++ ldr r0, =0x1e6ed07c @ Enable PCIe L1 support ++ ldr r1, =0xa8 ++ str r1, [r0] ++ ++ ldr r0, =0x1e6ed068 ++ ldr r1, =0xc81f0a ++ str r1, [r0] ++ ++ ldr r0, =0x1e6ed07c ++ mov r1, #0 ++ str r1, [r0] ++ + /****************************************************************************** + Configure MAC timing + ******************************************************************************/ diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch new file mode 100755 index 000000000..32a40261f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch @@ -0,0 +1,106 @@ +From 30c634b4969b8a3cd3afc079d60d23d2cb9f5f5c Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 11 Feb 2019 15:19:56 +0800 +Subject: [PATCH] Config host uart clock source using environment variable + +In order to support high speed uart for host uarts, +the uart clock needs to be switched between 24M and 192M. +Config SCU4C based on environment variable hostserialcfg, +this variable is set by IPMI OEM commands. + +Tested: +Change the hostserialcfg variable to 0/1/2/3, +using the below commands: + +ipmitool raw 0x32 0x90 1 0; reboot +cat /sys/class/tty/ttyS*/uartclk, all should be 24MHz + +ipmitool raw 0x32 0x90 1 1; reboot +cat /sys/class/tty/ttyS*/uartclk, ttyS0/2/3 should be 192MHz + +ipmitool raw 0x32 0x90 1 2; reboot +cat /sys/class/tty/ttyS*/uartclk, ttyS1 should be 192MHz + +ipmitool raw 0x32 0x90 1 3; reboot +cat /sys/class/tty/ttyS*/uartclk, ttyS0/12/3 should be 192MHz + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> + +--- + arch/arm/include/asm/arch-aspeed/regs-scu.h | 5 ++++ + board/aspeed/ast-g5/ast-g5-intel.c | 39 +++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h +index 10b983a..8a596ce 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -529,6 +529,11 @@ + /* AST_SCU_MAC_CLK 0x48 - MAC interface clock delay setting register */ + + /* AST_SCU_MISC2_CTRL 0x4C - Misc. 2 Control register */ ++#define SCU_UART5_HS_CLOCK (1 << 28) ++#define SCU_UART4_HS_CLOCK (1 << 27) ++#define SCU_UART3_HS_CLOCK (1 << 26) ++#define SCU_UART2_HS_CLOCK (1 << 25) ++#define SCU_UART1_HS_CLOCK (1 << 24) + #ifdef AST_SOC_G5 + #define SCU_PCIE_MAPPING_HIGH (1 << 15) + #define SCU_MALI_DTY_MODE (1 << 8) +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e0bf9ee..e19df03 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -103,6 +103,9 @@ static const GPIOValue gpio_table[] = { + #define SGPIO_ENABLE 1 + #define GPIO254 0x254 + ++#define HOST_SERIAL_A_HIGH_SPEED (1 << 0) ++#define HOST_SERIAL_B_HIGH_SPEED (1 << 1) ++ + static void sgpio_init(void) + { + uint32_t value; +@@ -368,6 +371,42 @@ void ast_g5_intel_late_init(void) + char value[32]; + u32 reset_reason = 0; + ++ /* By default host serail A and B use normal speed */ ++ uint32_t host_serial_cfg = 0; ++ char *host_serial_cfg_txt = NULL; ++ ++ /* Config the uart clock source based on environment configuration */ ++ host_serial_cfg_txt = getenv("hostserialcfg"); ++ ++ if (host_serial_cfg_txt != NULL) ++ host_serial_cfg = simple_strtoul(host_serial_cfg_txt, NULL, 16); ++ ++ if (host_serial_cfg > (HOST_SERIAL_A_HIGH_SPEED | HOST_SERIAL_B_HIGH_SPEED)) { ++ printf("Invalided hostserialcfg %x, use default!\n", host_serial_cfg); ++ host_serial_cfg = 0; ++ } ++ ++ /* SOL implementation requires uart1/uart3/uart4 have the same clock ++ * source for data forwarding, config uart3 and uart4 ++ */ ++ if (host_serial_cfg & HOST_SERIAL_A_HIGH_SPEED) { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) | ++ SCU_UART1_HS_CLOCK | SCU_UART3_HS_CLOCK | ++ SCU_UART4_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } else { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & ++ ~SCU_UART1_HS_CLOCK & ~SCU_UART3_HS_CLOCK & ++ ~SCU_UART4_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } ++ ++ if (host_serial_cfg & HOST_SERIAL_B_HIGH_SPEED) { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) | ++ SCU_UART2_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } else { ++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) & ++ ~SCU_UART2_HS_CLOCK, AST_SCU_MISC2_CTRL); ++ } ++ + /* save and clear reset status */ + reset_reason = ast_scu_read(AST_SCU_SYS_CTRL); + snprintf(value, sizeof(value), "0x%x", reset_reason); diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch new file mode 100644 index 000000000..63eebe56b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch @@ -0,0 +1,611 @@ +From 1264c57a485a238b715c489b7ca14982af396442 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 13 Mar 2019 14:28:05 +0530 +Subject: [PATCH] KCS driver support in uBoot + +Added KCS support in uBoot. This will enable +KCS channels and set the specified registers +to do KCS communication in uBoot. It also +consist of read and write KCS message transations +work flow implementation( As specified in IPMI +specification Section 9.15). It is enabled +only when Force Firmware Update Jumper is ON. + +Tested By: +Stopped booting in uBoot and sent IPMI commands +via KCS interfaces using cmdtool.efi. + - Get Device ID: + Req: cmdtool.efi 20 18 1 + Res: 00 23 00 12 03 02 BF 57 01 00 7B 00 00 00 00 00 + - Get Self Test Results + Req: cmdtool.efi 20 18 4 + Res: 00 56 00 + - All other commands + Req: cmdtool.efi 20 18 2 + Res: C1 (Invalid). + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 3 + + board/aspeed/ast-g5/ast-g5-kcs.c | 420 +++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-kcs.h | 112 ++++++++++ + 4 files changed, 536 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-kcs.c + create mode 100644 board/aspeed/ast-g5/ast-g5-kcs.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 9022433..05972b9 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -4,3 +4,4 @@ obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o + obj-y += ast-g5-gpio.o + obj-y += ast-g5-timer.o ++obj-y += ast-g5-kcs.o +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e19df03..adc6d10 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -480,6 +480,7 @@ static void pwm_init(void) + } + + extern void espi_init(void); ++extern void kcs_init(void); + void ast_g5_intel(void) + { + pwm_init(); +@@ -489,6 +490,8 @@ void ast_g5_intel(void) + timer8_init(); + if (intel_force_firmware_jumper_enabled()) { + id_led_control(GPIO_AMBER_LED, EIDLED_On); ++ kcs_init(); ++ /* TODO: need to stop the booting here. */ + } else { + id_led_control(GPIO_GREEN_LED, EIDLED_On); + } +diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c +new file mode 100644 +index 0000000..7bff26f +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-kcs.c +@@ -0,0 +1,420 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ast-g5-kcs.h" ++ ++#ifdef DEBUG_KCS_ENABLED ++#define DBG_KCS printf ++#else ++#define DBG_KCS(...) ++#endif ++ ++/* TODO: Move to IPMI file. */ ++#define IPMI_CC_OK 0x00 ++#define IPMI_CC_INVALID 0xC1 ++#define IPMI_CC_UNSPECIFIED 0xFF ++ ++#define KCS_CHANNEL_NO_3 3 ++ ++static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; ++ ++static const struct kcs_io_reg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = { ++ { .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 }, ++ { .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 }, ++ { .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 }, ++ { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 } ++}; ++ ++#define NO_OF_ENABLED_KCS_CHANNELS ARRAY_SIZE(enabled_kcs_channel) ++ ++static struct kcs_packet m_kcs_pkt[NO_OF_ENABLED_KCS_CHANNELS]; ++ ++static u16 read_status(u16 channel_num) ++{ ++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str); ++} ++ ++static void write_status(u16 channel_num, u16 value) ++{ ++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].str); ++} ++ ++static u16 read_data(u16 channel_num) ++{ ++ return readl(AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].idr); ++} ++ ++static void write_data(u16 channel_num, u16 value) ++{ ++ writel(value, AST_LPC_BASE + ast_kcs_bmc_ioregs[channel_num - 1].odr); ++} ++ ++static void set_kcs_state(u16 channel_num, u16 state) ++{ ++ u16 status = read_status(channel_num); ++ ++ status &= ~KCS_STATE_MASK; ++ status |= KCS_STATE(state) & KCS_STATE_MASK; ++ write_status(channel_num, status); ++} ++ ++static struct kcs_packet *get_kcs_packet(u16 channel_num) ++{ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ if (channel_num == enabled_kcs_channel[idx]) ++ return &m_kcs_pkt[idx]; ++ } ++ ++ /* very unlike code hits here. */ ++ DBG_KCS("ERROR: %s error. ChannelNo: %d\n", __func__, channel_num); ++ BUG(); ++} ++ ++static void kcs_force_abort(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ DBG_KCS("ERROR: KCS communication aborted (Channel:%d, Error:%d)\n", ++ channel_num, kcs_pkt->error); ++ set_kcs_state(channel_num, KCS_STATE_ERROR); ++ read_data(channel_num); ++ write_data(channel_num, ZERO_DATA); ++ ++ kcs_pkt->phase = KCS_PHASE_ERROR; ++ kcs_pkt->read_req_done = false; ++ kcs_pkt->data_in_idx = 0; ++} ++ ++static void init_kcs_packet(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ kcs_pkt->channel = channel_num; ++ kcs_pkt->read_req_done = false; ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ kcs_pkt->error = KCS_NO_ERROR; ++ kcs_pkt->data_in_idx = 0; ++ kcs_pkt->data_out_idx = 0; ++ kcs_pkt->data_out_len = 0; ++} ++ ++static void process_kcs_request(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ int i; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ if (!kcs_pkt->read_req_done) ++ return; ++ ++ DBG_KCS("%s:- chan:%d\n", __func__, channel_num); ++ ++#ifdef DEBUG_KCS_ENABLED ++ DBG_KCS("Request data(Len:%d): ", kcs_pkt->data_in_idx); ++ for (i = 0; i < kcs_pkt->data_in_idx; i++) ++ DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); ++ DBG_KCS("\n"); ++#endif ++ ++ /* ++ * TODO: Move it to IPMI Command Handler ++ * Below code is added for timebeing till ++ * we implement the IPMI command handler. ++ */ ++ kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */ ++ kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */ ++ ++ if (((kcs_pkt->data_in[0] >> 2) == 0x06) && ++ (kcs_pkt->data_in[1] == 0x01)) { ++ /* Get Device ID */ ++ u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02, ++ 0xBF, 0x57, 0x01, 0x00, 0x7B, ++ 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ for (i = 0; i < 15; i++) ++ kcs_pkt->data_out[i + 3] = device_id[i]; ++ kcs_pkt->data_out_len = 18; ++ } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) && ++ (kcs_pkt->data_in[1] == 0x04)) { ++ /* Get Self Test Results */ ++ kcs_pkt->data_out[3] = 0x56; ++ kcs_pkt->data_out[4] = 0x00; ++ kcs_pkt->data_out_len = 5; ++ } else { ++ kcs_pkt->data_out[2] = ++ IPMI_CC_INVALID; /* Invalid or not supported. */ ++ kcs_pkt->data_out_len = 3; ++ } ++ /* END: TODO */ ++ ++#ifdef DEBUG_KCS_ENABLED ++ DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); ++ for (i = 0; i < kcs_pkt->data_out_len; i++) ++ DBG_KCS(" 0x%02x", kcs_pkt->data_out[i]); ++ DBG_KCS("\n"); ++#endif ++ ++ kcs_pkt->phase = KCS_PHASE_READ; ++ write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]); ++ kcs_pkt->read_req_done = false; ++} ++ ++static void read_kcs_data(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ ++ switch (kcs_pkt->phase) { ++ case KCS_PHASE_WRITE_START: ++ kcs_pkt->phase = KCS_PHASE_WRITE_DATA; ++ /* fall through */ ++ ++ case KCS_PHASE_WRITE_DATA: ++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) { ++ kcs_pkt->error = KCS_LENGTH_ERROR; ++ kcs_force_abort(channel_num); ++ return; ++ } ++ set_kcs_state(channel_num, KCS_STATE_WRITE); ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] = ++ read_data(channel_num); ++ break; ++ ++ case KCS_PHASE_WRITE_END: ++ if (kcs_pkt->data_in_idx >= MAX_KCS_PKT_SIZE) { ++ kcs_pkt->error = KCS_LENGTH_ERROR; ++ kcs_force_abort(channel_num); ++ return; ++ } ++ set_kcs_state(channel_num, KCS_STATE_READ); ++ kcs_pkt->data_in[kcs_pkt->data_in_idx++] = ++ read_data(channel_num); ++ kcs_pkt->phase = KCS_PHASE_READ_WAIT; ++ kcs_pkt->read_req_done = true; ++ ++ process_kcs_request(channel_num); ++ break; ++ ++ case KCS_PHASE_READ: ++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ ++ u8 data = read_data(channel_num); ++ if (data != KCS_CTRL_CODE_READ) { ++ DBG_KCS("Invalid Read data. Phase:%d, Data:0x%02x\n", ++ kcs_pkt->phase, data); ++ set_kcs_state(channel_num, KCS_STATE_ERROR); ++ write_data(channel_num, ZERO_DATA); ++ break; ++ } ++ ++ if (kcs_pkt->data_out_idx == kcs_pkt->data_out_len) { ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ break; ++ } ++ write_data(channel_num, ++ kcs_pkt->data_out[kcs_pkt->data_out_idx++]); ++ break; ++ ++ case KCS_PHASE_ABORT_1: ++ set_kcs_state(channel_num, KCS_STATE_READ); ++ read_data(channel_num); ++ write_data(channel_num, kcs_pkt->error); ++ kcs_pkt->phase = KCS_PHASE_ABORT_2; ++ break; ++ ++ case KCS_PHASE_ABORT_2: ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ read_data(channel_num); ++ write_data(channel_num, ZERO_DATA); ++ kcs_pkt->phase = KCS_PHASE_IDLE; ++ break; ++ ++ default: ++ kcs_force_abort(channel_num); ++ } ++} ++ ++static void read_kcs_cmd(u16 channel_num) ++{ ++ struct kcs_packet *kcs_pkt = NULL; ++ ++ kcs_pkt = get_kcs_packet(channel_num); ++ ++ set_kcs_state(channel_num, KCS_STATE_WRITE); ++ write_data(channel_num, ZERO_DATA); ++ ++ u16 cmd = read_data(channel_num); ++ switch (cmd) { ++ case KCS_CTRL_CODE_WRITE_START: ++ init_kcs_packet(channel_num); ++ kcs_pkt->phase = KCS_PHASE_WRITE_START; ++ break; ++ ++ case KCS_CTRL_CODE_WRITE_END: ++ if (kcs_pkt->error != KCS_NO_ERROR) { ++ kcs_force_abort(channel_num); ++ return; ++ } ++ ++ kcs_pkt->phase = KCS_PHASE_WRITE_END; ++ break; ++ ++ case KCS_CTRL_CODE_GET_STATUS_ABORT: ++ kcs_pkt->phase = KCS_PHASE_ABORT_1; ++ kcs_pkt->error = KCS_ABORT_BY_CMD; ++ break; ++ ++ default: ++ kcs_pkt->error = KCS_ILLEGAL_CTRL_CMD; ++ kcs_force_abort(channel_num); ++ } ++} ++ ++static u16 kcs_irq_handler(struct pt_regs *regs) ++{ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ u16 channel_num = enabled_kcs_channel[idx]; ++ /* Look-up the interrupted KCS channel */ ++ u16 status = read_status(channel_num); ++ if (status & BIT_STATUS_IBF) { ++ if (status & BIT_STATUS_COD) ++ read_kcs_cmd(channel_num); ++ else ++ read_kcs_data(channel_num); ++ } ++ } ++ ++ return 0; ++} ++ ++static void set_kcs_channel_addr(u16 channel_num) ++{ ++ u32 val; ++ ++ switch (channel_num) { ++ case 1: ++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_LADR12AS; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = (KCS_CHANNEL1_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR12H); ++ val = (KCS_CHANNEL1_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR12L); ++ break; ++ ++ case 2: ++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_LADR12AS; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = (KCS_CHANNEL2_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR12H); ++ val = (KCS_CHANNEL2_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR12L); ++ break; ++ ++ case 3: ++ val = (KCS_CHANNEL3_ADDR >> 8); ++ writel(val, AST_LPC_BASE + LPC_LADR3H); ++ val = (KCS_CHANNEL3_ADDR & 0xFF); ++ writel(val, AST_LPC_BASE + LPC_LADR3L); ++ break; ++ ++ case 4: ++ val = (((KCS_CHANNEL4_ADDR + 1) << 16) | KCS_CHANNEL4_ADDR); ++ writel(val, AST_LPC_BASE + LPC_LADR4); ++ break; ++ ++ default: ++ DBG_KCS("Invalid channel (%d) specified\n", channel_num); ++ break; ++ } ++} ++ ++static void enable_kcs_channel(u16 channel_num, u16 enable) ++{ ++ u32 val; ++ ++ switch (channel_num) { ++ case 1: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE1; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC1E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC1E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE1; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 2: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE2; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC2E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC2E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE2; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 3: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICR2) | BIT_IBFIE3; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ val = readl(AST_LPC_BASE + LPC_HICR0) | BIT_LPC3E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR4) | BIT_KCSENBL; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICR0) & ~BIT_LPC3E; ++ writel(val, AST_LPC_BASE + LPC_HICR0); ++ val = readl(AST_LPC_BASE + LPC_HICR4) & ~BIT_KCSENBL; ++ writel(val, AST_LPC_BASE + LPC_HICR4); ++ val = readl(AST_LPC_BASE + LPC_HICR2) & ~BIT_IBFIE3; ++ writel(val, AST_LPC_BASE + LPC_HICR2); ++ } ++ break; ++ ++ case 4: ++ if (enable) { ++ val = readl(AST_LPC_BASE + LPC_HICRB) | BIT_IBFIE4 | ++ BIT_LPC4E; ++ writel(val, AST_LPC_BASE + LPC_HICRB); ++ } else { ++ val = readl(AST_LPC_BASE + LPC_HICRB) & ++ ~(BIT_IBFIE4 | BIT_LPC4E); ++ writel(val, AST_LPC_BASE + LPC_HICRB); ++ } ++ break; ++ ++ default: ++ DBG_KCS("Invalid channel (%d) specified\n", channel_num); ++ } ++} ++ ++void kcs_init(void) ++{ ++ /* Initialize the KCS channels. */ ++ for (u16 idx = 0; idx < NO_OF_ENABLED_KCS_CHANNELS; idx++) { ++ u16 channel_num = enabled_kcs_channel[idx]; ++ DBG_KCS("%s Channel: %d\n", __func__, channel_num); ++ set_kcs_channel_addr(channel_num); ++ enable_kcs_channel(channel_num, 1); ++ ++ /* Set KCS channel state to idle */ ++ set_kcs_state(channel_num, KCS_STATE_IDLE); ++ } ++ ++ /* KCS interrupt */ ++ request_irq(IRQ_SRC_LPC, kcs_irq_handler); ++} +diff --git a/board/aspeed/ast-g5/ast-g5-kcs.h b/board/aspeed/ast-g5/ast-g5-kcs.h +new file mode 100644 +index 0000000..bb697c4 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-kcs.h +@@ -0,0 +1,112 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018-2019 Intel Corporation */ ++ ++#include <asm/io.h> ++#include <common.h> ++ ++#include "ast-g5.h" ++ ++#define KCS_CHANNEL_MAX 4 ++#define IRQ_SRC_LPC 8 /* IRQ 8 */ ++#define MAX_KCS_PKT_SIZE (64 * 1024) ++/* KCS channel addresses */ ++#define KCS_CHANNEL1_ADDR 0xCA0 ++#define KCS_CHANNEL2_ADDR 0xCA8 ++#define KCS_CHANNEL3_ADDR 0xCA2 /* KCS SMS */ ++#define KCS_CHANNEL4_ADDR 0xCA4 /* KCS SMM */ ++ ++#define ZERO_DATA 0x00 ++ ++/* Aspeed KCS control registers */ ++#define LPC_HICR0 0x00 /* Host Interface Control Register 0 */ ++#define LPC_HICR1 0x04 /* Host Interface Control Register 1 */ ++#define LPC_HICR2 0x08 /* Host Interface Control Register 2 */ ++#define LPC_HICR3 0x0C /* Host Interface Control Register 3 */ ++#define LPC_HICR4 0x10 /* Host Interface Control Register 4 */ ++#define LPC_LADR3H 0x14 /* LPC channel #3 Address Register H */ ++#define LPC_LADR3L 0x18 /* LPC channel #3 Address Register H */ ++#define LPC_LADR12H 0x1C /* LPC channel #1#2 Address Register H */ ++#define LPC_LADR12L 0x20 /* LPC channel #1#2 Address Register L */ ++#define LPC_IDR1 0x24 /* Input Data Register 1 */ ++#define LPC_IDR2 0x28 /* Input Data Register 2 */ ++#define LPC_IDR3 0x2C /* Input Data Register 3 */ ++#define LPC_ODR1 0x30 /* Output Data Register 1 */ ++#define LPC_ODR2 0x34 /* Output Data Register 2 */ ++#define LPC_ODR3 0x38 /* Output Data Register 3 */ ++#define LPC_STR1 0x3C /* Status Register 1 */ ++#define LPC_STR2 0x40 /* Status Register 2 */ ++#define LPC_STR3 0x44 /* Status Register 3 */ ++#define LPC_HICRB 0x100 /* Host Interface Control Register B */ ++#define LPC_LADR4 0x110 /* LPC channel #4 Address Register */ ++#define LPC_IDR4 0x114 /* Input Data Register 4 */ ++#define LPC_ODR4 0x118 /* Output Data Register 4 */ ++#define LPC_STR4 0x11C /* Status Data Register 4 */ ++ ++/* LPC Bits */ ++#define BIT_LADR12AS BIT(7) /* Channel Address selection */ ++#define BIT_IBFIE1 BIT(1) /* Enable IDR1 Recv completion interrupt */ ++#define BIT_IBFIE2 BIT(2) /* Enable IDR2 Recv completion interrupt */ ++#define BIT_IBFIE3 BIT(3) /* Enable IBF13 interrupt */ ++#define BIT_LPC1E BIT(5) /* Enable LPC channel #1 */ ++#define BIT_LPC2E BIT(6) /* Enable LPC channel #2 */ ++#define BIT_LPC3E BIT(7) /* Enable LPC channel #2 */ ++#define BIT_KCSENBL BIT(2) /* Enable KCS interface in Channel #3 */ ++#define BIT_IBFIE4 BIT(1) ++#define BIT_LPC4E BIT(0) ++ ++#define BIT_STATUS_OBF BIT(0) /* Output Data Register full #1/#2/#3 */ ++#define BIT_STATUS_IBF BIT(1) /* Input Data Register full #1/#2/#3 */ ++#define BIT_STATUS_COD BIT(3) /* Command/Data - (1=command,0=data) */ ++ ++#define KCS_STATE_MASK 0xC0 /* BIT[6:7] of status register */ ++#define KCS_STATE(state) ((state) << 6) ++ ++/* IPMI2.0(section 9.7) - KCS interface State Bits */ ++#define KCS_STATE_IDLE 0x00 ++#define KCS_STATE_READ 0x01 ++#define KCS_STATE_WRITE 0x02 ++#define KCS_STATE_ERROR 0x03 ++ ++/* IPMI2.0(section 9.10) - KCS interface control codes */ ++#define KCS_CTRL_CODE_GET_STATUS_ABORT 0x60 ++#define KCS_CTRL_CODE_WRITE_START 0x61 ++#define KCS_CTRL_CODE_WRITE_END 0x62 ++#define KCS_CTRL_CODE_READ 0x68 ++ ++struct kcs_io_reg { ++ u32 idr; ++ u32 odr; ++ u32 str; ++}; ++ ++enum kcs_phase { ++ KCS_PHASE_IDLE = 0, ++ KCS_PHASE_WRITE_START = 1, ++ KCS_PHASE_WRITE_DATA = 2, ++ KCS_PHASE_WRITE_END = 3, ++ KCS_PHASE_READ_WAIT = 4, ++ KCS_PHASE_READ = 5, ++ KCS_PHASE_ABORT_1 = 6, ++ KCS_PHASE_ABORT_2 = 7, ++ KCS_PHASE_ERROR = 8 ++}; ++ ++enum kcs_error { ++ KCS_NO_ERROR = 0x00, ++ KCS_ABORT_BY_CMD = 0x01, ++ KCS_ILLEGAL_CTRL_CMD = 0x02, ++ KCS_LENGTH_ERROR = 0x06, ++ KCS_UNSPECIFIED_ERROR = 0xFF, ++}; ++ ++struct kcs_packet { ++ enum kcs_phase phase; ++ enum kcs_error error; ++ u16 channel; ++ bool read_req_done; ++ u16 data_in_idx; ++ u8 data_in[MAX_KCS_PKT_SIZE]; ++ u16 data_out_len; ++ u16 data_out_idx; ++ u8 data_out[MAX_KCS_PKT_SIZE]; ++}; diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-u-boot-env-change-for-PFR-image.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-u-boot-env-change-for-PFR-image.patch new file mode 100644 index 000000000..afba07abf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-u-boot-env-change-for-PFR-image.patch @@ -0,0 +1,37 @@ +From 4cbfb21b7792e6dae74e2db6e2e2d6803bf6cc1d Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Tue, 26 Mar 2019 20:34:51 +0530 +Subject: [PATCH] u-boot env change for PFR image + +Tested: verified BMC booting from 0x20b00000 + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + include/configs/ast-common.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/configs/ast-common.h b/include/configs/ast-common.h +index 0bc7f2d..821ea8f 100644 +--- a/include/configs/ast-common.h ++++ b/include/configs/ast-common.h +@@ -108,7 +108,7 @@ + #define CONFIG_SYS_MAX_FLASH_BANKS (CONFIG_FMC_CS) + #define CONFIG_SYS_MAX_FLASH_SECT (8192) /* max number of sectors on one chip */ + #define CONFIG_ENV_IS_IN_FLASH 1 +-#define CONFIG_ENV_OFFSET 0x2400000 /* environment starts here */ ++#define CONFIG_ENV_OFFSET 0xa0000 /* environment starts here */ + #define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET) + #define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ + +@@ -116,7 +116,7 @@ + #define CONFIG_ENV_ADDR_REDUND (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET_REDUND) + #define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE + +-#define CONFIG_BOOTCOMMAND "bootm 20080000" ++#define CONFIG_BOOTCOMMAND "bootm 20b00000" + #define CONFIG_ENV_OVERWRITE + + #define ASPEED_ENV_SETTINGS \ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0023-Add-TPM-enable-pulse-triggering.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0023-Add-TPM-enable-pulse-triggering.patch new file mode 100644 index 000000000..f3fc0738b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0023-Add-TPM-enable-pulse-triggering.patch @@ -0,0 +1,50 @@ +From 6b0f858e2dda7afce82797835f950e3501b3046d Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 29 Mar 2019 12:30:20 -0700 +Subject: [PATCH] Add TPM enable pulse triggering + +This commit adds onboard TPM enable pulse triggering. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> + +--- + board/aspeed/ast-g5/ast-g5-intel.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index adc6d10..55afa09 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -53,8 +53,8 @@ static const GPIOValue gpio_table[] = { + GPIO_DEBOUNCE_8MS}, + + /* Enable Pulse -- pin D6 */ +- [GPIO_ENABLE_TPM_PULSE] = {PORT_PIN(GPIO_PORT_D, GPIO_PIN_6), +- GPIO_CFG_DEFAULT, 0, GPIO_DEBOUNCE_8MS}, ++ [GPIO_ENABLE_TPM_PULSE] = {TPM_EN_PULSE_PORT_PIN, GPCFG_OUTPUT_EN, 0, ++ GPIO_DEBOUNCE_NONE}, + }; + + #define LPC_SNOOP_ADDR 0x80 +@@ -232,6 +232,13 @@ void id_led_control(int id, int action) + gpio_set_value(s_led_info[id].gpio, s_led_info[id].state); + } + ++static void enable_onboard_tpm(void) ++{ ++ gpio_set_value(GPIO_ENABLE_TPM_PULSE, 1); ++ mdelay(50); ++ gpio_set_value(GPIO_ENABLE_TPM_PULSE, 0); ++} ++ + static void timer8_irq_handler(void *regs) + { + int i; +@@ -488,6 +495,7 @@ void ast_g5_intel(void) + espi_init(); + sgpio_init(); + timer8_init(); ++ enable_onboard_tpm(); + if (intel_force_firmware_jumper_enabled()) { + id_led_control(GPIO_AMBER_LED, EIDLED_On); + kcs_init(); diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch new file mode 100644 index 000000000..252a9ea1b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch @@ -0,0 +1,330 @@ +From 2314db61ea792a98c35fcc75b0ac09cbc0db005d Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 21 May 2019 00:19:16 +0530 +Subject: [PATCH] IPMI command handler implementation in uboot + +IPMI command handler implemtation in uBoot. +Implemented IPMI commands: + 1) Get Device ID + 2) Get Self Test Result + +Tested By: +Ran the above IPMI command Via KCS channel +and got proper response. +- Get Device ID + Req: cmdtool.efi 20 18 1 + Res: 0x00 0x23 0x00 0x82 0x03 0x02 0x00 0x57 0x01 0x00 0x7b 0x00 0x00 0x00 0x00 0x00 +- Get Self Test Results + Req: cmdtool.efi 20 18 4 + Res: 00 56 00 + +Change-Id: I18b205bc45c34f7c4ef16adc29fa5bd494624ceb +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-kcs.c | 77 +++++++++++++----------- + board/aspeed/ast-g5/ipmi-handler.c | 118 +++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ipmi-handler.h | 40 +++++++++++++ + 4 files changed, 202 insertions(+), 34 deletions(-) + create mode 100644 board/aspeed/ast-g5/ipmi-handler.c + create mode 100644 board/aspeed/ast-g5/ipmi-handler.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 05972b9..f28fcfe 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -5,3 +5,4 @@ obj-y += ast-g5-irq.o + obj-y += ast-g5-gpio.o + obj-y += ast-g5-timer.o + obj-y += ast-g5-kcs.o ++obj-y += ipmi-handler.o +diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c +index 7bff26f..98bf69b 100644 +--- a/board/aspeed/ast-g5/ast-g5-kcs.c ++++ b/board/aspeed/ast-g5/ast-g5-kcs.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2018-2019 Intel Corporation + +-#include "ast-g5-kcs.h" ++#include "ipmi-handler.h" + + #ifdef DEBUG_KCS_ENABLED + #define DBG_KCS printf +@@ -9,11 +9,6 @@ + #define DBG_KCS(...) + #endif + +-/* TODO: Move to IPMI file. */ +-#define IPMI_CC_OK 0x00 +-#define IPMI_CC_INVALID 0xC1 +-#define IPMI_CC_UNSPECIFIED 0xFF +- + #define KCS_CHANNEL_NO_3 3 + + static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; +@@ -103,6 +98,7 @@ static void init_kcs_packet(u16 channel_num) + static void process_kcs_request(u16 channel_num) + { + struct kcs_packet *kcs_pkt = NULL; ++ struct ipmi_cmd_data ipmi_data; + int i; + + kcs_pkt = get_kcs_packet(channel_num); +@@ -117,37 +113,49 @@ static void process_kcs_request(u16 channel_num) + DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); + DBG_KCS("\n"); + #endif ++ u8 req_lun = kcs_pkt->data_in[0] & 0x03; /* LUN[1:0] */ ++ ipmi_data.net_fun = (kcs_pkt->data_in[0] >> 2); /* netfn[7:2] */ ++ ipmi_data.cmd = kcs_pkt->data_in[1]; /* cmd */ ++ /* We support only BMC LUN 00h */ ++ if (req_lun != LUN_BMC) { ++ kcs_pkt->data_out[0] = ++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_INVALID_CMD_LUN; /* CC code */ ++ kcs_pkt->data_out_len = 3; ++ goto done; ++ } + +- /* +- * TODO: Move it to IPMI Command Handler +- * Below code is added for timebeing till +- * we implement the IPMI command handler. +- */ +- kcs_pkt->data_out[0] = kcs_pkt->data_in[0]; /* netfn */ +- kcs_pkt->data_out[1] = kcs_pkt->data_in[1]; /* cmd */ +- kcs_pkt->data_out[2] = IPMI_CC_OK; /* cc */ +- +- if (((kcs_pkt->data_in[0] >> 2) == 0x06) && +- (kcs_pkt->data_in[1] == 0x01)) { +- /* Get Device ID */ +- u8 device_id[15] = { 0x23, 0x00, 0x12, 0x03, 0x02, +- 0xBF, 0x57, 0x01, 0x00, 0x7B, +- 0x00, 0x00, 0x00, 0x00, 0x00 }; +- for (i = 0; i < 15; i++) +- kcs_pkt->data_out[i + 3] = device_id[i]; +- kcs_pkt->data_out_len = 18; +- } else if (((kcs_pkt->data_in[0] >> 2) == 0x06) && +- (kcs_pkt->data_in[1] == 0x04)) { +- /* Get Self Test Results */ +- kcs_pkt->data_out[3] = 0x56; +- kcs_pkt->data_out[4] = 0x00; +- kcs_pkt->data_out_len = 5; +- } else { +- kcs_pkt->data_out[2] = +- IPMI_CC_INVALID; /* Invalid or not supported. */ ++ /* Boundary check */ ++ if ((kcs_pkt->data_in_idx - 2) > sizeof(ipmi_data.req_data)) { ++ kcs_pkt->data_out[0] = ++ GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; /* cmd */ ++ kcs_pkt->data_out[2] = IPMI_CC_OUT_OF_SPACE; /* CC code */ + kcs_pkt->data_out_len = 3; ++ goto done; + } +- /* END: TODO */ ++ /* Fill in IPMI request data */ ++ ipmi_data.req_len = kcs_pkt->data_in_idx - 2; ++ for (i = 0; i < kcs_pkt->data_in_idx - 2; i++) ++ ipmi_data.req_data[i] = kcs_pkt->data_in[i + 2]; ++ ++ /* Call IPMI command handler */ ++ ipmi_cmd_handler(&ipmi_data); ++ ++ /* Get IPMI response and fill KCS out data */ ++ /* First 2 bytes in KCS response are netFn, Cmd */ ++ kcs_pkt->data_out[0] = GET_RESP_NETFN_LUN(req_lun, ipmi_data.net_fun); ++ kcs_pkt->data_out[1] = ipmi_data.cmd; ++ if ((ipmi_data.res_len + 2) > sizeof(kcs_pkt->data_out)) { ++ kcs_pkt->data_out[2] = IPMI_CC_UNSPECIFIED; /* CC code */ ++ kcs_pkt->data_out_len = 3; ++ goto done; ++ } ++ for (i = 0; i < ipmi_data.res_len; i++) ++ kcs_pkt->data_out[i + 2] = ipmi_data.res_data[i]; ++ ++ kcs_pkt->data_out_len = ipmi_data.res_len + 2; + + #ifdef DEBUG_KCS_ENABLED + DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); +@@ -156,6 +164,7 @@ static void process_kcs_request(u16 channel_num) + DBG_KCS("\n"); + #endif + ++done: + kcs_pkt->phase = KCS_PHASE_READ; + write_data(channel_num, kcs_pkt->data_out[kcs_pkt->data_out_idx++]); + kcs_pkt->read_req_done = false; +diff --git a/board/aspeed/ast-g5/ipmi-handler.c b/board/aspeed/ast-g5/ipmi-handler.c +new file mode 100644 +index 0000000..9cccee9 +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-handler.c +@@ -0,0 +1,118 @@ ++ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ipmi-handler.h" ++ ++/* IPMI network function codes */ ++#define NETFN_APP 0x06 ++ ++/* IPMI command codes */ ++#define CMD_GET_DEV_ID 0x01 ++#define CMD_GET_SELF_TEST_RESULTS 0x04 ++ ++typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res); ++ ++struct get_dev_id { ++ u8 completion_code; ++ u8 dev_id; ++ u8 dev_rev; ++ u8 fw_rev1; ++ u8 fw_rev2; ++ u8 ipmi_ver; ++ u8 dev_support; ++ u8 mfg_id[3]; ++ u8 product_id[2]; ++ u8 aux_fw_rev[4]; ++}; ++struct self_test_res { ++ u8 completion_code; ++ u8 res_byte[2]; ++}; ++ ++struct ipmi_cmd_table { ++ u8 net_fun; ++ u8 cmd; ++ fun_handler process_cmd; ++}; ++ ++static u16 get_device_id(u8 *req, u16 req_len, u8 *res) ++{ ++ /* Get Device ID */ ++ bool operation = 1; /* Firmware operation */ ++ u8 intel_mfg_id[3] = { 0x57, 0x01, 0x00 }; ++ u8 platform_id[2] = { 0x7B, 0x00 }; ++ u8 aux_fw_rev[4] = { 0x00, 0x00, 0x00, 0x00 }; ++ struct get_dev_id *result = (struct get_dev_id *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->dev_id = 0x23; ++ result->dev_rev = 0x00; /* Not provides dev SDR */ ++ ++ result->ipmi_ver = 0x02; /* IPMI 2.0 */ ++ result->dev_support = 0x00; /* No dev support in this mode */ ++ memcpy(result->mfg_id, intel_mfg_id, sizeof(result->mfg_id)); ++ memcpy(result->aux_fw_rev, aux_fw_rev, sizeof(result->aux_fw_rev)); ++ ++ /* TODO: Get Firmware version from flash(PFM Header) */ ++ result->fw_rev1 = ((operation << 7) | (0x02 & 0x7F)); ++ result->fw_rev2 = 0x03; ++ /* TODO: Read Platform ID from GPIO */ ++ memcpy(result->product_id, platform_id, sizeof(result->product_id)); ++ ++ return sizeof(struct get_dev_id); ++} ++ ++static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res) ++{ ++ /* Get Self Test Results */ ++ struct self_test_res *result = (struct self_test_res *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->res_byte[0] = 0x56; /* Self test function not implemented. */ ++ result->res_byte[1] = 0x00; ++ ++ return sizeof(struct self_test_res); ++} ++ ++const struct ipmi_cmd_table cmd_info[] = { ++ { NETFN_APP, CMD_GET_DEV_ID, get_device_id }, ++ { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result } ++}; ++ ++#define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info) ++ ++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data) ++{ ++ int i = 0; ++ for (i = 0; i < CMD_TABLE_SIZE; i++) { ++ if ((cmd_info[i].net_fun == ipmi_data->net_fun) && ++ (cmd_info[i].cmd == ipmi_data->cmd)) { ++ break; ++ } ++ } ++ ++ if (i == CMD_TABLE_SIZE) { ++ /* Invalid or not supported. */ ++ ipmi_data->res_data[0] = IPMI_CC_INVALID_CMD; ++ ipmi_data->res_len = 1; ++ return; ++ } ++ ++ /* Call the appropriate function handler */ ++ ipmi_data->res_len = ++ cmd_info[i].process_cmd(ipmi_data->req_data, ipmi_data->req_len, ++ &ipmi_data->res_data[0]); ++ ++ return; ++} +diff --git a/board/aspeed/ast-g5/ipmi-handler.h b/board/aspeed/ast-g5/ipmi-handler.h +new file mode 100644 +index 0000000..9d46d9b +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-handler.h +@@ -0,0 +1,40 @@ ++ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018-2019 Intel Corporation */ ++ ++#include "ast-g5-kcs.h" ++ ++/* IPMI completion codes */ ++#define IPMI_CC_OK 0x00 ++#define IPMI_CC_NODE_BUSY 0xC0 ++#define IPMI_CC_INVALID_CMD 0xC1 ++#define IPMI_CC_INVALID_CMD_LUN 0xC2 ++#define IPMI_CC_OUT_OF_SPACE 0xC4 ++#define IPMI_CC_INVALID_DATA_LENGTH 0xC7 ++#define IPMI_CC_INVALID_DATA_FIELD 0xCC ++#define IPMI_CC_UNSPECIFIED 0xFF ++ ++/* BMC IPMB LUNs */ ++#define LUN_BMC 0x00 ++#define LUN_OEM1 0x01 ++#define LUN_SMS 0x02 ++#define LUN_OEM2 0x01 ++ ++ ++#define MAX_IPMI_REQ_DATA_SIZE MAX_KCS_PKT_SIZE ++#define MAX_IPMI_RES_DATA_SIZE 64 ++ ++/* Response netFn[7:2], Lun[1:0] */ ++#define GET_RESP_NETFN_LUN(lun, netfn) \ ++ ((lun & 0x03) | (((netfn + 1) << 2) & 0xFD)) ++ ++struct ipmi_cmd_data { ++ u8 net_fun; ++ u8 cmd; ++ u16 req_len; ++ u16 res_len; ++ u8 req_data[MAX_IPMI_REQ_DATA_SIZE]; ++ u8 res_data[MAX_IPMI_RES_DATA_SIZE]; ++}; ++ ++void ipmi_cmd_handler(struct ipmi_cmd_data *ipmi_data); diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch new file mode 100644 index 000000000..2d63314af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch @@ -0,0 +1,113 @@ +From 4c87d6074fb36d423f135392983d225785abf43a Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Thu, 20 Jun 2019 18:11:43 +0530 +Subject: [PATCH] Manufacturing mode physical presence detection + +Support for physical presence of manufacturing mode added. +Front panel power button press for 15 seconds will be detected +and marked as special mode for manufacturing request. +There will be 10 second Status LED blink for 10 seconds to +do the physical indication to the user. This indicates the +user that he has pressed power button long enough for +manufacturing mode detection. + +Tested: +1. Verified by holding the power button when u-boot boots for +15 seconds, and confirmed that bootargs passed to linux has +special=mfg string and status led blink physical indication +has been provided +2. Verified in normal condition special=mfg string is not passed +and no physical indication has been provided + +Change-Id: Id7e7c7e7860c7ef3ae8e3a7a7cfda7ff506c0f2b +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + board/aspeed/ast-g5/ast-g5-gpio.h | 2 +- + board/aspeed/ast-g5/ast-g5-intel.c | 35 +++++++++++++++++++++++++++++++++++ + 2 files changed, 36 insertions(+), 1 deletion(-) + +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h +index a820c0f..ed2499f 100644 +--- a/board/aspeed/ast-g5/ast-g5-gpio.h ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -72,7 +72,7 @@ + #define AMB_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_5) + #define FORCE_BMC_UPDATE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_0) + #define TPM_EN_PULSE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_6) +- ++#define FP_PWR_BTN_PORT_PIN PORT_PIN(GPIO_PORT_E, GPIO_PIN_2) + + // GPIO Configuration Register bits + #define GPCFG_EVENT_TO_SMI (1 << 7) // 1 == enabled +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 55afa09..452cb5c 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -24,6 +24,7 @@ enum gpio_names { + GPIO_AMBER_LED, + GPIO_FF_UPD_JUMPER, + GPIO_ENABLE_TPM_PULSE, ++ GPIO_FP_PWR_BTN, + }; + + #define GPIO_CFG_DEFAULT (GPCFG_ACTIVE_HIGH | GPCFG_LEVEL_TRIG) +@@ -55,6 +56,10 @@ static const GPIOValue gpio_table[] = { + /* Enable Pulse -- pin D6 */ + [GPIO_ENABLE_TPM_PULSE] = {TPM_EN_PULSE_PORT_PIN, GPCFG_OUTPUT_EN, 0, + GPIO_DEBOUNCE_NONE}, ++ /* Front Panel Power Button -- pin E2 */ ++ [GPIO_FP_PWR_BTN] = {FP_PWR_BTN_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ + }; + + #define LPC_SNOOP_ADDR 0x80 +@@ -373,6 +378,30 @@ static void update_bootargs_cmd(const char *key, const char *value) + free(buf); + } + ++static bool is_mfg_mode_phy_req(void) ++{ ++ /* ++ * Assume mfg mode physical request is made, if power button ++ * is pressed continously for 15 seconds, indicate the ++ * same in bootargs ++ */ ++ const uint32_t delay_in_ms = 100; ++ const uint32_t read_count = ((15 * 1000) / delay_in_ms); ++ const uint32_t delay_for_indication = 10 * 1000; ++ for (uint32_t count = 0; count < read_count; ++count) { ++ if (!gpio_get_value(GPIO_FP_PWR_BTN)) ++ return false; ++ ++ mdelay(delay_in_ms); ++ } ++ debug("is_mfg_mode_phy_req : detected mfg mode request\n"); ++ id_led_control(GPIO_GREEN_LED, EIDLED_Blink_3HZ); ++ /* Delay the boot to do physical indication for mfg mode */ ++ mdelay(delay_for_indication); ++ ++ return true; ++} ++ + void ast_g5_intel_late_init(void) + { + char value[32]; +@@ -420,6 +449,12 @@ void ast_g5_intel_late_init(void) + ast_scu_write(0, AST_SCU_SYS_CTRL); + + update_bootargs_cmd("resetreason", value); ++ ++ /* Update the special mode in bootargs */ ++ if (is_mfg_mode_phy_req()) ++ update_bootargs_cmd("special", "mfg"); ++ else ++ update_bootargs_cmd("special", NULL); + } + + static void pwm_init(void) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0026-Aspeed-I2C-support-in-U-Boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0026-Aspeed-I2C-support-in-U-Boot.patch new file mode 100644 index 000000000..be2c4018d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0026-Aspeed-I2C-support-in-U-Boot.patch @@ -0,0 +1,1524 @@ +From ea4f14a24b67d5085149d48c7fb38d00f3a7444a Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 6 May 2019 03:01:55 +0530 +Subject: [PATCH] Aspeed I2C support in U-Boot + +Adding Aspeed I2C support in u-boot and enabled +i2c command. It is mainly used for PFR to +communicate with PFR CPLD while BMC is in +"Force Firmware Update" mode. + +Tested: +Using i2c command in u-boot, validated +i2c functionalities like probe, read and write. + +Change-Id: Iad9af4a57a58bc8dc5c470bfadad9dac1371c238 +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + arch/arm/include/asm/arch-aspeed/ast_g5_platform.h | 14 + + arch/arm/include/asm/arch-aspeed/ast_scu.h | 5 + + arch/arm/include/asm/arch-aspeed/regs-iic.h | 204 +++++ + arch/arm/mach-aspeed/ast-scu.c | 122 +++ + board/aspeed/ast-g5/ast-g5.c | 8 + + configs/ast_g5_phy_defconfig | 2 + + drivers/i2c/Kconfig | 5 + + drivers/i2c/Makefile | 1 + + drivers/i2c/ast_i2c.c | 852 +++++++++++++++++++++ + drivers/i2c/ast_i2c.h | 131 ++++ + include/configs/ast-common.h | 5 + + 11 files changed, 1349 insertions(+) + create mode 100644 arch/arm/include/asm/arch-aspeed/regs-iic.h + create mode 100644 drivers/i2c/ast_i2c.c + create mode 100644 drivers/i2c/ast_i2c.h + +diff --git a/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h b/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h +index 4210873..a84f471 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_g5_platform.h +@@ -105,6 +105,20 @@ + #define AST_LPC_BASE 0x1E789000 /* LPC */ + #define AST_MBX_BASE 0x1E789200 /* Mailbox */ + #define AST_I2C_BASE 0x1E78A000 /* I2C */ ++#define AST_I2C_DEV0_BASE 0x1E78A040 /* I2C DEV1 */ ++#define AST_I2C_DEV1_BASE 0x1E78A080 /* I2C DEV2 */ ++#define AST_I2C_DEV2_BASE 0x1E78A0C0 /* I2C DEV3 */ ++#define AST_I2C_DEV3_BASE 0x1E78A100 /* I2C DEV4 */ ++#define AST_I2C_DEV4_BASE 0x1E78A140 /* I2C DEV5 */ ++#define AST_I2C_DEV5_BASE 0x1E78A180 /* I2C DEV6 */ ++#define AST_I2C_DEV6_BASE 0x1E78A1C0 /* I2C DEV7 */ ++#define AST_I2C_DEV7_BASE 0x1E78A300 /* I2C DEV8 */ ++#define AST_I2C_DEV8_BASE 0x1E78A340 /* I2C DEV9 */ ++#define AST_I2C_DEV9_BASE 0x1E78A380 /* I2C DEV10 */ ++#define AST_I2C_DEV10_BASE 0x1E78A3C0 /* I2C DEV11 */ ++#define AST_I2C_DEV11_BASE 0x1E78A400 /* I2C DEV12 */ ++#define AST_I2C_DEV12_BASE 0x1E78A440 /* I2C DEV13 */ ++#define AST_I2C_DEV13_BASE 0x1E78A480 /* I2C DEV14 */ + #define AST_PECI_BASE 0x1E78B000 /* PECI */ + #define AST_PCIARBITER_BASE 0x1E78C000 /* PCI ARBITER */ + #define AST_UART2_BASE 0x1E78D000 /* UART2 */ +diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h +index 369c4e3..b94d13e 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h ++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h +@@ -28,6 +28,8 @@ + #ifndef __AST_SCU_H + #define __AST_SCU_H + ++#include <common.h> ++ + extern void ast_scu_show_system_info (void); + extern void ast_scu_sys_rest_info(void); + extern void ast_scu_security_info(void); +@@ -39,13 +41,16 @@ extern u32 ast_get_clk_source(void); + extern u32 ast_get_h_pll_clk(void); + extern u32 ast_get_m_pll_clk(void); + extern u32 ast_get_ahbclk(void); ++extern u32 ast_get_pclk(void); + + extern u32 ast_scu_get_vga_memsize(void); + ++extern void ast_scu_init_i2c(void); + extern void ast_scu_init_eth(u8 num); + extern void ast_scu_multi_func_eth(u8 num); + extern void ast_scu_multi_func_romcs(u8 num); + extern void ast_scu_multi_func_sgpio(void); ++extern void ast_scu_multi_func_i2c(u8 bus_no); + + void ast_config_uart5_clk(void); + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-iic.h b/arch/arm/include/asm/arch-aspeed/regs-iic.h +new file mode 100644 +index 0000000..5eb3f0a +--- /dev/null ++++ b/arch/arm/include/asm/arch-aspeed/regs-iic.h +@@ -0,0 +1,204 @@ ++/* arch/arm/plat-aspeed/include/mach/regs-iic.h ++ * ++ * Copyright (c) 2012 ASPEED Technology Inc. <ryan_chen@aspeedtech.com> ++ * http://www.aspeedtech.com/ ++ * ++ * 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. ++ * ++ * ASPEED I2C Controller ++*/ ++ ++#ifndef __ASM_ARCH_REGS_IIC_H ++#define __ASM_ARCH_REGS_IIC_H __FILE__ ++ ++#ifdef CONFIG_ARCH_AST1010 ++#define AST_I2C_DMA_SIZE 512 ++#else ++#define AST_I2C_DMA_SIZE 4096 ++#endif ++#define AST_I2C_PAGE_SIZE 256 ++ ++#if defined(CONFIG_ARCH_AST2300) ++#define NUM_BUS 9 ++#elif defined(CONFIG_ARCH_AST2400) ++#define NUM_BUS 14 ++#elif defined(CONFIG_ARCH_AST1010) ++#define NUM_BUS 15 ++#elif defined(CONFIG_ARCH_AST1520) || defined(CONFIG_ARCH_AST3200) || defined(CONFIG_ARCH_AST2500) ++#define NUM_BUS 14 ++#elif defined(CONFIG_ARCH_AST1220) ++#define NUM_BUS 10 ++#else ++#err "NO define NUM_BUS" ++#endif ++ ++/* I2C Register */ ++#define I2C_FUN_CTRL_REG 0x00 ++#define I2C_AC_TIMING_REG1 0x04 ++#define I2C_AC_TIMING_REG2 0x08 ++#define I2C_INTR_CTRL_REG 0x0c ++#define I2C_INTR_STS_REG 0x10 ++#define I2C_CMD_REG 0x14 ++#define I2C_DEV_ADDR_REG 0x18 ++#define I2C_BUF_CTRL_REG 0x1c ++#define I2C_BYTE_BUF_REG 0x20 ++#define I2C_DMA_BASE_REG 0x24 ++#define I2C_DMA_LEN_REG 0x28 ++ ++ ++/* Gloable Register Definition */ ++/* 0x00 : I2C Interrupt Status Register */ ++/* 0x08 : I2C Interrupt Target Assignment */ ++#if defined(CONFIG_ARCH_AST2400) ++#define AST_I2CG_INTR14 (0x1 << 13) ++#define AST_I2CG_INTR13 (0x1 << 12) ++#define AST_I2CG_INTR12 (0x1 << 11) ++#define AST_I2CG_INTR11 (0x1 << 10) ++#define AST_I2CG_INTR10 (0x1 << 9) ++#elif defined(CONFIG_ARCH_AST1010) ++#define AST_I2CG_INTR14 (0x1 << 13) ++#define AST_I2CG_INTR13 (0x1 << 12) ++#define AST_I2CG_INTR12 (0x1 << 11) ++#define AST_I2CG_INTR11 (0x1 << 10) ++#define AST_I2CG_INTR10 (0x1 << 9) ++#endif ++#define AST_I2CG_INTR09 (0x1 << 8) ++#define AST_I2CG_INTR08 (0x1 << 7) ++#define AST_I2CG_INTR07 (0x1 << 6) ++#define AST_I2CG_INTR06 (0x1 << 5) ++#define AST_I2CG_INTR05 (0x1 << 4) ++#define AST_I2CG_INTR04 (0x1 << 3) ++#define AST_I2CG_INTR03 (0x1 << 2) ++#define AST_I2CG_INTR02 (0x1 << 1) ++#define AST_I2CG_INTR01 (0x1) ++ ++/* Device Register Definition */ ++/* 0x00 : I2CD Function Control Register */ ++#define AST_I2CD_BUFF_SEL_MASK (0x7 << 20) ++#define AST_I2CD_BUFF_SEL(x) (x << 20) // page 0 ~ 7 ++#define AST_I2CD_M_SDA_LOCK_EN (0x1 << 16) ++#define AST_I2CD_MULTI_MASTER_DIS (0x1 << 15) ++#define AST_I2CD_M_SCL_DRIVE_EN (0x1 << 14) ++#define AST_I2CD_MSB_STS (0x1 << 9) ++#define AST_I2CD_SDA_DRIVE_1T_EN (0x1 << 8) ++#define AST_I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) ++#define AST_I2CD_M_HIGH_SPEED_EN (0x1 << 6) ++#define AST_I2CD_DEF_ADDR_EN (0x1 << 5) ++#define AST_I2CD_DEF_ALERT_EN (0x1 << 4) ++#define AST_I2CD_DEF_ARP_EN (0x1 << 3) ++#define AST_I2CD_DEF_GCALL_EN (0x1 << 2) ++#define AST_I2CD_SLAVE_EN (0x1 << 1) ++#define AST_I2CD_MASTER_EN (0x1) ++ ++/* 0x04 : I2CD Clock and AC Timing Control Register #1 */ ++#define AST_I2CD_tBUF (0x1 << 28) // 0~7 ++#define AST_I2CD_tHDSTA (0x1 << 24) // 0~7 ++#define AST_I2CD_tACST (0x1 << 20) // 0~7 ++#define AST_I2CD_tCKHIGH (0x1 << 16) // 0~7 ++#define AST_I2CD_tCKLOW (0x1 << 12) // 0~7 ++#define AST_I2CD_tHDDAT (0x1 << 10) // 0~7 ++#define AST_I2CD_CLK_TO_BASE_DIV (0x1 << 8) // 0~3 ++#define AST_I2CD_CLK_BASE_DIV (0x1) // 0~0xf ++ ++/* 0x08 : I2CD Clock and AC Timing Control Register #2 */ ++#define AST_I2CD_tTIMEOUT (0x1) // 0~7 ++#define AST_NO_TIMEOUT_CTRL 0x0 ++ ++ ++/* 0x0c : I2CD Interrupt Control Register */ ++#define AST_I2CD_SDA_DL_TO_INTR_EN (0x1 << 14) ++#define AST_I2CD_BUS_RECOVER_INTR_EN (0x1 << 13) ++#define AST_I2CD_SMBUS_ALT_INTR_EN (0x1 << 12) ++#define AST_I2CD_SLAVE_MATCH_INTR_EN (0x1 << 7) ++#define AST_I2CD_SCL_TO_INTR_EN (0x1 << 6) ++#define AST_I2CD_ABNORMAL_INTR_EN (0x1 << 5) ++#define AST_I2CD_NORMAL_STOP_INTR_EN (0x1 << 4) ++#define AST_I2CD_ARBIT_LOSS_INTR_EN (0x1 << 3) ++#define AST_I2CD_RX_DOWN_INTR_EN (0x1 << 2) ++#define AST_I2CD_TX_NAK_INTR_EN (0x1 << 1) ++#define AST_I2CD_TX_ACK_INTR_EN (0x1) ++ ++/* 0x10 : I2CD Interrupt Status Register : WC */ ++#define AST_I2CD_INTR_STS_SDA_DL_TO (0x1 << 14) ++#define AST_I2CD_INTR_STS_BUS_RECOVER (0x1 << 13) ++#define AST_I2CD_INTR_STS_SMBUS_ALT (0x1 << 12) ++#define AST_I2CD_INTR_STS_SMBUS_ARP_ADDR (0x1 << 11) ++#define AST_I2CD_INTR_STS_SMBUS_DEV_ALT (0x1 << 10) ++#define AST_I2CD_INTR_STS_SMBUS_DEF_ADDR (0x1 << 9) ++#define AST_I2CD_INTR_STS_GCALL_ADDR (0x1 << 8) ++#define AST_I2CD_INTR_STS_SLAVE_MATCH (0x1 << 7) ++#define AST_I2CD_INTR_STS_SCL_TO (0x1 << 6) ++#define AST_I2CD_INTR_STS_ABNORMAL (0x1 << 5) ++#define AST_I2CD_INTR_STS_NORMAL_STOP (0x1 << 4) ++#define AST_I2CD_INTR_STS_ARBIT_LOSS (0x1 << 3) ++#define AST_I2CD_INTR_STS_RX_DOWN (0x1 << 2) ++#define AST_I2CD_INTR_STS_TX_NAK (0x1 << 1) ++#define AST_I2CD_INTR_STS_TX_ACK (0x1) ++ ++/* 0x14 : I2CD Command/Status Register */ ++#define AST_I2CD_SDA_OE (0x1 << 28) ++#define AST_I2CD_SDA_O (0x1 << 27) ++#define AST_I2CD_SCL_OE (0x1 << 26) ++#define AST_I2CD_SCL_O (0x1 << 25) ++#define AST_I2CD_TX_TIMING (0x1 << 24) // 0 ~3 ++#define AST_I2CD_TX_STATUS (0x1 << 23) ++// Tx State Machine ++#define AST_I2CD_IDLE 0x0 ++#define AST_I2CD_MACTIVE 0x8 ++#define AST_I2CD_MSTART 0x9 ++#define AST_I2CD_MSTARTR 0xa ++#define AST_I2CD_MSTOP 0xb ++#define AST_I2CD_MTXD 0xc ++#define AST_I2CD_MRXACK 0xd ++#define AST_I2CD_MRXD 0xe ++#define AST_I2CD_MTXACK 0xf ++#define AST_I2CD_SWAIT 0x1 ++#define AST_I2CD_SRXD 0x4 ++#define AST_I2CD_STXACK 0x5 ++#define AST_I2CD_STXD 0x6 ++#define AST_I2CD_SRXACK 0x7 ++#define AST_I2CD_RECOVER 0x3 ++ ++#define AST_I2CD_SCL_LINE_STS (0x1 << 18) ++#define AST_I2CD_SDA_LINE_STS (0x1 << 17) ++#define AST_I2CD_BUS_BUSY_STS (0x1 << 16) ++#define AST_I2CD_SDA_OE_OUT_DIR (0x1 << 15) ++#define AST_I2CD_SDA_O_OUT_DIR (0x1 << 14) ++#define AST_I2CD_SCL_OE_OUT_DIR (0x1 << 13) ++#define AST_I2CD_SCL_O_OUT_DIR (0x1 << 12) ++#define AST_I2CD_BUS_RECOVER_CMD_EN (0x1 << 11) ++#define AST_I2CD_S_ALT_EN (0x1 << 10) ++// 0 : DMA Buffer, 1: Pool Buffer ++//AST1070 DMA register ++#define AST_I2CD_RX_DMA_ENABLE (0x1 << 9) ++#define AST_I2CD_TX_DMA_ENABLE (0x1 << 8) ++ ++/* Command Bit */ ++#define AST_I2CD_RX_BUFF_ENABLE (0x1 << 7) ++#define AST_I2CD_TX_BUFF_ENABLE (0x1 << 6) ++#define AST_I2CD_M_STOP_CMD (0x1 << 5) ++#define AST_I2CD_M_S_RX_CMD_LAST (0x1 << 4) ++#define AST_I2CD_M_RX_CMD (0x1 << 3) ++#define AST_I2CD_S_TX_CMD (0x1 << 2) ++#define AST_I2CD_M_TX_CMD (0x1 << 1) ++#define AST_I2CD_M_START_CMD (0x1) ++ ++/* 0x18 : I2CD Slave Device Address Register */ ++ ++/* 0x1C : I2CD Pool Buffer Control Register */ ++#define AST_I2CD_RX_BUF_ADDR_GET(x) ((x >> 24) & 0xff) ++#define AST_I2CD_RX_BUF_END_ADDR_SET(x) (x << 16) ++#define AST_I2CD_TX_DATA_BUF_END_SET(x) ((x & 0xff) << 8) ++#define AST_I2CD_TX_DATA_BUF_GET(x) ((x >> 8) & 0xff) ++#define AST_I2CD_BUF_BASE_ADDR_SET(x) (x & 0x3f) ++ ++/* 0x20 : I2CD Transmit/Receive Byte Buffer Register */ ++#define AST_I2CD_GET_MODE(x) ((x >> 8) & 0x1) ++ ++#define AST_I2CD_RX_BYTE_BUFFER (0xff << 8) ++#define AST_I2CD_TX_BYTE_BUFFER (0xff) ++ ++ ++#endif /* __ASM_ARCH_REGS_IIC_H */ +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 976c59b..537cd4b 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -112,6 +112,12 @@ static struct soc_id soc_map_table[] = { + SOC_ID("AST2530-A2", 0x04030403), + }; + ++void ast_scu_init_i2c(void) ++{ ++ ast_scu_write(ast_scu_read(AST_SCU_RESET) & ~SCU_RESET_I2C, ++ AST_SCU_RESET); ++} ++ + void ast_scu_init_eth(u8 num) + { + /* Set MAC delay Timing */ +@@ -292,6 +298,23 @@ u32 ast_get_ahbclk(void) + return ((hpll / axi_div) / ahb_div); + } + ++u32 ast_get_pclk(void) ++{ ++ unsigned int div, hpll; ++ ++ hpll = ast_get_h_pll_clk(); ++ div = SCU_GET_PCLK_DIV(ast_scu_read(AST_SCU_CLK_SEL)); ++#ifdef AST_SOC_G5 ++ div = (div+1) << 2; ++#else ++ div = (div+1) << 1; ++#endif ++ ++ debug("HPLL=%d, Div=%d, PCLK=%d\n", hpll, div, hpll/div); ++ return (hpll/div); ++} ++ ++ + #else /* ! AST_SOC_G5 */ + + u32 ast_get_h_pll_clk(void) +@@ -457,6 +480,105 @@ void ast_scu_multi_func_sgpio(void) + AST_SCU_FUN_PIN_CTRL2); + } + ++extern void ast_scu_multi_func_i2c(u8 bus_no) ++{ ++#ifdef CONFIG_ARCH_AST1010 ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL4) | ++ SCU_FUN_PIN_SCL13 | ++ SCU_FUN_PIN_SDA13 | ++ SCU_FUN_PIN_SCL14 | ++ SCU_FUN_PIN_SDA14, ++ AST_SCU_FUN_PIN_CTRL4); ++ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL2) | ++ SCU_FUN_PIN_SCL1 | ++ SCU_FUN_PIN_SDA1 | ++ SCU_FUN_PIN_SCL2 | ++ SCU_FUN_PIN_SDA2 | ++ SCU_FUN_PIN_SCL3 | ++ SCU_FUN_PIN_SDA3 | ++ SCU_FUN_PIN_SCL4 | ++ SCU_FUN_PIN_SDA4 | ++ SCU_FUN_PIN_SCL5 | ++ SCU_FUN_PIN_SDA5 | ++ SCU_FUN_PIN_SCL6 | ++ SCU_FUN_PIN_SDA6 | ++ SCU_FUN_PIN_SCL7 | ++ SCU_FUN_PIN_SDA7 | ++ SCU_FUN_PIN_SCL8 | ++ SCU_FUN_PIN_SDA8 | ++ SCU_FUN_PIN_SALT1 | ++ SCU_FUN_PIN_SALT2 | ++ SCU_FUN_PIN_SALT3 | ++ SCU_FUN_PIN_SALT4, ++ AST_SCU_FUN_PIN_CTRL2); ++ ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) | ++ SCU_FUN_PIN_SCL9 | ++ SCU_FUN_PIN_SDA9 | ++ SCU_FUN_PIN_SCL10 | ++ SCU_FUN_PIN_SDA10 | ++ SCU_FUN_PIN_SCL11 | ++ SCU_FUN_PIN_SDA11 | ++ SCU_FUN_PIN_SCL12 | ++ SCU_FUN_PIN_SDA12, ++ AST_SCU_FUN_PIN_CTRL1); ++#else ++ //TODO check ... //In AST2400 Due to share pin with SD , please not enable I2C 10 ~14 ++ // AST 2400 have 14 , AST 2300 9 ... ++ u32 pin_ctrl = ast_scu_read(AST_SCU_FUN_PIN_CTRL5); ++ switch (bus_no) { ++ case 0: ++ break; ++ case 1: ++ break; ++ case 2: ++ pin_ctrl |= SCU_FUC_PIN_I2C3; ++ break; ++ case 3: ++ pin_ctrl |= SCU_FUC_PIN_I2C4; ++ break; ++ case 4: ++ pin_ctrl |= SCU_FUC_PIN_I2C5; ++ break; ++ case 5: ++ pin_ctrl |= SCU_FUC_PIN_I2C6; ++ break; ++ case 6: ++ pin_ctrl |= SCU_FUC_PIN_I2C7; ++ break; ++ case 7: ++ pin_ctrl |= SCU_FUC_PIN_I2C8; ++ break; ++ case 8: ++ pin_ctrl |= SCU_FUC_PIN_I2C9; ++ break; ++ case 9: ++ pin_ctrl |= SCU_FUC_PIN_I2C10; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 10: ++ pin_ctrl |= SCU_FUC_PIN_I2C11; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 11: ++ pin_ctrl |= SCU_FUC_PIN_I2C12; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 12: ++ pin_ctrl |= SCU_FUC_PIN_I2C13; ++ pin_ctrl &= ~SCU_FUC_PIN_SD1; ++ break; ++ case 13: ++ pin_ctrl |= SCU_FUC_PIN_I2C14; ++ break; ++ } ++ ++ ast_scu_write(pin_ctrl, AST_SCU_FUN_PIN_CTRL5); ++#endif ++} ++ ++ + u32 ast_scu_revision_id(void) + { + int i; +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index 0953677..3c33546 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -13,6 +13,7 @@ + #include <asm/arch/ast_scu.h> + #include <asm/arch/ast-sdmc.h> + #include <asm/io.h> ++#include <i2c.h> + + #include "ast-g5.h" + +@@ -37,6 +38,13 @@ int board_init(void) + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + gd->flags = 0; + ++ /* Initialize I2C */ ++#if defined(CONFIG_SYS_I2C) ++ i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr); ++#else ++ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); ++#endif ++ + ast_g5_intel(); + return 0; + } +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 4aefcf4..1b96ab7 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -13,3 +13,5 @@ CONFIG_OF_LIBFDT=y + CONFIG_SPI_FLASH=y + CONFIG_SYS_NS16550=y + CONFIG_USE_IRQ=y ++CONFIG_CMD_I2C=y ++CONFIG_SYS_I2C_AST=y +diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig +index 6e22bba..5368ba2 100644 +--- a/drivers/i2c/Kconfig ++++ b/drivers/i2c/Kconfig +@@ -58,6 +58,11 @@ config DM_I2C_GPIO + bindings are supported. + Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt + ++config SYS_I2C_AST ++ bool "Aspeed I2C bus driver" ++ help ++ Add support for Aspeed I2C busses on AST2500 processors. ++ + config SYS_I2C_FSL + bool "Freescale I2C bus driver" + depends on DM_I2C +diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile +index 167424d..b2a69ea 100644 +--- a/drivers/i2c/Makefile ++++ b/drivers/i2c/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o + obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o + + obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o ++obj-$(CONFIG_SYS_I2C_AST) += ast_i2c.o + obj-$(CONFIG_I2C_MV) += mv_i2c.o + obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o + obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o +diff --git a/drivers/i2c/ast_i2c.c b/drivers/i2c/ast_i2c.c +new file mode 100644 +index 0000000..533419f +--- /dev/null ++++ b/drivers/i2c/ast_i2c.c +@@ -0,0 +1,852 @@ ++/* ++ * i2c_adap_ast.c ++ * ++ * I2C adapter for the ASPEED I2C bus access. ++ * ++ * Copyright (C) 2012-2020 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 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * 2012.07.26: Initial version [Ryan Chen] ++ */ ++ ++#include <common.h> ++#include <configs/ast-common.h> ++#include <fdtdec.h> ++ ++#include <asm/arch/ast_scu.h> ++#include <i2c.h> ++ ++#include <asm/arch/regs-iic.h> ++#include <asm/io.h> ++ ++// AST2400 buffer mode issue , force I2C slave write use byte mode , read use ++// buffer mode ++/* Use platform_data instead of module parameters */ ++/* Fast Mode = 400 kHz, Standard = 100 kHz */ ++// static int clock = 100; /* Default: 100 kHz */ ++ ++/***************************************************************************/ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define I2C_TIMEOUT_COUNT 200 ++#define I2C_SLEEP_US 1000 ++ ++static unsigned int i2c_bus_num __attribute__((section(".data"))); ++ ++/* Information about i2c controller */ ++struct ast_i2c_bus { ++ u32 reg_base; /* virtual */ ++ u32 speed; ++ u32 state; /* I2C xfer mode state matchine */ ++ u16 addr; /* slave address */ ++ u16 flags; ++ u16 a_len; /* msg length */ ++ u8 *a_buf; /* pointer to msg data */ ++ u16 d_len; /* msg length */ ++ u8 *d_buf; /* pointer to msg data */ ++}; ++ ++static struct ast_i2c_bus ast_i2c[NUM_BUS] __attribute__((section(".data"))); ++ ++struct ast_i2c_timing_table { ++ u32 divisor; ++ u32 timing; ++}; ++ ++static struct ast_i2c_timing_table i2c_timing_table[] = { ++#if defined(AST_SOC_G5) ++ /* Divisor : Base Clock : tCK High : tCK Low */ ++ /* Divisor : [3:0] : [19:16]: [15:12] */ ++ { 6, 0x77700300 | (0x0) | (0x2 << 16) | (0x2 << 12) }, ++ { 7, 0x77700300 | (0x0) | (0x3 << 16) | (0x2 << 12) }, ++ { 8, 0x77700300 | (0x0) | (0x3 << 16) | (0x3 << 12) }, ++ { 9, 0x77700300 | (0x0) | (0x4 << 16) | (0x3 << 12) }, ++ { 10, 0x77700300 | (0x0) | (0x4 << 16) | (0x4 << 12) }, ++ { 11, 0x77700300 | (0x0) | (0x5 << 16) | (0x4 << 12) }, ++ { 12, 0x77700300 | (0x0) | (0x5 << 16) | (0x5 << 12) }, ++ { 13, 0x77700300 | (0x0) | (0x6 << 16) | (0x5 << 12) }, ++ { 14, 0x77700300 | (0x0) | (0x6 << 16) | (0x6 << 12) }, ++ { 15, 0x77700300 | (0x0) | (0x7 << 16) | (0x6 << 12) }, ++ { 16, 0x77700300 | (0x0) | (0x7 << 16) | (0x7 << 12) }, ++ { 17, 0x77700300 | (0x0) | (0x8 << 16) | (0x7 << 12) }, ++ { 18, 0x77700300 | (0x0) | (0x8 << 16) | (0x8 << 12) }, ++ { 19, 0x77700300 | (0x0) | (0x9 << 16) | (0x8 << 12) }, ++ { 20, 0x77700300 | (0x0) | (0x9 << 16) | (0x9 << 12) }, ++ { 21, 0x77700300 | (0x0) | (0xa << 16) | (0x9 << 12) }, ++ { 22, 0x77700300 | (0x0) | (0xa << 16) | (0xa << 12) }, ++ { 23, 0x77700300 | (0x0) | (0xb << 16) | (0xa << 12) }, ++ { 24, 0x77700300 | (0x0) | (0xb << 16) | (0xb << 12) }, ++ { 25, 0x77700300 | (0x0) | (0xc << 16) | (0xb << 12) }, ++ { 26, 0x77700300 | (0x0) | (0xc << 16) | (0xc << 12) }, ++ { 27, 0x77700300 | (0x0) | (0xd << 16) | (0xc << 12) }, ++ { 28, 0x77700300 | (0x0) | (0xd << 16) | (0xd << 12) }, ++ { 29, 0x77700300 | (0x0) | (0xe << 16) | (0xd << 12) }, ++ { 30, 0x77700300 | (0x0) | (0xe << 16) | (0xe << 12) }, ++ { 31, 0x77700300 | (0x0) | (0xf << 16) | (0xe << 12) }, ++ { 32, 0x77700300 | (0x0) | (0xf << 16) | (0xf << 12) }, ++ ++ { 34, 0x77700300 | (0x1) | (0x8 << 16) | (0x7 << 12) }, ++ { 36, 0x77700300 | (0x1) | (0x8 << 16) | (0x8 << 12) }, ++ { 38, 0x77700300 | (0x1) | (0x9 << 16) | (0x8 << 12) }, ++ { 40, 0x77700300 | (0x1) | (0x9 << 16) | (0x9 << 12) }, ++ { 42, 0x77700300 | (0x1) | (0xa << 16) | (0x9 << 12) }, ++ { 44, 0x77700300 | (0x1) | (0xa << 16) | (0xa << 12) }, ++ { 46, 0x77700300 | (0x1) | (0xb << 16) | (0xa << 12) }, ++ { 48, 0x77700300 | (0x1) | (0xb << 16) | (0xb << 12) }, ++ { 50, 0x77700300 | (0x1) | (0xc << 16) | (0xb << 12) }, ++ { 52, 0x77700300 | (0x1) | (0xc << 16) | (0xc << 12) }, ++ { 54, 0x77700300 | (0x1) | (0xd << 16) | (0xc << 12) }, ++ { 56, 0x77700300 | (0x1) | (0xd << 16) | (0xd << 12) }, ++ { 58, 0x77700300 | (0x1) | (0xe << 16) | (0xd << 12) }, ++ { 60, 0x77700300 | (0x1) | (0xe << 16) | (0xe << 12) }, ++ { 62, 0x77700300 | (0x1) | (0xf << 16) | (0xe << 12) }, ++ { 64, 0x77700300 | (0x1) | (0xf << 16) | (0xf << 12) }, ++ ++ { 68, 0x77700300 | (0x2) | (0x8 << 16) | (0x7 << 12) }, ++ { 72, 0x77700300 | (0x2) | (0x8 << 16) | (0x8 << 12) }, ++ { 76, 0x77700300 | (0x2) | (0x9 << 16) | (0x8 << 12) }, ++ { 80, 0x77700300 | (0x2) | (0x9 << 16) | (0x9 << 12) }, ++ { 84, 0x77700300 | (0x2) | (0xa << 16) | (0x9 << 12) }, ++ { 88, 0x77700300 | (0x2) | (0xa << 16) | (0xa << 12) }, ++ { 92, 0x77700300 | (0x2) | (0xb << 16) | (0xa << 12) }, ++ { 96, 0x77700300 | (0x2) | (0xb << 16) | (0xb << 12) }, ++ { 100, 0x77700300 | (0x2) | (0xc << 16) | (0xb << 12) }, ++ { 104, 0x77700300 | (0x2) | (0xc << 16) | (0xc << 12) }, ++ { 108, 0x77700300 | (0x2) | (0xd << 16) | (0xc << 12) }, ++ { 112, 0x77700300 | (0x2) | (0xd << 16) | (0xd << 12) }, ++ { 116, 0x77700300 | (0x2) | (0xe << 16) | (0xd << 12) }, ++ { 120, 0x77700300 | (0x2) | (0xe << 16) | (0xe << 12) }, ++ { 124, 0x77700300 | (0x2) | (0xf << 16) | (0xe << 12) }, ++ { 128, 0x77700300 | (0x2) | (0xf << 16) | (0xf << 12) }, ++ ++ { 136, 0x77700300 | (0x3) | (0x8 << 16) | (0x7 << 12) }, ++ { 144, 0x77700300 | (0x3) | (0x8 << 16) | (0x8 << 12) }, ++ { 152, 0x77700300 | (0x3) | (0x9 << 16) | (0x8 << 12) }, ++ { 160, 0x77700300 | (0x3) | (0x9 << 16) | (0x9 << 12) }, ++ { 168, 0x77700300 | (0x3) | (0xa << 16) | (0x9 << 12) }, ++ { 176, 0x77700300 | (0x3) | (0xa << 16) | (0xa << 12) }, ++ { 184, 0x77700300 | (0x3) | (0xb << 16) | (0xa << 12) }, ++ { 192, 0x77700300 | (0x3) | (0xb << 16) | (0xb << 12) }, ++ { 200, 0x77700300 | (0x3) | (0xc << 16) | (0xb << 12) }, ++ { 208, 0x77700300 | (0x3) | (0xc << 16) | (0xc << 12) }, ++ { 216, 0x77700300 | (0x3) | (0xd << 16) | (0xc << 12) }, ++ { 224, 0x77700300 | (0x3) | (0xd << 16) | (0xd << 12) }, ++ { 232, 0x77700300 | (0x3) | (0xe << 16) | (0xd << 12) }, ++ { 240, 0x77700300 | (0x3) | (0xe << 16) | (0xe << 12) }, ++ { 248, 0x77700300 | (0x3) | (0xf << 16) | (0xe << 12) }, ++ { 256, 0x77700300 | (0x3) | (0xf << 16) | (0xf << 12) }, ++ ++ { 272, 0x77700300 | (0x4) | (0x8 << 16) | (0x7 << 12) }, ++ { 288, 0x77700300 | (0x4) | (0x8 << 16) | (0x8 << 12) }, ++ { 304, 0x77700300 | (0x4) | (0x9 << 16) | (0x8 << 12) }, ++ { 320, 0x77700300 | (0x4) | (0x9 << 16) | (0x9 << 12) }, ++ { 336, 0x77700300 | (0x4) | (0xa << 16) | (0x9 << 12) }, ++ { 352, 0x77700300 | (0x4) | (0xa << 16) | (0xa << 12) }, ++ { 368, 0x77700300 | (0x4) | (0xb << 16) | (0xa << 12) }, ++ { 384, 0x77700300 | (0x4) | (0xb << 16) | (0xb << 12) }, ++ { 400, 0x77700300 | (0x4) | (0xc << 16) | (0xb << 12) }, ++ { 416, 0x77700300 | (0x4) | (0xc << 16) | (0xc << 12) }, ++ { 432, 0x77700300 | (0x4) | (0xd << 16) | (0xc << 12) }, ++ { 448, 0x77700300 | (0x4) | (0xd << 16) | (0xd << 12) }, ++ { 464, 0x77700300 | (0x4) | (0xe << 16) | (0xd << 12) }, ++ { 480, 0x77700300 | (0x4) | (0xe << 16) | (0xe << 12) }, ++ { 496, 0x77700300 | (0x4) | (0xf << 16) | (0xe << 12) }, ++ { 512, 0x77700300 | (0x4) | (0xf << 16) | (0xf << 12) }, ++ ++ { 544, 0x77700300 | (0x5) | (0x8 << 16) | (0x7 << 12) }, ++ { 576, 0x77700300 | (0x5) | (0x8 << 16) | (0x8 << 12) }, ++ { 608, 0x77700300 | (0x5) | (0x9 << 16) | (0x8 << 12) }, ++ { 640, 0x77700300 | (0x5) | (0x9 << 16) | (0x9 << 12) }, ++ { 672, 0x77700300 | (0x5) | (0xa << 16) | (0x9 << 12) }, ++ { 704, 0x77700300 | (0x5) | (0xa << 16) | (0xa << 12) }, ++ { 736, 0x77700300 | (0x5) | (0xb << 16) | (0xa << 12) }, ++ { 768, 0x77700300 | (0x5) | (0xb << 16) | (0xb << 12) }, ++ { 800, 0x77700300 | (0x5) | (0xc << 16) | (0xb << 12) }, ++ { 832, 0x77700300 | (0x5) | (0xc << 16) | (0xc << 12) }, ++ { 864, 0x77700300 | (0x5) | (0xd << 16) | (0xc << 12) }, ++ { 896, 0x77700300 | (0x5) | (0xd << 16) | (0xd << 12) }, ++ { 928, 0x77700300 | (0x5) | (0xe << 16) | (0xd << 12) }, ++ { 960, 0x77700300 | (0x5) | (0xe << 16) | (0xe << 12) }, ++ { 992, 0x77700300 | (0x5) | (0xf << 16) | (0xe << 12) }, ++ { 1024, 0x77700300 | (0x5) | (0xf << 16) | (0xf << 12) }, ++ ++ { 1088, 0x77700300 | (0x6) | (0x8 << 16) | (0x7 << 12) }, ++ { 1152, 0x77700300 | (0x6) | (0x8 << 16) | (0x8 << 12) }, ++ { 1216, 0x77700300 | (0x6) | (0x9 << 16) | (0x8 << 12) }, ++ { 1280, 0x77700300 | (0x6) | (0x9 << 16) | (0x9 << 12) }, ++ { 1344, 0x77700300 | (0x6) | (0xa << 16) | (0x9 << 12) }, ++ { 1408, 0x77700300 | (0x6) | (0xa << 16) | (0xa << 12) }, ++ { 1472, 0x77700300 | (0x6) | (0xb << 16) | (0xa << 12) }, ++ { 1536, 0x77700300 | (0x6) | (0xb << 16) | (0xb << 12) }, ++ { 1600, 0x77700300 | (0x6) | (0xc << 16) | (0xb << 12) }, ++ { 1664, 0x77700300 | (0x6) | (0xc << 16) | (0xc << 12) }, ++ { 1728, 0x77700300 | (0x6) | (0xd << 16) | (0xc << 12) }, ++ { 1792, 0x77700300 | (0x6) | (0xd << 16) | (0xd << 12) }, ++ { 1856, 0x77700300 | (0x6) | (0xe << 16) | (0xd << 12) }, ++ { 1920, 0x77700300 | (0x6) | (0xe << 16) | (0xe << 12) }, ++ { 1984, 0x77700300 | (0x6) | (0xf << 16) | (0xe << 12) }, ++ { 2048, 0x77700300 | (0x6) | (0xf << 16) | (0xf << 12) }, ++ ++ { 2176, 0x77700300 | (0x7) | (0x8 << 16) | (0x7 << 12) }, ++ { 2304, 0x77700300 | (0x7) | (0x8 << 16) | (0x8 << 12) }, ++ { 2432, 0x77700300 | (0x7) | (0x9 << 16) | (0x8 << 12) }, ++ { 2560, 0x77700300 | (0x7) | (0x9 << 16) | (0x9 << 12) }, ++ { 2688, 0x77700300 | (0x7) | (0xa << 16) | (0x9 << 12) }, ++ { 2816, 0x77700300 | (0x7) | (0xa << 16) | (0xa << 12) }, ++ { 2944, 0x77700300 | (0x7) | (0xb << 16) | (0xa << 12) }, ++ { 3072, 0x77700300 | (0x7) | (0xb << 16) | (0xb << 12) }, ++#else ++ /* Divisor : [3:0] : [18:16]: [13:12] */ ++ { 6, 0x77700300 | (0x0) | (0x2 << 16) | (0x2 << 12) }, ++ { 7, 0x77700300 | (0x0) | (0x3 << 16) | (0x2 << 12) }, ++ { 8, 0x77700300 | (0x0) | (0x3 << 16) | (0x3 << 12) }, ++ { 9, 0x77700300 | (0x0) | (0x4 << 16) | (0x3 << 12) }, ++ { 10, 0x77700300 | (0x0) | (0x4 << 16) | (0x4 << 12) }, ++ { 11, 0x77700300 | (0x0) | (0x5 << 16) | (0x4 << 12) }, ++ { 12, 0x77700300 | (0x0) | (0x5 << 16) | (0x5 << 12) }, ++ { 13, 0x77700300 | (0x0) | (0x6 << 16) | (0x5 << 12) }, ++ { 14, 0x77700300 | (0x0) | (0x6 << 16) | (0x6 << 12) }, ++ { 15, 0x77700300 | (0x0) | (0x7 << 16) | (0x6 << 12) }, ++ { 16, 0x77700300 | (0x0) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 18, 0x77700300 | (0x1) | (0x4 << 16) | (0x3 << 12) }, ++ { 20, 0x77700300 | (0x1) | (0x4 << 16) | (0x4 << 12) }, ++ { 22, 0x77700300 | (0x1) | (0x5 << 16) | (0x4 << 12) }, ++ { 24, 0x77700300 | (0x1) | (0x5 << 16) | (0x5 << 12) }, ++ { 26, 0x77700300 | (0x1) | (0x6 << 16) | (0x5 << 12) }, ++ { 28, 0x77700300 | (0x1) | (0x6 << 16) | (0x6 << 12) }, ++ { 30, 0x77700300 | (0x1) | (0x7 << 16) | (0x6 << 12) }, ++ { 32, 0x77700300 | (0x1) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 36, 0x77700300 | (0x2) | (0x4 << 16) | (0x3 << 12) }, ++ { 40, 0x77700300 | (0x2) | (0x4 << 16) | (0x4 << 12) }, ++ { 44, 0x77700300 | (0x2) | (0x5 << 16) | (0x4 << 12) }, ++ { 48, 0x77700300 | (0x2) | (0x5 << 16) | (0x5 << 12) }, ++ { 52, 0x77700300 | (0x2) | (0x6 << 16) | (0x5 << 12) }, ++ { 56, 0x77700300 | (0x2) | (0x6 << 16) | (0x6 << 12) }, ++ { 60, 0x77700300 | (0x2) | (0x7 << 16) | (0x6 << 12) }, ++ { 64, 0x77700300 | (0x2) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 72, 0x77700300 | (0x3) | (0x4 << 16) | (0x3 << 12) }, ++ { 80, 0x77700300 | (0x3) | (0x4 << 16) | (0x4 << 12) }, ++ { 88, 0x77700300 | (0x3) | (0x5 << 16) | (0x4 << 12) }, ++ { 96, 0x77700300 | (0x3) | (0x5 << 16) | (0x5 << 12) }, ++ { 104, 0x77700300 | (0x3) | (0x6 << 16) | (0x5 << 12) }, ++ { 112, 0x77700300 | (0x3) | (0x6 << 16) | (0x6 << 12) }, ++ { 120, 0x77700300 | (0x3) | (0x7 << 16) | (0x6 << 12) }, ++ { 128, 0x77700300 | (0x3) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 144, 0x77700300 | (0x4) | (0x4 << 16) | (0x3 << 12) }, ++ { 160, 0x77700300 | (0x4) | (0x4 << 16) | (0x4 << 12) }, ++ { 176, 0x77700300 | (0x4) | (0x5 << 16) | (0x4 << 12) }, ++ { 192, 0x77700300 | (0x4) | (0x5 << 16) | (0x5 << 12) }, ++ { 208, 0x77700300 | (0x4) | (0x6 << 16) | (0x5 << 12) }, ++ { 224, 0x77700300 | (0x4) | (0x6 << 16) | (0x6 << 12) }, ++ { 240, 0x77700300 | (0x4) | (0x7 << 16) | (0x6 << 12) }, ++ { 256, 0x77700300 | (0x4) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 288, 0x77700300 | (0x5) | (0x4 << 16) | (0x3 << 12) }, ++ { 320, 0x77700300 | (0x5) | (0x4 << 16) | (0x4 << 12) }, ++ { 352, 0x77700300 | (0x5) | (0x5 << 16) | (0x4 << 12) }, ++ { 384, 0x77700300 | (0x5) | (0x5 << 16) | (0x5 << 12) }, ++ { 416, 0x77700300 | (0x5) | (0x6 << 16) | (0x5 << 12) }, ++ { 448, 0x77700300 | (0x5) | (0x6 << 16) | (0x6 << 12) }, ++ { 480, 0x77700300 | (0x5) | (0x7 << 16) | (0x6 << 12) }, ++ { 512, 0x77700300 | (0x5) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 576, 0x77700300 | (0x6) | (0x4 << 16) | (0x3 << 12) }, ++ { 640, 0x77700300 | (0x6) | (0x4 << 16) | (0x4 << 12) }, ++ { 704, 0x77700300 | (0x6) | (0x5 << 16) | (0x4 << 12) }, ++ { 768, 0x77700300 | (0x6) | (0x5 << 16) | (0x5 << 12) }, ++ { 832, 0x77700300 | (0x6) | (0x6 << 16) | (0x5 << 12) }, ++ { 896, 0x77700300 | (0x6) | (0x6 << 16) | (0x6 << 12) }, ++ { 960, 0x77700300 | (0x6) | (0x7 << 16) | (0x6 << 12) }, ++ { 1024, 0x77700300 | (0x6) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 1152, 0x77700300 | (0x7) | (0x4 << 16) | (0x3 << 12) }, ++ { 1280, 0x77700300 | (0x7) | (0x4 << 16) | (0x4 << 12) }, ++ { 1408, 0x77700300 | (0x7) | (0x5 << 16) | (0x4 << 12) }, ++ { 1536, 0x77700300 | (0x7) | (0x5 << 16) | (0x5 << 12) }, ++ { 1664, 0x77700300 | (0x7) | (0x6 << 16) | (0x5 << 12) }, ++ { 1792, 0x77700300 | (0x7) | (0x6 << 16) | (0x6 << 12) }, ++ { 1920, 0x77700300 | (0x7) | (0x7 << 16) | (0x6 << 12) }, ++ { 2048, 0x77700300 | (0x7) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 2304, 0x77700300 | (0x8) | (0x4 << 16) | (0x3 << 12) }, ++ { 2560, 0x77700300 | (0x8) | (0x4 << 16) | (0x4 << 12) }, ++ { 2816, 0x77700300 | (0x8) | (0x5 << 16) | (0x4 << 12) }, ++ { 3072, 0x77700300 | (0x8) | (0x5 << 16) | (0x5 << 12) }, ++ { 3328, 0x77700300 | (0x8) | (0x6 << 16) | (0x5 << 12) }, ++ { 3584, 0x77700300 | (0x8) | (0x6 << 16) | (0x6 << 12) }, ++ { 3840, 0x77700300 | (0x8) | (0x7 << 16) | (0x6 << 12) }, ++ { 4096, 0x77700300 | (0x8) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 4608, 0x77700300 | (0x9) | (0x4 << 16) | (0x3 << 12) }, ++ { 5120, 0x77700300 | (0x9) | (0x4 << 16) | (0x4 << 12) }, ++ { 5632, 0x77700300 | (0x9) | (0x5 << 16) | (0x4 << 12) }, ++ { 6144, 0x77700300 | (0x9) | (0x5 << 16) | (0x5 << 12) }, ++ { 6656, 0x77700300 | (0x9) | (0x6 << 16) | (0x5 << 12) }, ++ { 7168, 0x77700300 | (0x9) | (0x6 << 16) | (0x6 << 12) }, ++ { 7680, 0x77700300 | (0x9) | (0x7 << 16) | (0x6 << 12) }, ++ { 8192, 0x77700300 | (0x9) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 9216, 0x77700300 | (0xa) | (0x4 << 16) | (0x3 << 12) }, ++ { 10240, 0x77700300 | (0xa) | (0x4 << 16) | (0x4 << 12) }, ++ { 11264, 0x77700300 | (0xa) | (0x5 << 16) | (0x4 << 12) }, ++ { 12288, 0x77700300 | (0xa) | (0x5 << 16) | (0x5 << 12) }, ++ { 13312, 0x77700300 | (0xa) | (0x6 << 16) | (0x5 << 12) }, ++ { 14336, 0x77700300 | (0xa) | (0x6 << 16) | (0x6 << 12) }, ++ { 15360, 0x77700300 | (0xa) | (0x7 << 16) | (0x6 << 12) }, ++ { 16384, 0x77700300 | (0xa) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 18432, 0x77700300 | (0xb) | (0x4 << 16) | (0x3 << 12) }, ++ { 20480, 0x77700300 | (0xb) | (0x4 << 16) | (0x4 << 12) }, ++ { 22528, 0x77700300 | (0xb) | (0x5 << 16) | (0x4 << 12) }, ++ { 24576, 0x77700300 | (0xb) | (0x5 << 16) | (0x5 << 12) }, ++ { 26624, 0x77700300 | (0xb) | (0x6 << 16) | (0x5 << 12) }, ++ { 28672, 0x77700300 | (0xb) | (0x6 << 16) | (0x6 << 12) }, ++ { 30720, 0x77700300 | (0xb) | (0x7 << 16) | (0x6 << 12) }, ++ { 32768, 0x77700300 | (0xb) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 36864, 0x77700300 | (0xc) | (0x4 << 16) | (0x3 << 12) }, ++ { 40960, 0x77700300 | (0xc) | (0x4 << 16) | (0x4 << 12) }, ++ { 45056, 0x77700300 | (0xc) | (0x5 << 16) | (0x4 << 12) }, ++ { 49152, 0x77700300 | (0xc) | (0x5 << 16) | (0x5 << 12) }, ++ { 53248, 0x77700300 | (0xc) | (0x6 << 16) | (0x5 << 12) }, ++ { 57344, 0x77700300 | (0xc) | (0x6 << 16) | (0x6 << 12) }, ++ { 61440, 0x77700300 | (0xc) | (0x7 << 16) | (0x6 << 12) }, ++ { 65536, 0x77700300 | (0xc) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 73728, 0x77700300 | (0xd) | (0x4 << 16) | (0x3 << 12) }, ++ { 81920, 0x77700300 | (0xd) | (0x4 << 16) | (0x4 << 12) }, ++ { 90112, 0x77700300 | (0xd) | (0x5 << 16) | (0x4 << 12) }, ++ { 98304, 0x77700300 | (0xd) | (0x5 << 16) | (0x5 << 12) }, ++ { 106496, 0x77700300 | (0xd) | (0x6 << 16) | (0x5 << 12) }, ++ { 114688, 0x77700300 | (0xd) | (0x6 << 16) | (0x6 << 12) }, ++ { 122880, 0x77700300 | (0xd) | (0x7 << 16) | (0x6 << 12) }, ++ { 131072, 0x77700300 | (0xd) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 147456, 0x77700300 | (0xe) | (0x4 << 16) | (0x3 << 12) }, ++ { 163840, 0x77700300 | (0xe) | (0x4 << 16) | (0x4 << 12) }, ++ { 180224, 0x77700300 | (0xe) | (0x5 << 16) | (0x4 << 12) }, ++ { 196608, 0x77700300 | (0xe) | (0x5 << 16) | (0x5 << 12) }, ++ { 212992, 0x77700300 | (0xe) | (0x6 << 16) | (0x5 << 12) }, ++ { 229376, 0x77700300 | (0xe) | (0x6 << 16) | (0x6 << 12) }, ++ { 245760, 0x77700300 | (0xe) | (0x7 << 16) | (0x6 << 12) }, ++ { 262144, 0x77700300 | (0xe) | (0x7 << 16) | (0x7 << 12) }, ++ ++ { 294912, 0x77700300 | (0xf) | (0x4 << 16) | (0x3 << 12) }, ++ { 327680, 0x77700300 | (0xf) | (0x4 << 16) | (0x4 << 12) }, ++ { 360448, 0x77700300 | (0xf) | (0x5 << 16) | (0x4 << 12) }, ++ { 393216, 0x77700300 | (0xf) | (0x5 << 16) | (0x5 << 12) }, ++ { 425984, 0x77700300 | (0xf) | (0x6 << 16) | (0x5 << 12) }, ++ { 458752, 0x77700300 | (0xf) | (0x6 << 16) | (0x6 << 12) }, ++ { 491520, 0x77700300 | (0xf) | (0x7 << 16) | (0x6 << 12) }, ++ { 524288, 0x77700300 | (0xf) | (0x7 << 16) | (0x7 << 12) }, ++#endif ++}; ++ ++static inline void ast_i2c_write(struct ast_i2c_bus *i2c_bus, u32 val, u32 reg) ++{ ++#if 0 ++ printf("%x: W : reg %x , val: %x\n", i2c_bus->reg_base, reg, val); ++#endif ++ __raw_writel(val, i2c_bus->reg_base + reg); ++} ++ ++static inline u32 ast_i2c_read(struct ast_i2c_bus *i2c_bus, u32 reg) ++{ ++#if 0 ++ u32 val = __raw_readl(i2c_bus->reg_base + reg); ++ printf("%x: R : reg %x , val: %x\n", i2c_bus->reg_base, reg, val); ++ return val; ++#else ++ return __raw_readl(i2c_bus->reg_base + reg); ++#endif ++} ++ ++static u32 select_i2c_clock(unsigned int bus_clk) ++{ ++#if 0 ++ unsigned int clk, inc = 0, div, divider_ratio; ++ u32 SCL_Low, SCL_High, data; ++ ++ clk = ast_get_pclk(); ++// debug("pclk = %d\n", clk); ++ divider_ratio = clk / bus_clk; ++ for (div = 0; divider_ratio >= 16; div++) ++ { ++ inc |= (divider_ratio & 1); ++ divider_ratio >>= 1; ++ } ++ divider_ratio += inc; ++ SCL_Low = (divider_ratio >> 1) - 1; ++ SCL_High = divider_ratio - SCL_Low - 2; ++ data = 0x77700300 | (SCL_High << 16) | (SCL_Low << 12) | div; ++// printk("I2CD04 for %d = %08X\n", target_speed, data); ++ return data; ++#else ++ int i; ++ unsigned int clk; ++ u32 data; ++ ++ clk = ast_get_pclk(); ++ // debug("pclk = %d\n", clk); ++ ++ for (i = 0; ++ i < sizeof(i2c_timing_table) / sizeof(struct ast_i2c_timing_table); ++ i++) { ++ if ((clk / i2c_timing_table[i].divisor) < bus_clk) { ++ break; ++ } ++ } ++ data = i2c_timing_table[i].timing; ++ // printk("divisor [%d], timing [%x]\n", i2c_timing_table[i].divisor, ++ // i2c_timing_table[i].timing); ++ return data; ++#endif ++} ++ ++static int ast_i2c_wait_isr(struct ast_i2c_bus *i2c_bus, u32 flag) ++{ ++ int timeout = 0; ++ ++ while (!(ast_i2c_read(i2c_bus, I2C_INTR_STS_REG) & flag) && ++ (timeout < I2C_TIMEOUT_COUNT)) { ++ udelay(I2C_SLEEP_US); ++ timeout++; ++ } ++ ++ /* Clear Interrupt */ ++ ast_i2c_write(i2c_bus, 0xfffffff, I2C_INTR_STS_REG); ++ ++ if (timeout >= I2C_TIMEOUT_COUNT) { ++ debug("%s timed out:- flag: %x\n", __func__, flag); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int ast_i2c_wait_tx(struct ast_i2c_bus *i2c_bus) ++{ ++ int sts; ++ int timeout = 0; ++ while (1) { ++ sts = ast_i2c_read(i2c_bus, I2C_INTR_STS_REG); ++ ++ if (timeout > I2C_TIMEOUT_COUNT) { ++ /* I2C Reset */ ++ debug("Timeout: Bus:%d, Addr:0x%02x\n", i2c_bus_num, ++ i2c_bus->addr); ++ ast_i2c_write(i2c_bus, 0, I2C_FUN_CTRL_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_MASTER_EN, ++ I2C_FUN_CTRL_REG); ++ ++ return -ETIMEDOUT; ++ } else if (sts & AST_I2CD_INTR_STS_TX_NAK) { ++ ast_i2c_write(i2c_bus, AST_I2CD_INTR_STS_TX_NAK, ++ I2C_INTR_STS_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, ++ I2C_CMD_REG); ++ ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_NORMAL_STOP); ++ ++ return -EREMOTEIO; ++ } else if (sts & AST_I2CD_INTR_STS_TX_ACK) { ++ ast_i2c_write(i2c_bus, AST_I2CD_INTR_STS_TX_ACK, ++ I2C_INTR_STS_REG); ++ break; ++ } else { ++ timeout++; ++ } ++ udelay(I2C_SLEEP_US); ++ } ++ ++ return 0; ++} ++ ++static int ast_i2c_deblock(struct ast_i2c_bus *i2c_bus) ++{ ++ u32 csr; ++ int ret = 0; ++ ++ if ((csr = ast_i2c_read(i2c_bus, I2C_CMD_REG)) & ++ AST_I2CD_BUS_BUSY_STS) { ++ if ((csr & AST_I2CD_SDA_LINE_STS) && ++ (csr & AST_I2CD_SCL_LINE_STS)) { ++ /* Bus idle */ ++ debug("Bus(%d) idle\n", i2c_bus_num); ++ ret = 0; ++ } else if (csr & AST_I2CD_SDA_LINE_STS) { ++ /* send stop command */ ++ debug("Unterminated TXN in (%x), sending stop...\n", ++ csr); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_NORMAL_STOP); ++ } else if (csr & AST_I2CD_SCL_LINE_STS) { ++ /* Possibly stuck slave */ ++ debug("Bus stuck (%x), attempting recovery...\n", csr); ++ ast_i2c_write(i2c_bus, AST_I2CD_BUS_RECOVER_CMD_EN, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_BUS_RECOVER); ++ } else { ++ debug("Bus(%d) slave(0x%02x) busy. Reseting bus...\n", ++ i2c_bus_num, i2c_bus->addr); ++ ast_i2c_write(i2c_bus, 0, I2C_FUN_CTRL_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_MASTER_EN, ++ I2C_FUN_CTRL_REG); ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++static int ast_i2c_xfer(struct ast_i2c_bus *i2c_bus) ++{ ++ int sts, i, ret = 0; ++ ++ /* Clear Interrupt */ ++ ast_i2c_write(i2c_bus, 0xfffffff, I2C_INTR_STS_REG); ++ ++ /* Check for bus busy */ ++ ret = ast_i2c_deblock(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ // first start ++ debug(" %sing %d byte%s %s 0x%02x\n", i2c_bus->flags ? "read" : "write", ++ i2c_bus->d_len, i2c_bus->d_len > 1 ? "s" : "", ++ i2c_bus->flags ? "from" : "to", i2c_bus->addr); ++ ++ if (i2c_bus->flags) { ++ // READ ++ if (i2c_bus->a_len) { ++ // send start ++ ast_i2c_write(i2c_bus, (i2c_bus->addr << 1), ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, ++ AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, ++ I2C_CMD_REG); ++ ++ /* Wait for ACK */ ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ /* Send Offset */ ++ for (i = 0; i < i2c_bus->a_len; i++) { ++ debug("offset [%x]\n", i2c_bus->a_buf[i]); ++ ast_i2c_write(i2c_bus, i2c_bus->a_buf[i], ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ } ++ } ++ ++ // repeat-start ++ ast_i2c_write(i2c_bus, (i2c_bus->addr << 1) | 0x1, ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, ++ I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ for (i = 0; i < i2c_bus->d_len; i++) { ++ if (i == (i2c_bus->d_len - 1)) { ++ ast_i2c_write(i2c_bus, ++ AST_I2CD_M_RX_CMD | ++ AST_I2CD_M_S_RX_CMD_LAST, ++ I2C_CMD_REG); ++ } else { ++ ast_i2c_write(i2c_bus, AST_I2CD_M_RX_CMD, ++ I2C_CMD_REG); ++ } ++ ++ ret = ast_i2c_wait_isr(i2c_bus, ++ AST_I2CD_INTR_STS_RX_DOWN); ++ if (ret != 0) ++ return ret; ++ ++ i2c_bus->d_buf[i] = ++ (ast_i2c_read(i2c_bus, I2C_BYTE_BUF_REG) & ++ AST_I2CD_RX_BYTE_BUFFER) >> ++ 8; ++ } ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, AST_I2CD_INTR_STS_NORMAL_STOP); ++ if (ret != 0) ++ return ret; ++ ++ } else { ++ // Write ++ // send start ++ ast_i2c_write(i2c_bus, (i2c_bus->addr << 1), I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD | AST_I2CD_M_START_CMD, ++ I2C_CMD_REG); ++ ++ /* Wait for ACK */ ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ ++ /* Send Offset */ ++ for (i = 0; i < i2c_bus->a_len; i++) { ++ debug("offset [%x]\n", i2c_bus->a_buf[i]); ++ ast_i2c_write(i2c_bus, i2c_bus->a_buf[i], ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ } ++ ++ /* Tx data */ ++ for (i = 0; i < i2c_bus->d_len; i++) { ++ debug("Tx data [%x]\n", i2c_bus->d_buf[i]); ++ ast_i2c_write(i2c_bus, i2c_bus->d_buf[i], ++ I2C_BYTE_BUF_REG); ++ ast_i2c_write(i2c_bus, AST_I2CD_M_TX_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_tx(i2c_bus); ++ if (ret != 0) ++ return ret; ++ } ++ ast_i2c_write(i2c_bus, AST_I2CD_M_STOP_CMD, I2C_CMD_REG); ++ ret = ast_i2c_wait_isr(i2c_bus, AST_I2CD_INTR_STS_NORMAL_STOP); ++ if (ret != 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/*****************************************************************************/ ++ ++unsigned int i2c_get_bus_speed(void) ++{ ++ return ast_i2c[i2c_bus_num].speed; ++} ++ ++int i2c_set_bus_speed(unsigned int speed) ++{ ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ /* Set AC Timing */ ++ ast_i2c_write(i2c_bus, select_i2c_clock(speed), I2C_AC_TIMING_REG1); ++ ast_i2c_write(i2c_bus, AST_NO_TIMEOUT_CTRL, I2C_AC_TIMING_REG2); ++ ++ i2c_bus->speed = speed; ++ ++ return 0; ++} ++ ++unsigned int i2c_get_base(int bus_no) ++{ ++ switch (bus_no) { ++ case 0: ++ return AST_I2C_DEV0_BASE; ++ break; ++ case 1: ++ return AST_I2C_DEV1_BASE; ++ break; ++ case 2: ++ return AST_I2C_DEV2_BASE; ++ break; ++ case 3: ++ return AST_I2C_DEV3_BASE; ++ break; ++ case 4: ++ return AST_I2C_DEV4_BASE; ++ break; ++ case 5: ++ return AST_I2C_DEV5_BASE; ++ break; ++ case 6: ++ return AST_I2C_DEV6_BASE; ++ break; ++ case 7: ++ return AST_I2C_DEV7_BASE; ++ break; ++ case 8: ++ return AST_I2C_DEV8_BASE; ++ break; ++ case 9: ++ return AST_I2C_DEV9_BASE; ++ break; ++ case 10: ++ return AST_I2C_DEV10_BASE; ++ break; ++ case 11: ++ return AST_I2C_DEV11_BASE; ++ break; ++ case 12: ++ return AST_I2C_DEV12_BASE; ++ break; ++ case 13: ++ return AST_I2C_DEV13_BASE; ++ break; ++ default: ++ printf("i2c base error\n"); ++ break; ++ }; ++ return 0; ++} ++ ++void i2c_init(int speed, int slaveaddr) ++{ ++ int i = 0; ++ struct ast_i2c_bus *i2c_bus; ++ ++ // SCU I2C Reset ++ ast_scu_init_i2c(); ++ ++ /* This will override the speed selected in the fdt for that port */ ++ debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr); ++ ++ for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; i++) { ++ i2c_bus = &ast_i2c[i]; ++ i2c_bus->reg_base = i2c_get_base(i); ++ ++ i2c_bus->speed = CONFIG_SYS_I2C_SPEED; ++ i2c_bus->state = 0; ++ ++ // I2C Multi-Pin ++ ast_scu_multi_func_i2c(i); ++ ++ // I2CG Reset ++ ast_i2c_write(i2c_bus, 0, I2C_FUN_CTRL_REG); ++ ++ // Enable Master Mode ++ ast_i2c_write(i2c_bus, AST_I2CD_MASTER_EN, I2C_FUN_CTRL_REG); ++ ++ // SLAVE mode enable ++#if 0 ++ if (slaveaddr) { ++ ast_i2c_write(i2c_bus, slaveaddr, I2C_DEV_ADDR_REG); ++ ast_i2c_write(i2c_bus, ++ ast_i2c_read(i2c_bus, I2C_FUN_CTRL_REG) | ++ AST_I2CD_SLAVE_EN, ++ I2C_FUN_CTRL_REG); ++ } ++#endif ++ ++ /* Set AC Timing */ ++ i2c_set_bus_speed(speed); ++ ++ // Clear Interrupt ++ ast_i2c_write(i2c_bus, 0xfffffff, I2C_INTR_STS_REG); ++ ++ /* Set interrupt generation of I2C controller */ ++ ast_i2c_write(i2c_bus, 0, I2C_INTR_CTRL_REG); ++ } ++ ++ i2c_bus_num = 0; ++ debug("end\n"); ++} ++ ++/* Probe to see if a chip is present. */ ++int i2c_probe(uchar addr) ++{ ++ uchar a_buf[1] = { 0 }; ++ ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ debug("i2c_probe[bus:%d]: addr=0x%x\n", i2c_bus_num, addr); ++ ++ i2c_bus->addr = addr; ++ i2c_bus->flags = 1; ++ i2c_bus->a_len = 1; ++ i2c_bus->a_buf = (u8 *)&a_buf; ++ i2c_bus->d_len = 1; ++ i2c_bus->d_buf = (u8 *)&a_buf; ++ ++ return ast_i2c_xfer(i2c_bus); ++} ++ ++/* Read bytes */ ++int i2c_read(uchar addr, uint offset, int alen, uchar *buffer, int len) ++{ ++ uchar xoffset[4]; ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ debug("i2c_read[bus:%d]: addr=0x%x, offset=0x%x, alen=0x%x len=0x%x\n", ++ i2c_bus_num, addr, offset, alen, len); ++ ++ if (alen > 4) { ++ debug("I2C read: addr len %d not supported\n", alen); ++ return 1; ++ } ++ ++ if (alen > 0) { ++ xoffset[0] = (offset >> 24) & 0xFF; ++ xoffset[1] = (offset >> 16) & 0xFF; ++ xoffset[2] = (offset >> 8) & 0xFF; ++ xoffset[3] = offset & 0xFF; ++ } ++ ++ i2c_bus->addr = addr; ++ i2c_bus->flags = 1; ++ i2c_bus->a_len = alen; ++ i2c_bus->a_buf = &xoffset[4 - alen]; ++ i2c_bus->d_len = len; ++ i2c_bus->d_buf = buffer; ++ ++ return ast_i2c_xfer(i2c_bus); ++} ++ ++/* Write bytes */ ++int i2c_write(uchar addr, uint offset, int alen, uchar *buffer, int len) ++{ ++ uchar xoffset[4]; ++ struct ast_i2c_bus *i2c_bus = &ast_i2c[i2c_bus_num]; ++ ++ debug("i2c_write[bus:%d]: addr=0x%x, offset=0x%x, alen=0x%x len=0x%x\n", ++ i2c_bus_num, addr, offset, alen, len); ++ ++ if (alen > 0) { ++ xoffset[0] = (offset >> 24) & 0xFF; ++ xoffset[1] = (offset >> 16) & 0xFF; ++ xoffset[2] = (offset >> 8) & 0xFF; ++ xoffset[3] = offset & 0xFF; ++ } ++ ++ i2c_bus->addr = addr; ++ i2c_bus->flags = 0; ++ i2c_bus->a_len = alen; ++ i2c_bus->a_buf = &xoffset[4 - alen]; ++ i2c_bus->d_len = len; ++ i2c_bus->d_buf = buffer; ++ ++ return ast_i2c_xfer(i2c_bus); ++} ++ ++#if defined(CONFIG_I2C_MULTI_BUS) ++/* ++ * Functions for multiple I2C bus handling ++ */ ++unsigned int i2c_get_bus_num(void) ++{ ++ return i2c_bus_num; ++} ++ ++int i2c_set_bus_num(unsigned int bus) ++{ ++ if (bus >= NUM_BUS) ++ return -1; ++ i2c_bus_num = bus; ++ ++ return 0; ++} ++#endif +diff --git a/drivers/i2c/ast_i2c.h b/drivers/i2c/ast_i2c.h +new file mode 100644 +index 0000000..7cff0e5 +--- /dev/null ++++ b/drivers/i2c/ast_i2c.h +@@ -0,0 +1,131 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2012-2020 ASPEED Technology Inc. ++ * Copyright 2016 IBM Corporation ++ * Copyright 2017 Google, Inc. ++ */ ++#ifndef __AST_I2C_H_ ++#define __AST_I2C_H_ ++ ++struct ast_i2c_regs { ++ u32 fcr; ++ u32 cactcr1; ++ u32 cactcr2; ++ u32 icr; ++ u32 isr; ++ u32 csr; ++ u32 sdar; ++ u32 pbcr; ++ u32 trbbr; ++#ifdef CONFIG_ASPEED_AST2500 ++ u32 dma_mbar; ++ u32 dma_tlr; ++#endif ++}; ++ ++/* Device Register Definition */ ++/* 0x00 : I2CD Function Control Register */ ++#define I2CD_BUFF_SEL_MASK (0x7 << 20) ++#define I2CD_BUFF_SEL(x) (x << 20) ++#define I2CD_M_SDA_LOCK_EN (0x1 << 16) ++#define I2CD_MULTI_MASTER_DIS (0x1 << 15) ++#define I2CD_M_SCL_DRIVE_EN (0x1 << 14) ++#define I2CD_MSB_STS (0x1 << 9) ++#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8) ++#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) ++#define I2CD_M_HIGH_SPEED_EN (0x1 << 6) ++#define I2CD_DEF_ADDR_EN (0x1 << 5) ++#define I2CD_DEF_ALERT_EN (0x1 << 4) ++#define I2CD_DEF_ARP_EN (0x1 << 3) ++#define I2CD_DEF_GCALL_EN (0x1 << 2) ++#define I2CD_SLAVE_EN (0x1 << 1) ++#define I2CD_MASTER_EN (0x1) ++ ++/* 0x04 : I2CD Clock and AC Timing Control Register #1 */ ++/* Base register value. These bits are always set by the driver. */ ++#define I2CD_CACTC_BASE 0xfff00300 ++#define I2CD_TCKHIGH_SHIFT 16 ++#define I2CD_TCKLOW_SHIFT 12 ++#define I2CD_THDDAT_SHIFT 10 ++#define I2CD_TO_DIV_SHIFT 8 ++#define I2CD_BASE_DIV_SHIFT 0 ++ ++/* 0x08 : I2CD Clock and AC Timing Control Register #2 */ ++#define I2CD_tTIMEOUT 1 ++#define I2CD_NO_TIMEOUT_CTRL 0 ++ ++/* 0x0c : I2CD Interrupt Control Register & ++ * 0x10 : I2CD Interrupt Status Register ++ * ++ * These share bit definitions, so use the same values for the enable & ++ * status bits. ++ */ ++#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) ++#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) ++#define I2CD_INTR_SMBUS_ALERT (0x1 << 12) ++#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11) ++#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) ++#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) ++#define I2CD_INTR_GCALL_ADDR (0x1 << 8) ++#define I2CD_INTR_SLAVE_MATCH (0x1 << 7) ++#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) ++#define I2CD_INTR_ABNORMAL (0x1 << 5) ++#define I2CD_INTR_NORMAL_STOP (0x1 << 4) ++#define I2CD_INTR_ARBIT_LOSS (0x1 << 3) ++#define I2CD_INTR_RX_DONE (0x1 << 2) ++#define I2CD_INTR_TX_NAK (0x1 << 1) ++#define I2CD_INTR_TX_ACK (0x1 << 0) ++ ++/* 0x14 : I2CD Command/Status Register */ ++#define I2CD_SDA_OE (0x1 << 28) ++#define I2CD_SDA_O (0x1 << 27) ++#define I2CD_SCL_OE (0x1 << 26) ++#define I2CD_SCL_O (0x1 << 25) ++#define I2CD_TX_TIMING (0x1 << 24) ++#define I2CD_TX_STATUS (0x1 << 23) ++ ++/* Tx State Machine */ ++#define I2CD_IDLE 0x0 ++#define I2CD_MACTIVE 0x8 ++#define I2CD_MSTART 0x9 ++#define I2CD_MSTARTR 0xa ++#define I2CD_MSTOP 0xb ++#define I2CD_MTXD 0xc ++#define I2CD_MRXACK 0xd ++#define I2CD_MRXD 0xe ++#define I2CD_MTXACK 0xf ++#define I2CD_SWAIT 0x1 ++#define I2CD_SRXD 0x4 ++#define I2CD_STXACK 0x5 ++#define I2CD_STXD 0x6 ++#define I2CD_SRXACK 0x7 ++#define I2CD_RECOVER 0x3 ++ ++#define I2CD_SCL_LINE_STS (0x1 << 18) ++#define I2CD_SDA_LINE_STS (0x1 << 17) ++#define I2CD_BUS_BUSY_STS (0x1 << 16) ++#define I2CD_SDA_OE_OUT_DIR (0x1 << 15) ++#define I2CD_SDA_O_OUT_DIR (0x1 << 14) ++#define I2CD_SCL_OE_OUT_DIR (0x1 << 13) ++#define I2CD_SCL_O_OUT_DIR (0x1 << 12) ++#define I2CD_BUS_RECOVER_CMD (0x1 << 11) ++#define I2CD_S_ALT_EN (0x1 << 10) ++#define I2CD_RX_DMA_ENABLE (0x1 << 9) ++#define I2CD_TX_DMA_ENABLE (0x1 << 8) ++ ++/* Command Bit */ ++#define I2CD_RX_BUFF_ENABLE (0x1 << 7) ++#define I2CD_TX_BUFF_ENABLE (0x1 << 6) ++#define I2CD_M_STOP_CMD (0x1 << 5) ++#define I2CD_M_S_RX_CMD_LAST (0x1 << 4) ++#define I2CD_M_RX_CMD (0x1 << 3) ++#define I2CD_S_TX_CMD (0x1 << 2) ++#define I2CD_M_TX_CMD (0x1 << 1) ++#define I2CD_M_START_CMD 0x1 ++ ++#define I2CD_RX_DATA_SHIFT 8 ++#define I2CD_RX_DATA_MASK (0xff << I2CD_RX_DATA_SHIFT) ++ ++#define I2C_HIGHSPEED_RATE 400000 ++ ++#endif /* __AST_I2C_H_ */ +diff --git a/include/configs/ast-common.h b/include/configs/ast-common.h +index b7d7192..0bc7f2d 100644 +--- a/include/configs/ast-common.h ++++ b/include/configs/ast-common.h +@@ -84,6 +84,11 @@ + #define CONFIG_SYS_MAXARGS 16 + #define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + ++/* I2C config */ ++#define CONFIG_I2C_MULTI_BUS 1 ++#define CONFIG_SYS_MAX_I2C_BUS 8 ++#define CONFIG_SYS_I2C_SPEED 100000 ++ + /* + * Optional MTD and UBI support + */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0027-CPLD-u-boot-commands-support-for-PFR.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0027-CPLD-u-boot-commands-support-for-PFR.patch new file mode 100644 index 000000000..b5f7ccf07 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0027-CPLD-u-boot-commands-support-for-PFR.patch @@ -0,0 +1,301 @@ +From cdb62eb60de0b99276ff755b896fc51c8ed2606d Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 7 May 2019 11:26:35 +0530 +Subject: [PATCH] CPLD u-boot commands support for PFR + +Implemented the cpld command in u-boot for +communicating with PFR CPLD. + +Tested: +Simulated test on different I2C bus and slave +as we don't have hardware available yet. +ast# cpld dump +*** Dumping CPLD Registers *** +0x0000 | 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f +---------------------------------------------------------- +0x0000 | 03 00 00 00 01 09 00 f5 01 09 19 cb 46 4c 45 -- +0x0001 | -- 52 4f 4e 49 43 53 cf 53 2d 31 31 30 30 41 44 +0x0002 | 55 -- 30 2d 32 30 31 ca 47 38 34 30 32 -- 2d -- +0x0003 | 30 37 c2 30 31 cc 45 58 57 44 36 34 39 30 30 38 +............................. +ast# cpld read 0x00 +CPLD read successful. Reg:0x00 Val:0x03 +ast# cpld write 0x00 0x04 +CPLD write successful. Reg:0x00 Val:0x04 +ast# cpld read 0x00 +CPLD read successful. Reg:0x00 Val:0x04 +ast# + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + cmd/Makefile | 1 + + cmd/cpld.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 245 insertions(+) + create mode 100644 cmd/cpld.c + +diff --git a/cmd/Makefile b/cmd/Makefile +index a1731be..c8ac0af 100644 +--- a/cmd/Makefile ++++ b/cmd/Makefile +@@ -66,6 +66,7 @@ obj-$(CONFIG_CMD_FUSE) += fuse.o + obj-$(CONFIG_CMD_GETTIME) += gettime.o + obj-$(CONFIG_CMD_GPIO) += gpio.o + obj-$(CONFIG_CMD_I2C) += i2c.o ++obj-$(CONFIG_CMD_I2C) += cpld.o + obj-$(CONFIG_CMD_IOTRACE) += iotrace.o + obj-$(CONFIG_CMD_HASH) += hash.o + obj-$(CONFIG_CMD_IDE) += ide.o +diff --git a/cmd/cpld.c b/cmd/cpld.c +new file mode 100644 +index 0000000..06b2e98 +--- /dev/null ++++ b/cmd/cpld.c +@@ -0,0 +1,244 @@ ++/* ++ * Copyright (c) 2018-2019 Intel Corporation ++ * Written by AppaRao Puli <apparao.puli@intel.com> ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include <common.h> ++#include <command.h> ++#include <cli.h> ++#include <i2c.h> ++#include <errno.h> ++#include <linux/compiler.h> ++ ++#define PFR_CPLD_I2C_BUSNO 4 ++#define PFR_CPLD_SLAVE_ADDR 0xE0 ++ ++#define CPLD_READ_TIMEOUT_ATTEMPTS 5 ++ ++/* Some CPLD registers are self cleared after read. ++ * We should skip them reading to avoid functionality impact.*/ ++/* TODO: Need to get this list from CPLD team. */ ++static uchar cpld_reg_skip_read[] = {}; ++ ++static bool skip_cpld_reg_read(u32 reg) ++{ ++ int size = ARRAY_SIZE(cpld_reg_skip_read); ++ for (int i = 0; i < size; i++) { ++ if (reg == cpld_reg_skip_read[i]) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int do_cpld_write(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ int ret = 0; ++ int current_bus_no; ++ u32 reg_addr; ++ uchar value; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ if (argc != 3) ++ return CMD_RET_USAGE; ++ ++ reg_addr = simple_strtoul(argv[1], NULL, 16); ++ if (reg_addr > 0xFF) { ++ printf("Invalid register. Valid range[0x00-0xFF]."); ++ return CMD_RET_FAILURE; ++ } ++ value = simple_strtoul(argv[2], NULL, 16); ++ ++ /* Get current I2C bus number to restore later. */ ++ current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failure changing bus number (%d)\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ ret = i2c_write(chip, reg_addr, 1, &value, 1); ++ if (ret) { ++ printf("Error writing the chip: %d\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ printf("CPLD write successful. Reg:0x%02x Val:0x%02x\n", reg_addr, ++ value); ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Error in restoring bus number.\n"); ++ ++ return ret; ++} ++ ++static int do_cpld_read(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ int ret = 0; ++ int current_bus_no; ++ u32 reg_addr; ++ uchar value[1]; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ if (argc != 2) ++ return CMD_RET_USAGE; ++ ++ reg_addr = simple_strtoul(argv[1], NULL, 16); ++ if (reg_addr > 0xFF) { ++ printf("Invalid register. Valid range[0x00-0xFF]."); ++ return CMD_RET_FAILURE; ++ } ++ ++ /* Get current I2C bus number to restore later. */ ++ current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failure changing bus number (%d)\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ if (skip_cpld_reg_read(reg_addr)) { ++ printf("CPLD register(0x%02x) reading is not allowed.\n", ++ reg_addr); ++ ret = 0; ++ goto done; ++ } ++ ++ ret = i2c_read(chip, reg_addr, 1, value, 1); ++ if (ret) { ++ printf("Error reading the chip: %d\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ printf("CPLD read successful. Reg:0x%02x Val:0x%02x\n", reg_addr, ++ value[0]); ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Error in restoring bus number.\n"); ++ ++ return ret; ++} ++ ++static int do_cpld_dump(cmd_tbl_t *cmdtp, int flag, int argc, ++ char *const argv[]) ++{ ++ int ret = 0; ++ int current_bus_no; ++ u32 reg_addr = 0x00; ++ uchar value[1]; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ if (argc != 1) ++ return CMD_RET_USAGE; ++ ++ /* Get current I2C bus number to restore later. */ ++ current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failure changing bus number (%d)\n", ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ ++ printf("*** Dumping CPLD Registers ***\n", reg_addr, value); ++ printf("0x%04x | ", reg_addr); ++ for (int i = 0; i < 0x10; i++) ++ printf(" %02x", i); ++ printf("\n----------------------------------------------------------\n"); ++ ++ while (reg_addr <= 0xFF) { ++ if ((reg_addr % 16) == 0) ++ printf("0x%04x | ", (reg_addr / 16)); ++ ++ if (skip_cpld_reg_read(reg_addr)) { ++ printf(" --"); ++ } else { ++ int timeout = 0; ++ while (i2c_read(chip, reg_addr, 1, value, 1) != 0) { ++ if (timeout++ >= CPLD_READ_TIMEOUT_ATTEMPTS) { ++ printf("\nERROR: Reading the chip: %d\n", ++ ret); ++ ret = CMD_RET_FAILURE; ++ goto done; ++ } ++ /* Need delay for I2C devices continous read */ ++ mdelay(3 * timeout); ++ } ++ printf(" %02x", value[0]); ++ } ++ ++ reg_addr++; ++ if ((reg_addr % 16) == 0) ++ printf("\n"); ++ } ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Error in restoring bus number.\n"); ++ ++ return ret; ++} ++static cmd_tbl_t cmd_cpld_sub[] = { ++ U_BOOT_CMD_MKENT(dump, 1, 1, do_cpld_dump, "", ""), ++ U_BOOT_CMD_MKENT(read, 2, 1, do_cpld_read, "", ""), ++ U_BOOT_CMD_MKENT(write, 3, 1, do_cpld_write, "", "") ++}; ++ ++/** ++ * do_cpld() - Handle the "cpld" command-line command ++ * @cmdtp: Command data struct pointer ++ * @flag: Command flag ++ * @argc: Command-line argument count ++ * @argv: Array of command-line arguments ++ * ++ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative ++ * on error. ++ */ ++static int do_cpld(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ cmd_tbl_t *c = NULL; ++ ++ if (argc < 2) ++ return CMD_RET_USAGE; ++ ++ /* Strip off leading 'cpld' command argument */ ++ argc--; ++ argv++; ++ ++ if (argc) ++ c = find_cmd_tbl(argv[0], cmd_cpld_sub, ++ ARRAY_SIZE(cmd_cpld_sub)); ++ ++ if (c) ++ return c->cmd(cmdtp, flag, argc, argv); ++ else ++ return CMD_RET_USAGE; ++} ++ ++#ifdef CONFIG_SYS_LONGHELP ++static char cpld_help_text[] = ++ "cpld dump - Dump all CPLD registers.\n" ++ "cpld read <reg> - Read CPLD register.\n" ++ "cpld write <reg> <val> - Write CPLD register.\n"; ++#endif ++ ++U_BOOT_CMD(cpld, 4, 1, do_cpld, "PFR CPLD information", cpld_help_text); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch new file mode 100644 index 000000000..0113fc3fe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch @@ -0,0 +1,59 @@ +From 41c08f1fcb5fa0b07ea541fc3d8bc322ddf8701d Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Mon, 13 May 2019 23:49:02 +0530 +Subject: [PATCH] Enabling uart1&uart2 in u-boot for BIOS messages + +Added uart init function in u-boot aspeed code +to enable uart1 and uart2 for BIOS serial messages. + +Tested: +Forced BMC to stop in u-boot( using Force Firmware Update +Jumper), AC cycled system for multiple times, booted system +to uefi, checked bios serial logs working fine and accessed +keyboard in uefi without any issues. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + board/aspeed/ast-g5/ast-g5-intel.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 812e3ef..e68ab85 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -453,6 +453,26 @@ void ast_g5_intel_late_init(void) + update_bootargs_cmd("special", NULL); + } + ++static void uart_init(void) ++{ ++ u32 val; ++ ++ /* Enable UART1 and UART2 for BIOS messages */ ++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL2); ++ ++ /* UART1 */ ++ val |= (SCU_FUN_PIN_UART1_NCTS | SCU_FUN_PIN_UART1_NDCD | ++ SCU_FUN_PIN_UART1_NDSR | SCU_FUN_PIN_UART1_NRI | ++ SCU_FUN_PIN_UART1_NDTR | SCU_FUN_PIN_UART1_NRTS | ++ SCU_FUN_PIN_UART1_TXD | SCU_FUN_PIN_UART1_RXD); ++ /* UART2 */ ++ val |= (SCU_FUN_PIN_UART2_NCTS | SCU_FUN_PIN_UART2_NDCD | ++ SCU_FUN_PIN_UART2_NDSR | SCU_FUN_PIN_UART2_NRI | ++ SCU_FUN_PIN_UART2_NDTR | SCU_FUN_PIN_UART2_NRTS | ++ SCU_FUN_PIN_UART2_TXD | SCU_FUN_PIN_UART2_RXD); ++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL2); ++} ++ + static void pwm_init(void) + { + uint32_t val; +@@ -521,6 +541,7 @@ extern void espi_init(void); + extern void kcs_init(void); + void ast_g5_intel(void) + { ++ uart_init(); + pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch new file mode 100644 index 000000000..f91ab8fea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch @@ -0,0 +1,1269 @@ +From 513ff559cd6fedd29412fb59b6f436f617620511 Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 21 May 2019 00:53:04 +0530 +Subject: [PATCH] FFUJ: FW IPMI commands and flash support in u-boot + +Firmware update and OEM ipmi commands implementation +for supporting Force Firmware Update Jumper(FFUJ) +mode. Also added support to update the fit images +in FFUJ mode. + +Firmware update commands: +1) Get BMC Execution Context(0x23) +2) Get Firmware Update Random Number(0x26) +3) Set Firmware Update Mode(0x27) +4) Exit Firmware Update Mode(0x28) +5) Set/Get Firmware Update Control(0x29) +6) Get Firmware Update status(0x2A) +7) Set Firmware Update Options(0x2B) +8) Firmware Image Write(0x2C) + +OEM Commands: +1) Get Buffer Size(0x66) + +Tested: + - Used cmdtool.efi to test the individual commands + implementation and negative cases. + - Used debug fwpiaupd.efi tool for validating Firmware + image transfer via KCS and flashing. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> + +--- + arch/arm/include/asm/arch-aspeed/ast-g5-intel.h | 1 + + board/aspeed/ast-g5/Makefile | 2 + + board/aspeed/ast-g5/fw-update.c | 486 ++++++++++++++++++++++++ + board/aspeed/ast-g5/fw-update.h | 50 +++ + board/aspeed/ast-g5/ipmi-fwupd.c | 402 ++++++++++++++++++++ + board/aspeed/ast-g5/ipmi-fwupd.h | 81 ++++ + board/aspeed/ast-g5/ipmi-handler.c | 66 +++- + board/aspeed/ast-g5/ipmi-handler.h | 3 +- + common/autoboot.c | 11 + + configs/ast_g5_phy_defconfig | 1 + + 10 files changed, 1091 insertions(+), 12 deletions(-) + create mode 100644 board/aspeed/ast-g5/fw-update.c + create mode 100644 board/aspeed/ast-g5/fw-update.h + create mode 100644 board/aspeed/ast-g5/ipmi-fwupd.c + create mode 100644 board/aspeed/ast-g5/ipmi-fwupd.h + +diff --git a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +index cd9a099..a88521a 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h ++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +@@ -14,6 +14,7 @@ + + #ifndef __ASSEMBLY__ + int intel_force_firmware_jumper_enabled(void); ++void start_fw_update_loop(void); + #endif + + #endif /* __AST_INTEL_G5_H__ */ +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index f28fcfe..0b2d936 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -6,3 +6,5 @@ obj-y += ast-g5-gpio.o + obj-y += ast-g5-timer.o + obj-y += ast-g5-kcs.o + obj-y += ipmi-handler.o ++obj-y += ipmi-fwupd.o ++obj-y += fw-update.o +diff --git a/board/aspeed/ast-g5/fw-update.c b/board/aspeed/ast-g5/fw-update.c +new file mode 100644 +index 0000000..9923993 +--- /dev/null ++++ b/board/aspeed/ast-g5/fw-update.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <common.h> ++#include <cli.h> ++#include <flash.h> ++ ++#include "fw-update.h" ++ ++#define BOOTCMD_BOOTM_STR "bootm " ++#define RANDOM_NUM_TIMEOUT 30 /* in seconds */ ++#define WAIT_STATE_TIMEOUT 10000 /* 10 seconds */ ++ ++#define PROTECT_OFF 0 ++#define PROTECT_ON 1 ++ ++extern struct fwupd_global_setting g_fwupd_settings; ++extern u32 g_write_addr; ++ ++bool g_fwupd_settings_lock = false; ++unsigned long long etime; ++ ++bool fwupd_settings_trylock(void) ++{ ++ if (g_fwupd_settings_lock) ++ return false; ++ ++ g_fwupd_settings_lock = true; ++ return g_fwupd_settings_lock; ++} ++ ++void fwupd_settings_unlock(void) ++{ ++ g_fwupd_settings_lock = false; ++} ++ ++u8 get_active_boot_image(void) ++{ ++ char *bootcmd = getenv("bootcmd"); ++ char *start = strstr(bootcmd, BOOTCMD_BOOTM_STR); ++ u8 boot_image = PRIMARY_IMAGE; ++ ++ if (start) { ++ ulong boot_addr = simple_strtoul( ++ (start + strlen(BOOTCMD_BOOTM_STR)), NULL, 16); ++ if (boot_addr == SECONDARY_FITIMAGE_START_ADDR) ++ return SECONDARY_IMAGE; ++ } ++ return boot_image; ++} ++ ++static ulong get_flash_image_address(void) ++{ ++ char *bootcmd = getenv("bootcmd"); ++ char *start = strstr(bootcmd, BOOTCMD_BOOTM_STR); ++ ulong boot_addr = PRIMARY_FITIMAGE_START_ADDR; ++ ++ if (start) { ++ boot_addr = simple_strtoul((start + strlen(BOOTCMD_BOOTM_STR)), ++ NULL, 16); ++ /* We update in backup region and set the bootcmd accordingly */ ++ if (boot_addr == PRIMARY_FITIMAGE_START_ADDR) ++ boot_addr = SECONDARY_FITIMAGE_START_ADDR; ++ else ++ boot_addr = PRIMARY_FITIMAGE_START_ADDR; ++ } ++ ++ return boot_addr; ++} ++ ++static void update_processing_status(u8 status, u8 percent) ++{ ++ if (!fwupd_settings_trylock()) ++ return; ++ ++ g_fwupd_settings.processing_status = status; ++ g_fwupd_settings.percentage_completion = percent; ++ ++ fwupd_settings_unlock(); ++ return; ++} ++ ++static void reset_all_settings(void) ++{ ++ if (!fwupd_settings_trylock()) ++ return; ++ ++ memset(&g_fwupd_settings, 0, sizeof(g_fwupd_settings)); ++ g_fwupd_settings.fwupd_mode_active = false; ++ g_fwupd_settings.start_update = false; ++ ++ fwupd_settings_unlock(); ++} ++ ++unsigned int get_seed(void) ++{ ++ char seed_str[] = { "INTEL" }; ++ unsigned int seed; ++ ++ for (int i = 0; i < strlen(seed_str); i++) ++ seed += (seed_str[i] << (i * 8)); ++ ++ return seed; ++} ++ ++int generate_random_number(void) ++{ ++ srand(get_seed()); ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ return -1; ++ } ++ for (int i = 0; i < RAND_NUMBER_SIZE; i++) ++ g_fwupd_settings.rand_num[i] = (u8)(rand() & 0xFF); ++ ++ g_fwupd_settings.random_number_valid = true; ++ ++ fwupd_settings_unlock(); ++ ++ /* Random number should be cleared after 30sec timeout */ ++ etime = endtick(RANDOM_NUM_TIMEOUT); ++ ++ return 0; ++} ++ ++static int sect_roundb(ulong *addr) ++{ ++ flash_info_t *info; ++ ulong bank, sector_end_addr; ++ char found; ++ int i; ++ ++ /* find the end addr of the sector where the *addr is */ ++ found = 0; ++ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS && !found; ++bank) { ++ info = &flash_info[bank]; ++ for (i = 0; i < info->sector_count && !found; ++i) { ++ /* get the end address of the sector */ ++ if (i == info->sector_count - 1) { ++ sector_end_addr = ++ info->start[0] + info->size - 1; ++ } else { ++ sector_end_addr = info->start[i + 1] - 1; ++ } ++ ++ if (*addr <= sector_end_addr && ++ *addr >= info->start[i]) { ++ found = 1; ++ /* adjust *addr if necessary */ ++ if (*addr < sector_end_addr) ++ *addr = sector_end_addr; ++ } /* sector */ ++ } /* bank */ ++ } ++ if (!found) { ++ /* error, address not in flash */ ++ printf("Error: end address (0x%08lx) not in flash!\n", *addr); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int fill_flash_sect_ranges(ulong addr_first, ulong addr_last, ++ int *s_first, int *s_last, int *s_count) ++{ ++ flash_info_t *info; ++ ulong bank; ++ int rcode = 0; ++ ++ *s_count = 0; ++ ++ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { ++ s_first[bank] = -1; /* first sector to erase */ ++ s_last[bank] = -1; /* last sector to erase */ ++ } ++ ++ for (bank = 0, info = &flash_info[0]; ++ (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (addr_first <= addr_last); ++ ++bank, ++info) { ++ ulong b_end; ++ int sect; ++ short s_end; ++ ++ if (info->flash_id == FLASH_UNKNOWN) ++ continue; ++ ++ b_end = info->start[0] + info->size - 1; /* bank end addr */ ++ s_end = info->sector_count - 1; /* last sector */ ++ ++ for (sect = 0; sect < info->sector_count; ++sect) { ++ ulong end; /* last address in current sect */ ++ ++ end = (sect == s_end) ? b_end : ++ info->start[sect + 1] - 1; ++ ++ if (addr_first > end) ++ continue; ++ if (addr_last < info->start[sect]) ++ continue; ++ ++ if (addr_first == info->start[sect]) ++ s_first[bank] = sect; ++ if (addr_last == end) ++ s_last[bank] = sect; ++ } ++ if (s_first[bank] >= 0) { ++ if (s_last[bank] < 0) { ++ if (addr_last > b_end) { ++ s_last[bank] = s_end; ++ } else { ++ printf("Error: end address not on sector boundary\n"); ++ rcode = 1; ++ break; ++ } ++ } ++ if (s_last[bank] < s_first[bank]) { ++ printf("Error: end sector precedes start sector\n"); ++ rcode = 1; ++ break; ++ } ++ sect = s_last[bank]; ++ addr_first = (sect == s_end) ? b_end + 1 : ++ info->start[sect + 1]; ++ (*s_count) += s_last[bank] - s_first[bank] + 1; ++ } else if (addr_first >= info->start[0] && addr_first < b_end) { ++ printf("Error: start address not on sector boundary\n"); ++ rcode = 1; ++ break; ++ } else if (s_last[bank] >= 0) { ++ printf("Error: cannot span across banks when they are mapped in reverse order\n"); ++ rcode = 1; ++ break; ++ } ++ } ++ ++ return rcode; ++} ++ ++static int protect_flash_sector(int state, ulong addr_first, ulong addr_last) ++{ ++ flash_info_t *info; ++ ulong bank; ++ int s_first[CONFIG_SYS_MAX_FLASH_BANKS], ++ s_last[CONFIG_SYS_MAX_FLASH_BANKS]; ++ int protected = 0; ++ int planned; ++ int rcode, i; ++ ++ rcode = fill_flash_sect_ranges(addr_first, addr_last, s_first, s_last, ++ &planned); ++ ++ if (planned && (rcode == 0)) { ++ for (bank = 0, info = &flash_info[0]; ++ bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) { ++ if (info->flash_id == FLASH_UNKNOWN) ++ continue; ++ ++ if (s_first[bank] >= 0 && ++ s_first[bank] <= s_last[bank]) { ++ debug("%sProtecting sectors %d..%d in bank %ld\n", ++ state ? "" : "Un-", s_first[bank], ++ s_last[bank], bank + 1); ++ protected ++ += s_last[bank] - s_first[bank] + 1; ++ for (i = s_first[bank]; i <= s_last[bank]; ++i) ++ info->protect[i] = state; ++ } ++ } ++ printf("%sProtected %d sectors\n", state ? "" : "Un-", ++ protected); ++ } else if (rcode == 0) { ++ printf("Error: start and/or end address not on sector boundary\n"); ++ rcode = 1; ++ } ++ ++ return rcode; ++} ++ ++static int erase_flash_sector(ulong addr_first, ulong addr_last) ++{ ++ flash_info_t *info; ++ ulong bank; ++ int s_first[CONFIG_SYS_MAX_FLASH_BANKS]; ++ int s_last[CONFIG_SYS_MAX_FLASH_BANKS]; ++ int erased = 0; ++ int planned; ++ int rcode = 0; ++ ++ rcode = fill_flash_sect_ranges(addr_first, addr_last, s_first, s_last, ++ &planned); ++ ++ if (planned && (rcode == 0)) { ++ for (bank = 0, info = &flash_info[0]; ++ (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (rcode == 0); ++ ++bank, ++info) { ++ if (s_first[bank] >= 0) { ++ erased += s_last[bank] - s_first[bank] + 1; ++ debug("Erase Flash from 0x%08lx to 0x%08lx " ++ "in Bank # %ld ", ++ info->start[s_first[bank]], ++ (s_last[bank] == info->sector_count) ? ++ info->start[0] + info->size - 1 : ++ info->start[s_last[bank] + 1] - 1, ++ bank + 1); ++ rcode = flash_erase(info, s_first[bank], ++ s_last[bank]); ++ } ++ } ++ if (rcode == 0) ++ printf("Erased %d sectors\n", erased); ++ } else if (rcode == 0) { ++ printf("Error: start and/or end address not on sector boundary\n"); ++ rcode = 1; ++ } ++ ++ return rcode; ++} ++ ++static int verify_image(void) ++{ ++ ulong src_addr = IMAGE_LOAD_RAM_ADDR; ++ void *hdr = (void *)src_addr; ++ ++ printf("\n## Checking Image at 0x%08lx ...\n", src_addr); ++ /* AT the moment, we only support FIT image flash */ ++ switch (genimg_get_format(hdr)) { ++ case IMAGE_FORMAT_FIT: ++ printf(" FIT image found\n"); ++ if (!fit_check_format(hdr)) { ++ printf("Bad FIT image format!\n"); ++ return -1; ++ } ++ ++ if (!fit_all_image_verify(hdr)) { ++ printf("Bad hash in FIT image!\n"); ++ return -1; ++ } ++ break; ++ default: ++ printf("Unknown image format!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int flash_image(void) ++{ ++ int rcode; ++ ulong max_size = MAX_FITIMAGE_SIZE; ++ ulong src_addr = IMAGE_LOAD_RAM_ADDR; ++ ulong addr_first = get_flash_image_address(); ++ ulong addr_last = addr_first + max_size - 1; ++ ++ if ((g_write_addr > max_size) || (g_write_addr == 0)) { ++ printf("ERROR: %s(): Invalid file uploaded. filesize(0x%08x)\n", ++ __func__, g_write_addr); ++ return -1; ++ } ++ ++ if (sect_roundb(&addr_last) > 0) { ++ printf("ERROR: %s(): sect_roundb failed\n", __func__); ++ return -1; ++ } ++ ++ if (addr_first >= addr_last) { ++ printf("ERROR: %s(): addr_first(0x%08lx) >= addr_last(0x%08lx)\n", ++ __func__, addr_first, addr_last); ++ return -1; ++ } ++ ++ /* Hack: To update the percentage update, ++ * treat logical division as below. ++ * Image verify - 10% ++ * Unprotecting flash sectors - 10% ++ * Erase flash sectors - 40% ++ * Copy to flash - 40% */ ++ ++ /* Unprotect the flash sectors */ ++ rcode = protect_flash_sector(PROTECT_OFF, addr_first, addr_last); ++ if (rcode != 0) { ++ printf("%s(): Protecting flash sector failed(%d).\n", __func__, ++ rcode); ++ return -1; ++ } ++ update_processing_status(IMG_PROGRAMMING, 20); ++ ++ /* erase flash sectors */ ++ rcode = erase_flash_sector(addr_first, addr_last); ++ if (rcode != 0) { ++ printf("%s(): Erasing flash sector failed(%d).\n", __func__, ++ rcode); ++ return -1; ++ } ++ update_processing_status(IMG_PROGRAMMING, 60); ++ ++ /* write to flash area */ ++ printf("Copy to Flash... "); ++ rcode = flash_write((char *)src_addr, addr_first, g_write_addr * 1); ++ if (rcode != 0) { ++ printf("%s(): Flash copy failed(%d).\n", __func__, rcode); ++ flash_perror(rcode); ++ return -1; ++ } ++ printf("done\n"); ++ return 0; ++} ++ ++void start_fw_update_loop(void) ++{ ++ int rc; ++ ulong boot_addr; ++ char boot_cmd[20]; ++ ++ while (1) { ++ if (g_fwupd_settings.random_number_valid) { ++ /* Random number should be cleared after 30seconds */ ++ if (get_ticks() >= etime) { ++ printf("Clearing random number\n"); ++ ++ if (!fwupd_settings_trylock()) ++ continue; ++ memcpy(g_fwupd_settings.rand_num, 0, ++ RAND_NUMBER_SIZE); ++ g_fwupd_settings.random_number_valid = false; ++ fwupd_settings_unlock(); ++ } ++ } ++ ++ if (g_fwupd_settings.start_update) { ++ update_processing_status(IMG_VALIDATING, 0); ++ ++ rc = verify_image(); ++ if (rc != 0) { ++ update_processing_status(UPDATE_ERROR, 100); ++ /* Adding delay to make consumer gets status */ ++ mdelay(WAIT_STATE_TIMEOUT); ++ ++ reset_all_settings(); ++ continue; ++ } ++ ++ update_processing_status(IMG_PROGRAMMING, 10); ++ ++ rc = flash_image(); ++ if (rc == 0) { ++ /* Update successful, change the boot command */ ++ boot_addr = get_flash_image_address(); ++ snprintf(boot_cmd, sizeof(boot_cmd), ++ "bootm %08x", boot_addr); ++ setenv("bootcmd", boot_cmd); ++ saveenv(); ++ ++ update_processing_status(UPDATE_SUCCESSFUL, ++ 100); ++ } else { ++ update_processing_status(UPDATE_ERROR, 100); ++ } ++ ++ /* Adding delay to make sure consumer gets status */ ++ mdelay(WAIT_STATE_TIMEOUT); ++ ++ reset_all_settings(); ++ ++ /* Reset BMC */ ++ do_reset(NULL, 0, 0, NULL); ++ } ++ mdelay(WAIT_STATE_TIMEOUT); ++ } ++ ++ return; ++} ++ ++#if 1 /* Debug purpose */ ++int do_fwupd(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ if (argc != 1) ++ return 1; ++ ++ start_fw_update_loop(); ++ return 0; ++} ++U_BOOT_CMD(fwupd, 1, 0, do_fwupd, "Start Firmware update process", ""); ++#endif +diff --git a/board/aspeed/ast-g5/fw-update.h b/board/aspeed/ast-g5/fw-update.h +new file mode 100644 +index 0000000..ed033ad +--- /dev/null ++++ b/board/aspeed/ast-g5/fw-update.h +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <common.h> ++ ++/* SPI flash map */ ++#define MAX_FITIMAGE_SIZE 0x1B80000 ++#define PRIMARY_FITIMAGE_START_ADDR 0x20080000 ++#define SECONDARY_FITIMAGE_START_ADDR 0x22480000 ++#define IMAGE_LOAD_RAM_ADDR 0x83000000 ++ ++#define MAX_FILENAME_LENGTH 256 ++#define RAND_NUMBER_SIZE 8 ++ ++enum boot_image { ++ PRIMARY_IMAGE = 0x01, ++ SECONDARY_IMAGE = 0x02 ++}; ++ ++enum update_status { ++ INITIALIZING = 0, ++ IDLE, ++ IMG_DOWNLOADING, ++ IMG_VALIDATING, ++ IMG_PROGRAMMING, ++ UPDATE_SUCCESSFUL, ++ UPDATE_ERROR = 0x0F, ++ UPDATE_FORBIDDEN = 0x80, ++ AC_CYCLE_REQUIRED = 0x83 ++}; ++ ++struct fwupd_global_setting { ++ bool fwupd_mode_active; ++ bool start_update; ++ bool random_number_valid; ++ u8 ctrl_state; ++ u8 options_mask; ++ u8 options_value; ++ u8 processing_status; ++ u8 percentage_completion; ++ u8 integrity_check_status; ++ u8 filename_len; ++ u8 filename[MAX_FILENAME_LENGTH]; ++ u8 rand_num[RAND_NUMBER_SIZE]; ++}; ++ ++bool fwupd_settings_trylock(void); ++void fwupd_settings_unlock(void); ++u8 get_active_boot_image(void); ++int generate_random_number(void); +diff --git a/board/aspeed/ast-g5/ipmi-fwupd.c b/board/aspeed/ast-g5/ipmi-fwupd.c +new file mode 100644 +index 0000000..3eba056 +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-fwupd.c +@@ -0,0 +1,402 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ipmi-fwupd.h" ++ ++struct fwupd_global_setting g_fwupd_settings; ++u32 g_write_addr = 0; ++ ++u16 fwupd_get_execution_ctx(u8 *req, u16 req_len, u8 *res) ++{ ++ int booting_image = 0x01; ++ struct fwupd_get_exe_ctx_res *result = ++ (struct fwupd_get_exe_ctx_res *)res; ++ ++ /* Get active image location(primary/secondary) */ ++ booting_image = get_active_boot_image(); ++ result->patition_ptr = booting_image; ++ result->exection_ctx = 0x11; /* Forced Firmware Update mode */ ++ ++ result->completion_code = IPMI_CC_OK; ++ return sizeof(struct fwupd_get_exe_ctx_res); ++} ++u16 fwupd_get_rand_number(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_rand_num_res *result = (struct fwupd_rand_num_res *)res; ++ ++ if (req_len != 0) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is it already in fwupdate mode */ ++ if (g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Already in firmware update mode\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ if (generate_random_number() != 0) { ++ printf("%s(): Random number generation failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ memcpy(result->rand_num, g_fwupd_settings.rand_num, RAND_NUMBER_SIZE); ++ ++ return sizeof(struct fwupd_rand_num_res); ++} ++ ++u16 fwupd_enter_update_mode(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_set_update_mode_res *result = ++ (struct fwupd_set_update_mode_res *)res; ++ ++ if (req_len != RAND_NUMBER_SIZE) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is it already in fwupdate mode */ ++ if (g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Already in firmware update mode\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* This command should excute within 30 seconds ++ * after random number generation. */ ++ if (!g_fwupd_settings.random_number_valid) { ++ printf("%s(): No valid random number exist.\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_CODE; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Validate the key to enter this mode */ ++ for (int i = 0; i < RAND_NUMBER_SIZE; i++) { ++ if (req[i] != g_fwupd_settings.rand_num[i]) { ++ printf("%s(): Invalid key entered\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_CODE; ++ return sizeof(result->completion_code); ++ } ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ /* Reset all the settings */ ++ memset(&g_fwupd_settings, 0, sizeof(g_fwupd_settings)); ++ g_fwupd_settings.fwupd_mode_active = true; ++ fwupd_settings_unlock(); ++ ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(struct fwupd_set_update_mode_res); ++} ++ ++u16 fwupd_exit_update_mode(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_exit_update_mode_res *result = ++ (struct fwupd_exit_update_mode_res *)res; ++ ++ if (req_len != 0) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Invalid command entered\n", __func__); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.fwupd_mode_active = false; ++ fwupd_settings_unlock(); ++ ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(struct fwupd_exit_update_mode_res); ++} ++u16 fwupd_set_options(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_options_req *options_req = (struct fwupd_options_req *)req; ++ struct fwupd_options_res *result = (struct fwupd_options_res *)res; ++ ++ if (req_len < 2) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Setting any reserved bits will result the command being rejected */ ++ if (((options_req->options_mask & 0xF0) != 0) || ++ ((options_req->options_value & 0xF0) != 0)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.options_mask = options_req->options_mask; ++ g_fwupd_settings.options_value = options_req->options_value; ++ fwupd_settings_unlock(); ++ ++ result->completion_code = IPMI_CC_OK; ++ result->options_value = (g_fwupd_settings.options_mask & ++ g_fwupd_settings.options_value); ++ ++ return sizeof(struct fwupd_options_res); ++} ++ ++u16 fwupd_set_get_control(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_control_req *ctrl_req = (struct fwupd_control_req *)req; ++ struct fwupd_control_res *result = (struct fwupd_control_res *)res; ++ ++ if (req_len < 1) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ if ((ctrl_req->ctrl_state == SET_FW_FILENAME) && (req_len < 3)) { ++ printf("%s(): Invalid request data\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } else if ((ctrl_req->ctrl_state != SET_FW_FILENAME) && ++ (req_len != 1)) { ++ printf("%s(): Invalid request data\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ if ((!g_fwupd_settings.fwupd_mode_active) && ++ (ctrl_req->ctrl_state != GET_CTRL_STATE)) { ++ printf("%s(): Invalid request. Control State: %d.\n", __func__, ++ ctrl_req->ctrl_state); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ switch (ctrl_req->ctrl_state) { ++ case GET_CTRL_STATE: ++ break; ++ case IMG_TRANSFER_START: ++ if ((g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.processing_status = IMG_DOWNLOADING; ++ /* Reset control state during start */ ++ g_fwupd_settings.ctrl_state = 0x00; ++ g_fwupd_settings.ctrl_state |= IMG_TRANSFER_CTRL_BIT_START; ++ /* Set current write address to ZERO */ ++ g_write_addr = 0x00; ++ fwupd_settings_unlock(); ++ break; ++ case IMG_TRANSFER_END: ++ if (!(g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.start_update = true; ++ g_fwupd_settings.ctrl_state |= IMG_TRANSFER_CTRL_BIT_END; ++ ++ g_fwupd_settings.ctrl_state &= ~(IMG_TRANSFER_CTRL_BIT_START | ++ IMG_TRANSFER_CTRL_BIT_ABORT); ++ fwupd_settings_unlock(); ++ break; ++ case IMG_TRANSFER_ABORT: ++ if (!(g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.processing_status = UPDATE_ERROR; ++ g_fwupd_settings.ctrl_state |= IMG_TRANSFER_CTRL_BIT_ABORT; ++ g_fwupd_settings.ctrl_state &= ~(IMG_TRANSFER_CTRL_BIT_START | ++ IMG_TRANSFER_CTRL_BIT_END); ++ fwupd_settings_unlock(); ++ break; ++ case SET_FW_FILENAME: ++ /* Not supporting now */ ++ if (ctrl_req->filename_len > sizeof(ctrl_req->filename)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!(g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.filename_len = ctrl_req->filename_len; ++ strncpy(g_fwupd_settings.filename, ctrl_req->filename, ++ ctrl_req->filename_len); ++ fwupd_settings_unlock(); ++ /* TODO: Used for TFTP update but not implemented yet. */ ++ /* TODO: Verify image and write to flash */ ++ break; ++ case USB_DEV_ATTACH: ++ /* Not supporting now */ ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ case USB_DEV_DETACH: ++ /* Not supporting now */ ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ break; ++ default: ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->curr_state = g_fwupd_settings.ctrl_state; ++ return sizeof(struct fwupd_control_res); ++} ++u16 fwupd_get_update_status(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_get_update_status_res *result = ++ (struct fwupd_get_update_status_res *)res; ++ ++ if (req_len != 0) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->processing_status = g_fwupd_settings.processing_status; ++ result->percent_completion = g_fwupd_settings.percentage_completion; ++ result->check_status = 0; ++ /* We don't support error code messages cmd(0x0EH) in uboot.*/ ++ result->error_code = 0; ++ ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(struct fwupd_get_update_status_res); ++} ++ ++u16 fwupd_image_write(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_image_write_res *result = ++ (struct fwupd_image_write_res *)res; ++ ++ if (req_len < 1) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!(g_fwupd_settings.ctrl_state & IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if ((g_write_addr + req_len) > MAX_FITIMAGE_SIZE) { ++ printf("%s(): Request length exceeded max size\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ u8 *mem_addr = (u8 *)((u32)IMAGE_LOAD_RAM_ADDR + g_write_addr); ++ ++ memcpy(mem_addr, req, req_len); ++ g_write_addr += req_len; ++ ++ result->completion_code = IPMI_CC_OK; ++ result->no_of_bytes_written = (u8)req_len; ++ ++ return sizeof(struct fwupd_image_write_res); ++} +diff --git a/board/aspeed/ast-g5/ipmi-fwupd.h b/board/aspeed/ast-g5/ipmi-fwupd.h +new file mode 100644 +index 0000000..e490f6b +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-fwupd.h +@@ -0,0 +1,81 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ipmi-handler.h" ++#include "fw-update.h" ++ ++enum control_state { ++ GET_CTRL_STATE = 0, ++ IMG_TRANSFER_START, ++ IMG_TRANSFER_END, ++ IMG_TRANSFER_ABORT, ++ SET_FW_FILENAME, ++ USB_DEV_ATTACH, ++ USB_DEV_DETACH ++}; ++enum control_state_bit { ++ IMG_TRANSFER_CTRL_BIT_START = (0x01 << 0), ++ IMG_TRANSFER_CTRL_BIT_END = (0x01 << 1), ++ IMG_TRANSFER_CTRL_BIT_ABORT = (0x01 << 2), ++ USB_CTRL_BIT_ATTACH = (0x01 << 3) ++}; ++enum update_options_bit { ++ NO_DOWN_REVISION = 0, ++ DEFER_BMC_RESET = 1, ++ SHA32_INTEGRITY_CHECK = 2, ++ CRC32_INTEGRITY_CHECK = 3 ++}; ++ ++struct fwupd_get_exe_ctx_res { ++ u8 completion_code; ++ u8 exection_ctx; ++ u8 patition_ptr; ++}; ++struct fwupd_rand_num_res { ++ u8 completion_code; ++ u8 rand_num[RAND_NUMBER_SIZE]; ++}; ++struct fwupd_set_update_mode_res { ++ u8 completion_code; ++}; ++struct fwupd_exit_update_mode_res { ++ u8 completion_code; ++}; ++struct fwupd_options_req { ++ u8 options_mask; ++ u8 options_value; ++ u8 integrity_check_value[32]; ++}; ++struct fwupd_options_res { ++ u8 completion_code; ++ u8 options_value; ++}; ++struct fwupd_control_req { ++ u8 ctrl_state; ++ u8 filename_len; ++ u8 filename[MAX_FILENAME_LENGTH]; ++}; ++struct fwupd_control_res { ++ u8 completion_code; ++ u8 curr_state; ++}; ++struct fwupd_get_update_status_res { ++ u8 completion_code; ++ u8 processing_status; ++ u8 percent_completion; ++ u8 check_status; ++ u8 error_code; ++}; ++struct fwupd_image_write_res { ++ u8 completion_code; ++ u8 no_of_bytes_written; ++}; ++ ++u16 fwupd_get_execution_ctx(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_get_rand_number(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_enter_update_mode(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_exit_update_mode(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_set_options(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_set_get_control(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_get_update_status(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_image_write(u8 *req, u16 req_len, u8 *res); +diff --git a/board/aspeed/ast-g5/ipmi-handler.c b/board/aspeed/ast-g5/ipmi-handler.c +index 9cccee9..5e78546 100644 +--- a/board/aspeed/ast-g5/ipmi-handler.c ++++ b/board/aspeed/ast-g5/ipmi-handler.c +@@ -1,18 +1,37 @@ +- + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2018-2019 Intel Corporation + +-#include "ipmi-handler.h" ++#include "ipmi-fwupd.h" + + /* IPMI network function codes */ + #define NETFN_APP 0x06 ++#define NETFN_FIRMWARE 0x08 ++#define NETFN_INTEL_OEM 0x30 + + /* IPMI command codes */ +-#define CMD_GET_DEV_ID 0x01 +-#define CMD_GET_SELF_TEST_RESULTS 0x04 ++#define CMD_APP_GET_DEV_ID 0x01 ++#define CMD_APP_GET_SELF_TEST_RESULTS 0x04 ++#define CMD_FWUPD_GET_EXECUTION_CTX 0x23 ++#define CMD_FWUPD_GET_RANDOM_NUMBER 0x26 ++#define CMD_FWUPD_SET_UPDATE_MODE 0x27 ++#define CMD_FWUPD_EXIT_UPDATE_MODE 0x28 ++#define CMD_FWUPD_CONTROL_GET_SET 0x29 ++#define CMD_FWUPD_GET_UPDATE_STATUS 0x2A ++#define CMD_FWUPD_SET_OPTIONS 0x2B ++#define CMD_FWUPD_IMAGE_WRITE 0x2C ++#define CMD_INTL_OEM_GET_BUFFER_SIZE 0x66 ++ ++#define MAX_KCS_BUF_SIZE 1020 /* (0xFF * 4) */ ++#define MAX_IPMB_BUF_SIZE 1020 /* (0xFF * 4) */ + + typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res); + ++struct ipmi_cmd_table { ++ u8 net_fun; ++ u8 cmd; ++ fun_handler process_cmd; ++}; ++ + struct get_dev_id { + u8 completion_code; + u8 dev_id; +@@ -29,11 +48,10 @@ struct self_test_res { + u8 completion_code; + u8 res_byte[2]; + }; +- +-struct ipmi_cmd_table { +- u8 net_fun; +- u8 cmd; +- fun_handler process_cmd; ++struct intc_get_buf_size_res { ++ u8 completion_code; ++ u8 kcs_size; ++ u8 ipmb_size; + }; + + static u16 get_device_id(u8 *req, u16 req_len, u8 *res) +@@ -84,10 +102,36 @@ static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res) + + return sizeof(struct self_test_res); + } ++static u16 intel_get_buffer_size(u8 *req, u16 req_len, u8 *res) ++{ ++ struct intc_get_buf_size_res *result = ++ (struct intc_get_buf_size_res *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Size is multiples of four bytes */ ++ result->completion_code = IPMI_CC_OK; ++ result->kcs_size = MAX_KCS_BUF_SIZE / 4; ++ result->ipmb_size = MAX_IPMB_BUF_SIZE / 4; ++ ++ return sizeof(struct intc_get_buf_size_res); ++} + + const struct ipmi_cmd_table cmd_info[] = { +- { NETFN_APP, CMD_GET_DEV_ID, get_device_id }, +- { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result } ++ { NETFN_APP, CMD_APP_GET_DEV_ID, get_device_id }, ++ { NETFN_APP, CMD_APP_GET_SELF_TEST_RESULTS, get_self_test_result }, ++ { NETFN_FIRMWARE, CMD_FWUPD_GET_EXECUTION_CTX, fwupd_get_execution_ctx }, ++ { NETFN_FIRMWARE, CMD_FWUPD_GET_RANDOM_NUMBER, fwupd_get_rand_number }, ++ { NETFN_FIRMWARE, CMD_FWUPD_SET_UPDATE_MODE, fwupd_enter_update_mode }, ++ { NETFN_FIRMWARE, CMD_FWUPD_EXIT_UPDATE_MODE, fwupd_exit_update_mode }, ++ { NETFN_FIRMWARE, CMD_FWUPD_CONTROL_GET_SET, fwupd_set_get_control }, ++ { NETFN_FIRMWARE, CMD_FWUPD_GET_UPDATE_STATUS, fwupd_get_update_status }, ++ { NETFN_FIRMWARE, CMD_FWUPD_SET_OPTIONS, fwupd_set_options }, ++ { NETFN_FIRMWARE, CMD_FWUPD_IMAGE_WRITE, fwupd_image_write }, ++ { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_BUFFER_SIZE, intel_get_buffer_size } + }; + + #define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info) +diff --git a/board/aspeed/ast-g5/ipmi-handler.h b/board/aspeed/ast-g5/ipmi-handler.h +index 9d46d9b..8eea930 100644 +--- a/board/aspeed/ast-g5/ipmi-handler.h ++++ b/board/aspeed/ast-g5/ipmi-handler.h +@@ -1,4 +1,3 @@ +- + /* SPDX-License-Identifier: GPL-2.0 */ + /* Copyright (c) 2018-2019 Intel Corporation */ + +@@ -6,12 +5,14 @@ + + /* IPMI completion codes */ + #define IPMI_CC_OK 0x00 ++#define IPMI_CC_INVALID_CODE 0x80 + #define IPMI_CC_NODE_BUSY 0xC0 + #define IPMI_CC_INVALID_CMD 0xC1 + #define IPMI_CC_INVALID_CMD_LUN 0xC2 + #define IPMI_CC_OUT_OF_SPACE 0xC4 + #define IPMI_CC_INVALID_DATA_LENGTH 0xC7 + #define IPMI_CC_INVALID_DATA_FIELD 0xCC ++#define IPMI_CC_NOT_SUPPORTED_IN_STATE 0xD5 + #define IPMI_CC_UNSPECIFIED 0xFF + + /* BMC IPMB LUNs */ +diff --git a/common/autoboot.c b/common/autoboot.c +index d66c0fa..45a600e 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -349,6 +349,17 @@ void autoboot_command(const char *s) + { + debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); + ++#ifdef AST_G5_INTEL ++ /* TODO: Make run_command_list as non-blocking(blocked by getc()) ++ * and make main u-boot loop to check both keyboard inputs as well ++ * as start_update firmware flags during FFUJ. ++ * This will make sure debug mode intact during FFUJ. ++ */ ++ if (intel_force_firmware_jumper_enabled()) { ++ start_fw_update_loop(); ++ } ++#endif ++ + if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { + #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) + int prev = disable_ctrlc(1); /* disable Control C checking */ +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 1b96ab7..5965a9b 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -15,3 +15,4 @@ CONFIG_SYS_NS16550=y + CONFIG_USE_IRQ=y + CONFIG_CMD_I2C=y + CONFIG_SYS_I2C_AST=y ++CONFIG_LIB_RAND=y diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0030-Support-Get-Set-Security-mode-command.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0030-Support-Get-Set-Security-mode-command.patch new file mode 100644 index 000000000..519977e19 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0030-Support-Get-Set-Security-mode-command.patch @@ -0,0 +1,124 @@ +From 294a5971c94099277ee5b5589c060896cf22c495 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Thu, 20 Jun 2019 15:26:50 +0530 +Subject: [PATCH] Support Get/Set Security mode command + +Support added for get/set security mode oem command. This +command is used to read / write the RestrictionMode property +which is saved in U-Boot environment variable. U-Boot +command provides a way to downgrade RestrictionMode property +value, which is not allowed in normal mode from Host interface + +Tested: +1. Verified get security mode returns proper value read from +U-Boot environment variable. cmdtool.efi 20 C0 B3 +2. Verified set security mode updates U-Boot environment variable +and it is reflected in linux too cmdtool.efi 20 C0 B4 4 +3. Verified negative test cases with improper values and it +throws correct errors + +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> + +--- + board/aspeed/ast-g5/ipmi-handler.c | 63 +++++++++++++++++++++++++++++++++++++- + 1 file changed, 62 insertions(+), 1 deletion(-) + +diff --git a/board/aspeed/ast-g5/ipmi-handler.c b/board/aspeed/ast-g5/ipmi-handler.c +index 5e78546..4e921bd 100644 +--- a/board/aspeed/ast-g5/ipmi-handler.c ++++ b/board/aspeed/ast-g5/ipmi-handler.c +@@ -20,10 +20,19 @@ + #define CMD_FWUPD_SET_OPTIONS 0x2B + #define CMD_FWUPD_IMAGE_WRITE 0x2C + #define CMD_INTL_OEM_GET_BUFFER_SIZE 0x66 ++#define CMD_INTL_OEM_GET_SEC_MODE 0xB3 ++#define CMD_INTL_OEM_SET_SEC_MODE 0xB4 + + #define MAX_KCS_BUF_SIZE 1020 /* (0xFF * 4) */ + #define MAX_IPMB_BUF_SIZE 1020 /* (0xFF * 4) */ + ++/* Restriction mode values */ ++#define RESTRICTION_MODE_MIN_VALUE 3 /*Provisioning*/ ++#define RESTRICION_MODE_MAX_VALUE 5 /*Provisioned host disabled */ ++ ++#define STR_ENV_PROVISION "provision" ++ ++ + typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res); + + struct ipmi_cmd_table { +@@ -53,6 +62,11 @@ struct intc_get_buf_size_res { + u8 kcs_size; + u8 ipmb_size; + }; ++struct intc_get_secuirty_mode_res { ++ u8 completion_code; ++ u8 restriction_mode; ++ u8 special_mode; ++}; + + static u16 get_device_id(u8 *req, u16 req_len, u8 *res) + { +@@ -120,6 +134,51 @@ static u16 intel_get_buffer_size(u8 *req, u16 req_len, u8 *res) + return sizeof(struct intc_get_buf_size_res); + } + ++static u16 intel_get_security_mode(u8 *req, u16 req_len, u8 *res) ++{ ++ char *cmdline = NULL; ++ struct intc_get_secuirty_mode_res *result = ++ (struct intc_get_secuirty_mode_res *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ cmdline = getenv(STR_ENV_PROVISION); ++ if (!cmdline) { ++ /* Default provision must be set only by linux */ ++ result->completion_code = IPMI_CC_UNSPECIFIED; ++ return sizeof(result->completion_code); ++ } ++ result->restriction_mode = simple_strtol(cmdline, NULL, 10); ++ /* special mode is non-volatile and not applicable in U-Boot */ ++ result->special_mode = 0; ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(*result); ++} ++ ++static u16 intel_set_security_mode(u8 *req, u16 req_len, u8 *res) ++{ ++ if (req_len != sizeof(*req)) { ++ *res = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(*res); ++ } ++ ++ if (*req > RESTRICION_MODE_MAX_VALUE || ++ *req < RESTRICTION_MODE_MIN_VALUE) { ++ *res = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(*res); ++ } ++ ++ setenv_ulong(STR_ENV_PROVISION, *req); ++ saveenv(); ++ *res = IPMI_CC_OK; ++ ++ return sizeof(*res); ++} ++ + const struct ipmi_cmd_table cmd_info[] = { + { NETFN_APP, CMD_APP_GET_DEV_ID, get_device_id }, + { NETFN_APP, CMD_APP_GET_SELF_TEST_RESULTS, get_self_test_result }, +@@ -131,7 +190,9 @@ const struct ipmi_cmd_table cmd_info[] = { + { NETFN_FIRMWARE, CMD_FWUPD_GET_UPDATE_STATUS, fwupd_get_update_status }, + { NETFN_FIRMWARE, CMD_FWUPD_SET_OPTIONS, fwupd_set_options }, + { NETFN_FIRMWARE, CMD_FWUPD_IMAGE_WRITE, fwupd_image_write }, +- { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_BUFFER_SIZE, intel_get_buffer_size } ++ { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_BUFFER_SIZE, intel_get_buffer_size }, ++ { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_SEC_MODE, intel_get_security_mode }, ++ { NETFN_INTEL_OEM, CMD_INTL_OEM_SET_SEC_MODE, intel_set_security_mode }, + }; + + #define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info) diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0031-Make-it-so-TFTP-port-can-be-modified.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0031-Make-it-so-TFTP-port-can-be-modified.patch new file mode 100644 index 000000000..b70427fe0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0031-Make-it-so-TFTP-port-can-be-modified.patch @@ -0,0 +1,40 @@ +From 1d680678abb76bdea7cf2128b7ce6db4a5652151 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Tue, 16 Jul 2019 16:30:02 -0700 +Subject: [PATCH 1/1] Make it so TFTP port can be modified + +This makes it so we can use non-privileged tftp ports. + +Tested: Can load fw from non-privileged port. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + include/configs/ast-g5-ncsi.h | 2 ++ + include/configs/ast-g5-phy.h | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/include/configs/ast-g5-ncsi.h b/include/configs/ast-g5-ncsi.h +index 12d6684551..20864b2798 100644 +--- a/include/configs/ast-g5-ncsi.h ++++ b/include/configs/ast-g5-ncsi.h +@@ -28,4 +28,6 @@ + + #define CONFIG_HW_WATCHDOG + ++#define CONFIG_TFTP_PORT ++ + #endif /* __AST_G5_NCSI_CONFIG_H */ +diff --git a/include/configs/ast-g5-phy.h b/include/configs/ast-g5-phy.h +index 62ddb841e5..371f50a1db 100644 +--- a/include/configs/ast-g5-phy.h ++++ b/include/configs/ast-g5-phy.h +@@ -30,4 +30,6 @@ + /* platform.S */ + #define CONFIG_DRAM_ECC_SIZE 0x10000000 + ++#define CONFIG_TFTP_PORT ++ + #endif /* __AST_G5_PHY_CONFIG_H */ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0032-PFR-FW-update-and-checkpoint-support-in-u-boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0032-PFR-FW-update-and-checkpoint-support-in-u-boot.patch new file mode 100644 index 000000000..7700e067f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0032-PFR-FW-update-and-checkpoint-support-in-u-boot.patch @@ -0,0 +1,529 @@ +From 0c975e64ca8bd5fdaf12f15b4dbc9ceaa942c36c Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 24 Jul 2019 20:11:30 +0530 +Subject: [PATCH] PFR FW update and checkpoint support in u-boot + +1) Added firmware update ipmi commands support +for PFR images. This enables PFR based firmware +updates for components BMC, BIOS and CPLD during +FFUJ mode. + +2) Added two PFR boot flow checkpoint in u-boot + - Set the booting starts checkpoint(0x01) + - Set FFUJ checkpoint(0x07) when jumper on. + +Tested: + +Tested: +1) Using debug fwpiaupd.efi utility, validated the PFR +BMC image update via KCS ( In FFUJ mode). +2) Loaded the image, dumped all cpld registers and +cross verified the check-points properly set or not. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 10 ++++ + board/aspeed/ast-g5/fw-update.c | 112 +++++++++++++++++++------------------ + board/aspeed/ast-g5/fw-update.h | 7 +++ + board/aspeed/ast-g5/ipmi-fwupd.c | 37 ++++++++++++ + board/aspeed/ast-g5/ipmi-fwupd.h | 6 -- + board/aspeed/ast-g5/pfr-mgr.c | 73 ++++++++++++++++++++++++ + board/aspeed/ast-g5/pfr-mgr.h | 73 ++++++++++++++++++++++++ + 8 files changed, 258 insertions(+), 61 deletions(-) + create mode 100644 board/aspeed/ast-g5/pfr-mgr.c + create mode 100644 board/aspeed/ast-g5/pfr-mgr.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 0b2d936..9021d7f 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -8,3 +8,4 @@ obj-y += ast-g5-kcs.o + obj-y += ipmi-handler.o + obj-y += ipmi-fwupd.o + obj-y += fw-update.o ++obj-y += pfr-mgr.o +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e68ab85..cd359ce 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -16,6 +16,7 @@ + #include "ast-g5.h" + #include "ast-g5-gpio.h" + #include "ast-g5-timer.h" ++#include "pfr-mgr.h" + + /* Names to match the GPIOs */ + enum gpio_names { +@@ -541,6 +542,10 @@ extern void espi_init(void); + extern void kcs_init(void); + void ast_g5_intel(void) + { ++ /* To notify the CPLD about the start of bootloader ++ * and hardware initialization */ ++ set_cpld_reg(PFR_CPLD_BOOT_CHECKPOINT_REG, PFR_CPLD_CHKPOINT_START); ++ + uart_init(); + pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); +@@ -551,6 +556,11 @@ void ast_g5_intel(void) + if (intel_force_firmware_jumper_enabled()) { + id_led_control(GPIO_AMBER_LED, EIDLED_On); + kcs_init(); ++ /* Notify CPLD about FFUJ jumper set and pause ++ * of booting for indefinitely time. It will be ++ * resumed once reset is done. */ ++ set_cpld_reg(PFR_CPLD_BOOT_CHECKPOINT_REG, ++ PFR_CPLD_CHKPOINT_FFUJ); + /* TODO: need to stop the booting here. */ + } else { + id_led_control(GPIO_GREEN_LED, EIDLED_On); +diff --git a/board/aspeed/ast-g5/fw-update.c b/board/aspeed/ast-g5/fw-update.c +index 9923993..89fe5fd 100644 +--- a/board/aspeed/ast-g5/fw-update.c ++++ b/board/aspeed/ast-g5/fw-update.c +@@ -6,6 +6,7 @@ + #include <flash.h> + + #include "fw-update.h" ++#include "pfr-mgr.h" + + #define BOOTCMD_BOOTM_STR "bootm " + #define RANDOM_NUM_TIMEOUT 30 /* in seconds */ +@@ -15,7 +16,7 @@ + #define PROTECT_ON 1 + + extern struct fwupd_global_setting g_fwupd_settings; +-extern u32 g_write_addr; ++extern struct fwupd_image_info g_img_info; + + bool g_fwupd_settings_lock = false; + unsigned long long etime; +@@ -36,16 +37,8 @@ void fwupd_settings_unlock(void) + + u8 get_active_boot_image(void) + { +- char *bootcmd = getenv("bootcmd"); +- char *start = strstr(bootcmd, BOOTCMD_BOOTM_STR); ++ /* For PFR, its always active region */ + u8 boot_image = PRIMARY_IMAGE; +- +- if (start) { +- ulong boot_addr = simple_strtoul( +- (start + strlen(BOOTCMD_BOOTM_STR)), NULL, 16); +- if (boot_addr == SECONDARY_FITIMAGE_START_ADDR) +- return SECONDARY_IMAGE; +- } + return boot_image; + } + +@@ -318,45 +311,22 @@ static int erase_flash_sector(ulong addr_first, ulong addr_last) + return rcode; + } + +-static int verify_image(void) ++static int verify_image(ulong src_addr, ulong img_length) + { +- ulong src_addr = IMAGE_LOAD_RAM_ADDR; +- void *hdr = (void *)src_addr; +- +- printf("\n## Checking Image at 0x%08lx ...\n", src_addr); +- /* AT the moment, we only support FIT image flash */ +- switch (genimg_get_format(hdr)) { +- case IMAGE_FORMAT_FIT: +- printf(" FIT image found\n"); +- if (!fit_check_format(hdr)) { +- printf("Bad FIT image format!\n"); +- return -1; +- } +- +- if (!fit_all_image_verify(hdr)) { +- printf("Bad hash in FIT image!\n"); +- return -1; +- } +- break; +- default: +- printf("Unknown image format!\n"); +- return -1; +- } +- ++ /* TODO: Verify the hash alone here.*/ ++ /* Full image verification is done in CPLD. */ + return 0; + } + +-static int flash_image(void) ++static int flash_image(ulong src_addr, ulong addr_first, ulong max_size, ++ ulong img_length) + { + int rcode; +- ulong max_size = MAX_FITIMAGE_SIZE; +- ulong src_addr = IMAGE_LOAD_RAM_ADDR; +- ulong addr_first = get_flash_image_address(); + ulong addr_last = addr_first + max_size - 1; + +- if ((g_write_addr > max_size) || (g_write_addr == 0)) { ++ if ((img_length > max_size) || (img_length == 0)) { + printf("ERROR: %s(): Invalid file uploaded. filesize(0x%08x)\n", +- __func__, g_write_addr); ++ __func__, img_length); + return -1; + } + +@@ -398,7 +368,7 @@ static int flash_image(void) + + /* write to flash area */ + printf("Copy to Flash... "); +- rcode = flash_write((char *)src_addr, addr_first, g_write_addr * 1); ++ rcode = flash_write((char *)src_addr, addr_first, img_length); + if (rcode != 0) { + printf("%s(): Flash copy failed(%d).\n", __func__, rcode); + flash_perror(rcode); +@@ -430,10 +400,27 @@ void start_fw_update_loop(void) + } + + if (g_fwupd_settings.start_update) { ++ printf("Starting image copy to staging area.....\n"); + update_processing_status(IMG_VALIDATING, 0); +- +- rc = verify_image(); ++ u8 update_intent = 0x00; ++ if ((g_fwupd_settings.options_mask & ++ g_fwupd_settings.options_value) & DEFER_BMC_RESET) ++ update_intent |= DEFER_UPDATES_TO_RESET; ++ ++ ulong offset = ++ get_flash_region_offset(g_img_info.img_type); ++ ulong max_size = ++ get_image_max_size(g_img_info.img_type); ++ ulong src_addr = IMAGE_LOAD_RAM_ADDR; ++ ulong flash_addr = PFR_IMAGE_STAGING_BASE_ADDR + offset; ++ ++ debug("FWUPD: offset:0x%08lx, max_size:0x%08lx, " ++ "src_addr:0x%08lx, flash_addr:0x%08lx\n", ++ offset, max_size, src_addr, flash_addr); ++ ++ rc = verify_image(src_addr, g_img_info.img_length); + if (rc != 0) { ++ printf("Image verification failed.\n"); + update_processing_status(UPDATE_ERROR, 100); + /* Adding delay to make consumer gets status */ + mdelay(WAIT_STATE_TIMEOUT); +@@ -441,31 +428,46 @@ void start_fw_update_loop(void) + reset_all_settings(); + continue; + } ++ printf("Image verification success.\n"); + + update_processing_status(IMG_PROGRAMMING, 10); + +- rc = flash_image(); ++ rc = flash_image(src_addr, flash_addr, max_size, ++ g_img_info.img_length); + if (rc == 0) { +- /* Update successful, change the boot command */ +- boot_addr = get_flash_image_address(); +- snprintf(boot_cmd, sizeof(boot_cmd), +- "bootm %08x", boot_addr); +- setenv("bootcmd", boot_cmd); +- saveenv(); ++ update_processing_status(IMG_PROGRAMMING, 90); ++ } else { ++ update_processing_status(UPDATE_ERROR, 100); ++ } + ++ printf("Image copy to staging area %s.\n", ++ ((rc == 0) ? "successful" : "failed")); ++ ++ /* Set the BMC update intent BIT to CPLD register */ ++ update_intent != get_update_intent(g_img_info.img_type); ++ ++ /* TODO: We ned a way to protect the staging area from ++ * next write data. After setting cpld intent bit, CPLD ++ * read the stagging region for associated image types ++ * and update active/recovery area. During this stage, ++ * staging area should be protected from next write. ++ * Working with CPLD team for identifying this state. */ ++ if (0 != set_cpld_reg(PFR_CPLD_BMC_UPDATE_INTENT_REG, ++ update_intent)) { ++ update_processing_status(UPDATE_ERROR, 100); ++ } else { ++ printf("CPLD: Update intent set successfully.\n"); + update_processing_status(UPDATE_SUCCESSFUL, + 100); +- } else { +- update_processing_status(UPDATE_ERROR, 100); ++ ++ if (update_intent & DEFER_UPDATES_TO_RESET) ++ printf("CPLD: Update defered to next reset.\n"); + } + + /* Adding delay to make sure consumer gets status */ + mdelay(WAIT_STATE_TIMEOUT); +- + reset_all_settings(); + +- /* Reset BMC */ +- do_reset(NULL, 0, 0, NULL); + } + mdelay(WAIT_STATE_TIMEOUT); + } +diff --git a/board/aspeed/ast-g5/fw-update.h b/board/aspeed/ast-g5/fw-update.h +index ed033ad..45e46ba 100644 +--- a/board/aspeed/ast-g5/fw-update.h ++++ b/board/aspeed/ast-g5/fw-update.h +@@ -28,6 +28,12 @@ enum update_status { + UPDATE_FORBIDDEN = 0x80, + AC_CYCLE_REQUIRED = 0x83 + }; ++enum update_options { ++ NO_DOWN_REVISION = BIT(0), ++ DEFER_BMC_RESET = BIT(1), ++ SHA32_INTEGRITY_CHECK = BIT(2), ++ CRC32_INTEGRITY_CHECK = BIT(3) ++}; + + struct fwupd_global_setting { + bool fwupd_mode_active; +@@ -48,3 +54,4 @@ bool fwupd_settings_trylock(void); + void fwupd_settings_unlock(void); + u8 get_active_boot_image(void); + int generate_random_number(void); ++ +diff --git a/board/aspeed/ast-g5/ipmi-fwupd.c b/board/aspeed/ast-g5/ipmi-fwupd.c +index 3eba056..6afc8d6 100644 +--- a/board/aspeed/ast-g5/ipmi-fwupd.c ++++ b/board/aspeed/ast-g5/ipmi-fwupd.c +@@ -2,10 +2,14 @@ + // Copyright (c) 2018-2019 Intel Corporation + + #include "ipmi-fwupd.h" ++#include "pfr-mgr.h" + + struct fwupd_global_setting g_fwupd_settings; + u32 g_write_addr = 0; + ++struct fwupd_image_info g_img_info; ++static bool block0_mapped = false; ++ + u16 fwupd_get_execution_ctx(u8 *req, u16 req_len, u8 *res) + { + int booting_image = 0x01; +@@ -395,6 +399,39 @@ u16 fwupd_image_write(u8 *req, u16 req_len, u8 *res) + memcpy(mem_addr, req, req_len); + g_write_addr += req_len; + ++ /* Get the PFR block 0 data and read the uploaded image ++ * information( Image type, length, hash etc) */ ++ if ((g_write_addr >= sizeof(struct pfr_image_block0)) && ++ (!block0_mapped)) { ++ struct pfr_image_block0 *block0_data = ++ (struct pfr_image_block0 *)IMAGE_LOAD_RAM_ADDR; ++ u32 magic_num = (u32)((*block0_data->tag) | ++ LSH(*(block0_data->tag + 1), 8) | ++ LSH(*(block0_data->tag + 2), 16) | ++ LSH(*(block0_data->tag + 3), 24)); ++ /* Validate the magic number */ ++ if (magic_num != PFR_BLOCK0_MAGIC_NUM) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Fill the image info structure for later use */ ++ g_img_info.magic_num = magic_num; ++ g_img_info.img_length = ++ (u32)((*block0_data->pc_length) | ++ LSH(*(block0_data->pc_length + 1), 8) | ++ LSH(*(block0_data->pc_length + 2), 16) | ++ LSH(*(block0_data->pc_length + 3), 24)); ++ g_img_info.img_type = ++ (u32)((*block0_data->pc_type) | ++ LSH(*(block0_data->pc_type + 1), 8) | ++ LSH(*(block0_data->pc_type + 2), 16) | ++ LSH(*(block0_data->pc_type + 3), 24)); ++ /* Add Authentication data struct length for full image */ ++ g_img_info.img_length += PFR_AUTH_DATA_STRUCT_LEN; ++ block0_mapped = true; ++ } ++ + result->completion_code = IPMI_CC_OK; + result->no_of_bytes_written = (u8)req_len; + +diff --git a/board/aspeed/ast-g5/ipmi-fwupd.h b/board/aspeed/ast-g5/ipmi-fwupd.h +index e490f6b..7409d2e 100644 +--- a/board/aspeed/ast-g5/ipmi-fwupd.h ++++ b/board/aspeed/ast-g5/ipmi-fwupd.h +@@ -19,12 +19,6 @@ enum control_state_bit { + IMG_TRANSFER_CTRL_BIT_ABORT = (0x01 << 2), + USB_CTRL_BIT_ATTACH = (0x01 << 3) + }; +-enum update_options_bit { +- NO_DOWN_REVISION = 0, +- DEFER_BMC_RESET = 1, +- SHA32_INTEGRITY_CHECK = 2, +- CRC32_INTEGRITY_CHECK = 3 +-}; + + struct fwupd_get_exe_ctx_res { + u8 completion_code; +diff --git a/board/aspeed/ast-g5/pfr-mgr.c b/board/aspeed/ast-g5/pfr-mgr.c +new file mode 100644 +index 0000000..7713168 +--- /dev/null ++++ b/board/aspeed/ast-g5/pfr-mgr.c +@@ -0,0 +1,73 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "pfr-mgr.h" ++ ++int set_cpld_reg(u8 reg_addr, u8 value) ++{ ++ int ret = 0; ++ int chip = (PFR_CPLD_SLAVE_ADDR >> 1); ++ ++ /* Get current I2C bus number to restore later. */ ++ int current_bus_no = i2c_get_bus_num(); ++ ++ /* Set I2C bus number to PFR CPLD I2C bus. */ ++ ret = i2c_set_bus_num(PFR_CPLD_I2C_BUSNO); ++ if (ret) { ++ printf("Failed to change I2C bus number (%d)\n", ret); ++ goto done; ++ } ++ ++ ret = i2c_write(chip, reg_addr, 1, &value, 1); ++ if (ret) { ++ printf("Error writing the chip: %d\n", ret); ++ goto done; ++ } ++ ++done: ++ /* Restore I2C bus number */ ++ if (i2c_set_bus_num(current_bus_no)) ++ printf("Failed to restore I2C bus number.\n"); ++ ++ return ret; ++} ++ ++ulong get_update_intent(u32 type) ++{ ++ ulong intent = 0; ++ if (type == PFR_CPLD_UPDATE_CAPSULE) ++ intent = CPLD_IMAGE_UPDATE; ++ else if (type == PFR_PCH_UPDATE_CAPSULE) ++ intent = PCH_SPI_FLASH_ACTIVE; ++ else if (type == PFR_BMC_UPDATE_CAPSULE) ++ intent = BMC_SPI_FLASH_ACTIVE; ++ ++ return intent; ++} ++ ++ulong get_image_max_size(u32 type) ++{ ++ ulong max_size = MAX_BMC_IMAGE_SIZE; ++ if (type == PFR_CPLD_UPDATE_CAPSULE) ++ max_size = MAX_CPLD_IMAGE_SIZE; ++ else if (type == PFR_PCH_UPDATE_CAPSULE) ++ max_size = MAX_BIOS_IMAGE_SIZE; ++ else if (type == PFR_BMC_UPDATE_CAPSULE) ++ max_size = MAX_BMC_IMAGE_SIZE; ++ ++ return max_size; ++} ++ ++ulong get_flash_region_offset(u32 type) ++{ ++ ulong offset = 0; ++ if (type == PFR_CPLD_UPDATE_CAPSULE) ++ offset = PFR_CPLD_IMAGE_REGION_OFFSET; ++ else if (type == PFR_PCH_UPDATE_CAPSULE) ++ offset = PFR_BIOS_IMAGE_REGION_OFFSET; ++ else if (type == PFR_BMC_UPDATE_CAPSULE) ++ offset = PFR_BMC_IMAGE_REGION_OFFSET; ++ ++ return offset; ++} ++ +diff --git a/board/aspeed/ast-g5/pfr-mgr.h b/board/aspeed/ast-g5/pfr-mgr.h +new file mode 100644 +index 0000000..6cf8c6d +--- /dev/null ++++ b/board/aspeed/ast-g5/pfr-mgr.h +@@ -0,0 +1,73 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <common.h> ++ ++/* CPLD I2C device defines */ ++#define PFR_CPLD_I2C_BUSNO 4 ++#define PFR_CPLD_SLAVE_ADDR 0xE0 ++ ++/* CPLD registers */ ++#define PFR_CPLD_BOOT_CHECKPOINT_REG 0x0F ++#define PFR_CPLD_BMC_UPDATE_INTENT_REG 0x13 ++ ++/* PFR checkpoints */ ++#define PFR_CPLD_CHKPOINT_START 0x01 ++#define PFR_CPLD_CHKPOINT_FFUJ 0x07 ++#define PFR_CPLD_CHKPOINT_FINISHED 0x09 ++ ++#define PFR_BLOCK0_MAGIC_NUM 0xB6EAFD19 ++#define PFR_AUTH_DATA_STRUCT_LEN 1024 /* Block0 & Block1 */ ++ ++/* SPI Flash MAP */ ++#define PFR_IMAGE_STAGING_BASE_ADDR 0x24A00000 /* 54MB */ ++#define MAX_BMC_IMAGE_SIZE 0x2000000 /* 32MB */ ++#define MAX_BIOS_IMAGE_SIZE 0x1000000 /* 16MB */ ++#define MAX_CPLD_IMAGE_SIZE 0x400000 /* 4MB */ ++#define PFR_BMC_IMAGE_REGION_OFFSET 0 ++#define PFR_BIOS_IMAGE_REGION_OFFSET \ ++ (PFR_BMC_IMAGE_REGION_OFFSET + MAX_BMC_IMAGE_SIZE) ++#define PFR_CPLD_IMAGE_REGION_OFFSET \ ++ (PFR_BIOS_IMAGE_REGION_OFFSET + MAX_BIOS_IMAGE_SIZE) ++ ++#define LSH(data, num) ((data) << (num)) ++ ++/* Bit mapping for CPLD 'BMC update intent' */ ++enum cpld_update_intent { ++ PCH_SPI_FLASH_ACTIVE = BIT(0), ++ PCH_SPI_FLASH_RECOVERY = BIT(1), ++ CPLD_IMAGE_UPDATE = BIT(2), ++ BMC_SPI_FLASH_ACTIVE = BIT(3), ++ BMC_SPI_FLASH_RECOVERY = BIT(4), ++ DEFER_UPDATES_TO_RESET = BIT(7) ++}; ++ ++enum pfr_block0_pc_type { ++ PFR_CPLD_UPDATE_CAPSULE = 0x00, ++ PFR_PCH_PFM = 0x01, ++ PFR_PCH_UPDATE_CAPSULE = 0x02, ++ PFR_BMC_PFM = 0x03, ++ PFR_BMC_UPDATE_CAPSULE = 0x04 ++}; ++ ++/* PFR image block 0 - As defined in HAS */ ++struct pfr_image_block0 { ++ u8 tag[4]; ++ u8 pc_length[4]; ++ u8 pc_type[4]; ++ u8 reserved_1[4]; ++ u8 hash_256[32]; ++ u8 hash_384[48]; ++ u8 reserved_2[32]; ++}; ++ ++struct fwupd_image_info { ++ u32 magic_num; ++ u32 img_length; ++ u32 img_type; ++}; ++ ++int set_cpld_reg(u8 reg_addr, u8 value); ++ulong get_update_intent(u32 type); ++ulong get_flash_region_offset(u32 type); ++ulong get_image_max_size(u32 type); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0033-Reboot-into-UBOOT-on-Watchdog-Failures.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0033-Reboot-into-UBOOT-on-Watchdog-Failures.patch new file mode 100644 index 000000000..e673da7ee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0033-Reboot-into-UBOOT-on-Watchdog-Failures.patch @@ -0,0 +1,110 @@ +From c82bf9de515cbbdb4ea1a350be83fb89f4a83631 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Wed, 31 Jul 2019 16:01:49 -0700 +Subject: [PATCH 1/1] Reboot into UBOOT on Watchdog Failures + +We use watchdog1 to reboot when there is a watchdog +error. Reboot into u-boot as we are using that as +safe mode. + +Tested: watchdog -T 0 -F /dev/watchdog1 reboots into +uboot after 3 times + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + .../include/asm/arch-aspeed/ast-g5-intel.h | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 31 +++++++++++++++++++ + common/autoboot.c | 2 ++ + 3 files changed, 34 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +index a88521a1b3..64f4ed17bf 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h ++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +@@ -14,6 +14,7 @@ + + #ifndef __ASSEMBLY__ + int intel_force_firmware_jumper_enabled(void); ++int intel_failed_boot(void); + void start_fw_update_loop(void); + #endif + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e68ab8546a..c003d9a7bc 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -111,6 +111,24 @@ static const GPIOValue gpio_table[] = { + #define HOST_SERIAL_A_HIGH_SPEED (1 << 0) + #define HOST_SERIAL_B_HIGH_SPEED (1 << 1) + ++#define WATCHDOG_RESET_BIT 0x8 ++#define BOOT_FAILURE_LIMIT 0x3 ++ ++static int get_boot_failures(void) ++{ ++ return getenv_ulong("bootfailures", 10, 0); ++} ++ ++static void set_boot_failures(u32 count) ++{ ++ if (count > BOOT_FAILURE_LIMIT) ++ return; ++ ++ setenv_ulong("bootfailures", count); ++ saveenv(); ++} ++ ++ + static void sgpio_init(void) + { + uint32_t value; +@@ -270,6 +288,11 @@ int intel_force_firmware_jumper_enabled(void) + return gpio_get_value(GPIO_FF_UPD_JUMPER); + } + ++int intel_failed_boot(void) ++{ ++ return get_boot_failures() >= BOOT_FAILURE_LIMIT; ++} ++ + void arch_preboot_os(void) + { + // last second before booting... set the LEDs +@@ -402,6 +425,7 @@ void ast_g5_intel_late_init(void) + { + char value[32]; + u32 reset_reason = 0; ++ u32 boot_failures = 0; + + /* By default host serail A and B use normal speed */ + uint32_t host_serial_cfg = 0; +@@ -446,6 +470,13 @@ void ast_g5_intel_late_init(void) + + update_bootargs_cmd("resetreason", value); + ++ boot_failures = get_boot_failures(); ++ ++ if (reset_reason & WATCHDOG_RESET_BIT) ++ set_boot_failures(boot_failures + 1); ++ else ++ set_boot_failures(0); ++ + /* Update the special mode in bootargs */ + if (is_mfg_mode_phy_req()) + update_bootargs_cmd("special", "mfg"); +diff --git a/common/autoboot.c b/common/autoboot.c +index 45a600e663..03fd164501 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -263,6 +263,8 @@ static int abortboot(int bootdelay) + # ifdef AST_G5_INTEL + if (intel_force_firmware_jumper_enabled()) + return 1; ++ if (intel_failed_boot()) ++ return 1; + # endif + + if (bootdelay >= 0) +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend new file mode 100644 index 000000000..09544cfb2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend @@ -0,0 +1,57 @@ +FILESEXTRAPATHS_append_intel-ast2500:= "${THISDIR}/files:" + +# the meta-phosphor layer adds this patch, which conflicts +# with the intel layout for environment +SRC_URI_remove_intel-ast2500 = " file://0001-configs-ast-Add-redundnant-env.patch" + +SRC_URI_append_intel-ast2500 = " \ + file://0001-flash-use-readX-writeX-not-udelay.patch \ + file://0002-intel-layout-environment-addr.patch \ + file://0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch \ + file://0005-enable-passthrough-in-uboot.patch \ + file://0006-Add-Aspeed-g5-interrupt-support.patch \ + file://0007-Add-espi-support.patch \ + file://0008-add-sgio-support-for-port80-snoop-post-LEDs.patch \ + file://0009-Add-basic-GPIO-support.patch \ + file://0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch \ + file://0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch \ + file://0012-Add-status-and-ID-LED-support.patch \ + file://0013-aspeed-Add-Pwm-Driver.patch \ + file://0014-Keep-interrupts-enabled-until-last-second.patch \ + file://0015-Rewrite-memmove-to-optimize-on-word-transfers.patch \ + file://0019-u-boot-full-platform-reset-espi-oob-ready.patch \ + file://0020-Enable-PCIe-L1-support.patch \ + file://0020-Add-system-reset-status-support.patch \ + file://0021-Config-host-uart-clock-source-using-environment-vari.patch \ + file://0022-KCS-driver-support-in-uBoot.patch \ + file://0023-Add-TPM-enable-pulse-triggering.patch \ + file://0024-IPMI-command-handler-implementation-in-uboot.patch \ + file://0025-Manufacturing-mode-physical-presence-detection.patch \ + file://0026-Aspeed-I2C-support-in-U-Boot.patch \ + file://0027-CPLD-u-boot-commands-support-for-PFR.patch \ + file://0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch \ + file://0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch \ + file://0030-Support-Get-Set-Security-mode-command.patch \ + file://0031-Make-it-so-TFTP-port-can-be-modified.patch \ + file://0033-Reboot-into-UBOOT-on-Watchdog-Failures.patch \ + " +PFR_SRC_URI = " \ + file://0022-u-boot-env-change-for-PFR-image.patch \ + file://0032-PFR-FW-update-and-checkpoint-support-in-u-boot.patch \ + " +SRC_URI_append_intel-ast2500 += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', PFR_SRC_URI, '', d)}" + +require recipes-core/os-release/version-vars.inc + +python do_version () { + with open(d.expand('${S}/board/aspeed/ast-g5/intel-version.h'), 'w') as f: + f.write(d.expand('#define VER_MAJOR ${IPMI_MAJOR}\n')) + f.write(d.expand('#define VER_MINOR ${IPMI_MINOR}\n')) + f.write(d.expand('#define VER_AUX13 ${IPMI_AUX13}\n')) + f.write(d.expand('#define VER_AUX14 ${IPMI_AUX14}\n')) + f.write(d.expand('#define VER_AUX15 ${IPMI_AUX15}\n')) + f.write(d.expand('#define VER_AUX16 ${IPMI_AUX16}\n')) +} + +do_version[vardepsexclude] = "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16 PRODUCT_GENERATION VERSION VERSION_ID BUILD_ID" +addtask do_version after do_configure before do_compile diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend new file mode 100644 index 000000000..09544cfb2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend @@ -0,0 +1,57 @@ +FILESEXTRAPATHS_append_intel-ast2500:= "${THISDIR}/files:" + +# the meta-phosphor layer adds this patch, which conflicts +# with the intel layout for environment +SRC_URI_remove_intel-ast2500 = " file://0001-configs-ast-Add-redundnant-env.patch" + +SRC_URI_append_intel-ast2500 = " \ + file://0001-flash-use-readX-writeX-not-udelay.patch \ + file://0002-intel-layout-environment-addr.patch \ + file://0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch \ + file://0005-enable-passthrough-in-uboot.patch \ + file://0006-Add-Aspeed-g5-interrupt-support.patch \ + file://0007-Add-espi-support.patch \ + file://0008-add-sgio-support-for-port80-snoop-post-LEDs.patch \ + file://0009-Add-basic-GPIO-support.patch \ + file://0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch \ + file://0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch \ + file://0012-Add-status-and-ID-LED-support.patch \ + file://0013-aspeed-Add-Pwm-Driver.patch \ + file://0014-Keep-interrupts-enabled-until-last-second.patch \ + file://0015-Rewrite-memmove-to-optimize-on-word-transfers.patch \ + file://0019-u-boot-full-platform-reset-espi-oob-ready.patch \ + file://0020-Enable-PCIe-L1-support.patch \ + file://0020-Add-system-reset-status-support.patch \ + file://0021-Config-host-uart-clock-source-using-environment-vari.patch \ + file://0022-KCS-driver-support-in-uBoot.patch \ + file://0023-Add-TPM-enable-pulse-triggering.patch \ + file://0024-IPMI-command-handler-implementation-in-uboot.patch \ + file://0025-Manufacturing-mode-physical-presence-detection.patch \ + file://0026-Aspeed-I2C-support-in-U-Boot.patch \ + file://0027-CPLD-u-boot-commands-support-for-PFR.patch \ + file://0028-Enabling-uart1-uart2-in-u-boot-for-BIOS-messages.patch \ + file://0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch \ + file://0030-Support-Get-Set-Security-mode-command.patch \ + file://0031-Make-it-so-TFTP-port-can-be-modified.patch \ + file://0033-Reboot-into-UBOOT-on-Watchdog-Failures.patch \ + " +PFR_SRC_URI = " \ + file://0022-u-boot-env-change-for-PFR-image.patch \ + file://0032-PFR-FW-update-and-checkpoint-support-in-u-boot.patch \ + " +SRC_URI_append_intel-ast2500 += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', PFR_SRC_URI, '', d)}" + +require recipes-core/os-release/version-vars.inc + +python do_version () { + with open(d.expand('${S}/board/aspeed/ast-g5/intel-version.h'), 'w') as f: + f.write(d.expand('#define VER_MAJOR ${IPMI_MAJOR}\n')) + f.write(d.expand('#define VER_MINOR ${IPMI_MINOR}\n')) + f.write(d.expand('#define VER_AUX13 ${IPMI_AUX13}\n')) + f.write(d.expand('#define VER_AUX14 ${IPMI_AUX14}\n')) + f.write(d.expand('#define VER_AUX15 ${IPMI_AUX15}\n')) + f.write(d.expand('#define VER_AUX16 ${IPMI_AUX16}\n')) +} + +do_version[vardepsexclude] = "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16 PRODUCT_GENERATION VERSION VERSION_ID BUILD_ID" +addtask do_version after do_configure before do_compile 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..de607f1a7 --- /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=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..170f41a94 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb @@ -0,0 +1,26 @@ +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" + +do_configure[depends] += "virtual/kernel:do_shared_workdir" + +SRC_URI = "git://git@github.com/Intel-BMC/asd;protocol=ssh;nobranch=1" +SRCREV = "73d4cc11b859ba91f313a7bb85f2dbb26e36d0ee" + +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..a7c238ffe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service @@ -0,0 +1,13 @@ +[Unit] +Description=Intel BMC At Scale Debug +Requires=network-online.target + +[Service] +Restart=always +RestartSec=30 +ExecStart={bindir}/asd +Type=simple +SyslogIdentifier=asd + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service new file mode 100644 index 000000000..281d1a993 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service @@ -0,0 +1,12 @@ +[Unit] +Description=Intel BMC At Scale Debug JTAG test to check if remote debug setting is enabled + +[Service] +Type=oneshot +ExecStartPre=/bin/sleep 10 +ExecStart={bindir}/jtag_test +SyslogIdentifier=jtag_test +RemainAfterExit=true + +[Install] +WantedBy=obmc-host-start@0.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab new file mode 100644 index 000000000..0b53093ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab @@ -0,0 +1,10 @@ +/dev/root / auto defaults 1 1 +proc /proc proc defaults 0 0 +devpts /dev/pts devpts mode=0620,gid=5 0 0 +tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 +tmpfs /var/lib/systemd/coredump tmpfs rw,nosuid,nodev,size=67108864 0 0 +tmpfs /media tmpfs rw 0 0 + +# uncomment this if your device has a SD/MMC/Transflash slot +#/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend new file mode 100644 index 000000000..79e529179 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend @@ -0,0 +1,2 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI_append = " file://fstab" diff --git a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb new file mode 100644 index 000000000..68a548b02 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb @@ -0,0 +1,29 @@ +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 " +inherit cmake + +EXTRA_OECMAKE = "-DCRASHDUMP_BUILD_UT=ON" + +LICENSE = "Proprietary" +LIC_FILES_CHKSUM = "file://LICENSE;md5=26bb6d0733830e7bab774914a8f8f20a" + +SRC_URI = "git://git@github.com/Intel-BMC/crashdump;protocol=ssh;nobranch=1" +SRCREV = "c99e4fb7727545501fe65b90a8a97e84d469d45e" + +S = "${WORKDIR}/git" +PACKAGES += "libpeci" + +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/fw-update/files/fwupd.sh b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh new file mode 100644 index 000000000..dd3b7f69a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh @@ -0,0 +1,116 @@ +#!/bin/sh + +SSH_ID=$HOME/.ssh/id_rsa.db +[ -e $HOME/.fwupd.defaults ] && source $HOME/.fwupd.defaults + +usage() { + echo "usage: $(basename $0) uri" + echo " uri is something like: file:///path/to/fw" + echo " tftp://tftp.server.ip.addr/path/to/fw" + echo " scp://[user@]scp.server.ip.addr:/path/to/fw" + echo " http[s]://web.server.ip.addr/path/to/fw" + echo " ftp://[user@]ftp.server.ip.addr/path/to/fw" + exit 1 +} + +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage; fi +if [ $# -eq 0 ]; then + # set DEFURI in $HOME/.fwupd.defaults + URI="$DEFURI" +else + URI="$1" +fi + +PROTO=$(echo "$URI" | sed 's,\([a-z]*\)://.*$,\1,') +REMOTE=$(echo "$URI" | sed 's,.*://\(.*\)$,\1,') +REMOTE_HOST=$(echo "$REMOTE" | sed 's,\([^/]*\)/.*$,\1,') +if [ "$PROTO" = 'scp' ]; then + REMOTE_PATH=$(echo "$REMOTE" | cut -d':' -f2) +else + REMOTE_PATH=$(echo "$REMOTE" | sed 's,[^/]*/\(.*\)$,\1,') +fi +LOCAL_PATH="/tmp/$(basename $REMOTE_PATH)" +echo "PROTO=$PROTO" +echo "REMOTE=$REMOTE" +echo "REMOTE_HOST=$REMOTE_HOST" +echo "REMOTE_PATH=$REMOTE_PATH" +if [ ! -e $LOCAL_PATH ] || [ $(stat -c %s $LOCAL_PATH) -eq 0 ]; then + echo "Download '$REMOTE_PATH' from $PROTO $REMOTE_HOST $REMOTE_PATH" + case "$PROTO" in + scp) + mkdir -p $HOME/.ssh + if [ -e "$SSH_ID" ]; then + ARG_ID="-i $SSH_ID" + fi + scp $ARG_ID $REMOTE_HOST$REMOTE_PATH $LOCAL_PATH + if [ $? -ne 0 ]; then + echo "scp $REMOTE $LOCAL_PATH failed!" + exit 255 + fi + ;; + tftp) + cd /tmp + tftp -g -r "$REMOTE_PATH" "$REMOTE_HOST" + if [ $? -ne 0 ]; then + echo "tftp -g -r \"$REMOTE_PATH\" \"$REMOTE_HOST\" failed!" + exit 255 + fi + ;; + http|https|ftp) + wget --no-check-certificate "$URI" -O "$LOCAL_PATH" + if [ $? -ne 0 ]; then + echo "wget $URI failed!" + exit 255 + fi + ;; + file) + cp "$REMOTE_PATH" "$LOCAL_PATH" + ;; + *) + echo "Invalid URI $URI" + exit 1; + ;; + esac +fi + +# do a quick sanity check on the image +if [ $(stat -c "%s" "$LOCAL_PATH") -lt 10000000 ]; then + echo "Update file "$LOCAL_PATH" seems to be too small" + exit 1 +fi +dtc -I dtb -O dtb "$LOCAL_PATH" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "Update file $LOCAL_PATH doesn't seem to be in the proper format" + exit 1 +fi + +#this file being created at build time for PFR images +#TODO: Need to do runtime detection of PFR platform +#TODO: Also to check if PFR is provisioned or not +if [ -e /usr/share/pfr ] +then +TGT="/dev/mtd/image-stg" +echo "Updating $(basename $TGT)" +flash_erase $TGT 0 0 +echo "Writing $(stat -c "%s" "$LOCAL_PATH") bytes" +cat "$LOCAL_PATH" > "$TGT" +#TODO: Add I2C command to write to PFRCPLD about BMC update intent. +else +# guess based on fw_env which partition we booted from +BOOTADDR=$(fw_printenv bootcmd | awk '{print $2}') + +TGT="/dev/mtd/image-a" +case "$BOOTADDR" in + 20080000) TGT="/dev/mtd/image-b"; BOOTADDR="22480000" ;; + 22480000) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;; + *) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;; +esac +echo "Updating $(basename $TGT) (use bootm $BOOTADDR)" +flash_erase $TGT 0 0 +echo "Writing $(stat -c "%s" "$LOCAL_PATH") bytes" +cat "$LOCAL_PATH" > "$TGT" +fw_setenv "bootcmd" "bootm ${BOOTADDR}" + +# reboot +reboot +fi 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..d7595696e --- /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 parted" + +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_git.bb b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_git.bb new file mode 100644 index 000000000..483a9bf12 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_git.bb @@ -0,0 +1,14 @@ +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +inherit cmake systemd + +SRC_URI = "git://git@github.com/Intel-BMC/at-scale-debug;protocol=ssh" + +DEPENDS = "boost sdbusplus libgpiod" + +PV = "0.1+git${SRCPV}" +SRCREV = "6ed87657134c7379da1febcccd5d87617c702347" + +S = "${WORKDIR}/git/host_error_monitor" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.HostErrorMonitor.service" 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-Add-smbus-support-to-Cmake-Lists.patch b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Add-smbus-support-to-Cmake-Lists.patch new file mode 100644 index 000000000..8bb9ce485 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Add-smbus-support-to-Cmake-Lists.patch @@ -0,0 +1,36 @@ +From 21f2f29129a7eba8aecdf07875004bafc6a74269 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Thu, 20 Jun 2019 08:58:44 -0700 +Subject: [PATCH] Add smbus support to Cmake Lists + +This adds smbus changes needed for libmctp. + +Change-Id: I06fc950337e6f3d5b1cef0fb445be2d448d49e44 +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + CMakeLists.txt | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index a5b1042..04c4bdf 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -3,7 +3,7 @@ cmake_minimum_required (VERSION 3.5 FATAL_ERROR) + add_definitions (-DMCTP_LOG_STDERR) + add_definitions (-DMCTP_FILEIO) + +-add_library (libmctp STATIC alloc.c core.c log.c libmctp.h serial.c) ++add_library (libmctp STATIC alloc.c core.c log.c libmctp.h serial.c smbus.c) + + target_include_directories (libmctp PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> +@@ -18,5 +18,5 @@ 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 DESTINATION include) ++install (FILES libmctp.h libmctp-smbus.h libmctp-serial.h DESTINATION include) + +-- +2.17.1 + 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..d6b1d11e2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h @@ -0,0 +1,9 @@ +#ifndef CRC32C_H +#define CRC32C_H + +#include <stdint.h> +#include <stdlib.h> + +uint32_t crc32c(uint8_t *buf, int len); + +#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..b3beadb0c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef _LIBMCTP_SMBUS_H +#define _LIBMCTP_SMBUS_H + +#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); +#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..8679a5185 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef MCTP_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; + struct mctp *mctp; + 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 + +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; +}; + +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; + uint8_t *buf; + size_t len; + int r; + struct i2c_msg msg; + struct i2c_rdwr_ioctl_data data; + + data.msgs = &msg; + data.nmsgs = 1; + + uint16_t timeout = 1000; + int i; + + /* the length field in the header excludes smbus framing + * and escape sequences */ + len = mctp_pktbuf_size(pkt); + + hdr = (void *)smbus->txbuf; + + // hdr->len = len + 1; // +1 for PET byte + hdr->source_slave_address = MCTP_SOURCE_SLAVE_ADDRESS; + + buf = (void *)(hdr + sizeof(*hdr)); + + if (len + sizeof(*hdr) > sizeof(smbus->txbuf)) + return -1; + + memcpy(buf, &pkt->data[pkt->start], len); + + buf += len; + + if (ioctl(smbus->out_fd, I2C_SLAVE, MCTP_SLAVE_ADDRESS) < 0) { + mctp_prerr("Can't set slave"); + return -1; + } + if (ioctl(smbus->out_fd, I2C_PEC, 1) < 0) { + mctp_prerr("Cant set PEC byte"); + return -1; + } + + if (i2c_smbus_write_block_data(smbus->out_fd, MCTP_COMMAND_CODE, + sizeof(*hdr) + len, (void *)smbus->txbuf) + < 0) { + mctp_prerr("Failed to send"); + return -1; + } + + return 0; +} + +#ifdef MCTP_FILEIO +int mctp_smbus_read(struct mctp_binding_smbus *smbus) +{ + ssize_t len; + int r; + struct mctp_smbus_header_rx *hdr; + + r = lseek(smbus->in_fd, 0, SEEK_SET); + if (r < 0) { + mctp_prerr("Failed to seek"); + return -1; + } + len = read(smbus->in_fd, smbus->rxbuf, sizeof(smbus->rxbuf)); + if (len < sizeof(*hdr)) { + // TODO Don't return an error here, as it seems to happen from + // time to time, even with a properly written poll loop, + // although it's not clear why. + return 0; + } + + 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); + return 0; + } + if (hdr->command_code != MCTP_COMMAND_CODE) { + mctp_prerr("Got bad command code %d", hdr->command_code); + // Not a payload intended for us + return 0; + } + + 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)); + return 0; + } + + if (len < 0) { + mctp_prerr("can't read from smbus device: %m"); + return -1; + } + + smbus->rx_pkt = mctp_pktbuf_alloc(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"); + return -1; + } + + mctp_bus_rx(&(smbus->binding), smbus->rx_pkt); + + mctp_pktbuf_free(smbus->rx_pkt); + smbus->rx_pkt = NULL; + + return 0; +} + +int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus) +{ + return smbus->in_fd; +} + +int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus) +{ + return smbus->out_fd; +} + +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; + char slave_mqueue[20]; + size_t mqueue_size; + + int fd; + + size_t size; + int address_7_bit; + + address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1; + size = sizeof(filename); + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", + root_bus_num, root_bus_num, + (address_7_bit << 8) + 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", + (address_7_bit << 8) + 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, + (address_7_bit << 8) + 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) +{ + assert(smbus->out_fd >= 0); + assert(smbus->in_fd >= 0); + smbus->mctp = mctp; + smbus->bus_id = mctp_register_bus(mctp, &smbus->binding, eid); +} + +struct mctp_binding_smbus *mctp_smbus_init(void) +{ + struct mctp_binding_smbus *smbus; + + smbus = __mctp_alloc(sizeof(*smbus)); + smbus->in_fd = -1; + smbus->out_fd = -1; + + smbus->rx_pkt = NULL; + smbus->binding.name = "smbus"; + smbus->binding.version = 1; + + smbus->binding.tx = mctp_binding_smbus_tx; + + return 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..d9359cfeb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb @@ -0,0 +1,30 @@ +SUMMARY = "libmctp" +DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" + +SRC_URI = "git://github.com/openbmc/libmctp.git" +SRCREV = "195a7c5e212f7fb50c850880519073ec99133607" + +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" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Add-smbus-support-to-Cmake-Lists.patch \ + 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} +} + 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..53fc218c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend @@ -0,0 +1,2 @@ +SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git" +SRCREV = "773703a58db91f69f2ecb32d3c69d9984fba504e" diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb b/meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb new file mode 100644 index 000000000..7f6d406d4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb @@ -0,0 +1,32 @@ +SUMMARY = "Intel IPMI Providers" +DESCRIPTION = "IPMI Provider Libraries" + +SRC_URI = "git://git@github.com/Intel-BMC/intel-ipmi-providers;protocol=ssh" +SRCREV = "b2c6184269e3bdf601c38f716ac7ee73379af71b" + +S = "${WORKDIR}/git" +PV = "0.1+git${SRCPV}" + +DEPENDS = "boost phosphor-ipmi-host intel-ipmi-oem systemd microsoft-gsl" + +inherit cmake obmc-phosphor-ipmiprovider-symlink + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" + +EXTRA_OECMAKE="-DENABLE_TEST=0 -DYOCTO=1" + +LIBRARY_NAMES += "libmtmcmds.so" +LIBRARY_NAMES += "libsmbioshandler.so" +LIBRARY_NAMES += "libzbridgecmd.so" +LIBRARY_NAMES += "libsmbiosmdrv2.so" +LIBRARY_NAMES += "libfwupdcmds.so" + +HOSTIPMI_PROVIDER_LIBRARY += "${LIBRARY_NAMES}" +NETIPMI_PROVIDER_LIBRARY += "${LIBRARY_NAMES}" + +FILES_${PN}_append = " ${libdir}/ipmid-providers/lib*${SOLIBS}" +FILES_${PN}_append = " ${libdir}/host-ipmid/lib*${SOLIBS}" +FILES_${PN}_append = " ${libdir}/net-ipmid/lib*${SOLIBS}" +FILES_${PN}-dev_append = " ${libdir}/ipmid-providers/lib*${SOLIBSDEV}" + 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/microsoft-gsl/microsoft-gsl.bb b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb new file mode 100644 index 000000000..8cb593bce --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb @@ -0,0 +1,24 @@ +# Add GSL: Guideline Support Library for c++ +# https://github.com/Microsoft/GSL + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://LICENSE;md5=363055e71e77071107ba2bb9a54bd9a7" + +SRC_URI = "git://github.com/Microsoft/GSL.git;protocol=https" + +# Modify these as desired +PV = "1.0+git${SRCPV}" +#SRCREV = "${AUTOREV}" +SRCREV = "be43c79742dc36ee55b21c5d531a5ff301d0ef8d" + +S = "${WORKDIR}/git" + +do_install () { + install -d ${D}/usr/include + install -d ${D}/usr/include/gsl + for F in ${S}/include/gsl/*; do + install -m 0644 ${F} ${D}/usr/include/gsl + done +} + +ALLOW_EMPTY_${PN} = "1" diff --git a/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend new file mode 100644 index 000000000..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..b6a2504a2 --- /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(int(versionList[3]))) + 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..e19e5fc93 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb @@ -0,0 +1,24 @@ +# NOTE: LICENSE is being set to "CLOSED" for now. The PCIe reads over PECI expose +# more information than is accessible from the BIOS or OS, so we need to keep this +# internal to Intel until it's resolved. +LICENSE = "CLOSED" +LIC_FILES_CHKSUM = "" +inherit cmake systemd + +SRC_URI = "git://git@github.com/Intel-BMC/at-scale-debug;protocol=ssh" + +DEPENDS = "boost sdbusplus crashdump" + +PV = "0.1+git${SRCPV}" +SRCREV = "6ed87657134c7379da1febcccd5d87617c702347" + +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..a6d94fc51 --- /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 = "f1708afcbba69f75e80920b75aa3d7baee3f611d" +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/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/000-ro-rootfs-tmpfile-defaults.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/000-ro-rootfs-tmpfile-defaults.patch new file mode 100644 index 000000000..d16f3a2dc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/000-ro-rootfs-tmpfile-defaults.patch @@ -0,0 +1,51 @@ +From 05e1b853abfd54d117dad25185c602d1791d83f6 Mon Sep 17 00:00:00 2001 +From: David Cobbley <david.j.cobbley@linux.intel.com> +Date: Tue, 26 Jun 2018 16:10:14 -0700 +Subject: [PATCH] ro-rootfs-tmpfile-defaults + +--- + tmpfiles.d/home.conf | 1 - + tmpfiles.d/tmp.conf | 1 - + tmpfiles.d/var.conf.m4 | 5 ++++- + 3 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/tmpfiles.d/home.conf b/tmpfiles.d/home.conf +index 9f25b83..5c7513a 100644 +--- a/tmpfiles.d/home.conf ++++ b/tmpfiles.d/home.conf +@@ -8,4 +8,3 @@ + # See tmpfiles.d(5) for details + + Q /home 0755 - - - +-q /srv 0755 - - - +diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf +index 22555a0..aad1b98 100644 +--- a/tmpfiles.d/tmp.conf ++++ b/tmpfiles.d/tmp.conf +@@ -9,7 +9,6 @@ + + # Clear tmp directories separately, to make them easier to override + q /tmp 1777 root root 10d +-q /var/tmp 1777 root root 30d + + # Exclude namespace mountpoints created with PrivateTmp=yes + x /tmp/systemd-private-%b-* +diff --git a/tmpfiles.d/var.conf.m4 b/tmpfiles.d/var.conf.m4 +index 0e2c509..fa288b8 100644 +--- a/tmpfiles.d/var.conf.m4 ++++ b/tmpfiles.d/var.conf.m4 +@@ -11,7 +11,10 @@ q /var 0755 - - - + + L /var/run - - - - ../run + +-d /var/log 0755 - - - ++# now /var/log and /var/tmp really live in volatile ++L /var/log - - - - volatile/log ++L /var/tmp - - - - volatile/tmp ++ + m4_ifdef(`ENABLE_UTMP', + f /var/log/wtmp 0664 root utmp - + f /var/log/btmp 0660 root utmp - +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch new file mode 100644 index 000000000..f72052e0c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch @@ -0,0 +1,28 @@ +From 3016898f4300fdd8db74f821cd6ea54dbf39fdc8 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Tue, 6 Mar 2018 16:06:33 -0800 +Subject: [PATCH 1/1] Modfiy system.conf DefaultTimeoutStopSec + +Current time is 5 minutes, change it to 10 seconds. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + src/core/system.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 746572b..ba2a265 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -33,7 +33,7 @@ + #DefaultStandardOutput=journal + #DefaultStandardError=inherit + #DefaultTimeoutStartSec=90s +-#DefaultTimeoutStopSec=90s ++DefaultTimeoutStopSec=10s + #DefaultRestartSec=100ms + #DefaultStartLimitIntervalSec=10s + #DefaultStartLimitBurst=5 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/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/systemd-timesyncd.service b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-timesyncd.service new file mode 100644 index 000000000..9a5fffbb3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-timesyncd.service @@ -0,0 +1,53 @@ +# 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=Network Time Synchronization +Documentation=man:systemd-timesyncd.service(8) +ConditionCapability=CAP_SYS_TIME +ConditionVirtualization=!container +DefaultDependencies=no +After=systemd-remount-fs.service systemd-sysusers.service var.mount +Before=time-set.target sysinit.target shutdown.target +Conflicts=shutdown.target +Wants=time-set.target time-sync.target + +[Service] +AmbientCapabilities=CAP_SYS_TIME +CapabilityBoundingSet=CAP_SYS_TIME +ExecStart=!!/lib/systemd/systemd-timesyncd +LockPersonality=yes +MemoryDenyWriteExecute=yes +NoNewPrivileges=yes +PrivateDevices=yes +PrivateTmp=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectHostname=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectSystem=strict +Restart=always +RestartSec=0 +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +RestrictNamespaces=yes +RestrictRealtime=yes +RestrictSUIDSGID=yes +RuntimeDirectory=systemd/timesync +StateDirectory=systemd/timesync +SystemCallArchitectures=native +SystemCallErrorNumber=EPERM +SystemCallFilter=@system-service @clock +Type=notify +User=systemd-timesync +WatchdogSec=3min + +[Install] +WantedBy=sysinit.target +Alias=dbus-org.freedesktop.timesync1.service 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..3e5adf7ce --- /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://000-ro-rootfs-tmpfile-defaults.patch \ + file://0001-Modfiy-system.conf-DefaultTimeoutStopSec.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/dtoverlay/dtoverlay.bb b/meta-openbmc-mods/meta-common/recipes-devtools/dtoverlay/dtoverlay.bb new file mode 100644 index 000000000..66107d81b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/dtoverlay/dtoverlay.bb @@ -0,0 +1,31 @@ +SUMMARY = "dtoverlay" +DESCRIPTION = "device tree overlay application" + +SRC_URI = "git://github.com/raspberrypi/userland.git" +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://LICENCE;md5=0448d6488ef8cc380632b1569ee6d196" + +SRCREV = "11389772c79685442e0ab8aa9be8ad0e32703f68" +requires = "chrpath-native" + +S = "${WORKDIR}/git" + +PV = "1" + +inherit cmake + +FILES_${PN} += "${libdir} ${libdir}libdtovl.so.${PV}" + +do_compile_append(){ + chrpath -d ${S}/build/bin/dtoverlay +} + +do_install() { + install -d ${D}${libdir} + install -m 0644 ${S}/build/lib/libdtovl.so ${D}${libdir}/libdtovl.so.${PV} + install -d ${D}${bindir} + install -m 0755 ${S}/build/bin/dtoverlay ${D}${bindir}/dtoverlay + + ln -sf libdtovl.so.${PV} ${D}{libdir}libdtovl.so +} + diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb new file mode 100644 index 000000000..46a185cdf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb @@ -0,0 +1,20 @@ +DESCRIPTION = "OpenBMC mtd-util" + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://COPYING;md5=b77c43ae4eaf67bd73fb6452b2f113a3" + +SRC_URI = "git://git@github.com/Intel-BMC/mtd-util;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "0414bd37ba324867c5c89fc91ab80714309f4c80" + + +S = "${WORKDIR}/git" + +DEPENDS += "dbus openssl zlib boost microsoft-gsl" + +inherit cmake pkgconfig + +# Specify any options you want to pass to cmake using EXTRA_OECMAKE: +EXTRA_OECMAKE = "" + diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/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..5d13a8c44 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb @@ -0,0 +1,18 @@ +SUMMARY = "HelloWorld app with phosphor-logging usage example." +DESCRIPTION = "NOTE: Phosphor-logging has dependencies on systemd and sdbusplus." + +SRC_URI = "git://git-amr-2.devtools.intel.com:29418/openbmc_template-recipe;protocol=ssh" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +# Modify these as desired +PV = "1.0+git${SRCPV}" +SRCREV = "2d5d731254319de8b42d6438b0ce3908dd5b0dec" + +S = "${WORKDIR}/git" + +inherit cmake + +DEPENDS = "systemd sdbusplus phosphor-logging" +RDEPENDS_${PN} = "libsystemd sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rotate-event-logs.service b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rotate-event-logs.service new file mode 100644 index 000000000..fdeefd417 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rotate-event-logs.service @@ -0,0 +1,9 @@ +[Unit] +Description=Rotates the event logs + +[Service] +Type=oneshot +ExecStart=/usr/sbin/logrotate /etc/logrotate.d/logrotate.rsyslog + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rotate-event-logs.timer b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rotate-event-logs.timer new file mode 100644 index 000000000..148f8e4ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rotate-event-logs.timer @@ -0,0 +1,8 @@ +[Unit] +Description=Run rotate-event-logs.service every minute + +[Timer] +OnCalendar=*-*-* *:*:00 + +[Install] +WantedBy=timers.target diff --git a/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog-override.conf b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog-override.conf new file mode 100644 index 000000000..14bcc0781 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog-override.conf @@ -0,0 +1,2 @@ +[Service] +ExecReload=/bin/kill -HUP $MAINPID diff --git a/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog.conf b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog.conf new file mode 100644 index 000000000..f00046b45 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog.conf @@ -0,0 +1,62 @@ +# if you experience problems, check +# http://www.rsyslog.com/troubleshoot for assistance + +# rsyslog v3: load input modules +# If you do not load inputs, nothing happens! +# You may need to set the module load path if modules are not found. +# +# Ported from debian's sysklogd.conf + +# Journal-style logging +# Limit to no more than 2000 entries in one minute and enable the +# journal workaround to avoid duplicate entries +module(load="imjournal" StateFile="/var/log/state" + RateLimit.Interval="60" + RateLimit.Burst="2000") + +# Template for IPMI SEL messages +# "<timestamp> <ID>,<Type>,<EventData>,[<Generator ID>,<Path>,<Direction>]" +template(name="IPMISELTemplate" type="list") { + property(name="timereported" dateFormat="rfc3339") + constant(value=" ") + property(name="$!IPMI_SEL_RECORD_ID") + constant(value=",") + property(name="$!IPMI_SEL_RECORD_TYPE") + constant(value=",") + property(name="$!IPMI_SEL_DATA") + constant(value=",") + property(name="$!IPMI_SEL_GENERATOR_ID") + constant(value=",") + property(name="$!IPMI_SEL_SENSOR_PATH") + constant(value=",") + property(name="$!IPMI_SEL_EVENT_DIR") + constant(value="\n") +} + +# Template for Redfish messages +# "<timestamp> <MessageId>,<MessageArgs>" +template(name="RedfishTemplate" type="list") { + property(name="timereported" dateFormat="rfc3339") + constant(value=" ") + property(name="$!REDFISH_MESSAGE_ID") + constant(value=",") + property(name="$!REDFISH_MESSAGE_ARGS") + constant(value="\n") +} + +# If the journal entry has the IPMI SEL MESSAGE_ID, save as IPMI SEL +# The MESSAGE_ID string is generated using journalctl and must match the +# MESSAGE_ID used in IPMI to correctly find the SEL entries. +if ($!MESSAGE_ID == "b370836ccf2f4850ac5bee185b77893a") then { + action(type="omfile" file="/var/log/ipmi_sel" template="IPMISELTemplate") +} + +# If the journal entry has a Redfish MessageId, save as a Redfish event +if ($!REDFISH_MESSAGE_ID != "") then { + action(type="omfile" file="/var/log/redfish" template="RedfishTemplate") +} + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf diff --git a/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog.logrotate b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog.logrotate new file mode 100644 index 000000000..a6ba28d86 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog/rsyslog.logrotate @@ -0,0 +1,22 @@ +# /etc/logrotate.d/rsyslog - Ported from Debian + +# Keep up to four 64k files for ipmi_sel (256k total) +/var/log/ipmi_sel +{ + rotate 3 + size 64k + missingok + postrotate + systemctl reload rsyslog 2> /dev/null || true + endscript +} +# Keep up to four 64k files for redfish (256k total) +/var/log/redfish +{ + rotate 3 + size 64k + missingok + postrotate + systemctl reload rsyslog 2> /dev/null || true + endscript +} diff --git a/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog_%.bbappend new file mode 100644 index 000000000..15e557c79 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/rsyslog/rsyslog_%.bbappend @@ -0,0 +1,31 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# Pin to rsyslog v8.1904.0 for now +# v8.1903.0 has a couple issues with the imjournal module: +# 1. Enabling the "WorkAroundJournalBug" option causes rsyslogd to fail to start +# 2. Logging data especially while rotating the journal causes a double free error +PV = "8.1904.0" +SRC_URI[md5sum] = "b9398b5aa68a829bf2c18a87490d30c0" +SRC_URI[sha256sum] = "7098b459dfc3f8bfc35d5b114c56e7945614ba76efa4e513b1db9c38b0ff9c3d" + +SRC_URI += "file://rsyslog.conf \ + file://rsyslog.logrotate \ + file://rotate-event-logs.service \ + file://rotate-event-logs.timer \ + file://rsyslog-override.conf \ +" + +FILES_${PN} += "${systemd_system_unitdir}/rsyslog.service.d/rsyslog-override.conf" + +PACKAGECONFIG_append = " imjournal" + +do_install_append() { + install -m 0644 ${WORKDIR}/rotate-event-logs.service ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/rotate-event-logs.timer ${D}${systemd_system_unitdir} + install -d ${D}${systemd_system_unitdir}/rsyslog.service.d + install -m 0644 ${WORKDIR}/rsyslog-override.conf \ + ${D}${systemd_system_unitdir}/rsyslog.service.d/rsyslog-override.conf + rm ${D}${sysconfdir}/rsyslog.d/imjournal.conf +} + +SYSTEMD_SERVICE_${PN} += " rotate-event-logs.service rotate-event-logs.timer" diff --git a/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend new file mode 100644 index 000000000..a7fefea96 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/sdbusplus/sdbusplus_%.bbappend @@ -0,0 +1,4 @@ + +#SRC_URI += "git://github.com/openbmc/sdbusplus" +SRCREV = "4212292bcf136d04b38ba5116aa568b0fa312798" + 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..0d9012235 --- /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 = "091b9eb739a95c8c969e2e6865c255b0d170f95f" diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Add-flow-control-to-prevent-buffer-over-run.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Add-flow-control-to-prevent-buffer-over-run.patch new file mode 100644 index 000000000..70f2da4a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0001-Add-flow-control-to-prevent-buffer-over-run.patch @@ -0,0 +1,121 @@ +From 88337ce8246a453cd3c6e60e96aead43549a5e1d Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +Date: Thu, 9 May 2019 16:26:53 -0700 +Subject: [PATCH] Add flow control to prevent buffer over run + +This service uses direct frame update with bypassing image +compression and invalidating logic in libvncserver to achieve +better performance by using of H/W compressed JPEG frames as those +come from the video engine driver. + +This behavior helps quick frame update using very small amount of +CPU resources but it causes a side effect which crashes bmcweb +by OOM killer due to a buffer over run issue. Usually, this issue +happens often in a slow speed connection because this service +keeps sending all frames without any handshaking with clients so +a session buffer in the bmcweb gets bigger and bigger since the +low speed connection can't send all stream data on time. + +To fix this issue, this commit adds flow control logic to make +frame updating handshakes with client so that it'll send frames +only when it recieved client frame update messages. All other +frames when the client doesn't request will be dropped out to +prevent the buffer over run issue. + +Tested: +bmcweb didn't keep increasing its KVM session buffer. +KVM worked well with showing good refresh speed. + +resolves https://github.com/openbmc/bmcweb/issues/80 + +Change-Id: I6b09a711137d15a38fce59adada9bf3d00afde86 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +--- + ikvm_server.cpp | 20 ++++++++++++++++++++ + ikvm_server.hpp | 11 +++++++++++ + 2 files changed, 31 insertions(+) + +diff --git a/ikvm_server.cpp b/ikvm_server.cpp +index 35310da292be..dfafe3a82e64 100644 +--- a/ikvm_server.cpp ++++ b/ikvm_server.cpp +@@ -119,6 +119,12 @@ void Server::sendFrame() + continue; + } + ++ if (!cd->needUpdate) ++ { ++ continue; ++ } ++ cd->needUpdate = false; ++ + if (cl->enableLastRectEncoding) + { + fu->nRects = 0xFFFF; +@@ -149,6 +155,19 @@ void Server::sendFrame() + rfbReleaseClientIterator(it); + } + ++void Server::clientFramebufferUpdateRequest( ++ rfbClientPtr cl, rfbFramebufferUpdateRequestMsg *furMsg) ++{ ++ ClientData *cd = (ClientData *)cl->clientData; ++ ++ if (!cd) ++ return; ++ ++ // Ignore the furMsg info. This service uses full frame update always. ++ ++ cd->needUpdate = true; ++} ++ + void Server::clientGone(rfbClientPtr cl) + { + Server* server = (Server*)cl->screen->screenData; +@@ -170,6 +189,7 @@ enum rfbNewClientAction Server::newClient(rfbClientPtr cl) + cl->clientData = + new ClientData(server->video.getFrameRate(), &server->input); + cl->clientGoneHook = clientGone; ++ cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest; + if (!server->numClients++) + { + server->pendingResize = false; +diff --git a/ikvm_server.hpp b/ikvm_server.hpp +index b8062017b8ca..ebe4ad2b287e 100644 +--- a/ikvm_server.hpp ++++ b/ikvm_server.hpp +@@ -32,6 +32,7 @@ class Server + */ + ClientData(int s, Input* i) : skipFrame(s), input(i) + { ++ needUpdate = false; + } + ~ClientData() = default; + ClientData(const ClientData&) = default; +@@ -41,6 +42,7 @@ class Server + + int skipFrame; + Input* input; ++ bool needUpdate; + }; + + /* +@@ -85,6 +87,15 @@ class Server + + private: + /* ++ * @brief Handler for a client frame update message ++ * ++ * @param[in] cl - Handle to the client object ++ * @param[in] furMsg - Pointer of the FUR message ++ */ ++ static void ++ clientFramebufferUpdateRequest(rfbClientPtr cl, ++ rfbFramebufferUpdateRequestMsg *furMsg); ++ /* + * @brief Handler for a client disconnecting + * + * @param[in] cl - Handle to the client object +-- +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..cc18a9b43 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +#SRC_URI = "git://github.com/openbmc/obmc-ikvm" +SRCREV = "95a3b35bf30f730d2bc512bd42aea45746c625e6" + +SRC_URI += "file://0001-Add-flow-control-to-prevent-buffer-over-run.patch" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb new file mode 100644 index 000000000..f727b4536 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb @@ -0,0 +1,24 @@ +SUMMARY = "Chassis Power Control service for Intel based platform" +DESCRIPTION = "Chassis Power Control service for Intel based platfrom" + +SRC_URI = "git://git@github.com/Intel-BMC/intel-chassis-control.git;protocol=ssh" +SRCREV = "b9e1b13e42359baf21592480874a176548071cf2" + +S = "${WORKDIR}/git/services/chassis/" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.Chassis.Control.Power.service" + +DEPENDS += " \ + boost \ + i2c-tools \ + libgpiod \ + sdbusplus \ + phosphor-logging \ + " 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..545ecae7f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb @@ -0,0 +1,17 @@ +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 = "" + +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/bmc_config.xml b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/bmc_config.xml new file mode 100644 index 000000000..9e7d3f82d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/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/csk_prv.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/csk_prv.pem new file mode 100644 index 000000000..a46fa2a2b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/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/csk_pub.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/csk_pub.pem new file mode 100644 index 000000000..cc70d6e28 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/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/pfm_config.xml b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfm_config.xml new file mode 100644 index 000000000..78c816191 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/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/pfr_image.py b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py new file mode 100755 index 000000000..5cda38b79 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py @@ -0,0 +1,374 @@ +#/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, 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 +SHA256 = 0x1 +SHA256_SIZE = 32 +PFM_DEF_SIZE = 16 +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 == 1: + 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): + + 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.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'])) + print(self.image_parts) + + self.act_dgst = hashlib.sha256() + + # 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'])) + print(self.i2c_rules) + + # 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: + hash_dgst = hashlib.sha256() + + 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 = b'\x00' * 32 + hash_pres = 0 + + if hash_flag == 1: + # region's hash + hash = hash_dgst.hexdigest() + hash_pres = SHA256 + 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: + print(i[0], i[1], i[2], i[3]) + 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 = 128 - (self.pfm_bytes % 128) + self.pfm_bytes += padding_bytes + parts['pfm_len'] = struct.pack('<I', self.pfm_bytes) + print("PFM size={}".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 == 1: + f.write(i.spi_hash.decode('hex')) + + 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) != 6: #< pfr_image.py manifest.json> <update.bin> <build_version> <build_number> <build_hash> + print('usage: {} <manifest.json> <firmware.bin> <build_version> <build_number> <build_hash>'.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] + + # function to generate BMC PFM, PBC header and BMC compressed image + pfr_bmc_image(json_file, firmware_file, build_ver, build_num, build_hash) + +if __name__ == '__main__': + main() diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_manifest.json b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_manifest.json new file mode 100644 index 000000000..adea41eab --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_manifest.json @@ -0,0 +1,120 @@ +{ + "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": "0x3600000", + "prot_mask": 3, + "pfm": 1, + "hash": 0, + "compress": 0 + } + ], + "i2c-rules": [{ + "bus-id": 5, + "rule-id": 1, + "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": 5, + "rule-id": 2, + "address": "0xD6", + "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": 8, + "rule-id": 3, + "address": "0xB0", + "cmd-whitelist": ["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": 8, + "rule-id": 4, + "address": "0xB2", + "cmd-whitelist": ["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"] + } + ] +} diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/rk_prv.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/rk_prv.pem new file mode 100644 index 000000000..9e8616795 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/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/rk_pub.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/rk_pub.pem new file mode 100644 index 000000000..117e08bae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/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..12394dd91 --- /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://git@github.com/Intel-BMC/blocksign;protocol=ssh"
+
+SRCREV = "60d76db038a0d85851098b13451246abb0d876ed"
+
+S = "${WORKDIR}/git/"
+
+do_install_append() {
+ install -d ${STAGING_DIR}/intel-pfr-files
+ install -m 775 ${B}/blocksign ${STAGING_DIR}/intel-pfr-files
+}
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..96bfec0a8 --- /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://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Intel.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..307fe1829 --- /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 manifest and signing key for development and testing"
+DESCRIPTION = "Do not use this signing keys to sign CI and release images."
+
+PR = "r1"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+inherit native
+
+PFR_KEY_NAME ?= "pfr-dev-key"
+PFR_SIGN_UTIL ?= "blocksign"
+DEPENDS += " intel-blocksign-native"
+
+SRC_URI = " \
+ file://pfr_manifest.json \
+ file://pfr_image.py \
+ file://pfm_config.xml \
+ file://bmc_config.xml \
+ file://csk_prv.pem \
+ file://csk_pub.pem \
+ file://rk_pub.pem \
+ file://rk_prv.pem \
+ "
+
+do_install() {
+ bbplain "Copying the intel pfr image generation scripts and image signing keys"
+
+ install -d ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/pfr_manifest.json ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/pfm_config.xml ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/bmc_config.xml ${STAGING_DIR}/intel-pfr-files
+ install -m 775 ${WORKDIR}/pfr_image.py ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/csk_prv.pem ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/csk_pub.pem ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/rk_pub.pem ${STAGING_DIR}/intel-pfr-files
+ install -m 400 ${WORKDIR}/rk_prv.pem ${STAGING_DIR}/intel-pfr-files
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/ipccli/ipccli_svn.bb b/meta-openbmc-mods/meta-common/recipes-intel/ipccli/ipccli_svn.bb new file mode 100644 index 000000000..ce7d79975 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/ipccli/ipccli_svn.bb @@ -0,0 +1,14 @@ +SUMMARY = "ipccli" +HOMEPAGE = "https://www.intel.com" +LICENSE = "CLOSED" +LIC_FILES_CHKSUM = "" + +SRC_URI[md5sum] = "917092bfe4244aa4312b572c2c9c303f" +SRC_URI = "svn://ssvn.pdx.intel.com/deg/pve/csv/pythonsv/subprojects/;module=ipccli;rev=804701;protocol=https;user=etanous;pswd=Cardinal2bali!" + +DEPENDS_${PN} += "python-setuptools-native" + +S = "${WORKDIR}/ipccli/trunk" +inherit setuptools + +BBCLASSEXTEND = "native nativesdk" 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..06cc3b972 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb @@ -0,0 +1,39 @@ +SUMMARY = "OpenBMC for Intel - Applications" +PR = "r1" + +inherit packagegroup + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES = "${PACKAGES}" +PACKAGES = " \ + ${PN}-chassis \ + ${PN}-fans \ + ${PN}-flash \ + ${PN}-system \ + " + +PROVIDES += "virtual/obmc-chassis-mgmt" +PROVIDES += "virtual/obmc-fan-mgmt" +PROVIDES += "virtual/obmc-flash-mgmt" +PROVIDES += "virtual/obmc-system-mgmt" + +RPROVIDES_${PN}-chassis += "virtual-obmc-chassis-mgmt" +RPROVIDES_${PN}-fans += "virtual-obmc-fan-mgmt" +RPROVIDES_${PN}-flash += "virtual-obmc-flash-mgmt" +RPROVIDES_${PN}-system += "virtual-obmc-system-mgmt" + +SUMMARY_${PN}-chassis = "Intel Chassis" +RDEPENDS_${PN}-chassis = " \ + intel-chassis-control \ + obmc-host-failure-reboots \ + " + +SUMMARY_${PN}-fans = "Intel Fans" +RDEPENDS_${PN}-fans = " \ + phosphor-pid-control \ + " + +SUMMARY_${PN}-flash = "Intel Flash" +RDEPENDS_${PN}-flash = "" 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..d3b283202 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend @@ -0,0 +1 @@ +RDEPENDS_${PN}-extrasdevtools = "libgpiod-tools" 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..63576a3de --- /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://git@github.com/Intel-BMC/provingground.git;protocol=ssh;nobranch=1" +SRCREV = "fe33964c744f871f3e024dd8d0b6ffba67394c30" + +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} += "cold-redundancy.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..0f6893ed6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb @@ -0,0 +1,33 @@ +SUMMARY = "SMBIOS MDR version 1 service for Intel based platform" +DESCRIPTION = "SMBIOS MDR version 1 service for Intel based platfrom" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +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..71ac31348 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb @@ -0,0 +1,33 @@ +SUMMARY = "SMBIOS MDR version 2 service for Intel based platform" +DESCRIPTION = "SMBIOS MDR version 2 service for Intel based platfrom" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +S = "${WORKDIR}/git/services/smbios-mdrv2/" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake pkgconfig pythonnative +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "smbios-mdrv2.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service new file mode 100644 index 000000000..b72873406 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service @@ -0,0 +1,12 @@ +[Unit] +Description=Intel BMC SMBIOS MDR V2 + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env smbiosmdrv2app +SyslogIdentifier=smbiosmdrv2app + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-set-idle-disconnect-to-true-in-all-cases.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-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/0001-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/0005-arm-dts-aspeed-g5-add-espi.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch new file mode 100644 index 000000000..165596f25 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch @@ -0,0 +1,56 @@ +From f72d4767835e530ce6bc4673ff30cc1099c88af5 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 | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index dc58eb8c6969..db82f47339aa 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -283,7 +283,7 @@ + #gpio-cells = <2>; + gpio-controller; + compatible = "aspeed,ast2500-gpio"; +- reg = <0x1e780000 0x1000>; ++ reg = <0x1e780000 0x0200>; + interrupts = <20>; + gpio-ranges = <&pinctrl 0 0 220>; + clocks = <&syscon ASPEED_CLK_APB>; +@@ -291,6 +291,15 @@ + #interrupt-cells = <2>; + }; + ++ sgpio: sgpio@1e780200 { ++ #gpio-cells = <2>; ++ gpio-controller; ++ compatible = "aspeed,ast2500-sgpio"; ++ reg = <0x1e780200 0x0100>; ++ interrupts = <40>; ++ interrupt-controller; ++ }; ++ + rtc: rtc@1e781000 { + compatible = "aspeed,ast2500-rtc"; + reg = <0x1e781000 0x18>; +@@ -366,6 +375,13 @@ + status = "disabled"; + }; + ++ espi: espi@1e6ee000 { ++ compatible = "aspeed,ast2500-espi-slave"; ++ reg = <0x1e6ee000 0x100>; ++ interrupts = <23>; ++ status = "disabled"; ++ }; ++ + lpc: lpc@1e789000 { + compatible = "aspeed,ast2500-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch new file mode 100644 index 000000000..695491d28 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-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/0008-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch new file mode 100644 index 000000000..146a725dd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch @@ -0,0 +1,764 @@ +From e6923abbc90b5b00bc9ea401fbb2a28971d19cbe 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] gpio: aspeed: 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 | 708 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 717 insertions(+) + create mode 100644 drivers/gpio/sgpio-aspeed.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index acd40eb51c46..20808e48229a 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -124,6 +124,14 @@ config GPIO_ASPEED + help + Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. + ++config SGPIO_ASPEED ++ bool "ASPEED SGPIO support" ++ depends on ARCH_ASPEED ++ select GPIO_GENERIC ++ select GPIOLIB_IRQCHIP ++ help ++ Say Y here to support ASPEED SGPIO functionality. ++ + config GPIO_ATH79 + tristate "Atheros AR71XX/AR724X/AR913X GPIO support" + default y if ATH79 +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 6700eee860b7..77c6ec0ee98f 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_ATH79) += gpio-ath79.o + obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o ++obj-$(CONFIG_SGPIO_ASPEED) += sgpio-aspeed.o + obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o + obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o + obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o +diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c +new file mode 100644 +index 000000000000..6fb402a3f74d +--- /dev/null ++++ b/drivers/gpio/sgpio-aspeed.c +@@ -0,0 +1,708 @@ ++// 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; ++ spinlock_t lock; ++ void __iomem *base; ++ int irq; ++ const struct aspeed_sgpio_config *config; ++ ++ u32 *dcache; ++}; ++ ++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; ++ ++ 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, ®, 32) { ++ girq = irq_find_mapping(gc->irq.domain, i * 32 + p); ++ generic_handle_irq(girq); ++ } ++ } ++ ++ chained_irq_exit(ic, desc); ++} ++ ++static struct irq_chip aspeed_sgpio_irqchip = { ++ .name = "aspeed-sgpio", ++ .irq_ack = aspeed_sgpio_irq_ack, ++ .irq_mask = aspeed_sgpio_irq_mask, ++ .irq_unmask = aspeed_sgpio_irq_unmask, ++ .irq_set_type = aspeed_sgpio_set_type, ++}; ++ ++static void set_irq_valid_mask(struct aspeed_sgpio *gpio) ++{ ++ 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->config->nr_gpios) ++ break; ++ ++ clear_bit(i, gpio->chip.irq.valid_mask); ++ } ++ ++ props++; ++ } ++} ++ ++static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, ++ struct platform_device *pdev) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ 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; ++ ++ set_irq_valid_mask(gpio); ++ ++ rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_sgpio_irqchip, ++ 0, handle_bad_irq, IRQ_TYPE_NONE); ++ if (rc) { ++ dev_info(&pdev->dev, "Could not add irqchip\n"); ++ return rc; ++ } ++ ++ gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_sgpio_irqchip, ++ gpio->irq, aspeed_sgpio_irq_handler); ++ ++ 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 }, ++ { } ++}; ++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, banks; ++ ++ 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)) { ++ dev_err(&pdev->dev, "Failed to get clk source.\n"); ++ return PTR_ERR(clk); ++ } ++ ++ /* ++ * 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; ++ gpio->chip.irq.need_valid_mask = true; ++ ++ /* Allocate a cache of the output registers */ ++ banks = gpio->config->nr_gpios >> 5; ++ ++ gpio->dcache = devm_kcalloc(&pdev->dev, ++ banks, sizeof(u32), GFP_KERNEL); ++ ++ if (!gpio->dcache) ++ return -ENOMEM; ++ ++ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); ++ if (rc < 0) ++ return rc; ++ ++ return aspeed_sgpio_setup_irqs(gpio, pdev); ++} ++ ++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/0009-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch new file mode 100644 index 000000000..4210d9f67 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch @@ -0,0 +1,244 @@ +From 0f63ecc25766fdf66610d08441e59147a4cbde78 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 | 10 ++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 ++++++++++++------------- + drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 4 +++ + 4 files changed, 58 insertions(+), 60 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index fd857be397bf..58306a8232c9 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -207,6 +207,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"; +@@ -1180,44 +1194,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 db82f47339aa..425a542690de 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -298,6 +298,11 @@ + 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"; + }; + + rtc: rtc@1e781000 { +@@ -1403,6 +1408,11 @@ + groups = "SDA2"; + }; + ++ pinctrl_sgpm_default: sgpm_default { ++ function = "SGPM"; ++ groups = "SGPM"; ++ }; ++ + pinctrl_sgps1_default: sgps1_default { + function = "SGPS1"; + groups = "SGPS1"; +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +index 384396cbb22d..a78ed8c33e96 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +@@ -423,16 +423,22 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30)); + SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31)); + + #define A14 48 +-SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPSCK, SGPS, SIG_DESC_SET(SCU84, 0)); ++SS_PIN_DECL(A14, GPIOG0, SGPSCK); + + #define E13 49 +-SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPSLD, SGPS, SIG_DESC_SET(SCU84, 1)); ++SS_PIN_DECL(E13, GPIOG1, SGPSLD); + + #define D13 50 +-SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPSIO, SGPS, SIG_DESC_SET(SCU84, 2)); ++SS_PIN_DECL(D13, GPIOG2, SGPSIO); + + #define C13 51 +-SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPSI1, SGPS, SIG_DESC_SET(SCU84, 3)); ++SS_PIN_DECL(C13, GPIOG3, SGPSI1); ++ ++FUNC_GROUP_DECL(SGPS, A14, E13, D13, C13); + + #define B13 52 + SIG_EXPR_LIST_DECL_SINGLE(OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1)); +@@ -598,16 +604,22 @@ FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20); + FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20); + + #define J5 72 +-SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8)); ++SS_PIN_DECL(J5, GPIOJ0, SGPMCK); + + #define J4 73 +-SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9)); ++SS_PIN_DECL(J4, GPIOJ1, SGPMLD); + + #define K5 74 +-SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPMO, SGPM, SIG_DESC_SET(SCU84, 10)); ++SS_PIN_DECL(K5, GPIOJ2, SGPMO); + + #define J3 75 +-SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11)); ++SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); ++SS_PIN_DECL(J3, GPIOJ3, SGPMI); ++ ++FUNC_GROUP_DECL(SGPM, J5, J4, K5, J3); + + #define T4 76 + SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, SIG_DESC_SET(SCU84, 12)); +@@ -2105,14 +2117,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), +@@ -2260,14 +2266,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { + ASPEED_PINCTRL_FUNC(SALT4), + ASPEED_PINCTRL_FUNC(SD1), + ASPEED_PINCTRL_FUNC(SD2), +- ASPEED_PINCTRL_FUNC(SGPMCK), +- ASPEED_PINCTRL_FUNC(SGPMI), +- ASPEED_PINCTRL_FUNC(SGPMLD), +- ASPEED_PINCTRL_FUNC(SGPMO), +- ASPEED_PINCTRL_FUNC(SGPSCK), +- ASPEED_PINCTRL_FUNC(SGPSI0), +- ASPEED_PINCTRL_FUNC(SGPSI1), +- ASPEED_PINCTRL_FUNC(SGPSLD), ++ ASPEED_PINCTRL_FUNC(SGPM), ++ ASPEED_PINCTRL_FUNC(SGPS), + ASPEED_PINCTRL_FUNC(SIOONCTRL), + ASPEED_PINCTRL_FUNC(SIOPBI), + ASPEED_PINCTRL_FUNC(SIOPBO), +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index 6f151e7c8d81..c088f010c554 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -599,6 +599,8 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO); + SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); + SS_PIN_DECL(N4, GPIOJ3, SGPMI); + ++FUNC_GROUP_DECL(SGPM, R2, L2, N3, N4); ++ + #define N5 76 + SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12)); + SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8)); +@@ -2149,6 +2151,7 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = { + ASPEED_PINCTRL_GROUP(SD2), + ASPEED_PINCTRL_GROUP(SDA1), + ASPEED_PINCTRL_GROUP(SDA2), ++ ASPEED_PINCTRL_GROUP(SGPM), + ASPEED_PINCTRL_GROUP(SGPS1), + ASPEED_PINCTRL_GROUP(SGPS2), + ASPEED_PINCTRL_GROUP(SIOONCTRL), +@@ -2318,6 +2321,7 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = { + ASPEED_PINCTRL_FUNC(SD2), + ASPEED_PINCTRL_FUNC(SDA1), + ASPEED_PINCTRL_FUNC(SDA2), ++ ASPEED_PINCTRL_FUNC(SGPM), + ASPEED_PINCTRL_FUNC(SGPS1), + ASPEED_PINCTRL_FUNC(SGPS2), + ASPEED_PINCTRL_FUNC(SIOONCTRL), +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch new file mode 100644 index 000000000..329a92cd6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch @@ -0,0 +1,5566 @@ +From 691b8580a1592eddb919e8dd295e6c1f136a4c00 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 7 Jan 2019 09:56:10 -0800 +Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version + +Upstreaming is in holding. It's for adding DTS sensor with PECI +subsystem code update. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + Documentation/hwmon/peci-cputemp | 34 +- + drivers/hwmon/Kconfig | 4 +- + drivers/hwmon/peci-cputemp.c | 171 ++++--- + drivers/hwmon/peci-dimmtemp.c | 184 +++++-- + drivers/hwmon/peci-hwmon.h | 9 +- + drivers/mfd/Kconfig | 5 +- + drivers/mfd/intel-peci-client.c | 51 +- + drivers/peci/Kconfig | 46 +- + drivers/peci/Makefile | 7 +- + drivers/peci/busses/Kconfig | 32 ++ + drivers/peci/busses/Makefile | 7 + + drivers/peci/busses/peci-aspeed.c | 492 ++++++++++++++++++ + drivers/peci/busses/peci-npcm.c | 410 +++++++++++++++ + drivers/peci/peci-aspeed.c | 505 ------------------- + drivers/peci/peci-core.c | 914 ++++++++++++++++++---------------- + drivers/peci/peci-dev.c | 346 +++++++++++++ + drivers/peci/peci-npcm.c | 410 --------------- + include/linux/mfd/intel-peci-client.h | 31 +- + include/linux/peci.h | 30 +- + include/uapi/linux/peci-ioctl.h | 416 +++++++++------- + 20 files changed, 2402 insertions(+), 1702 deletions(-) + create mode 100644 drivers/peci/busses/Kconfig + create mode 100644 drivers/peci/busses/Makefile + create mode 100644 drivers/peci/busses/peci-aspeed.c + create mode 100644 drivers/peci/busses/peci-npcm.c + delete mode 100644 drivers/peci/peci-aspeed.c + create mode 100644 drivers/peci/peci-dev.c + delete mode 100644 drivers/peci/peci-npcm.c + +diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp +index 821a9258f2e6..a3a3e465c888 100644 +--- a/Documentation/hwmon/peci-cputemp ++++ b/Documentation/hwmon/peci-cputemp +@@ -51,28 +51,38 @@ temp1_crit Provides shutdown temperature of the CPU package which + temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of + the CPU package. + +-temp2_label "Tcontrol" +-temp2_input Provides current Tcontrol temperature of the CPU ++temp2_label "DTS" ++temp2_input Provides current DTS temperature of the CPU package. ++temp2_max Provides thermal control temperature of the CPU package ++ which is also known as Tcontrol. ++temp2_crit Provides shutdown temperature of the CPU package which ++ is also known as the maximum processor junction ++ temperature, Tjmax or Tprochot. ++temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of ++ the CPU package. ++ ++temp3_label "Tcontrol" ++temp3_input Provides current Tcontrol temperature of the CPU + package which is also known as Fan Temperature target. + Indicates the relative value from thermal monitor trip + temperature at which fans should be engaged. +-temp2_crit Provides Tcontrol critical value of the CPU package ++temp3_crit Provides Tcontrol critical value of the CPU package + which is same to Tjmax. + +-temp3_label "Tthrottle" +-temp3_input Provides current Tthrottle temperature of the CPU ++temp4_label "Tthrottle" ++temp4_input Provides current Tthrottle temperature of the CPU + package. Used for throttling temperature. If this value + is allowed and lower than Tjmax - the throttle will + occur and reported at lower than Tjmax. + +-temp4_label "Tjmax" +-temp4_input Provides the maximum junction temperature, Tjmax of the ++temp5_label "Tjmax" ++temp5_input Provides the maximum junction temperature, Tjmax of the + CPU package. + +-temp[5-*]_label Provides string "Core X", where X is resolved core ++temp[6-*]_label Provides string "Core X", where X is resolved core + number. +-temp[5-*]_input Provides current temperature of each core. +-temp[5-*]_max Provides thermal control temperature of the core. +-temp[5-*]_crit Provides shutdown temperature of the core. +-temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of ++temp[6-*]_input Provides current temperature of each core. ++temp[6-*]_max Provides thermal control temperature of the core. ++temp[6-*]_crit Provides shutdown temperature of the core. ++temp[6-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of + the core. +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index c0623fa5ba41..7399c3cef30c 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1333,7 +1333,7 @@ config SENSORS_PECI_CPUTEMP + the PECI Client Command Suite via the processor PECI client. + Check Documentation/hwmon/peci-cputemp for details. + +- This driver can also be built as a module. If so, the module ++ This driver can also be built as a module. If so, the module + will be called peci-cputemp. + + config SENSORS_PECI_DIMMTEMP +@@ -1347,7 +1347,7 @@ config SENSORS_PECI_DIMMTEMP + Suite via the processor PECI client. + Check Documentation/hwmon/peci-dimmtemp for details. + +- This driver can also be built as a module. If so, the module ++ This driver can also be built as a module. If so, the module + will be called peci-dimmtemp. + + source "drivers/hwmon/pmbus/Kconfig" +diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c +index 11880c86a854..d0d68e88889f 100644 +--- a/drivers/hwmon/peci-cputemp.c ++++ b/drivers/hwmon/peci-cputemp.c +@@ -1,5 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include <linux/hwmon.h> + #include <linux/jiffies.h> +@@ -9,18 +9,13 @@ + #include <linux/platform_device.h> + #include "peci-hwmon.h" + +-#define DEFAULT_CHANNEL_NUMS 4 ++#define DEFAULT_CHANNEL_NUMS 5 + #define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX + #define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS) + +-/* The RESOLVED_CORES register in PCU of a client CPU */ +-#define REG_RESOLVED_CORES_BUS 1 +-#define REG_RESOLVED_CORES_DEVICE 30 +-#define REG_RESOLVED_CORES_FUNCTION 3 +-#define REG_RESOLVED_CORES_OFFSET 0xB4 +- + struct temp_group { + struct temp_data die; ++ struct temp_data dts; + struct temp_data tcontrol; + struct temp_data tthrottle; + struct temp_data tjmax; +@@ -43,6 +38,7 @@ struct peci_cputemp { + + enum cputemp_channels { + channel_die, ++ channel_dts, + channel_tcontrol, + channel_tthrottle, + channel_tjmax, +@@ -54,6 +50,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { + HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + ++ /* DTS margin */ ++ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_CRIT_HYST, ++ + /* Tcontrol temperature */ + HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT, + +@@ -70,6 +70,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { + + static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = { + "Die", ++ "DTS", + "Tcontrol", + "Tthrottle", + "Tjmax", +@@ -92,19 +93,20 @@ static int get_temp_targets(struct peci_cputemp *priv) + s32 tthrottle_offset; + s32 tcontrol_margin; + u8 pkg_cfg[4]; +- int rc; ++ int ret; + +- /** ++ /* + * Just use only the tcontrol marker to determine if target values need + * update. + */ + if (!peci_temp_need_update(&priv->temp.tcontrol)) + return 0; + +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_TEMP_TARGET, 0, pkg_cfg); +- if (rc) +- return rc; ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_TEMP_TARGET, 0, ++ pkg_cfg); ++ if (ret) ++ return ret; + + priv->temp.tjmax.value = pkg_cfg[2] * 1000; + +@@ -123,17 +125,16 @@ static int get_temp_targets(struct peci_cputemp *priv) + static int get_die_temp(struct peci_cputemp *priv) + { + struct peci_get_temp_msg msg; +- int rc; ++ int ret; + + if (!peci_temp_need_update(&priv->temp.die)) + return 0; + + msg.addr = priv->mgr->client->addr; + +- rc = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, +- &msg); +- if (rc) +- return rc; ++ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, &msg); ++ if (ret) ++ return ret; + + /* Note that the tjmax should be available before calling it */ + priv->temp.die.value = priv->temp.tjmax.value + +@@ -144,24 +145,64 @@ static int get_die_temp(struct peci_cputemp *priv) + return 0; + } + ++static int get_dts(struct peci_cputemp *priv) ++{ ++ s32 dts_margin; ++ u8 pkg_cfg[4]; ++ int ret; ++ ++ if (!peci_temp_need_update(&priv->temp.dts)) ++ return 0; ++ ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_DTS_MARGIN, 0, ++ pkg_cfg); ++ ++ if (ret) ++ return ret; ++ ++ dts_margin = (pkg_cfg[1] << 8) | pkg_cfg[0]; ++ ++ /** ++ * Processors return a value of DTS reading in 10.6 format ++ * (10 bits signed decimal, 6 bits fractional). ++ * Error codes: ++ * 0x8000: General sensor error ++ * 0x8001: Reserved ++ * 0x8002: Underflow on reading value ++ * 0x8003-0x81ff: Reserved ++ */ ++ if (dts_margin >= 0x8000 && dts_margin <= 0x81ff) ++ return -EIO; ++ ++ dts_margin = ten_dot_six_to_millidegree(dts_margin); ++ ++ /* Note that the tcontrol should be available before calling it */ ++ priv->temp.dts.value = priv->temp.tcontrol.value - dts_margin; ++ ++ peci_temp_mark_updated(&priv->temp.dts); ++ ++ return 0; ++} ++ + static int get_core_temp(struct peci_cputemp *priv, int core_index) + { + s32 core_dts_margin; + u8 pkg_cfg[4]; +- int rc; ++ int ret; + + if (!peci_temp_need_update(&priv->temp.core[core_index])) + return 0; + +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_PER_CORE_DTS_TEMP, +- core_index, pkg_cfg); +- if (rc) +- return rc; ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_PER_CORE_DTS_TEMP, ++ core_index, pkg_cfg); ++ if (ret) ++ return ret; + + core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg); + +- /** ++ /* + * Processors return a value of the core DTS reading in 10.6 format + * (10 bits signed decimal, 6 bits fractional). + * Error codes: +@@ -192,6 +233,7 @@ static int cputemp_read_string(struct device *dev, + return -EOPNOTSUPP; + + *str = cputemp_label[channel]; ++ + return 0; + } + +@@ -200,26 +242,33 @@ static int cputemp_read(struct device *dev, + u32 attr, int channel, long *val) + { + struct peci_cputemp *priv = dev_get_drvdata(dev); +- int rc, core_index; ++ int ret, core_index; + + if (channel >= CPUTEMP_CHANNEL_NUMS || + !(priv->temp_config[channel] & BIT(attr))) + return -EOPNOTSUPP; + +- rc = get_temp_targets(priv); +- if (rc) +- return rc; ++ ret = get_temp_targets(priv); ++ if (ret) ++ return ret; + + switch (attr) { + case hwmon_temp_input: + switch (channel) { + case channel_die: +- rc = get_die_temp(priv); +- if (rc) ++ ret = get_die_temp(priv); ++ if (ret) + break; + + *val = priv->temp.die.value; + break; ++ case channel_dts: ++ ret = get_dts(priv); ++ if (ret) ++ break; ++ ++ *val = priv->temp.dts.value; ++ break; + case channel_tcontrol: + *val = priv->temp.tcontrol.value; + break; +@@ -231,8 +280,8 @@ static int cputemp_read(struct device *dev, + break; + default: + core_index = channel - DEFAULT_CHANNEL_NUMS; +- rc = get_core_temp(priv, core_index); +- if (rc) ++ ret = get_core_temp(priv, core_index); ++ if (ret) + break; + + *val = priv->temp.core[core_index].value; +@@ -249,11 +298,11 @@ static int cputemp_read(struct device *dev, + *val = priv->temp.tjmax.value - priv->temp.tcontrol.value; + break; + default: +- rc = -EOPNOTSUPP; ++ ret = -EOPNOTSUPP; + break; + } + +- return rc; ++ return ret; + } + + static umode_t cputemp_is_visible(const void *data, +@@ -262,11 +311,11 @@ static umode_t cputemp_is_visible(const void *data, + { + const struct peci_cputemp *priv = data; + +- if (priv->temp_config[channel] & BIT(attr)) +- if (channel < DEFAULT_CHANNEL_NUMS || +- (channel >= DEFAULT_CHANNEL_NUMS && +- (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS)))) +- return 0444; ++ if ((priv->temp_config[channel] & BIT(attr)) && ++ (channel < DEFAULT_CHANNEL_NUMS || ++ (channel >= DEFAULT_CHANNEL_NUMS && ++ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))) ++ return 0444; + + return 0; + } +@@ -280,40 +329,43 @@ static const struct hwmon_ops cputemp_ops = { + static int check_resolved_cores(struct peci_cputemp *priv) + { + struct peci_rd_pci_cfg_local_msg msg; +- int rc; ++ int ret; + + /* Get the RESOLVED_CORES register value */ + msg.addr = priv->mgr->client->addr; +- msg.bus = REG_RESOLVED_CORES_BUS; +- msg.device = REG_RESOLVED_CORES_DEVICE; +- msg.function = REG_RESOLVED_CORES_FUNCTION; +- msg.reg = REG_RESOLVED_CORES_OFFSET; ++ msg.bus = 1; ++ msg.device = 30; ++ msg.function = 3; ++ msg.reg = 0xb4; + msg.rx_len = 4; + +- rc = peci_command(priv->mgr->client->adapter, +- PECI_CMD_RD_PCI_CFG_LOCAL, &msg); +- if (rc) +- return rc; ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &msg); ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; + + priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config); + if (!priv->core_mask) + return -EAGAIN; + + dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask); ++ + return 0; + } + + static int create_core_temp_info(struct peci_cputemp *priv) + { +- int rc, i; ++ int ret, i; + +- rc = check_resolved_cores(priv); +- if (rc) +- return rc; ++ ret = check_resolved_cores(priv); ++ if (ret) ++ return ret; + + for (i = 0; i < priv->gen_info->core_max; i++) + if (priv->core_mask & BIT(i)) +- while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx) ++ while (priv->config_idx <= i + DEFAULT_CHANNEL_NUMS) + priv->temp_config[priv->config_idx++] = + config_table[channel_core]; + +@@ -326,7 +378,7 @@ static int peci_cputemp_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct peci_cputemp *priv; + struct device *hwmon_dev; +- int rc; ++ int ret; + + if ((mgr->client->adapter->cmd_mask & + (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != +@@ -346,12 +398,13 @@ static int peci_cputemp_probe(struct platform_device *pdev) + mgr->client->addr - PECI_BASE_ADDR); + + priv->temp_config[priv->config_idx++] = config_table[channel_die]; ++ priv->temp_config[priv->config_idx++] = config_table[channel_dts]; + priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol]; + priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle]; + priv->temp_config[priv->config_idx++] = config_table[channel_tjmax]; + +- rc = create_core_temp_info(priv); +- if (rc) ++ ret = create_core_temp_info(priv); ++ if (ret) + dev_dbg(dev, "Skipped creating core temp info\n"); + + priv->chip.ops = &cputemp_ops; +@@ -385,7 +438,7 @@ MODULE_DEVICE_TABLE(platform, peci_cputemp_ids); + static struct platform_driver peci_cputemp_driver = { + .probe = peci_cputemp_probe, + .id_table = peci_cputemp_ids, +- .driver = { .name = "peci-cputemp", }, ++ .driver = { .name = KBUILD_MODNAME, }, + }; + module_platform_driver(peci_cputemp_driver); + +diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c +index 86a45a90805b..a404b6ea4ba3 100644 +--- a/drivers/hwmon/peci-dimmtemp.c ++++ b/drivers/hwmon/peci-dimmtemp.c +@@ -1,5 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include <linux/hwmon.h> + #include <linux/jiffies.h> +@@ -21,6 +21,8 @@ struct peci_dimmtemp { + struct workqueue_struct *work_queue; + struct delayed_work work_handler; + struct temp_data temp[DIMM_NUMS_MAX]; ++ long temp_max[DIMM_NUMS_MAX]; ++ long temp_crit[DIMM_NUMS_MAX]; + u32 dimm_mask; + int retry_count; + u32 temp_config[DIMM_NUMS_MAX + 1]; +@@ -44,20 +46,106 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no) + { + int dimm_order = dimm_no % priv->gen_info->dimm_idx_max; + int chan_rank = dimm_no / priv->gen_info->dimm_idx_max; ++ struct peci_rd_pci_cfg_local_msg rp_msg; + u8 cfg_data[4]; +- int rc; ++ int ret; + + if (!peci_temp_need_update(&priv->temp[dimm_no])) + return 0; + +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_DDR_DIMM_TEMP, +- chan_rank, cfg_data); +- if (rc) +- return rc; ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_DDR_DIMM_TEMP, ++ chan_rank, cfg_data); ++ if (ret) ++ return ret; + + priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000; + ++ switch (priv->gen_info->model) { ++ case INTEL_FAM6_SKYLAKE_X: ++ rp_msg.addr = priv->mgr->client->addr; ++ rp_msg.bus = 2; ++ /* ++ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 ++ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 ++ * Device 11, Function 2: IMC 0 channel 2 -> rank 2 ++ * Device 12, Function 2: IMC 1 channel 0 -> rank 3 ++ * Device 12, Function 6: IMC 1 channel 1 -> rank 4 ++ * Device 13, Function 2: IMC 1 channel 2 -> rank 5 ++ */ ++ rp_msg.device = 10 + chan_rank / 3 * 2 + ++ (chan_rank % 3 == 2 ? 1 : 0); ++ rp_msg.function = chan_rank % 3 == 1 ? 6 : 2; ++ rp_msg.reg = 0x120 + dimm_order * 4; ++ rp_msg.rx_len = 4; ++ ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); ++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; ++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; ++ break; ++ case INTEL_FAM6_SKYLAKE_XD: ++ rp_msg.addr = priv->mgr->client->addr; ++ rp_msg.bus = 2; ++ /* ++ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 ++ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 ++ * Device 12, Function 2: IMC 1 channel 0 -> rank 2 ++ * Device 12, Function 6: IMC 1 channel 1 -> rank 3 ++ */ ++ rp_msg.device = 10 + chan_rank / 2 * 2; ++ rp_msg.function = chan_rank % 2 ? 6 : 2; ++ rp_msg.reg = 0x120 + dimm_order * 4; ++ rp_msg.rx_len = 4; ++ ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); ++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; ++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; ++ break; ++ case INTEL_FAM6_HASWELL_X: ++ case INTEL_FAM6_BROADWELL_X: ++ rp_msg.addr = priv->mgr->client->addr; ++ rp_msg.bus = 1; ++ /* ++ * Device 20, Function 0: IMC 0 channel 0 -> rank 0 ++ * Device 20, Function 1: IMC 0 channel 1 -> rank 1 ++ * Device 21, Function 0: IMC 0 channel 2 -> rank 2 ++ * Device 21, Function 1: IMC 0 channel 3 -> rank 3 ++ * Device 23, Function 0: IMC 1 channel 0 -> rank 4 ++ * Device 23, Function 1: IMC 1 channel 1 -> rank 5 ++ * Device 24, Function 0: IMC 1 channel 2 -> rank 6 ++ * Device 24, Function 1: IMC 1 channel 3 -> rank 7 ++ */ ++ rp_msg.device = 20 + chan_rank / 2 + chan_rank / 4; ++ rp_msg.function = chan_rank % 2; ++ rp_msg.reg = 0x120 + dimm_order * 4; ++ rp_msg.rx_len = 4; ++ ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); ++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; ++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ + peci_temp_mark_updated(&priv->temp[dimm_no]); + + return 0; +@@ -77,6 +165,7 @@ static int dimmtemp_read_string(struct device *dev, + chan_rank = channel / dimm_idx_max; + dimm_idx = channel % dimm_idx_max; + *str = dimmtemp_label[chan_rank][dimm_idx]; ++ + return 0; + } + +@@ -84,17 +173,28 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) + { + struct peci_dimmtemp *priv = dev_get_drvdata(dev); +- int rc; +- +- if (attr != hwmon_temp_input) +- return -EOPNOTSUPP; +- +- rc = get_dimm_temp(priv, channel); +- if (rc) +- return rc; ++ int ret; ++ ++ ret = get_dimm_temp(priv, channel); ++ if (ret) ++ return ret; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ *val = priv->temp[channel].value; ++ break; ++ case hwmon_temp_max: ++ *val = priv->temp_max[channel]; ++ break; ++ case hwmon_temp_crit: ++ *val = priv->temp_crit[channel]; ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } + +- *val = priv->temp[channel].value; +- return 0; ++ return ret; + } + + static umode_t dimmtemp_is_visible(const void *data, +@@ -120,16 +220,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) + { + u32 chan_rank_max = priv->gen_info->chan_rank_max; + u32 dimm_idx_max = priv->gen_info->dimm_idx_max; +- int chan_rank, dimm_idx, rc; ++ int chan_rank, dimm_idx, ret; + u8 cfg_data[4]; + + for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) { +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_DDR_DIMM_TEMP, +- chan_rank, cfg_data); +- if (rc) { ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_DDR_DIMM_TEMP, ++ chan_rank, cfg_data); ++ if (ret) { + priv->dimm_mask = 0; +- return rc; ++ return ret; + } + + for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++) +@@ -143,17 +243,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) + return -EAGAIN; + + dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask); ++ + return 0; + } + + static int create_dimm_temp_info(struct peci_dimmtemp *priv) + { +- int rc, i, config_idx, channels; ++ int ret, i, config_idx, channels; + struct device *hwmon_dev; + +- rc = check_populated_dimms(priv); +- if (rc) { +- if (rc == -EAGAIN) { ++ ret = check_populated_dimms(priv); ++ if (ret) { ++ if (ret == -EAGAIN) { + if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) { + queue_delayed_work(priv->work_queue, + &priv->work_handler, +@@ -164,11 +265,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) + } else { + dev_err(priv->dev, + "Timeout DIMM temp info creation\n"); +- rc = -ETIMEDOUT; ++ ret = -ETIMEDOUT; + } + } + +- return rc; ++ return ret; + } + + channels = priv->gen_info->chan_rank_max * +@@ -177,7 +278,8 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) + if (priv->dimm_mask & BIT(i)) + while (i >= config_idx) + priv->temp_config[config_idx++] = +- HWMON_T_LABEL | HWMON_T_INPUT; ++ HWMON_T_LABEL | HWMON_T_INPUT | ++ HWMON_T_MAX | HWMON_T_CRIT; + + priv->chip.ops = &dimmtemp_ops; + priv->chip.info = priv->info; +@@ -192,12 +294,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) + priv, + &priv->chip, + NULL); +- rc = PTR_ERR_OR_ZERO(hwmon_dev); +- if (!rc) ++ ret = PTR_ERR_OR_ZERO(hwmon_dev); ++ if (!ret) + dev_dbg(priv->dev, "%s: sensor '%s'\n", + dev_name(hwmon_dev), priv->name); + +- return rc; ++ return ret; + } + + static void create_dimm_temp_info_delayed(struct work_struct *work) +@@ -205,10 +307,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work) + struct delayed_work *dwork = to_delayed_work(work); + struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp, + work_handler); +- int rc; ++ int ret; + +- rc = create_dimm_temp_info(priv); +- if (rc && rc != -EAGAIN) ++ ret = create_dimm_temp_info(priv); ++ if (ret && ret != -EAGAIN) + dev_dbg(priv->dev, "Failed to create DIMM temp info\n"); + } + +@@ -217,7 +319,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) + struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct peci_dimmtemp *priv; +- int rc; ++ int ret; + + if ((mgr->client->adapter->cmd_mask & + (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != +@@ -242,8 +344,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) + + INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed); + +- rc = create_dimm_temp_info(priv); +- if (rc && rc != -EAGAIN) { ++ ret = create_dimm_temp_info(priv); ++ if (ret && ret != -EAGAIN) { + dev_err(dev, "Failed to create DIMM temp info\n"); + goto err_free_wq; + } +@@ -252,7 +354,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) + + err_free_wq: + destroy_workqueue(priv->work_queue); +- return rc; ++ return ret; + } + + static int peci_dimmtemp_remove(struct platform_device *pdev) +@@ -275,7 +377,7 @@ static struct platform_driver peci_dimmtemp_driver = { + .probe = peci_dimmtemp_probe, + .remove = peci_dimmtemp_remove, + .id_table = peci_dimmtemp_ids, +- .driver = { .name = "peci-dimmtemp", }, ++ .driver = { .name = KBUILD_MODNAME, }, + }; + module_platform_driver(peci_dimmtemp_driver); + +diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h +index 6ca1855a86bb..ce6b470eae63 100644 +--- a/drivers/hwmon/peci-hwmon.h ++++ b/drivers/hwmon/peci-hwmon.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __PECI_HWMON_H + #define __PECI_HWMON_H +@@ -29,11 +29,8 @@ struct temp_data { + */ + static inline bool peci_temp_need_update(struct temp_data *temp) + { +- if (temp->valid && +- time_before(jiffies, temp->last_updated + UPDATE_INTERVAL)) +- return false; +- +- return true; ++ return !temp->valid || ++ time_after(jiffies, temp->last_updated + UPDATE_INTERVAL); + } + + /** +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 75dbcc7da87c..6f7ee4dd08f6 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -616,7 +616,7 @@ config MFD_INTEL_MSIC + devices used in Intel Medfield platforms. + + config MFD_INTEL_PECI_CLIENT +- bool "Intel PECI client" ++ tristate "Intel PECI client" + depends on (PECI || COMPILE_TEST) + select MFD_CORE + help +@@ -629,6 +629,9 @@ config MFD_INTEL_PECI_CLIENT + Additional drivers must be enabled in order to use the functionality + of the device. + ++ This driver can also be built as a module. If so, the module ++ will be called intel-peci-client. ++ + config MFD_IPAQ_MICRO + bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" + depends on SA1100_H3100 || SA1100_H3600 +diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c +index d53e4f1078ac..18bf0af0e09e 100644 +--- a/drivers/mfd/intel-peci-client.c ++++ b/drivers/mfd/intel-peci-client.c +@@ -1,12 +1,12 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include <linux/bitfield.h> + #include <linux/mfd/core.h> + #include <linux/mfd/intel-peci-client.h> + #include <linux/module.h> +-#include <linux/peci.h> + #include <linux/of_device.h> ++#include <linux/peci.h> + + #define CPU_ID_MODEL_MASK GENMASK(7, 4) + #define CPU_ID_FAMILY_MASK GENMASK(11, 8) +@@ -18,12 +18,6 @@ + #define LOWER_BYTE_MASK GENMASK(7, 0) + #define UPPER_BYTE_MASK GENMASK(16, 8) + +-enum cpu_gens { +- CPU_GEN_HSX = 0, /* Haswell Xeon */ +- CPU_GEN_BRX, /* Broadwell Xeon */ +- CPU_GEN_SKX, /* Skylake Xeon */ +-}; +- + static struct mfd_cell peci_functions[] = { + { .name = "peci-cputemp", }, + { .name = "peci-dimmtemp", }, +@@ -31,38 +25,45 @@ static struct mfd_cell peci_functions[] = { + }; + + static const struct cpu_gen_info cpu_gen_info_table[] = { +- [CPU_GEN_HSX] = { ++ { /* Haswell Xeon */ + .family = 6, /* Family code */ + .model = INTEL_FAM6_HASWELL_X, + .core_max = CORE_MAX_ON_HSX, + .chan_rank_max = CHAN_RANK_MAX_ON_HSX, + .dimm_idx_max = DIMM_IDX_MAX_ON_HSX }, +- [CPU_GEN_BRX] = { ++ { /* Broadwell Xeon */ + .family = 6, /* Family code */ + .model = INTEL_FAM6_BROADWELL_X, + .core_max = CORE_MAX_ON_BDX, + .chan_rank_max = CHAN_RANK_MAX_ON_BDX, + .dimm_idx_max = DIMM_IDX_MAX_ON_BDX }, +- [CPU_GEN_SKX] = { ++ { /* Skylake Xeon */ + .family = 6, /* Family code */ + .model = INTEL_FAM6_SKYLAKE_X, + .core_max = CORE_MAX_ON_SKX, + .chan_rank_max = CHAN_RANK_MAX_ON_SKX, + .dimm_idx_max = DIMM_IDX_MAX_ON_SKX }, ++ { /* Skylake Xeon D */ ++ .family = 6, /* Family code */ ++ .model = INTEL_FAM6_SKYLAKE_XD, ++ .core_max = CORE_MAX_ON_SKXD, ++ .chan_rank_max = CHAN_RANK_MAX_ON_SKXD, ++ .dimm_idx_max = DIMM_IDX_MAX_ON_SKXD }, + }; + + static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) + { ++ struct device *dev = &priv->client->dev; + u32 cpu_id; + u16 family; + u8 model; +- int rc; ++ int ret; + int i; + +- rc = peci_get_cpu_id(priv->client->adapter, priv->client->addr, +- &cpu_id); +- if (rc) +- return rc; ++ ret = peci_get_cpu_id(priv->client->adapter, priv->client->addr, ++ &cpu_id); ++ if (ret) ++ return ret; + + family = FIELD_PREP(LOWER_BYTE_MASK, + FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) | +@@ -83,11 +84,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) + } + + if (!priv->gen_info) { +- dev_err(priv->dev, "Can't support this CPU: 0x%x\n", cpu_id); +- rc = -ENODEV; ++ dev_err(dev, "Can't support this CPU: 0x%x\n", cpu_id); ++ ret = -ENODEV; + } + +- return rc; ++ return ret; + } + + static int peci_client_probe(struct peci_client *client) +@@ -103,31 +104,29 @@ static int peci_client_probe(struct peci_client *client) + + dev_set_drvdata(dev, priv); + priv->client = client; +- priv->dev = dev; + cpu_no = client->addr - PECI_BASE_ADDR; + + ret = peci_client_get_cpu_gen_info(priv); + if (ret) + return ret; + +- ret = devm_mfd_add_devices(priv->dev, cpu_no, peci_functions, ++ ret = devm_mfd_add_devices(dev, cpu_no, peci_functions, + ARRAY_SIZE(peci_functions), NULL, 0, NULL); + if (ret < 0) { +- dev_err(priv->dev, "Failed to register child devices: %d\n", +- ret); ++ dev_err(dev, "Failed to register child devices: %d\n", ret); + return ret; + } + + return 0; + } + +-#ifdef CONFIG_OF ++#if IS_ENABLED(CONFIG_OF) + static const struct of_device_id peci_client_of_table[] = { + { .compatible = "intel,peci-client" }, + { } + }; + MODULE_DEVICE_TABLE(of, peci_client_of_table); +-#endif ++#endif /* CONFIG_OF */ + + static const struct peci_device_id peci_client_ids[] = { + { .name = "peci-client" }, +@@ -139,7 +138,7 @@ static struct peci_driver peci_client_driver = { + .probe = peci_client_probe, + .id_table = peci_client_ids, + .driver = { +- .name = "peci-client", ++ .name = KBUILD_MODNAME, + .of_match_table = of_match_ptr(peci_client_of_table), + }, + }; +diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig +index 7293108fb543..9752feee2454 100644 +--- a/drivers/peci/Kconfig ++++ b/drivers/peci/Kconfig +@@ -2,10 +2,12 @@ + # Platform Environment Control Interface (PECI) subsystem configuration + # + ++menu "PECI support" ++ + config PECI +- bool "PECI support" +- select RT_MUTEXES ++ tristate "PECI support" + select CRC8 ++ default n + help + The Platform Environment Control Interface (PECI) is a one-wire bus + interface that provides a communication channel from Intel processors +@@ -14,37 +16,23 @@ config PECI + If you want PECI support, you should say Y here and also to the + specific driver for your bus adapter(s) below. + +-if PECI +- +-# +-# PECI hardware bus configuration +-# +- +-menu "PECI Hardware Bus support" +- +-config PECI_ASPEED +- tristate "ASPEED PECI support" +- select REGMAP_MMIO +- depends on OF +- depends on ARCH_ASPEED || COMPILE_TEST +- help +- Say Y here if you want support for the Platform Environment Control +- Interface (PECI) bus adapter driver on the ASPEED SoCs. ++ This support is also available as a module. If so, the module ++ will be called peci-core. + +- This support is also available as a module. If so, the module +- will be called peci-aspeed. ++if PECI + +-config PECI_NPCM +- tristate "Nuvoton NPCM PECI support" +- select REGMAP_MMIO +- depends on OF +- depends on ARCH_NPCM || COMPILE_TEST ++config PECI_CHARDEV ++ tristate "PECI device interface" + help +- Say Y here if you want support for the Platform Environment Control +- Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. ++ Say Y here to use peci-* device files, usually found in the /dev ++ directory on your system. They make it possible to have user-space ++ programs use the PECI bus. + + This support is also available as a module. If so, the module +- will be called peci-npcm. +-endmenu ++ will be called peci-dev. ++ ++source "drivers/peci/busses/Kconfig" + + endif # PECI ++ ++endmenu +diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile +index 3326da54a21a..da8b0a33fa42 100644 +--- a/drivers/peci/Makefile ++++ b/drivers/peci/Makefile +@@ -1,10 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0 + # +-# Makefile for the PECI core and bus drivers. ++# Makefile for the PECI core drivers. + # + + # Core functionality + obj-$(CONFIG_PECI) += peci-core.o ++obj-$(CONFIG_PECI_CHARDEV) += peci-dev.o + + # Hardware specific bus drivers +-obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o +-obj-$(CONFIG_PECI_NPCM) += peci-npcm.o ++obj-y += busses/ +diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig +new file mode 100644 +index 000000000000..bfacafb7a7ba +--- /dev/null ++++ b/drivers/peci/busses/Kconfig +@@ -0,0 +1,32 @@ ++# ++# PECI hardware bus configuration ++# ++ ++menu "PECI Hardware Bus support" ++ ++config PECI_ASPEED ++ tristate "ASPEED PECI support" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ depends on OF ++ depends on PECI ++ help ++ Say Y here if you want support for the Platform Environment Control ++ Interface (PECI) bus adapter driver on the ASPEED SoCs. ++ ++ This support is also available as a module. If so, the module ++ will be called peci-aspeed. ++ ++config PECI_NPCM ++ tristate "Nuvoton NPCM PECI support" ++ select REGMAP_MMIO ++ depends on OF ++ depends on ARCH_NPCM || COMPILE_TEST ++ depends on PECI ++ help ++ Say Y here if you want support for the Platform Environment Control ++ Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. ++ ++ This support is also available as a module. If so, the module ++ will be called peci-npcm. ++ ++endmenu +diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile +new file mode 100644 +index 000000000000..aa8ce3ae5947 +--- /dev/null ++++ b/drivers/peci/busses/Makefile +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for the PECI hardware bus drivers. ++# ++ ++obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o ++obj-$(CONFIG_PECI_NPCM) += peci-npcm.o +diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c +new file mode 100644 +index 000000000000..851b71e32eac +--- /dev/null ++++ b/drivers/peci/busses/peci-aspeed.c +@@ -0,0 +1,492 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) 2012-2017 ASPEED Technology Inc. ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <linux/bitfield.h> ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/jiffies.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/peci.h> ++#include <linux/platform_device.h> ++#include <linux/reset.h> ++ ++/* ASPEED PECI Registers */ ++/* Control Register */ ++#define ASPEED_PECI_CTRL 0x00 ++#define ASPEED_PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) ++#define ASPEED_PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) ++#define ASPEED_PECI_CTRL_READ_MODE_COUNT BIT(12) ++#define ASPEED_PECI_CTRL_READ_MODE_DBG BIT(13) ++#define ASPEED_PECI_CTRL_CLK_SOURCE_MASK BIT(11) ++#define ASPEED_PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) ++#define ASPEED_PECI_CTRL_INVERT_OUT BIT(7) ++#define ASPEED_PECI_CTRL_INVERT_IN BIT(6) ++#define ASPEED_PECI_CTRL_BUS_CONTENT_EN BIT(5) ++#define ASPEED_PECI_CTRL_PECI_EN BIT(4) ++#define ASPEED_PECI_CTRL_PECI_CLK_EN BIT(0) ++ ++/* Timing Negotiation Register */ ++#define ASPEED_PECI_TIMING_NEGOTIATION 0x04 ++#define ASPEED_PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) ++#define ASPEED_PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) ++ ++/* Command Register */ ++#define ASPEED_PECI_CMD 0x08 ++#define ASPEED_PECI_CMD_PIN_MON BIT(31) ++#define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24) ++#define ASPEED_PECI_CMD_IDLE_MASK (ASPEED_PECI_CMD_STS_MASK | \ ++ ASPEED_PECI_CMD_PIN_MON) ++#define ASPEED_PECI_CMD_FIRE BIT(0) ++ ++/* Read/Write Length Register */ ++#define ASPEED_PECI_RW_LENGTH 0x0c ++#define ASPEED_PECI_AW_FCS_EN BIT(31) ++#define ASPEED_PECI_READ_LEN_MASK GENMASK(23, 16) ++#define ASPEED_PECI_WRITE_LEN_MASK GENMASK(15, 8) ++#define ASPEED_PECI_TAGET_ADDR_MASK GENMASK(7, 0) ++ ++/* Expected FCS Data Register */ ++#define ASPEED_PECI_EXP_FCS 0x10 ++#define ASPEED_PECI_EXP_READ_FCS_MASK GENMASK(23, 16) ++#define ASPEED_PECI_EXP_AW_FCS_AUTO_MASK GENMASK(15, 8) ++#define ASPEED_PECI_EXP_WRITE_FCS_MASK GENMASK(7, 0) ++ ++/* Captured FCS Data Register */ ++#define ASPEED_PECI_CAP_FCS 0x14 ++#define ASPEED_PECI_CAP_READ_FCS_MASK GENMASK(23, 16) ++#define ASPEED_PECI_CAP_WRITE_FCS_MASK GENMASK(7, 0) ++ ++/* Interrupt Register */ ++#define ASPEED_PECI_INT_CTRL 0x18 ++#define ASPEED_PECI_TIMING_NEGO_SEL_MASK GENMASK(31, 30) ++#define ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO 0 ++#define ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO 1 ++#define ASPEED_PECI_MESSAGE_NEGO 2 ++#define ASPEED_PECI_INT_MASK GENMASK(4, 0) ++#define ASPEED_PECI_INT_BUS_TIMEOUT BIT(4) ++#define ASPEED_PECI_INT_BUS_CONNECT BIT(3) ++#define ASPEED_PECI_INT_W_FCS_BAD BIT(2) ++#define ASPEED_PECI_INT_W_FCS_ABORT BIT(1) ++#define ASPEED_PECI_INT_CMD_DONE BIT(0) ++ ++/* Interrupt Status Register */ ++#define ASPEED_PECI_INT_STS 0x1c ++#define ASPEED_PECI_INT_TIMING_RESULT_MASK GENMASK(29, 16) ++ /* bits[4..0]: Same bit fields in the 'Interrupt Register' */ ++ ++/* Rx/Tx Data Buffer Registers */ ++#define ASPEED_PECI_W_DATA0 0x20 ++#define ASPEED_PECI_W_DATA1 0x24 ++#define ASPEED_PECI_W_DATA2 0x28 ++#define ASPEED_PECI_W_DATA3 0x2c ++#define ASPEED_PECI_R_DATA0 0x30 ++#define ASPEED_PECI_R_DATA1 0x34 ++#define ASPEED_PECI_R_DATA2 0x38 ++#define ASPEED_PECI_R_DATA3 0x3c ++#define ASPEED_PECI_W_DATA4 0x40 ++#define ASPEED_PECI_W_DATA5 0x44 ++#define ASPEED_PECI_W_DATA6 0x48 ++#define ASPEED_PECI_W_DATA7 0x4c ++#define ASPEED_PECI_R_DATA4 0x50 ++#define ASPEED_PECI_R_DATA5 0x54 ++#define ASPEED_PECI_R_DATA6 0x58 ++#define ASPEED_PECI_R_DATA7 0x5c ++#define ASPEED_PECI_DATA_BUF_SIZE_MAX 32 ++ ++/* Timing Negotiation */ ++#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT 8 ++#define ASPEED_PECI_RD_SAMPLING_POINT_MAX 15 ++#define ASPEED_PECI_CLK_DIV_DEFAULT 0 ++#define ASPEED_PECI_CLK_DIV_MAX 7 ++#define ASPEED_PECI_MSG_TIMING_DEFAULT 1 ++#define ASPEED_PECI_MSG_TIMING_MAX 255 ++#define ASPEED_PECI_ADDR_TIMING_DEFAULT 1 ++#define ASPEED_PECI_ADDR_TIMING_MAX 255 ++ ++/* Timeout */ ++#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 ++#define ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC 10000 ++#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 ++#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX 60000 ++ ++struct aspeed_peci { ++ struct peci_adapter *adapter; ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ struct reset_control *rst; ++ int irq; ++ spinlock_t lock; /* to sync completion status handling */ ++ struct completion xfer_complete; ++ u32 status; ++ u32 cmd_timeout_ms; ++}; ++ ++static int aspeed_peci_check_idle(struct aspeed_peci *priv) ++{ ++ ulong timeout = jiffies + usecs_to_jiffies(ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC); ++ u32 cmd_sts; ++ ++ for (;;) { ++ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); ++ if (!(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK)) ++ break; ++ if (time_after(jiffies, timeout)) { ++ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); ++ break; ++ } ++ usleep_range((ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC >> 2) + 1, ++ ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC); ++ } ++ ++ return !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK) ? 0 : -ETIMEDOUT; ++} ++ ++static int aspeed_peci_xfer(struct peci_adapter *adapter, ++ struct peci_xfer_msg *msg) ++{ ++ struct aspeed_peci *priv = peci_get_adapdata(adapter); ++ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); ++ u32 peci_head, peci_state, rx_data = 0; ++ ulong flags; ++ int i, ret; ++ uint reg; ++ ++ if (msg->tx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX || ++ msg->rx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX) ++ return -EINVAL; ++ ++ /* Check command sts and bus idle state */ ++ ret = aspeed_peci_check_idle(priv); ++ if (ret) ++ return ret; /* -ETIMEDOUT */ ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ reinit_completion(&priv->xfer_complete); ++ ++ peci_head = FIELD_PREP(ASPEED_PECI_TAGET_ADDR_MASK, msg->addr) | ++ FIELD_PREP(ASPEED_PECI_WRITE_LEN_MASK, msg->tx_len) | ++ FIELD_PREP(ASPEED_PECI_READ_LEN_MASK, msg->rx_len); ++ ++ writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH); ++ ++ for (i = 0; i < msg->tx_len; i += 4) { ++ reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : ++ ASPEED_PECI_W_DATA4 + i % 16; ++ writel(le32_to_cpup((__le32 *)&msg->tx_buf[i]), ++ priv->base + reg); ++ } ++ ++ dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); ++ print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, ++ msg->tx_buf, msg->tx_len, true); ++ ++ priv->status = 0; ++ writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, ++ timeout); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); ++ peci_state = readl(priv->base + ASPEED_PECI_CMD); ++ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", ++ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); ++ ++ writel(0, priv->base + ASPEED_PECI_CMD); ++ ++ if (err <= 0 || priv->status != ASPEED_PECI_INT_CMD_DONE) { ++ if (err < 0) { /* -ERESTARTSYS */ ++ ret = (int)err; ++ goto err_irqrestore; ++ } else if (err == 0) { ++ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); ++ ret = -ETIMEDOUT; ++ goto err_irqrestore; ++ } ++ ++ dev_dbg(priv->dev, "No valid response!\n"); ++ ret = -EIO; ++ goto err_irqrestore; ++ } ++ ++ /* ++ * Note that rx_len and rx_buf size can be an odd number. ++ * Byte handling is more efficient. ++ */ ++ for (i = 0; i < msg->rx_len; i++) { ++ u8 byte_offset = i % 4; ++ ++ if (byte_offset == 0) { ++ reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : ++ ASPEED_PECI_R_DATA4 + i % 16; ++ rx_data = readl(priv->base + reg); ++ } ++ ++ msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); ++ } ++ ++ print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, ++ msg->rx_buf, msg->rx_len, true); ++ ++ peci_state = readl(priv->base + ASPEED_PECI_CMD); ++ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", ++ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); ++ dev_dbg(priv->dev, "------------------------\n"); ++ ++err_irqrestore: ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return ret; ++} ++ ++static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) ++{ ++ struct aspeed_peci *priv = arg; ++ u32 status; ++ ++ spin_lock(&priv->lock); ++ status = readl(priv->base + ASPEED_PECI_INT_STS); ++ writel(status, priv->base + ASPEED_PECI_INT_STS); ++ priv->status |= (status & ASPEED_PECI_INT_MASK); ++ ++ /* ++ * In most cases, interrupt bits will be set one by one but also note ++ * that multiple interrupt bits could be set at the same time. ++ */ ++ if (status & ASPEED_PECI_INT_BUS_TIMEOUT) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_TIMEOUT\n"); ++ } ++ ++ if (status & ASPEED_PECI_INT_BUS_CONNECT) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_CONNECT\n"); ++ } ++ ++ if (status & ASPEED_PECI_INT_W_FCS_BAD) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_BAD\n"); ++ } ++ ++ if (status & ASPEED_PECI_INT_W_FCS_ABORT) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_ABORT\n"); ++ } ++ ++ /* ++ * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit ++ * set even in an error case. ++ */ ++ if (status & ASPEED_PECI_INT_CMD_DONE) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_CMD_DONE\n"); ++ complete(&priv->xfer_complete); ++ } ++ ++ spin_unlock(&priv->lock); ++ return IRQ_HANDLED; ++} ++ ++static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) ++{ ++ u32 msg_timing, addr_timing, rd_sampling_point; ++ u32 clk_freq, clk_divisor, clk_div_val = 0; ++ int ret; ++ ++ priv->clk = devm_clk_get(priv->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(priv->dev, "Failed to get clk source.\n"); ++ return PTR_ERR(priv->clk); ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(priv->dev, "Failed to enable clock.\n"); ++ return ret; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "clock-frequency", &clk_freq); ++ if (ret) { ++ dev_err(priv->dev, ++ "Could not read clock-frequency property.\n"); ++ clk_disable_unprepare(priv->clk); ++ return ret; ++ } ++ ++ clk_divisor = clk_get_rate(priv->clk) / clk_freq; ++ ++ while ((clk_divisor >> 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX)) ++ clk_div_val++; ++ ++ ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing); ++ if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid msg-timing : %u, Use default : %u\n", ++ msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT); ++ msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing); ++ if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid addr-timing : %u, Use default : %u\n", ++ addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT); ++ addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "rd-sampling-point", ++ &rd_sampling_point); ++ if (ret || rd_sampling_point > ASPEED_PECI_RD_SAMPLING_POINT_MAX) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid rd-sampling-point : %u. Use default : %u\n", ++ rd_sampling_point, ++ ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT); ++ rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "cmd-timeout-ms", ++ &priv->cmd_timeout_ms); ++ if (ret || priv->cmd_timeout_ms > ASPEED_PECI_CMD_TIMEOUT_MS_MAX || ++ priv->cmd_timeout_ms == 0) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid cmd-timeout-ms : %u. Use default : %u\n", ++ priv->cmd_timeout_ms, ++ ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT); ++ priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT; ++ } ++ ++ writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, ++ ASPEED_PECI_CLK_DIV_DEFAULT) | ++ ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL); ++ ++ /* ++ * Timing negotiation period setting. ++ * The unit of the programmed value is 4 times of PECI clock period. ++ */ ++ writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) | ++ FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing), ++ priv->base + ASPEED_PECI_TIMING_NEGOTIATION); ++ ++ /* Clear interrupts */ ++ writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK, ++ priv->base + ASPEED_PECI_INT_STS); ++ ++ /* Set timing negotiation mode and enable interrupts */ ++ writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, ++ ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) | ++ ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL); ++ ++ /* Read sampling point and clock speed setting */ ++ writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | ++ FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) | ++ ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN, ++ priv->base + ASPEED_PECI_CTRL); ++ ++ return 0; ++} ++ ++static int aspeed_peci_probe(struct platform_device *pdev) ++{ ++ struct peci_adapter *adapter; ++ struct aspeed_peci *priv; ++ int ret; ++ ++ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); ++ if (!adapter) ++ return -ENOMEM; ++ ++ priv = peci_get_adapdata(adapter); ++ priv->adapter = adapter; ++ priv->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, priv); ++ ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) { ++ ret = PTR_ERR(priv->base); ++ goto err_put_adapter_dev; ++ } ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (!priv->irq) { ++ ret = -ENODEV; ++ goto err_put_adapter_dev; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, ++ 0, "peci-aspeed-irq", priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ init_completion(&priv->xfer_complete); ++ spin_lock_init(&priv->lock); ++ ++ priv->adapter->owner = THIS_MODULE; ++ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); ++ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); ++ priv->adapter->xfer = aspeed_peci_xfer; ++ priv->adapter->use_dma = false; ++ ++ priv->rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->rst)) { ++ dev_err(&pdev->dev, ++ "missing or invalid reset controller entry\n"); ++ ret = PTR_ERR(priv->rst); ++ goto err_put_adapter_dev; ++ } ++ reset_control_deassert(priv->rst); ++ ++ ret = aspeed_peci_init_ctrl(priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ ret = peci_add_adapter(priv->adapter); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", ++ priv->adapter->nr, priv->irq); ++ ++ return 0; ++ ++err_put_adapter_dev: ++ put_device(&adapter->dev); ++ return ret; ++} ++ ++static int aspeed_peci_remove(struct platform_device *pdev) ++{ ++ struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(priv->clk); ++ reset_control_assert(priv->rst); ++ peci_del_adapter(priv->adapter); ++ of_node_put(priv->adapter->dev.of_node); ++ ++ return 0; ++} ++ ++static const struct of_device_id aspeed_peci_of_table[] = { ++ { .compatible = "aspeed,ast2400-peci", }, ++ { .compatible = "aspeed,ast2500-peci", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); ++ ++static struct platform_driver aspeed_peci_driver = { ++ .probe = aspeed_peci_probe, ++ .remove = aspeed_peci_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_match_ptr(aspeed_peci_of_table), ++ }, ++}; ++module_platform_driver(aspeed_peci_driver); ++ ++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); ++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); ++MODULE_DESCRIPTION("ASPEED PECI driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/busses/peci-npcm.c b/drivers/peci/busses/peci-npcm.c +new file mode 100644 +index 000000000000..f632365b1416 +--- /dev/null ++++ b/drivers/peci/busses/peci-npcm.c +@@ -0,0 +1,410 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2019 Nuvoton Technology corporation. ++ ++#include <linux/bitfield.h> ++#include <linux/clk.h> ++#include <linux/interrupt.h> ++#include <linux/jiffies.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/peci.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/mfd/syscon.h> ++#include <linux/reset.h> ++ ++/* NPCM7xx GCR module */ ++#define NPCM7XX_INTCR3_OFFSET 0x9C ++#define NPCM7XX_INTCR3_PECIVSEL BIT(19) ++ ++/* NPCM PECI Registers */ ++#define NPCM_PECI_CTL_STS 0x00 ++#define NPCM_PECI_RD_LENGTH 0x04 ++#define NPCM_PECI_ADDR 0x08 ++#define NPCM_PECI_CMD 0x0C ++#define NPCM_PECI_CTL2 0x10 ++#define NPCM_PECI_WR_LENGTH 0x1C ++#define NPCM_PECI_PDDR 0x2C ++#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) ++ ++#define NPCM_PECI_MAX_REG 0x200 ++ ++/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ ++#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) ++#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) ++#define NPCM_PECI_CTRL_CRC_ERR BIT(3) ++#define NPCM_PECI_CTRL_DONE BIT(1) ++#define NPCM_PECI_CTRL_START_BUSY BIT(0) ++ ++/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ ++#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) ++ ++/* NPCM_PECI_CMD - 0x10 : Command Register */ ++#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) ++ ++/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ ++#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) ++ ++/* NPCM_PECI_PDDR - 0x2C : Command Register */ ++#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) ++ ++#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ ++ NPCM_PECI_CTRL_CRC_ERR | \ ++ NPCM_PECI_CTRL_DONE) ++ ++#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 ++#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 ++#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 ++#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 ++#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 ++#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 ++#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 ++#define NPCM_PECI_PULL_DOWN_DEFAULT 0 ++#define NPCM_PECI_PULL_DOWN_MAX 2 ++ ++struct npcm_peci { ++ u32 cmd_timeout_ms; ++ u32 host_bit_rate; ++ struct completion xfer_complete; ++ struct regmap *gcr_regmap; ++ struct peci_adapter *adapter; ++ struct regmap *regmap; ++ u32 status; ++ spinlock_t lock; /* to sync completion status handling */ ++ struct device *dev; ++ struct clk *clk; ++ int irq; ++}; ++ ++static int npcm_peci_xfer_native(struct npcm_peci *priv, ++ struct peci_xfer_msg *msg) ++{ ++ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); ++ unsigned long flags; ++ unsigned int msg_rd; ++ u32 cmd_sts; ++ int i, rc; ++ ++ /* Check command sts and bus idle state */ ++ rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, ++ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), ++ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, ++ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); ++ if (rc) ++ return rc; /* -ETIMEDOUT */ ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ reinit_completion(&priv->xfer_complete); ++ ++ regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); ++ regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, ++ NPCM_PECI_WR_LEN_MASK & msg->rx_len); ++ regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, ++ NPCM_PECI_WR_LEN_MASK & msg->tx_len); ++ ++ if (msg->tx_len) { ++ regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); ++ ++ for (i = 0; i < (msg->tx_len - 1); i++) ++ regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), ++ msg->tx_buf[i + 1]); ++ } ++ ++ priv->status = 0; ++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, ++ NPCM_PECI_CTRL_START_BUSY, ++ NPCM_PECI_CTRL_START_BUSY); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, ++ timeout); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ regmap_write(priv->regmap, NPCM_PECI_CMD, 0); ++ ++ if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { ++ if (err < 0) { /* -ERESTARTSYS */ ++ rc = (int)err; ++ goto err_irqrestore; ++ } else if (err == 0) { ++ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); ++ rc = -ETIMEDOUT; ++ goto err_irqrestore; ++ } ++ ++ dev_dbg(priv->dev, "No valid response!\n"); ++ rc = -EIO; ++ goto err_irqrestore; ++ } ++ ++ for (i = 0; i < msg->rx_len; i++) { ++ regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); ++ msg->rx_buf[i] = (u8)msg_rd; ++ } ++ ++err_irqrestore: ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return rc; ++} ++ ++static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) ++{ ++ struct npcm_peci *priv = arg; ++ u32 status_ack = 0; ++ u32 status; ++ ++ spin_lock(&priv->lock); ++ regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); ++ priv->status |= (status & NPCM_PECI_INT_MASK); ++ ++ if (status & NPCM_PECI_CTRL_CRC_ERR) { ++ dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); ++ status_ack |= NPCM_PECI_CTRL_CRC_ERR; ++ } ++ ++ if (status & NPCM_PECI_CTRL_ABRT_ERR) { ++ dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); ++ status_ack |= NPCM_PECI_CTRL_ABRT_ERR; ++ } ++ ++ /* ++ * All commands should be ended up with a NPCM_PECI_CTRL_DONE ++ * bit set even in an error case. ++ */ ++ if (status & NPCM_PECI_CTRL_DONE) { ++ dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); ++ status_ack |= NPCM_PECI_CTRL_DONE; ++ complete(&priv->xfer_complete); ++ } ++ ++ regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, ++ NPCM_PECI_INT_MASK, status_ack); ++ ++ spin_unlock(&priv->lock); ++ return IRQ_HANDLED; ++} ++ ++static int npcm_peci_init_ctrl(struct npcm_peci *priv) ++{ ++ u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; ++ int ret; ++ bool volt; ++ ++ priv->clk = devm_clk_get(priv->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(priv->dev, "Failed to get clk source.\n"); ++ return PTR_ERR(priv->clk); ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(priv->dev, "Failed to enable clock.\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", ++ &priv->cmd_timeout_ms); ++ if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || ++ priv->cmd_timeout_ms == 0) { ++ if (ret) ++ dev_warn(priv->dev, ++ "cmd-timeout-ms not found, use default : %u\n", ++ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); ++ else ++ dev_warn(priv->dev, ++ "Invalid cmd-timeout-ms : %u. Use default : %u\n", ++ priv->cmd_timeout_ms, ++ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); ++ ++ priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; ++ } ++ ++ if (of_device_is_compatible(priv->dev->of_node, ++ "nuvoton,npcm750-peci")) { ++ priv->gcr_regmap = syscon_regmap_lookup_by_compatible ++ ("nuvoton,npcm750-gcr"); ++ if (!IS_ERR(priv->gcr_regmap)) { ++ volt = of_property_read_bool(priv->dev->of_node, ++ "high-volt-range"); ++ if (volt) ++ regmap_update_bits(priv->gcr_regmap, ++ NPCM7XX_INTCR3_OFFSET, ++ NPCM7XX_INTCR3_PECIVSEL, ++ NPCM7XX_INTCR3_PECIVSEL); ++ else ++ regmap_update_bits(priv->gcr_regmap, ++ NPCM7XX_INTCR3_OFFSET, ++ NPCM7XX_INTCR3_PECIVSEL, 0); ++ } ++ } ++ ++ ret = of_property_read_u32(priv->dev->of_node, "pull-down", ++ &pull_down); ++ if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { ++ if (ret) ++ dev_warn(priv->dev, ++ "pull-down not found, use default : %u\n", ++ NPCM_PECI_PULL_DOWN_DEFAULT); ++ else ++ dev_warn(priv->dev, ++ "Invalid pull-down : %u. Use default : %u\n", ++ pull_down, ++ NPCM_PECI_PULL_DOWN_DEFAULT); ++ pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; ++ } ++ ++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, ++ pull_down << 6); ++ ++ ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", ++ &host_neg_bit_rate); ++ if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || ++ host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { ++ if (ret) ++ dev_warn(priv->dev, ++ "host-neg-bit-rate not found, use default : %u\n", ++ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); ++ else ++ dev_warn(priv->dev, ++ "Invalid host-neg-bit-rate : %u. Use default : %u\n", ++ host_neg_bit_rate, ++ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); ++ host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; ++ } ++ ++ regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, ++ host_neg_bit_rate); ++ ++ priv->host_bit_rate = clk_get_rate(priv->clk) / ++ (4 * (host_neg_bit_rate + 1)); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, ++ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), ++ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, ++ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); ++ if (ret) ++ return ret; /* -ETIMEDOUT */ ++ ++ /* PECI interrupt enable */ ++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, ++ NPCM_PECI_CTRL_DONE_INT_EN, ++ NPCM_PECI_CTRL_DONE_INT_EN); ++ ++ return 0; ++} ++ ++static const struct regmap_config npcm_peci_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = NPCM_PECI_MAX_REG, ++ .fast_io = true, ++}; ++ ++static int npcm_peci_xfer(struct peci_adapter *adapter, ++ struct peci_xfer_msg *msg) ++{ ++ struct npcm_peci *priv = peci_get_adapdata(adapter); ++ ++ return npcm_peci_xfer_native(priv, msg); ++} ++ ++static int npcm_peci_probe(struct platform_device *pdev) ++{ ++ struct peci_adapter *adapter; ++ struct npcm_peci *priv; ++ struct resource *res; ++ void __iomem *base; ++ int ret; ++ ++ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); ++ if (!adapter) ++ return -ENOMEM; ++ ++ priv = peci_get_adapdata(adapter); ++ priv->adapter = adapter; ++ priv->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, priv); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ goto err_put_adapter_dev; ++ } ++ ++ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, ++ &npcm_peci_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ ret = PTR_ERR(priv->regmap); ++ goto err_put_adapter_dev; ++ } ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (!priv->irq) { ++ ret = -ENODEV; ++ goto err_put_adapter_dev; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, ++ 0, "peci-npcm-irq", priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ init_completion(&priv->xfer_complete); ++ spin_lock_init(&priv->lock); ++ ++ priv->adapter->owner = THIS_MODULE; ++ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); ++ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); ++ priv->adapter->xfer = npcm_peci_xfer; ++ ++ ret = npcm_peci_init_ctrl(priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ ret = peci_add_adapter(priv->adapter); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", ++ priv->adapter->nr, priv->host_bit_rate); ++ ++ return 0; ++ ++err_put_adapter_dev: ++ put_device(&adapter->dev); ++ return ret; ++} ++ ++static int npcm_peci_remove(struct platform_device *pdev) ++{ ++ struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(priv->clk); ++ peci_del_adapter(priv->adapter); ++ of_node_put(priv->adapter->dev.of_node); ++ ++ return 0; ++} ++ ++static const struct of_device_id npcm_peci_of_table[] = { ++ { .compatible = "nuvoton,npcm750-peci", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, npcm_peci_of_table); ++ ++static struct platform_driver npcm_peci_driver = { ++ .probe = npcm_peci_probe, ++ .remove = npcm_peci_remove, ++ .driver = { ++ .name = "peci-npcm", ++ .of_match_table = of_match_ptr(npcm_peci_of_table), ++ }, ++}; ++module_platform_driver(npcm_peci_driver); ++ ++MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); ++MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/peci-aspeed.c b/drivers/peci/peci-aspeed.c +deleted file mode 100644 +index 51cb2563ceb6..000000000000 +--- a/drivers/peci/peci-aspeed.c ++++ /dev/null +@@ -1,505 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-// Copyright (C) 2012-2017 ASPEED Technology Inc. +-// Copyright (c) 2018 Intel Corporation +- +-#include <linux/bitfield.h> +-#include <linux/clk.h> +-#include <linux/interrupt.h> +-#include <linux/jiffies.h> +-#include <linux/module.h> +-#include <linux/of.h> +-#include <linux/peci.h> +-#include <linux/platform_device.h> +-#include <linux/regmap.h> +-#include <linux/reset.h> +- +-/* ASPEED PECI Registers */ +-#define ASPEED_PECI_CTRL 0x00 +-#define ASPEED_PECI_TIMING 0x04 +-#define ASPEED_PECI_CMD 0x08 +-#define ASPEED_PECI_CMD_CTRL 0x0c +-#define ASPEED_PECI_EXP_FCS 0x10 +-#define ASPEED_PECI_CAP_FCS 0x14 +-#define ASPEED_PECI_INT_CTRL 0x18 +-#define ASPEED_PECI_INT_STS 0x1c +-#define ASPEED_PECI_W_DATA0 0x20 +-#define ASPEED_PECI_W_DATA1 0x24 +-#define ASPEED_PECI_W_DATA2 0x28 +-#define ASPEED_PECI_W_DATA3 0x2c +-#define ASPEED_PECI_R_DATA0 0x30 +-#define ASPEED_PECI_R_DATA1 0x34 +-#define ASPEED_PECI_R_DATA2 0x38 +-#define ASPEED_PECI_R_DATA3 0x3c +-#define ASPEED_PECI_W_DATA4 0x40 +-#define ASPEED_PECI_W_DATA5 0x44 +-#define ASPEED_PECI_W_DATA6 0x48 +-#define ASPEED_PECI_W_DATA7 0x4c +-#define ASPEED_PECI_R_DATA4 0x50 +-#define ASPEED_PECI_R_DATA5 0x54 +-#define ASPEED_PECI_R_DATA6 0x58 +-#define ASPEED_PECI_R_DATA7 0x5c +- +-/* ASPEED_PECI_CTRL - 0x00 : Control Register */ +-#define PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) +-#define PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) +-#define PECI_CTRL_READ_MODE_COUNT BIT(12) +-#define PECI_CTRL_READ_MODE_DBG BIT(13) +-#define PECI_CTRL_CLK_SOURCE_MASK BIT(11) +-#define PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) +-#define PECI_CTRL_INVERT_OUT BIT(7) +-#define PECI_CTRL_INVERT_IN BIT(6) +-#define PECI_CTRL_BUS_CONTENT_EN BIT(5) +-#define PECI_CTRL_PECI_EN BIT(4) +-#define PECI_CTRL_PECI_CLK_EN BIT(0) +- +-/* ASPEED_PECI_TIMING - 0x04 : Timing Negotiation Register */ +-#define PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) +-#define PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_CMD - 0x08 : Command Register */ +-#define PECI_CMD_PIN_MON BIT(31) +-#define PECI_CMD_STS_MASK GENMASK(27, 24) +-#define PECI_CMD_IDLE_MASK (PECI_CMD_STS_MASK | PECI_CMD_PIN_MON) +-#define PECI_CMD_FIRE BIT(0) +- +-/* ASPEED_PECI_LEN - 0x0C : Read/Write Length Register */ +-#define PECI_AW_FCS_EN BIT(31) +-#define PECI_READ_LEN_MASK GENMASK(23, 16) +-#define PECI_WRITE_LEN_MASK GENMASK(15, 8) +-#define PECI_TAGET_ADDR_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_EXP_FCS - 0x10 : Expected FCS Data Register */ +-#define PECI_EXPECT_READ_FCS_MASK GENMASK(23, 16) +-#define PECI_EXPECT_AW_FCS_AUTO_MASK GENMASK(15, 8) +-#define PECI_EXPECT_WRITE_FCS_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_CAP_FCS - 0x14 : Captured FCS Data Register */ +-#define PECI_CAPTURE_READ_FCS_MASK GENMASK(23, 16) +-#define PECI_CAPTURE_WRITE_FCS_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_INT_CTRL/STS - 0x18/0x1c : Interrupt Register */ +-#define PECI_INT_TIMING_RESULT_MASK GENMASK(31, 30) +-#define PECI_INT_TIMEOUT BIT(4) +-#define PECI_INT_CONNECT BIT(3) +-#define PECI_INT_W_FCS_BAD BIT(2) +-#define PECI_INT_W_FCS_ABORT BIT(1) +-#define PECI_INT_CMD_DONE BIT(0) +- +-#define PECI_INT_MASK (PECI_INT_TIMEOUT | PECI_INT_CONNECT | \ +- PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT | \ +- PECI_INT_CMD_DONE) +- +-#define PECI_IDLE_CHECK_TIMEOUT_USEC 50000 +-#define PECI_IDLE_CHECK_INTERVAL_USEC 10000 +- +-#define PECI_RD_SAMPLING_POINT_DEFAULT 8 +-#define PECI_RD_SAMPLING_POINT_MAX 15 +-#define PECI_CLK_DIV_DEFAULT 0 +-#define PECI_CLK_DIV_MAX 7 +-#define PECI_MSG_TIMING_DEFAULT 1 +-#define PECI_MSG_TIMING_MAX 255 +-#define PECI_ADDR_TIMING_DEFAULT 1 +-#define PECI_ADDR_TIMING_MAX 255 +-#define PECI_CMD_TIMEOUT_MS_DEFAULT 1000 +-#define PECI_CMD_TIMEOUT_MS_MAX 60000 +- +-struct aspeed_peci { +- struct peci_adapter *adapter; +- struct device *dev; +- struct regmap *regmap; +- struct clk *clk; +- struct reset_control *rst; +- int irq; +- spinlock_t lock; /* to sync completion status handling */ +- struct completion xfer_complete; +- u32 status; +- u32 cmd_timeout_ms; +-}; +- +-static int aspeed_peci_xfer_native(struct aspeed_peci *priv, +- struct peci_xfer_msg *msg) +-{ +- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); +- u32 peci_head, peci_state, rx_data, cmd_sts; +- unsigned long flags; +- int i, rc; +- uint reg; +- +- /* Check command sts and bus idle state */ +- rc = regmap_read_poll_timeout(priv->regmap, ASPEED_PECI_CMD, cmd_sts, +- !(cmd_sts & PECI_CMD_IDLE_MASK), +- PECI_IDLE_CHECK_INTERVAL_USEC, +- PECI_IDLE_CHECK_TIMEOUT_USEC); +- if (rc) +- return rc; /* -ETIMEDOUT */ +- +- spin_lock_irqsave(&priv->lock, flags); +- reinit_completion(&priv->xfer_complete); +- +- peci_head = FIELD_PREP(PECI_TAGET_ADDR_MASK, msg->addr) | +- FIELD_PREP(PECI_WRITE_LEN_MASK, msg->tx_len) | +- FIELD_PREP(PECI_READ_LEN_MASK, msg->rx_len); +- +- regmap_write(priv->regmap, ASPEED_PECI_CMD_CTRL, peci_head); +- +- for (i = 0; i < msg->tx_len; i += 4) { +- reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : +- ASPEED_PECI_W_DATA4 + i % 16; +- regmap_write(priv->regmap, reg, +- le32_to_cpup((__le32 *)&msg->tx_buf[i])); +- } +- +- dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); +- print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, +- msg->tx_buf, msg->tx_len, true); +- +- priv->status = 0; +- regmap_write(priv->regmap, ASPEED_PECI_CMD, PECI_CMD_FIRE); +- spin_unlock_irqrestore(&priv->lock, flags); +- +- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, +- timeout); +- +- spin_lock_irqsave(&priv->lock, flags); +- dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); +- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); +- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", +- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); +- +- regmap_write(priv->regmap, ASPEED_PECI_CMD, 0); +- +- if (err <= 0 || priv->status != PECI_INT_CMD_DONE) { +- if (err < 0) { /* -ERESTARTSYS */ +- rc = (int)err; +- goto err_irqrestore; +- } else if (err == 0) { +- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); +- rc = -ETIMEDOUT; +- goto err_irqrestore; +- } +- +- dev_dbg(priv->dev, "No valid response!\n"); +- rc = -EIO; +- goto err_irqrestore; +- } +- +- /** +- * Note that rx_len and rx_buf size can be an odd number. +- * Byte handling is more efficient. +- */ +- for (i = 0; i < msg->rx_len; i++) { +- u8 byte_offset = i % 4; +- +- if (byte_offset == 0) { +- reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : +- ASPEED_PECI_R_DATA4 + i % 16; +- regmap_read(priv->regmap, reg, &rx_data); +- } +- +- msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); +- } +- +- print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, +- msg->rx_buf, msg->rx_len, true); +- +- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); +- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", +- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); +- dev_dbg(priv->dev, "------------------------\n"); +- +-err_irqrestore: +- spin_unlock_irqrestore(&priv->lock, flags); +- return rc; +-} +- +-static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) +-{ +- struct aspeed_peci *priv = arg; +- u32 status_ack = 0; +- u32 status; +- +- spin_lock(&priv->lock); +- regmap_read(priv->regmap, ASPEED_PECI_INT_STS, &status); +- priv->status |= (status & PECI_INT_MASK); +- +- /** +- * In most cases, interrupt bits will be set one by one but also note +- * that multiple interrupt bits could be set at the same time. +- */ +- if (status & PECI_INT_TIMEOUT) { +- dev_dbg(priv->dev, "PECI_INT_TIMEOUT\n"); +- status_ack |= PECI_INT_TIMEOUT; +- } +- +- if (status & PECI_INT_CONNECT) { +- dev_dbg(priv->dev, "PECI_INT_CONNECT\n"); +- status_ack |= PECI_INT_CONNECT; +- } +- +- if (status & PECI_INT_W_FCS_BAD) { +- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); +- status_ack |= PECI_INT_W_FCS_BAD; +- } +- +- if (status & PECI_INT_W_FCS_ABORT) { +- dev_dbg(priv->dev, "PECI_INT_W_FCS_ABORT\n"); +- status_ack |= PECI_INT_W_FCS_ABORT; +- } +- +- /** +- * All commands should be ended up with a PECI_INT_CMD_DONE bit set +- * even in an error case. +- */ +- if (status & PECI_INT_CMD_DONE) { +- dev_dbg(priv->dev, "PECI_INT_CMD_DONE\n"); +- status_ack |= PECI_INT_CMD_DONE; +- complete(&priv->xfer_complete); +- } +- +- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, status_ack); +- spin_unlock(&priv->lock); +- return IRQ_HANDLED; +-} +- +-static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) +-{ +- u32 msg_timing, addr_timing, rd_sampling_point; +- u32 clk_freq, clk_divisor, clk_div_val = 0; +- int ret; +- +- priv->clk = devm_clk_get(priv->dev, NULL); +- if (IS_ERR(priv->clk)) { +- dev_err(priv->dev, "Failed to get clk source.\n"); +- return PTR_ERR(priv->clk); +- } +- +- ret = clk_prepare_enable(priv->clk); +- if (ret) { +- dev_err(priv->dev, "Failed to enable clock.\n"); +- return ret; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "clock-frequency", +- &clk_freq); +- if (ret) { +- dev_err(priv->dev, +- "Could not read clock-frequency property.\n"); +- clk_disable_unprepare(priv->clk); +- return ret; +- } +- +- clk_divisor = clk_get_rate(priv->clk) / clk_freq; +- +- while ((clk_divisor >> 1) && (clk_div_val < PECI_CLK_DIV_MAX)) +- clk_div_val++; +- +- ret = of_property_read_u32(priv->dev->of_node, "msg-timing", +- &msg_timing); +- if (ret || msg_timing > PECI_MSG_TIMING_MAX) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid msg-timing : %u, Use default : %u\n", +- msg_timing, PECI_MSG_TIMING_DEFAULT); +- msg_timing = PECI_MSG_TIMING_DEFAULT; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "addr-timing", +- &addr_timing); +- if (ret || addr_timing > PECI_ADDR_TIMING_MAX) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid addr-timing : %u, Use default : %u\n", +- addr_timing, PECI_ADDR_TIMING_DEFAULT); +- addr_timing = PECI_ADDR_TIMING_DEFAULT; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "rd-sampling-point", +- &rd_sampling_point); +- if (ret || rd_sampling_point > PECI_RD_SAMPLING_POINT_MAX) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid rd-sampling-point : %u. Use default : %u\n", +- rd_sampling_point, +- PECI_RD_SAMPLING_POINT_DEFAULT); +- rd_sampling_point = PECI_RD_SAMPLING_POINT_DEFAULT; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", +- &priv->cmd_timeout_ms); +- if (ret || priv->cmd_timeout_ms > PECI_CMD_TIMEOUT_MS_MAX || +- priv->cmd_timeout_ms == 0) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid cmd-timeout-ms : %u. Use default : %u\n", +- priv->cmd_timeout_ms, +- PECI_CMD_TIMEOUT_MS_DEFAULT); +- priv->cmd_timeout_ms = PECI_CMD_TIMEOUT_MS_DEFAULT; +- } +- +- regmap_write(priv->regmap, ASPEED_PECI_CTRL, +- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, PECI_CLK_DIV_DEFAULT) | +- PECI_CTRL_PECI_CLK_EN); +- +- /** +- * Timing negotiation period setting. +- * The unit of the programmed value is 4 times of PECI clock period. +- */ +- regmap_write(priv->regmap, ASPEED_PECI_TIMING, +- FIELD_PREP(PECI_TIMING_MESSAGE_MASK, msg_timing) | +- FIELD_PREP(PECI_TIMING_ADDRESS_MASK, addr_timing)); +- +- /* Clear interrupts */ +- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, PECI_INT_MASK); +- +- /* Enable interrupts */ +- regmap_write(priv->regmap, ASPEED_PECI_INT_CTRL, PECI_INT_MASK); +- +- /* Read sampling point and clock speed setting */ +- regmap_write(priv->regmap, ASPEED_PECI_CTRL, +- FIELD_PREP(PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | +- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, clk_div_val) | +- PECI_CTRL_PECI_EN | PECI_CTRL_PECI_CLK_EN); +- +- return 0; +-} +- +-static const struct regmap_config aspeed_peci_regmap_config = { +- .reg_bits = 32, +- .val_bits = 32, +- .reg_stride = 4, +- .max_register = ASPEED_PECI_R_DATA7, +- .val_format_endian = REGMAP_ENDIAN_LITTLE, +- .fast_io = true, +-}; +- +-static int aspeed_peci_xfer(struct peci_adapter *adapter, +- struct peci_xfer_msg *msg) +-{ +- struct aspeed_peci *priv = peci_get_adapdata(adapter); +- +- return aspeed_peci_xfer_native(priv, msg); +-} +- +-static int aspeed_peci_probe(struct platform_device *pdev) +-{ +- struct peci_adapter *adapter; +- struct aspeed_peci *priv; +- struct resource *res; +- void __iomem *base; +- u32 cmd_sts; +- int ret; +- +- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); +- if (!adapter) +- return -ENOMEM; +- +- priv = peci_get_adapdata(adapter); +- priv->adapter = adapter; +- priv->dev = &pdev->dev; +- dev_set_drvdata(&pdev->dev, priv); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- base = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(base)) { +- ret = PTR_ERR(base); +- goto err_put_adapter_dev; +- } +- +- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, +- &aspeed_peci_regmap_config); +- if (IS_ERR(priv->regmap)) { +- ret = PTR_ERR(priv->regmap); +- goto err_put_adapter_dev; +- } +- +- /** +- * We check that the regmap works on this very first access, +- * but as this is an MMIO-backed regmap, subsequent regmap +- * access is not going to fail and we skip error checks from +- * this point. +- */ +- ret = regmap_read(priv->regmap, ASPEED_PECI_CMD, &cmd_sts); +- if (ret) { +- ret = -EIO; +- goto err_put_adapter_dev; +- } +- +- priv->irq = platform_get_irq(pdev, 0); +- if (!priv->irq) { +- ret = -ENODEV; +- goto err_put_adapter_dev; +- } +- +- ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, +- 0, "peci-aspeed-irq", priv); +- if (ret) +- goto err_put_adapter_dev; +- +- init_completion(&priv->xfer_complete); +- spin_lock_init(&priv->lock); +- +- priv->adapter->owner = THIS_MODULE; +- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); +- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); +- priv->adapter->xfer = aspeed_peci_xfer; +- +- priv->rst = devm_reset_control_get(&pdev->dev, NULL); +- if (IS_ERR(priv->rst)) { +- dev_err(&pdev->dev, +- "missing or invalid reset controller entry"); +- ret = PTR_ERR(priv->rst); +- goto err_put_adapter_dev; +- } +- reset_control_deassert(priv->rst); +- +- ret = aspeed_peci_init_ctrl(priv); +- if (ret) +- goto err_put_adapter_dev; +- +- ret = peci_add_adapter(priv->adapter); +- if (ret) +- goto err_put_adapter_dev; +- +- dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", +- priv->adapter->nr, priv->irq); +- +- return 0; +- +-err_put_adapter_dev: +- put_device(&adapter->dev); +- return ret; +-} +- +-static int aspeed_peci_remove(struct platform_device *pdev) +-{ +- struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); +- +- clk_disable_unprepare(priv->clk); +- reset_control_assert(priv->rst); +- peci_del_adapter(priv->adapter); +- of_node_put(priv->adapter->dev.of_node); +- +- return 0; +-} +- +-static const struct of_device_id aspeed_peci_of_table[] = { +- { .compatible = "aspeed,ast2400-peci", }, +- { .compatible = "aspeed,ast2500-peci", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); +- +-static struct platform_driver aspeed_peci_driver = { +- .probe = aspeed_peci_probe, +- .remove = aspeed_peci_remove, +- .driver = { +- .name = "peci-aspeed", +- .of_match_table = of_match_ptr(aspeed_peci_of_table), +- }, +-}; +-module_platform_driver(aspeed_peci_driver); +- +-MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); +-MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); +-MODULE_DESCRIPTION("ASPEED PECI driver"); +-MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index 6f241469ec7e..48f29de09311 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -1,38 +1,31 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include <linux/bitfield.h> + #include <linux/crc8.h> + #include <linux/delay.h> +-#include <linux/fs.h> ++#include <linux/mm.h> + #include <linux/module.h> + #include <linux/of_device.h> + #include <linux/peci.h> + #include <linux/pm_domain.h> + #include <linux/pm_runtime.h> ++#include <linux/sched/task_stack.h> + #include <linux/slab.h> +-#include <linux/uaccess.h> + + /* Mask for getting minor revision number from DIB */ + #define REVISION_NUM_MASK GENMASK(15, 8) + +-/* CRC8 table for Assure Write Frame Check */ ++/* CRC8 table for Assured Write Frame Check */ + #define PECI_CRC8_POLYNOMIAL 0x07 + DECLARE_CRC8_TABLE(peci_crc8_table); + +-static struct device_type peci_adapter_type; +-static struct device_type peci_client_type; +- +-/* Max number of peci cdev */ +-#define PECI_CDEV_MAX 16 +- +-static dev_t peci_devt; + static bool is_registered; + + static DEFINE_MUTEX(core_lock); + static DEFINE_IDR(peci_adapter_idr); + +-static struct peci_adapter *peci_get_adapter(int nr) ++struct peci_adapter *peci_get_adapter(int nr) + { + struct peci_adapter *adapter; + +@@ -48,10 +41,12 @@ static struct peci_adapter *peci_get_adapter(int nr) + + out_unlock: + mutex_unlock(&core_lock); ++ + return adapter; + } ++EXPORT_SYMBOL_GPL(peci_get_adapter); + +-static void peci_put_adapter(struct peci_adapter *adapter) ++void peci_put_adapter(struct peci_adapter *adapter) + { + if (!adapter) + return; +@@ -59,6 +54,7 @@ static void peci_put_adapter(struct peci_adapter *adapter) + put_device(&adapter->dev); + module_put(adapter->owner); + } ++EXPORT_SYMBOL_GPL(peci_put_adapter); + + static ssize_t name_show(struct device *dev, + struct device_attribute *attr, +@@ -84,10 +80,11 @@ static struct attribute *peci_device_attrs[] = { + }; + ATTRIBUTE_GROUPS(peci_device); + +-static struct device_type peci_client_type = { ++struct device_type peci_client_type = { + .groups = peci_device_groups, + .release = peci_client_dev_release, + }; ++EXPORT_SYMBOL_GPL(peci_client_type); + + /** + * peci_verify_client - return parameter as peci_client, or NULL +@@ -103,19 +100,120 @@ struct peci_client *peci_verify_client(struct device *dev) + } + EXPORT_SYMBOL_GPL(peci_verify_client); + +-static u8 peci_aw_fcs(u8 *data, int len) ++/** ++ * peci_get_xfer_msg() - get a DMA safe peci_xfer_msg for the given tx and rx ++ * length ++ * @tx_len: the length of tx_buf. May be 0 if tx_buf isn't needed. ++ * @rx_len: the length of rx_buf. May be 0 if rx_buf isn't needed. ++ * ++ * Return: NULL if a DMA safe buffer was not obtained. ++ * Or a valid pointer to be used with DMA. After use, release it by ++ * calling peci_put_xfer_msg(). ++ * ++ * This function must only be called from process context! ++ */ ++struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len) + { +- return crc8(peci_crc8_table, data, (size_t)len, 0); ++ struct peci_xfer_msg *msg; ++ u8 *tx_buf, *rx_buf; ++ ++ if (tx_len) { ++ tx_buf = kzalloc(tx_len, GFP_KERNEL); ++ if (!tx_buf) ++ return NULL; ++ } else { ++ tx_buf = NULL; ++ } ++ ++ if (rx_len) { ++ rx_buf = kzalloc(rx_len, GFP_KERNEL); ++ if (!rx_buf) ++ goto err_free_tx_buf; ++ } else { ++ rx_buf = NULL; ++ } ++ ++ msg = kzalloc(sizeof(struct peci_xfer_msg), GFP_KERNEL); ++ if (!msg) ++ goto err_free_tx_rx_buf; ++ ++ msg->tx_len = tx_len; ++ msg->tx_buf = tx_buf; ++ msg->rx_len = rx_len; ++ msg->rx_buf = rx_buf; ++ ++ return msg; ++ ++err_free_tx_rx_buf: ++ kfree(rx_buf); ++err_free_tx_buf: ++ kfree(tx_buf); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(peci_get_xfer_msg); ++ ++/** ++ * peci_put_xfer_msg - release a DMA safe peci_xfer_msg ++ * @msg: the message obtained from peci_get_xfer_msg(). May be NULL. ++ */ ++void peci_put_xfer_msg(struct peci_xfer_msg *msg) ++{ ++ if (!msg) ++ return; ++ ++ kfree(msg->rx_buf); ++ kfree(msg->tx_buf); ++ kfree(msg); ++} ++EXPORT_SYMBOL_GPL(peci_put_xfer_msg); ++ ++/* Calculate an Assured Write Frame Check Sequence byte */ ++static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs) ++{ ++ u8 *tmp_buf; ++ ++ /* Allocate a temporary buffer to use a contiguous byte array */ ++ tmp_buf = kmalloc(len, GFP_KERNEL); ++ if (!tmp_buf) ++ return -ENOMEM; ++ ++ tmp_buf[0] = msg->addr; ++ tmp_buf[1] = msg->tx_len; ++ tmp_buf[2] = msg->rx_len; ++ memcpy(&tmp_buf[3], msg->tx_buf, len - 3); ++ ++ *aw_fcs = crc8(peci_crc8_table, tmp_buf, (size_t)len, 0); ++ ++ kfree(tmp_buf); ++ ++ return 0; + } + + static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + bool do_retry, bool has_aw_fcs) + { +- ktime_t start, end; +- s64 elapsed_ms; +- int rc = 0; ++ ulong timeout = jiffies; ++ u8 aw_fcs; ++ int ret; ++ ++ /* ++ * In case if adapter uses DMA, check at here whether tx and rx buffers ++ * are DMA capable or not. ++ */ ++ if (IS_ENABLED(CONFIG_HAS_DMA) && adapter->use_dma) { ++ if (is_vmalloc_addr(msg->tx_buf) || ++ is_vmalloc_addr(msg->rx_buf)) { ++ WARN_ONCE(1, "xfer msg is not dma capable\n"); ++ return -EAGAIN; ++ } else if (object_is_on_stack(msg->tx_buf) || ++ object_is_on_stack(msg->rx_buf)) { ++ WARN_ONCE(1, "xfer msg is on stack\n"); ++ return -EAGAIN; ++ } ++ } + +- /** ++ /* + * For some commands, the PECI originator may need to retry a command if + * the processor PECI client responds with a 0x8x completion code. In + * each instance, the processor PECI client may have started the +@@ -125,55 +223,51 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + */ + + if (do_retry) +- start = ktime_get(); ++ timeout += msecs_to_jiffies(PECI_DEV_RETRY_TIME_MS); + +- do { +- rc = adapter->xfer(adapter, msg); ++ for (;;) { ++ ret = adapter->xfer(adapter, msg); + +- if (!do_retry || rc) +- break; +- +- if (msg->rx_buf[0] == DEV_PECI_CC_SUCCESS) ++ if (!do_retry || ret || !msg->rx_buf) + break; + + /* Retry is needed when completion code is 0x8x */ +- if ((msg->rx_buf[0] & DEV_PECI_CC_RETRY_CHECK_MASK) != +- DEV_PECI_CC_NEED_RETRY) { +- rc = -EIO; ++ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) != ++ PECI_DEV_CC_NEED_RETRY) + break; +- } + + /* Set the retry bit to indicate a retry attempt */ +- msg->tx_buf[1] |= DEV_PECI_RETRY_BIT; ++ msg->tx_buf[1] |= PECI_DEV_RETRY_BIT; + + /* Recalculate the AW FCS if it has one */ +- if (has_aw_fcs) +- msg->tx_buf[msg->tx_len - 1] = 0x80 ^ +- peci_aw_fcs((u8 *)msg, +- 2 + msg->tx_len); ++ if (has_aw_fcs) { ++ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); ++ if (ret) ++ break; ++ ++ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs; ++ } + +- /** ++ /* + * Retry for at least 250ms before returning an error. + * Retry interval guideline: + * No minimum < Retry Interval < No maximum + * (recommend 10ms) + */ +- end = ktime_get(); +- elapsed_ms = ktime_to_ms(ktime_sub(end, start)); +- if (elapsed_ms >= DEV_PECI_RETRY_TIME_MS) { ++ if (time_after(jiffies, timeout)) { + dev_dbg(&adapter->dev, "Timeout retrying xfer!\n"); +- rc = -ETIMEDOUT; ++ ret = -ETIMEDOUT; + break; + } + +- usleep_range((DEV_PECI_RETRY_INTERVAL_USEC >> 2) + 1, +- DEV_PECI_RETRY_INTERVAL_USEC); +- } while (true); ++ usleep_range((PECI_DEV_RETRY_INTERVAL_USEC >> 2) + 1, ++ PECI_DEV_RETRY_INTERVAL_USEC); ++ } + +- if (rc) +- dev_dbg(&adapter->dev, "xfer error, rc: %d\n", rc); ++ if (ret) ++ dev_dbg(&adapter->dev, "xfer error: %d\n", ret); + +- return rc; ++ return ret; + } + + static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg) +@@ -190,34 +284,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter, + + static int peci_scan_cmd_mask(struct peci_adapter *adapter) + { +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; + u8 revision; +- int rc = 0; ++ int ret; + u64 dib; + + /* Update command mask just once */ + if (adapter->cmd_mask & BIT(PECI_CMD_XFER)) + return 0; + +- msg.addr = PECI_BASE_ADDR; +- msg.tx_len = GET_DIB_WR_LEN; +- msg.rx_len = GET_DIB_RD_LEN; +- msg.tx_buf[0] = GET_DIB_PECI_CMD; ++ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = PECI_BASE_ADDR; ++ msg->tx_buf[0] = PECI_GET_DIB_CMD; + +- rc = peci_xfer(adapter, &msg); +- if (rc) +- return rc; ++ ret = peci_xfer(adapter, msg); ++ if (ret) ++ return ret; + +- dib = le64_to_cpup((__le64 *)msg.rx_buf); ++ dib = le64_to_cpup((__le64 *)msg->rx_buf); + + /* Check special case for Get DIB command */ + if (dib == 0) { + dev_dbg(&adapter->dev, "DIB read as 0\n"); +- return -EIO; ++ ret = -EIO; ++ goto out; + } + +- /** +- * Setting up the supporting commands based on minor revision number. ++ /* ++ * Setting up the supporting commands based on revision number. + * See PECI Spec Table 3-1. + */ + revision = FIELD_GET(REVISION_NUM_MASK, dib); +@@ -243,10 +340,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) + adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB); + adapter->cmd_mask |= BIT(PECI_CMD_PING); + +- return rc; ++out: ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) ++static int peci_check_cmd_support(struct peci_adapter *adapter, ++ enum peci_cmd cmd) + { + if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) && + peci_scan_cmd_mask(adapter) < 0) { +@@ -262,70 +363,87 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) + return 0; + } + +-static int peci_ioctl_xfer(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg) + { + struct peci_xfer_msg *msg = vmsg; + + return peci_xfer(adapter, msg); + } + +-static int peci_ioctl_ping(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_ping(struct peci_adapter *adapter, void *vmsg) + { + struct peci_ping_msg *umsg = vmsg; +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ msg = peci_get_xfer_msg(0, 0); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; + +- msg.addr = umsg->addr; +- msg.tx_len = 0; +- msg.rx_len = 0; ++ ret = peci_xfer(adapter, msg); + +- return peci_xfer(adapter, &msg); ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_get_dib(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_get_dib(struct peci_adapter *adapter, void *vmsg) + { + struct peci_get_dib_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc; ++ struct peci_xfer_msg *msg; ++ int ret; + +- msg.addr = umsg->addr; +- msg.tx_len = GET_DIB_WR_LEN; +- msg.rx_len = GET_DIB_RD_LEN; +- msg.tx_buf[0] = GET_DIB_PECI_CMD; ++ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); ++ if (!msg) ++ return -ENOMEM; + +- rc = peci_xfer(adapter, &msg); +- if (rc) +- return rc; ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_GET_DIB_CMD; + +- umsg->dib = le64_to_cpup((__le64 *)msg.rx_buf); ++ ret = peci_xfer(adapter, msg); ++ if (ret) ++ goto out; + +- return 0; ++ umsg->dib = le64_to_cpup((__le64 *)msg->rx_buf); ++ ++out: ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_get_temp(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_get_temp(struct peci_adapter *adapter, void *vmsg) + { + struct peci_get_temp_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc; ++ struct peci_xfer_msg *msg; ++ int ret; + +- msg.addr = umsg->addr; +- msg.tx_len = GET_TEMP_WR_LEN; +- msg.rx_len = GET_TEMP_RD_LEN; +- msg.tx_buf[0] = GET_TEMP_PECI_CMD; ++ msg = peci_get_xfer_msg(PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN); ++ if (!msg) ++ return -ENOMEM; + +- rc = peci_xfer(adapter, &msg); +- if (rc) +- return rc; ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_GET_TEMP_CMD; + +- umsg->temp_raw = le16_to_cpup((__le16 *)msg.rx_buf); ++ ret = peci_xfer(adapter, msg); ++ if (ret) ++ goto out; + +- return 0; ++ umsg->temp_raw = le16_to_cpup((__le16 *)msg->rx_buf); ++ ++out: ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_pkg_cfg_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0; ++ struct peci_xfer_msg *msg; ++ int ret; + + /* Per the PECI spec, the read length must be a byte, word, or dword */ + if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { +@@ -334,29 +452,35 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + +- msg.addr = umsg->addr; +- msg.tx_len = RDPKGCFG_WRITE_LEN; +- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ +- msg.rx_len = RDPKGCFG_READ_LEN_BASE + umsg->rx_len; +- msg.tx_buf[0] = RDPKGCFG_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ +- /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ +- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ +- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ ++ msg = peci_get_xfer_msg(PECI_RDPKGCFG_WRITE_LEN, ++ PECI_RDPKGCFG_READ_LEN_BASE + umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDPKGCFG_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ ++ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ ++ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ + +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(umsg->pkg_config, &msg.rx_buf[1], umsg->rx_len); ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len); + +- return rc; ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + { + struct peci_wr_pkg_cfg_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0, i; ++ struct peci_xfer_msg *msg; ++ int ret, i; ++ u8 aw_fcs; + + /* Per the PECI spec, the write length must be a dword */ + if (umsg->tx_len != 4) { +@@ -365,86 +489,116 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + +- msg.addr = umsg->addr; +- msg.tx_len = WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len; +- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ +- msg.rx_len = WRPKGCFG_READ_LEN; +- msg.tx_buf[0] = WRPKGCFG_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ msg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len, ++ PECI_WRPKGCFG_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_WRPKGCFG_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ + /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ +- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ +- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ ++ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ ++ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ ++ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ + for (i = 0; i < umsg->tx_len; i++) +- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ ++ /* Add an Assured Write Frame Check Sequence byte */ ++ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); ++ if (ret) ++ goto out; + +- /* Add an Assure Write Frame Check Sequence byte */ +- msg.tx_buf[5 + i] = 0x80 ^ +- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); ++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; + +- rc = peci_xfer_with_retries(adapter, &msg, true); ++ ret = peci_xfer_with_retries(adapter, msg, true); + +- return rc; ++out: ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_ia_msr_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0; +- +- msg.addr = umsg->addr; +- msg.tx_len = RDIAMSR_WRITE_LEN; +- msg.rx_len = RDIAMSR_READ_LEN; +- msg.tx_buf[0] = RDIAMSR_PECI_CMD; +- msg.tx_buf[1] = 0; +- msg.tx_buf[2] = umsg->thread_id; +- msg.tx_buf[3] = (u8)umsg->address; +- msg.tx_buf[4] = (u8)(umsg->address >> 8); +- +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(&umsg->value, &msg.rx_buf[1], sizeof(uint64_t)); +- +- return rc; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ msg = peci_get_xfer_msg(PECI_RDIAMSR_WRITE_LEN, PECI_RDIAMSR_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDIAMSR_CMD; ++ msg->tx_buf[1] = 0; ++ msg->tx_buf[2] = umsg->thread_id; ++ msg->tx_buf[3] = (u8)umsg->address; ++ msg->tx_buf[4] = (u8)(umsg->address >> 8); ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t)); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg) ++{ ++ return -ENOSYS; /* Not implemented yet */ ++} ++ ++static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_pci_cfg_msg *umsg = vmsg; +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; + u32 address; +- int rc = 0; ++ int ret; ++ ++ msg = peci_get_xfer_msg(PECI_RDPCICFG_WRITE_LEN, ++ PECI_RDPCICFG_READ_LEN); ++ if (!msg) ++ return -ENOMEM; + + address = umsg->reg; /* [11:0] - Register */ + address |= (u32)umsg->function << 12; /* [14:12] - Function */ + address |= (u32)umsg->device << 15; /* [19:15] - Device */ + address |= (u32)umsg->bus << 20; /* [27:20] - Bus */ + /* [31:28] - Reserved */ +- msg.addr = umsg->addr; +- msg.tx_len = RDPCICFG_WRITE_LEN; +- msg.rx_len = RDPCICFG_READ_LEN; +- msg.tx_buf[0] = RDPCICFG_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDPCICFG_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ + /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ +- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ +- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ +- msg.tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ ++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ ++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ ++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ ++ msg->tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->pci_config, &msg->rx_buf[1], 4); + +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(umsg->pci_config, &msg.rx_buf[1], 4); ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- return rc; ++ return ret; + } + +-static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_pci_cfg(struct peci_adapter *adapter, void *vmsg) ++{ ++ return -ENOSYS; /* Not implemented yet */ ++} ++ ++static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_pci_cfg_local_msg *umsg = vmsg; +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; + u32 address; +- int rc = 0; ++ int ret; + + /* Per the PECI spec, the read length must be a byte, word, or dword */ + if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { +@@ -453,34 +607,42 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + ++ msg = peci_get_xfer_msg(PECI_RDPCICFGLOCAL_WRITE_LEN, ++ PECI_RDPCICFGLOCAL_READ_LEN_BASE + ++ umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ + address = umsg->reg; /* [11:0] - Register */ + address |= (u32)umsg->function << 12; /* [14:12] - Function */ + address |= (u32)umsg->device << 15; /* [19:15] - Device */ + address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ + +- msg.addr = umsg->addr; +- msg.tx_len = RDPCICFGLOCAL_WRITE_LEN; +- msg.rx_len = RDPCICFGLOCAL_READ_LEN_BASE + umsg->rx_len; +- msg.tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ +- /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ +- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ +- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDPCICFGLOCAL_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ ++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ ++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len); + +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(umsg->pci_config, &msg.rx_buf[1], umsg->rx_len); ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- return rc; ++ return ret; + } + +-static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + { + struct peci_wr_pci_cfg_local_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0, i; ++ struct peci_xfer_msg *msg; + u32 address; ++ int ret, i; ++ u8 aw_fcs; + + /* Per the PECI spec, the write length must be a byte, word, or dword */ + if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) { +@@ -489,47 +651,57 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + ++ msg = peci_get_xfer_msg(PECI_WRPCICFGLOCAL_WRITE_LEN_BASE + ++ umsg->tx_len, PECI_WRPCICFGLOCAL_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ + address = umsg->reg; /* [11:0] - Register */ + address |= (u32)umsg->function << 12; /* [14:12] - Function */ + address |= (u32)umsg->device << 15; /* [19:15] - Device */ + address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ + +- msg.addr = umsg->addr; +- msg.tx_len = WRPCICFGLOCAL_WRITE_LEN_BASE + umsg->tx_len; +- msg.rx_len = WRPCICFGLOCAL_READ_LEN; +- msg.tx_buf[0] = WRPCICFGLOCAL_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ +- /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ +- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ +- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_WRPCICFGLOCAL_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ ++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ ++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ + for (i = 0; i < umsg->tx_len; i++) +- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ ++ /* Add an Assured Write Frame Check Sequence byte */ ++ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); ++ if (ret) ++ goto out; ++ ++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; + +- /* Add an Assure Write Frame Check Sequence byte */ +- msg.tx_buf[5 + i] = 0x80 ^ +- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); ++ ret = peci_xfer_with_retries(adapter, msg, true); + +- rc = peci_xfer_with_retries(adapter, &msg, true); ++out: ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- return rc; ++ return ret; + } + +-typedef int (*peci_ioctl_fn_type)(struct peci_adapter *, void *); +- +-static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { +- peci_ioctl_xfer, +- peci_ioctl_ping, +- peci_ioctl_get_dib, +- peci_ioctl_get_temp, +- peci_ioctl_rd_pkg_cfg, +- peci_ioctl_wr_pkg_cfg, +- peci_ioctl_rd_ia_msr, +- NULL, /* Reserved */ +- peci_ioctl_rd_pci_cfg, +- NULL, /* Reserved */ +- peci_ioctl_rd_pci_cfg_local, +- peci_ioctl_wr_pci_cfg_local, ++typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *); ++ ++static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { ++ peci_cmd_xfer, ++ peci_cmd_ping, ++ peci_cmd_get_dib, ++ peci_cmd_get_temp, ++ peci_cmd_rd_pkg_cfg, ++ peci_cmd_wr_pkg_cfg, ++ peci_cmd_rd_ia_msr, ++ peci_cmd_wr_ia_msr, ++ peci_cmd_rd_pci_cfg, ++ peci_cmd_wr_pci_cfg, ++ peci_cmd_rd_pci_cfg_local, ++ peci_cmd_wr_pci_cfg_local, + }; + + /** +@@ -545,109 +717,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { + */ + int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg) + { +- int rc = 0; ++ int ret; + + if (cmd >= PECI_CMD_MAX || cmd < PECI_CMD_XFER) +- return -EINVAL; ++ return -ENOTTY; + + dev_dbg(&adapter->dev, "%s, cmd=0x%02x\n", __func__, cmd); + +- if (!peci_ioctl_fn[cmd]) ++ if (!peci_cmd_fn[cmd]) + return -EINVAL; + +- rt_mutex_lock(&adapter->bus_lock); ++ mutex_lock(&adapter->bus_lock); + +- rc = peci_cmd_support(adapter, cmd); +- if (!rc) +- rc = peci_ioctl_fn[cmd](adapter, vmsg); ++ ret = peci_check_cmd_support(adapter, cmd); ++ if (!ret) ++ ret = peci_cmd_fn[cmd](adapter, vmsg); + +- rt_mutex_unlock(&adapter->bus_lock); ++ mutex_unlock(&adapter->bus_lock); + +- return rc; ++ return ret; + } + EXPORT_SYMBOL_GPL(peci_command); + +-static long peci_ioctl(struct file *file, unsigned int iocmd, unsigned long arg) +-{ +- struct peci_adapter *adapter = file->private_data; +- void __user *argp = (void __user *)arg; +- unsigned int msg_len; +- enum peci_cmd cmd; +- int rc = 0; +- u8 *msg; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- dev_dbg(&adapter->dev, "ioctl, cmd=0x%x, arg=0x%lx\n", iocmd, arg); +- +- switch (iocmd) { +- case PECI_IOC_XFER: +- case PECI_IOC_PING: +- case PECI_IOC_GET_DIB: +- case PECI_IOC_GET_TEMP: +- case PECI_IOC_RD_PKG_CFG: +- case PECI_IOC_WR_PKG_CFG: +- case PECI_IOC_RD_IA_MSR: +- case PECI_IOC_RD_PCI_CFG: +- case PECI_IOC_RD_PCI_CFG_LOCAL: +- case PECI_IOC_WR_PCI_CFG_LOCAL: +- cmd = _IOC_NR(iocmd); +- msg_len = _IOC_SIZE(iocmd); +- break; +- +- default: +- dev_dbg(&adapter->dev, "Invalid ioctl cmd : 0x%x\n", iocmd); +- return -ENOTTY; +- } +- +- if (!access_ok(argp, msg_len)) +- return -EFAULT; +- +- msg = memdup_user(argp, msg_len); +- if (IS_ERR(msg)) +- return PTR_ERR(msg); +- +- rc = peci_command(adapter, cmd, msg); +- +- if (!rc && copy_to_user(argp, msg, msg_len)) +- rc = -EFAULT; +- +- kfree(msg); +- return (long)rc; +-} +- +-static int peci_open(struct inode *inode, struct file *file) +-{ +- unsigned int minor = iminor(inode); +- struct peci_adapter *adapter; +- +- adapter = peci_get_adapter(minor); +- if (!adapter) +- return -ENODEV; +- +- file->private_data = adapter; +- +- return 0; +-} +- +-static int peci_release(struct inode *inode, struct file *file) +-{ +- struct peci_adapter *adapter = file->private_data; +- +- peci_put_adapter(adapter); +- file->private_data = NULL; +- +- return 0; +-} +- +-static const struct file_operations peci_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = peci_ioctl, +- .open = peci_open, +- .release = peci_release, +-}; +- + static int peci_detect(struct peci_adapter *adapter, u8 addr) + { + struct peci_ping_msg msg; +@@ -666,9 +757,9 @@ peci_of_match_device(const struct of_device_id *matches, + return NULL; + + return of_match_device(matches, &client->dev); +-#else ++#else /* CONFIG_OF */ + return NULL; +-#endif ++#endif /* CONFIG_OF */ + } + + static const struct peci_device_id * +@@ -737,6 +828,7 @@ static int peci_device_probe(struct device *dev) + + err_detach_pm_domain: + dev_pm_domain_detach(&client->dev, true); ++ + return status; + } + +@@ -775,13 +867,14 @@ static void peci_device_shutdown(struct device *dev) + driver->shutdown(client); + } + +-static struct bus_type peci_bus_type = { ++struct bus_type peci_bus_type = { + .name = "peci", + .match = peci_device_match, + .probe = peci_device_probe, + .remove = peci_device_remove, + .shutdown = peci_device_shutdown, + }; ++EXPORT_SYMBOL_GPL(peci_bus_type); + + static int peci_check_addr_validity(u8 addr) + { +@@ -814,18 +907,22 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p) + int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id) + { + struct peci_rd_pkg_cfg_msg msg; +- int rc; ++ int ret; + + msg.addr = addr; +- msg.index = MBX_INDEX_CPU_ID; +- msg.param = PKG_ID_CPU_ID; ++ msg.index = PECI_MBX_INDEX_CPU_ID; ++ msg.param = PECI_PKG_ID_CPU_ID; + msg.rx_len = 4; + +- rc = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); +- if (!rc) +- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); ++ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); + +- return rc; ++ return 0; + } + EXPORT_SYMBOL_GPL(peci_get_cpu_id); + +@@ -833,7 +930,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, + struct peci_board_info const *info) + { + struct peci_client *client; +- int rc; ++ int ret; + + /* Increase reference count for the adapter assigned */ + if (!peci_get_adapter(adapter->nr)) +@@ -847,46 +944,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, + client->addr = info->addr; + strlcpy(client->name, info->type, sizeof(client->name)); + +- rc = peci_check_addr_validity(client->addr); +- if (rc) { ++ ret = peci_check_addr_validity(client->addr); ++ if (ret) { + dev_err(&adapter->dev, "Invalid PECI CPU address 0x%02hx\n", + client->addr); + goto err_free_client_silent; + } + + /* Check online status of client */ +- rc = peci_detect(adapter, client->addr); +- if (rc) ++ ret = peci_detect(adapter, client->addr); ++ if (ret) + goto err_free_client; + +- rc = device_for_each_child(&adapter->dev, client, +- peci_check_client_busy); +- if (rc) ++ ret = device_for_each_child(&adapter->dev, client, ++ peci_check_client_busy); ++ if (ret) + goto err_free_client; + + client->dev.parent = &client->adapter->dev; + client->dev.bus = &peci_bus_type; + client->dev.type = &peci_client_type; +- client->dev.of_node = info->of_node; ++ client->dev.of_node = of_node_get(info->of_node); + dev_set_name(&client->dev, "%d-%02x", adapter->nr, client->addr); + +- rc = device_register(&client->dev); +- if (rc) +- goto err_free_client; ++ ret = device_register(&client->dev); ++ if (ret) ++ goto err_put_of_node; + + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", + client->name, dev_name(&client->dev)); + + return client; + ++err_put_of_node: ++ of_node_put(info->of_node); + err_free_client: + dev_err(&adapter->dev, + "Failed to register peci client %s at 0x%02x (%d)\n", +- client->name, client->addr, rc); ++ client->name, client->addr, ret); + err_free_client_silent: + kfree(client); + err_put_adapter: + peci_put_adapter(adapter); ++ + return NULL; + } + +@@ -895,8 +995,10 @@ static void peci_unregister_device(struct peci_client *client) + if (!client) + return; + +- if (client->dev.of_node) ++ if (client->dev.of_node) { + of_node_clear_flag(client->dev.of_node, OF_POPULATED); ++ of_node_put(client->dev.of_node); ++ } + + device_unregister(&client->dev); + } +@@ -916,7 +1018,7 @@ static void peci_adapter_dev_release(struct device *dev) + + dev_dbg(dev, "%s: %s\n", __func__, adapter->name); + mutex_destroy(&adapter->userspace_clients_lock); +- rt_mutex_destroy(&adapter->bus_lock); ++ mutex_destroy(&adapter->bus_lock); + kfree(adapter); + } + +@@ -928,7 +1030,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, + struct peci_board_info info = {}; + struct peci_client *client; + char *blank, end; +- int rc; ++ short addr; ++ int ret; + + /* Parse device type */ + blank = strchr(buf, ' '); +@@ -943,16 +1046,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev, + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ +- rc = sscanf(++blank, "%hi%c", &info.addr, &end); +- if (rc < 1) { ++ ret = sscanf(++blank, "%hi%c", &addr, &end); ++ if (ret < 1) { + dev_err(dev, "%s: Can't parse client address\n", "new_device"); + return -EINVAL; + } +- if (rc > 1 && end != '\n') { ++ if (ret > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "new_device"); + return -EINVAL; + } + ++ info.addr = (u8)addr; + client = peci_new_device(adapter, &info); + if (!client) + return -EINVAL; +@@ -961,8 +1065,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, + mutex_lock(&adapter->userspace_clients_lock); + list_add_tail(&client->detected, &adapter->userspace_clients); + mutex_unlock(&adapter->userspace_clients_lock); +- dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", +- info.type, info.addr); ++ dev_dbg(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", ++ info.type, info.addr); + + return count; + } +@@ -975,9 +1079,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, + struct peci_adapter *adapter = to_peci_adapter(dev); + struct peci_client *client, *next; + struct peci_board_info info = {}; +- struct peci_driver *driver; + char *blank, end; +- int rc; ++ short addr; ++ int ret; + + /* Parse device type */ + blank = strchr(buf, ' '); +@@ -992,41 +1096,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ +- rc = sscanf(++blank, "%hi%c", &info.addr, &end); +- if (rc < 1) { ++ ret = sscanf(++blank, "%hi%c", &addr, &end); ++ if (ret < 1) { + dev_err(dev, "%s: Can't parse client address\n", + "delete_device"); + return -EINVAL; + } +- if (rc > 1 && end != '\n') { ++ if (ret > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "delete_device"); + return -EINVAL; + } + ++ info.addr = (u8)addr; ++ + /* Make sure the device was added through sysfs */ +- rc = -ENOENT; ++ ret = -ENOENT; + mutex_lock(&adapter->userspace_clients_lock); + list_for_each_entry_safe(client, next, &adapter->userspace_clients, + detected) { +- driver = to_peci_driver(client->dev.driver); +- + if (client->addr == info.addr && + !strncmp(client->name, info.type, PECI_NAME_SIZE)) { +- dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", +- "delete_device", client->name, client->addr); ++ dev_dbg(dev, "%s: Deleting device %s at 0x%02hx\n", ++ "delete_device", client->name, client->addr); + list_del(&client->detected); + peci_unregister_device(client); +- rc = count; ++ ret = count; + break; + } + } + mutex_unlock(&adapter->userspace_clients_lock); + +- if (rc < 0) +- dev_err(dev, "%s: Can't find device in list\n", ++ if (ret < 0) ++ dev_dbg(dev, "%s: Can't find device in list\n", + "delete_device"); + +- return rc; ++ return ret; + } + static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL, + peci_sysfs_delete_device); +@@ -1039,10 +1143,11 @@ static struct attribute *peci_adapter_attrs[] = { + }; + ATTRIBUTE_GROUPS(peci_adapter); + +-static struct device_type peci_adapter_type = { ++struct device_type peci_adapter_type = { + .groups = peci_adapter_groups, + .release = peci_adapter_dev_release, + }; ++EXPORT_SYMBOL_GPL(peci_adapter_type); + + /** + * peci_verify_adapter - return parameter as peci_adapter, or NULL +@@ -1063,32 +1168,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter, + struct device_node *node) + { + struct peci_board_info info = {}; +- struct peci_client *result; +- const __be32 *addr_be; +- int len; ++ struct peci_client *client; ++ u32 addr; ++ int ret; + + dev_dbg(&adapter->dev, "register %pOF\n", node); + +- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { +- dev_err(&adapter->dev, "modalias failure on %pOF\n", node); +- return ERR_PTR(-EINVAL); +- } +- +- addr_be = of_get_property(node, "reg", &len); +- if (!addr_be || len < sizeof(*addr_be)) { ++ ret = of_property_read_u32(node, "reg", &addr); ++ if (ret) { + dev_err(&adapter->dev, "invalid reg on %pOF\n", node); +- return ERR_PTR(-EINVAL); ++ return ERR_PTR(ret); + } + +- info.addr = be32_to_cpup(addr_be); +- info.of_node = of_node_get(node); ++ info.addr = addr; ++ info.of_node = node; + +- result = peci_new_device(adapter, &info); +- if (!result) +- result = ERR_PTR(-EINVAL); ++ client = peci_new_device(adapter, &info); ++ if (!client) ++ client = ERR_PTR(-EINVAL); + +- of_node_put(node); +- return result; ++ return client; + } + + static void peci_of_register_devices(struct peci_adapter *adapter) +@@ -1119,7 +1218,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter) + + of_node_put(bus); + } +-#else ++#else /* CONFIG_OF */ + static void peci_of_register_devices(struct peci_adapter *adapter) { } + #endif /* CONFIG_OF */ + +@@ -1163,9 +1262,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node) + return adapter; + } + +-static int peci_of_notify(struct notifier_block *nb, +- unsigned long action, +- void *arg) ++static int peci_of_notify(struct notifier_block *nb, ulong action, void *arg) + { + struct of_reconfig_data *rd = arg; + struct peci_adapter *adapter; +@@ -1216,7 +1313,7 @@ static int peci_of_notify(struct notifier_block *nb, + static struct notifier_block peci_of_notifier = { + .notifier_call = peci_of_notify, + }; +-#else ++#else /* CONFIG_OF_DYNAMIC */ + extern struct notifier_block peci_of_notifier; + #endif /* CONFIG_OF_DYNAMIC */ + +@@ -1240,7 +1337,7 @@ extern struct notifier_block peci_of_notifier; + * + * Return: the peci_adapter structure on success, else NULL. + */ +-struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size) ++struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size) + { + struct peci_adapter *adapter; + +@@ -1263,7 +1360,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter); + + static int peci_register_adapter(struct peci_adapter *adapter) + { +- int rc = -EINVAL; ++ int ret = -EINVAL; + + /* Can't register until after driver model init */ + if (WARN_ON(!is_registered)) +@@ -1275,27 +1372,17 @@ static int peci_register_adapter(struct peci_adapter *adapter) + if (WARN(!adapter->xfer, "peci adapter has no xfer function\n")) + goto err_free_idr; + +- rt_mutex_init(&adapter->bus_lock); ++ mutex_init(&adapter->bus_lock); + mutex_init(&adapter->userspace_clients_lock); + INIT_LIST_HEAD(&adapter->userspace_clients); + + dev_set_name(&adapter->dev, "peci-%d", adapter->nr); + +- /* cdev */ +- cdev_init(&adapter->cdev, &peci_fops); +- adapter->cdev.owner = THIS_MODULE; +- adapter->dev.devt = MKDEV(MAJOR(peci_devt), adapter->nr); +- rc = cdev_add(&adapter->cdev, adapter->dev.devt, 1); +- if (rc) { +- pr_err("adapter '%s': can't add cdev (%d)\n", +- adapter->name, rc); +- goto err_free_idr; +- } +- rc = device_add(&adapter->dev); +- if (rc) { ++ ret = device_add(&adapter->dev); ++ if (ret) { + pr_err("adapter '%s': can't add device (%d)\n", +- adapter->name, rc); +- goto err_del_cdev; ++ adapter->name, ret); ++ goto err_free_idr; + } + + dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name); +@@ -1309,13 +1396,11 @@ static int peci_register_adapter(struct peci_adapter *adapter) + + return 0; + +-err_del_cdev: +- cdev_del(&adapter->cdev); + err_free_idr: + mutex_lock(&core_lock); + idr_remove(&peci_adapter_idr, adapter->nr); + mutex_unlock(&core_lock); +- return rc; ++ return ret; + } + + static int peci_add_numbered_adapter(struct peci_adapter *adapter) +@@ -1354,12 +1439,10 @@ int peci_add_adapter(struct peci_adapter *adapter) + struct device *dev = &adapter->dev; + int id; + +- if (dev->of_node) { +- id = of_alias_get_id(dev->of_node, "peci"); +- if (id >= 0) { +- adapter->nr = id; +- return peci_add_numbered_adapter(adapter); +- } ++ id = of_alias_get_id(dev->of_node, "peci"); ++ if (id >= 0) { ++ adapter->nr = id; ++ return peci_add_numbered_adapter(adapter); + } + + mutex_lock(&core_lock); +@@ -1411,7 +1494,7 @@ void peci_del_adapter(struct peci_adapter *adapter) + } + mutex_unlock(&adapter->userspace_clients_lock); + +- /** ++ /* + * Detach any active clients. This can't fail, thus we do not + * check the returned value. + */ +@@ -1420,13 +1503,8 @@ void peci_del_adapter(struct peci_adapter *adapter) + /* device name is gone after device_unregister */ + dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name); + +- /* free cdev */ +- cdev_del(&adapter->cdev); +- + pm_runtime_disable(&adapter->dev); +- + nr = adapter->nr; +- + device_unregister(&adapter->dev); + + /* free bus id */ +@@ -1436,6 +1514,18 @@ void peci_del_adapter(struct peci_adapter *adapter) + } + EXPORT_SYMBOL_GPL(peci_del_adapter); + ++int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)) ++{ ++ int ret; ++ ++ mutex_lock(&core_lock); ++ ret = bus_for_each_dev(&peci_bus_type, NULL, data, fn); ++ mutex_unlock(&core_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(peci_for_each_dev); ++ + /** + * peci_register_driver - register a PECI driver + * @owner: owner module of the driver being registered +@@ -1446,7 +1536,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter); + */ + int peci_register_driver(struct module *owner, struct peci_driver *driver) + { +- int rc; ++ int ret; + + /* Can't register until after driver model init */ + if (WARN_ON(!is_registered)) +@@ -1456,13 +1546,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver) + driver->driver.owner = owner; + driver->driver.bus = &peci_bus_type; + +- /** ++ /* + * When registration returns, the driver core + * will have called probe() for all matching-but-unbound devices. + */ +- rc = driver_register(&driver->driver); +- if (rc) +- return rc; ++ ret = driver_register(&driver->driver); ++ if (ret) ++ return ret; + + pr_debug("driver [%s] registered\n", driver->driver.name); + +@@ -1492,13 +1582,6 @@ static int __init peci_init(void) + return ret; + } + +- ret = alloc_chrdev_region(&peci_devt, 0, PECI_CDEV_MAX, "peci"); +- if (ret < 0) { +- pr_err("peci: Failed to allocate chr dev region!\n"); +- bus_unregister(&peci_bus_type); +- return ret; +- } +- + crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL); + + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) +@@ -1514,11 +1597,10 @@ static void __exit peci_exit(void) + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier)); + +- unregister_chrdev_region(peci_devt, PECI_CDEV_MAX); + bus_unregister(&peci_bus_type); + } + +-postcore_initcall(peci_init); ++subsys_initcall(peci_init); + module_exit(peci_exit); + + MODULE_AUTHOR("Jason M Biils <jason.m.bills@linux.intel.com>"); +diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c +new file mode 100644 +index 000000000000..ac9cba0fb429 +--- /dev/null ++++ b/drivers/peci/peci-dev.c +@@ -0,0 +1,346 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <linux/cdev.h> ++#include <linux/fs.h> ++#include <linux/list.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/peci.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++ ++/* ++ * A peci_dev represents an peci_adapter ... an PECI or SMBus master, not a ++ * slave (peci_client) with which messages will be exchanged. It's coupled ++ * with a character special file which is accessed by user mode drivers. ++ * ++ * The list of peci_dev structures is parallel to the peci_adapter lists ++ * maintained by the driver model, and is updated using bus notifications. ++ */ ++struct peci_dev { ++ struct list_head list; ++ struct peci_adapter *adapter; ++ struct device *dev; ++ struct cdev cdev; ++}; ++ ++#define PECI_MINORS MINORMASK ++ ++static dev_t peci_devt; ++static LIST_HEAD(peci_dev_list); ++static DEFINE_SPINLOCK(peci_dev_list_lock); ++ ++static struct peci_dev *peci_dev_get_by_minor(uint index) ++{ ++ struct peci_dev *peci_dev; ++ ++ spin_lock(&peci_dev_list_lock); ++ list_for_each_entry(peci_dev, &peci_dev_list, list) { ++ if (peci_dev->adapter->nr == index) ++ goto found; ++ } ++ peci_dev = NULL; ++found: ++ spin_unlock(&peci_dev_list_lock); ++ ++ return peci_dev; ++} ++ ++static struct peci_dev *peci_dev_alloc(struct peci_adapter *adapter) ++{ ++ struct peci_dev *peci_dev; ++ ++ if (adapter->nr >= PECI_MINORS) { ++ printk(KERN_ERR "peci-dev: Out of device minors (%d)\n", ++ adapter->nr); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ peci_dev = kzalloc(sizeof(*peci_dev), GFP_KERNEL); ++ if (!peci_dev) ++ return ERR_PTR(-ENOMEM); ++ peci_dev->adapter = adapter; ++ ++ spin_lock(&peci_dev_list_lock); ++ list_add_tail(&peci_dev->list, &peci_dev_list); ++ spin_unlock(&peci_dev_list_lock); ++ ++ return peci_dev; ++} ++ ++static void peci_dev_put(struct peci_dev *peci_dev) ++{ ++ spin_lock(&peci_dev_list_lock); ++ list_del(&peci_dev->list); ++ spin_unlock(&peci_dev_list_lock); ++ kfree(peci_dev); ++} ++ ++static ssize_t name_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct peci_dev *peci_dev = peci_dev_get_by_minor(MINOR(dev->devt)); ++ ++ if (!peci_dev) ++ return -ENODEV; ++ ++ return sprintf(buf, "%s\n", peci_dev->adapter->name); ++} ++static DEVICE_ATTR_RO(name); ++ ++static struct attribute *peci_dev_attrs[] = { ++ &dev_attr_name.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(peci_dev); ++ ++static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg) ++{ ++ struct peci_dev *peci_dev = file->private_data; ++ void __user *umsg = (void __user *)arg; ++ struct peci_xfer_msg *xmsg = NULL; ++ struct peci_xfer_msg uxmsg; ++ enum peci_cmd cmd; ++ u8 *msg = NULL; ++ uint msg_len; ++ int ret; ++ ++ cmd = _IOC_NR(iocmd); ++ msg_len = _IOC_SIZE(iocmd); ++ ++ switch (cmd) { ++ case PECI_CMD_XFER: ++ if (msg_len != sizeof(struct peci_xfer_msg)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ if (copy_from_user(&uxmsg, umsg, msg_len)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len); ++ if (IS_ERR(xmsg)) { ++ ret = PTR_ERR(xmsg); ++ break; ++ } ++ ++ if (uxmsg.tx_len && ++ copy_from_user(xmsg->tx_buf, uxmsg.tx_buf, uxmsg.tx_len)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ xmsg->addr = uxmsg.addr; ++ xmsg->tx_len = uxmsg.tx_len; ++ xmsg->rx_len = uxmsg.rx_len; ++ ++ ret = peci_command(peci_dev->adapter, cmd, xmsg); ++ if (!ret && xmsg->rx_len && ++ copy_to_user(uxmsg.rx_buf, xmsg->rx_buf, xmsg->rx_len)) ++ ret = -EFAULT; ++ ++ break; ++ ++ default: ++ msg = memdup_user(umsg, msg_len); ++ if (IS_ERR(msg)) { ++ ret = PTR_ERR(msg); ++ break; ++ } ++ ++ ret = peci_command(peci_dev->adapter, cmd, msg); ++ if ((!ret || ret == -ETIMEDOUT) && ++ copy_to_user(umsg, msg, msg_len)) ++ ret = -EFAULT; ++ ++ break; ++ } ++ ++ peci_put_xfer_msg(xmsg); ++ kfree(msg); ++ ++ return (long)ret; ++} ++ ++static int peci_dev_open(struct inode *inode, struct file *file) ++{ ++ struct peci_adapter *adapter; ++ struct peci_dev *peci_dev; ++ ++ peci_dev = peci_dev_get_by_minor(iminor(inode)); ++ if (!peci_dev) ++ return -ENODEV; ++ ++ adapter = peci_get_adapter(peci_dev->adapter->nr); ++ if (!adapter) ++ return -ENODEV; ++ ++ file->private_data = peci_dev; ++ ++ return 0; ++} ++ ++static int peci_dev_release(struct inode *inode, struct file *file) ++{ ++ struct peci_dev *peci_dev = file->private_data; ++ ++ peci_put_adapter(peci_dev->adapter); ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static const struct file_operations peci_dev_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = peci_dev_ioctl, ++ .open = peci_dev_open, ++ .release = peci_dev_release, ++ .llseek = no_llseek, ++}; ++ ++static struct class *peci_dev_class; ++ ++static int peci_dev_attach_adapter(struct device *dev, void *dummy) ++{ ++ struct peci_adapter *adapter; ++ struct peci_dev *peci_dev; ++ dev_t devt; ++ int ret; ++ ++ if (dev->type != &peci_adapter_type) ++ return 0; ++ ++ adapter = to_peci_adapter(dev); ++ peci_dev = peci_dev_alloc(adapter); ++ if (IS_ERR(peci_dev)) ++ return PTR_ERR(peci_dev); ++ ++ cdev_init(&peci_dev->cdev, &peci_dev_fops); ++ peci_dev->cdev.owner = THIS_MODULE; ++ devt = MKDEV(MAJOR(peci_devt), adapter->nr); ++ ++ ret = cdev_add(&peci_dev->cdev, devt, 1); ++ if (ret) ++ goto err_put_dev; ++ ++ /* register this peci device with the driver core */ ++ peci_dev->dev = device_create(peci_dev_class, &adapter->dev, devt, NULL, ++ "peci-%d", adapter->nr); ++ if (IS_ERR(peci_dev->dev)) { ++ ret = PTR_ERR(peci_dev->dev); ++ goto err_del_cdev; ++ } ++ ++ pr_info("peci-dev: adapter [%s] registered as minor %d\n", ++ adapter->name, adapter->nr); ++ ++ return 0; ++ ++err_del_cdev: ++ cdev_del(&peci_dev->cdev); ++err_put_dev: ++ peci_dev_put(peci_dev); ++ ++ return ret; ++} ++ ++static int peci_dev_detach_adapter(struct device *dev, void *dummy) ++{ ++ struct peci_adapter *adapter; ++ struct peci_dev *peci_dev; ++ dev_t devt; ++ ++ if (dev->type != &peci_adapter_type) ++ return 0; ++ ++ adapter = to_peci_adapter(dev); ++ peci_dev = peci_dev_get_by_minor(adapter->nr); ++ if (!peci_dev) ++ return 0; ++ ++ cdev_del(&peci_dev->cdev); ++ devt = peci_dev->dev->devt; ++ peci_dev_put(peci_dev); ++ device_destroy(peci_dev_class, devt); ++ ++ pr_info("peci-dev: adapter [%s] unregistered\n", adapter->name); ++ ++ return 0; ++} ++ ++static int peci_dev_notifier_call(struct notifier_block *nb, ulong action, ++ void *data) ++{ ++ struct device *dev = data; ++ ++ switch (action) { ++ case BUS_NOTIFY_ADD_DEVICE: ++ return peci_dev_attach_adapter(dev, NULL); ++ case BUS_NOTIFY_DEL_DEVICE: ++ return peci_dev_detach_adapter(dev, NULL); ++ } ++ ++ return 0; ++} ++ ++static struct notifier_block peci_dev_notifier = { ++ .notifier_call = peci_dev_notifier_call, ++}; ++ ++static int __init peci_dev_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "peci /dev entries driver\n"); ++ ++ ret = alloc_chrdev_region(&peci_devt, 0, PECI_MINORS, "peci"); ++ if (ret < 0) { ++ pr_err("peci: Failed to allocate chr dev region!\n"); ++ bus_unregister(&peci_bus_type); ++ goto err; ++ } ++ ++ peci_dev_class = class_create(THIS_MODULE, "peci-dev"); ++ if (IS_ERR(peci_dev_class)) { ++ ret = PTR_ERR(peci_dev_class); ++ goto err_unreg_chrdev; ++ } ++ peci_dev_class->dev_groups = peci_dev_groups; ++ ++ /* Keep track of adapters which will be added or removed later */ ++ ret = bus_register_notifier(&peci_bus_type, &peci_dev_notifier); ++ if (ret) ++ goto err_destroy_class; ++ ++ /* Bind to already existing adapters right away */ ++ peci_for_each_dev(NULL, peci_dev_attach_adapter); ++ ++ return 0; ++ ++err_destroy_class: ++ class_destroy(peci_dev_class); ++err_unreg_chrdev: ++ unregister_chrdev_region(peci_devt, PECI_MINORS); ++err: ++ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__); ++ ++ return ret; ++} ++ ++static void __exit peci_dev_exit(void) ++{ ++ bus_unregister_notifier(&peci_bus_type, &peci_dev_notifier); ++ peci_for_each_dev(NULL, peci_dev_detach_adapter); ++ class_destroy(peci_dev_class); ++ unregister_chrdev_region(peci_devt, PECI_MINORS); ++} ++ ++module_init(peci_dev_init); ++module_exit(peci_dev_exit); ++ ++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); ++MODULE_DESCRIPTION("PECI /dev entries driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/peci-npcm.c b/drivers/peci/peci-npcm.c +deleted file mode 100644 +index f632365b1416..000000000000 +--- a/drivers/peci/peci-npcm.c ++++ /dev/null +@@ -1,410 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2019 Nuvoton Technology corporation. +- +-#include <linux/bitfield.h> +-#include <linux/clk.h> +-#include <linux/interrupt.h> +-#include <linux/jiffies.h> +-#include <linux/module.h> +-#include <linux/of.h> +-#include <linux/peci.h> +-#include <linux/platform_device.h> +-#include <linux/regmap.h> +-#include <linux/mfd/syscon.h> +-#include <linux/reset.h> +- +-/* NPCM7xx GCR module */ +-#define NPCM7XX_INTCR3_OFFSET 0x9C +-#define NPCM7XX_INTCR3_PECIVSEL BIT(19) +- +-/* NPCM PECI Registers */ +-#define NPCM_PECI_CTL_STS 0x00 +-#define NPCM_PECI_RD_LENGTH 0x04 +-#define NPCM_PECI_ADDR 0x08 +-#define NPCM_PECI_CMD 0x0C +-#define NPCM_PECI_CTL2 0x10 +-#define NPCM_PECI_WR_LENGTH 0x1C +-#define NPCM_PECI_PDDR 0x2C +-#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) +- +-#define NPCM_PECI_MAX_REG 0x200 +- +-/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ +-#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) +-#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) +-#define NPCM_PECI_CTRL_CRC_ERR BIT(3) +-#define NPCM_PECI_CTRL_DONE BIT(1) +-#define NPCM_PECI_CTRL_START_BUSY BIT(0) +- +-/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ +-#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) +- +-/* NPCM_PECI_CMD - 0x10 : Command Register */ +-#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) +- +-/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ +-#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) +- +-/* NPCM_PECI_PDDR - 0x2C : Command Register */ +-#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) +- +-#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ +- NPCM_PECI_CTRL_CRC_ERR | \ +- NPCM_PECI_CTRL_DONE) +- +-#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 +-#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 +-#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 +-#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 +-#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 +-#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 +-#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 +-#define NPCM_PECI_PULL_DOWN_DEFAULT 0 +-#define NPCM_PECI_PULL_DOWN_MAX 2 +- +-struct npcm_peci { +- u32 cmd_timeout_ms; +- u32 host_bit_rate; +- struct completion xfer_complete; +- struct regmap *gcr_regmap; +- struct peci_adapter *adapter; +- struct regmap *regmap; +- u32 status; +- spinlock_t lock; /* to sync completion status handling */ +- struct device *dev; +- struct clk *clk; +- int irq; +-}; +- +-static int npcm_peci_xfer_native(struct npcm_peci *priv, +- struct peci_xfer_msg *msg) +-{ +- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); +- unsigned long flags; +- unsigned int msg_rd; +- u32 cmd_sts; +- int i, rc; +- +- /* Check command sts and bus idle state */ +- rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, +- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), +- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, +- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); +- if (rc) +- return rc; /* -ETIMEDOUT */ +- +- spin_lock_irqsave(&priv->lock, flags); +- reinit_completion(&priv->xfer_complete); +- +- regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); +- regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, +- NPCM_PECI_WR_LEN_MASK & msg->rx_len); +- regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, +- NPCM_PECI_WR_LEN_MASK & msg->tx_len); +- +- if (msg->tx_len) { +- regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); +- +- for (i = 0; i < (msg->tx_len - 1); i++) +- regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), +- msg->tx_buf[i + 1]); +- } +- +- priv->status = 0; +- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, +- NPCM_PECI_CTRL_START_BUSY, +- NPCM_PECI_CTRL_START_BUSY); +- +- spin_unlock_irqrestore(&priv->lock, flags); +- +- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, +- timeout); +- +- spin_lock_irqsave(&priv->lock, flags); +- +- regmap_write(priv->regmap, NPCM_PECI_CMD, 0); +- +- if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { +- if (err < 0) { /* -ERESTARTSYS */ +- rc = (int)err; +- goto err_irqrestore; +- } else if (err == 0) { +- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); +- rc = -ETIMEDOUT; +- goto err_irqrestore; +- } +- +- dev_dbg(priv->dev, "No valid response!\n"); +- rc = -EIO; +- goto err_irqrestore; +- } +- +- for (i = 0; i < msg->rx_len; i++) { +- regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); +- msg->rx_buf[i] = (u8)msg_rd; +- } +- +-err_irqrestore: +- spin_unlock_irqrestore(&priv->lock, flags); +- return rc; +-} +- +-static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) +-{ +- struct npcm_peci *priv = arg; +- u32 status_ack = 0; +- u32 status; +- +- spin_lock(&priv->lock); +- regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); +- priv->status |= (status & NPCM_PECI_INT_MASK); +- +- if (status & NPCM_PECI_CTRL_CRC_ERR) { +- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); +- status_ack |= NPCM_PECI_CTRL_CRC_ERR; +- } +- +- if (status & NPCM_PECI_CTRL_ABRT_ERR) { +- dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); +- status_ack |= NPCM_PECI_CTRL_ABRT_ERR; +- } +- +- /* +- * All commands should be ended up with a NPCM_PECI_CTRL_DONE +- * bit set even in an error case. +- */ +- if (status & NPCM_PECI_CTRL_DONE) { +- dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); +- status_ack |= NPCM_PECI_CTRL_DONE; +- complete(&priv->xfer_complete); +- } +- +- regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, +- NPCM_PECI_INT_MASK, status_ack); +- +- spin_unlock(&priv->lock); +- return IRQ_HANDLED; +-} +- +-static int npcm_peci_init_ctrl(struct npcm_peci *priv) +-{ +- u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; +- int ret; +- bool volt; +- +- priv->clk = devm_clk_get(priv->dev, NULL); +- if (IS_ERR(priv->clk)) { +- dev_err(priv->dev, "Failed to get clk source.\n"); +- return PTR_ERR(priv->clk); +- } +- +- ret = clk_prepare_enable(priv->clk); +- if (ret) { +- dev_err(priv->dev, "Failed to enable clock.\n"); +- return ret; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", +- &priv->cmd_timeout_ms); +- if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || +- priv->cmd_timeout_ms == 0) { +- if (ret) +- dev_warn(priv->dev, +- "cmd-timeout-ms not found, use default : %u\n", +- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); +- else +- dev_warn(priv->dev, +- "Invalid cmd-timeout-ms : %u. Use default : %u\n", +- priv->cmd_timeout_ms, +- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); +- +- priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; +- } +- +- if (of_device_is_compatible(priv->dev->of_node, +- "nuvoton,npcm750-peci")) { +- priv->gcr_regmap = syscon_regmap_lookup_by_compatible +- ("nuvoton,npcm750-gcr"); +- if (!IS_ERR(priv->gcr_regmap)) { +- volt = of_property_read_bool(priv->dev->of_node, +- "high-volt-range"); +- if (volt) +- regmap_update_bits(priv->gcr_regmap, +- NPCM7XX_INTCR3_OFFSET, +- NPCM7XX_INTCR3_PECIVSEL, +- NPCM7XX_INTCR3_PECIVSEL); +- else +- regmap_update_bits(priv->gcr_regmap, +- NPCM7XX_INTCR3_OFFSET, +- NPCM7XX_INTCR3_PECIVSEL, 0); +- } +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "pull-down", +- &pull_down); +- if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { +- if (ret) +- dev_warn(priv->dev, +- "pull-down not found, use default : %u\n", +- NPCM_PECI_PULL_DOWN_DEFAULT); +- else +- dev_warn(priv->dev, +- "Invalid pull-down : %u. Use default : %u\n", +- pull_down, +- NPCM_PECI_PULL_DOWN_DEFAULT); +- pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; +- } +- +- regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, +- pull_down << 6); +- +- ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", +- &host_neg_bit_rate); +- if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || +- host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { +- if (ret) +- dev_warn(priv->dev, +- "host-neg-bit-rate not found, use default : %u\n", +- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); +- else +- dev_warn(priv->dev, +- "Invalid host-neg-bit-rate : %u. Use default : %u\n", +- host_neg_bit_rate, +- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); +- host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; +- } +- +- regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, +- host_neg_bit_rate); +- +- priv->host_bit_rate = clk_get_rate(priv->clk) / +- (4 * (host_neg_bit_rate + 1)); +- +- ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, +- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), +- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, +- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); +- if (ret) +- return ret; /* -ETIMEDOUT */ +- +- /* PECI interrupt enable */ +- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, +- NPCM_PECI_CTRL_DONE_INT_EN, +- NPCM_PECI_CTRL_DONE_INT_EN); +- +- return 0; +-} +- +-static const struct regmap_config npcm_peci_regmap_config = { +- .reg_bits = 8, +- .val_bits = 8, +- .max_register = NPCM_PECI_MAX_REG, +- .fast_io = true, +-}; +- +-static int npcm_peci_xfer(struct peci_adapter *adapter, +- struct peci_xfer_msg *msg) +-{ +- struct npcm_peci *priv = peci_get_adapdata(adapter); +- +- return npcm_peci_xfer_native(priv, msg); +-} +- +-static int npcm_peci_probe(struct platform_device *pdev) +-{ +- struct peci_adapter *adapter; +- struct npcm_peci *priv; +- struct resource *res; +- void __iomem *base; +- int ret; +- +- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); +- if (!adapter) +- return -ENOMEM; +- +- priv = peci_get_adapdata(adapter); +- priv->adapter = adapter; +- priv->dev = &pdev->dev; +- dev_set_drvdata(&pdev->dev, priv); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- base = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(base)) { +- ret = PTR_ERR(base); +- goto err_put_adapter_dev; +- } +- +- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, +- &npcm_peci_regmap_config); +- if (IS_ERR(priv->regmap)) { +- ret = PTR_ERR(priv->regmap); +- goto err_put_adapter_dev; +- } +- +- priv->irq = platform_get_irq(pdev, 0); +- if (!priv->irq) { +- ret = -ENODEV; +- goto err_put_adapter_dev; +- } +- +- ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, +- 0, "peci-npcm-irq", priv); +- if (ret) +- goto err_put_adapter_dev; +- +- init_completion(&priv->xfer_complete); +- spin_lock_init(&priv->lock); +- +- priv->adapter->owner = THIS_MODULE; +- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); +- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); +- priv->adapter->xfer = npcm_peci_xfer; +- +- ret = npcm_peci_init_ctrl(priv); +- if (ret) +- goto err_put_adapter_dev; +- +- ret = peci_add_adapter(priv->adapter); +- if (ret) +- goto err_put_adapter_dev; +- +- dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", +- priv->adapter->nr, priv->host_bit_rate); +- +- return 0; +- +-err_put_adapter_dev: +- put_device(&adapter->dev); +- return ret; +-} +- +-static int npcm_peci_remove(struct platform_device *pdev) +-{ +- struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); +- +- clk_disable_unprepare(priv->clk); +- peci_del_adapter(priv->adapter); +- of_node_put(priv->adapter->dev.of_node); +- +- return 0; +-} +- +-static const struct of_device_id npcm_peci_of_table[] = { +- { .compatible = "nuvoton,npcm750-peci", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, npcm_peci_of_table); +- +-static struct platform_driver npcm_peci_driver = { +- .probe = npcm_peci_probe, +- .remove = npcm_peci_remove, +- .driver = { +- .name = "peci-npcm", +- .of_match_table = of_match_ptr(npcm_peci_of_table), +- }, +-}; +-module_platform_driver(npcm_peci_driver); +- +-MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); +-MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); +-MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h +index 8f6d823a59cd..9854303bbc26 100644 +--- a/include/linux/mfd/intel-peci-client.h ++++ b/include/linux/mfd/intel-peci-client.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H + #define __LINUX_MFD_INTEL_PECI_CLIENT_H +@@ -9,14 +9,15 @@ + #if IS_ENABLED(CONFIG_X86) + #include <asm/intel-family.h> + #else +-/** ++/* + * Architectures other than x86 cannot include the header file so define these + * at here. These are needed for detecting type of client x86 CPUs behind a PECI + * connection. + */ +-#define INTEL_FAM6_HASWELL_X 0x3F +-#define INTEL_FAM6_BROADWELL_X 0x4F +-#define INTEL_FAM6_SKYLAKE_X 0x55 ++#define INTEL_FAM6_HASWELL_X 0x3F ++#define INTEL_FAM6_BROADWELL_X 0x4F ++#define INTEL_FAM6_SKYLAKE_X 0x55 ++#define INTEL_FAM6_SKYLAKE_XD 0x56 + #endif + + #define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */ +@@ -31,6 +32,10 @@ + #define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */ + #define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */ + ++#define CORE_MAX_ON_SKXD 16 /* Max number of cores on Skylake D */ ++#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */ ++#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */ ++ + #define CORE_NUMS_MAX CORE_MAX_ON_SKX + #define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX + #define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX +@@ -58,7 +63,6 @@ struct cpu_gen_info { + /** + * struct peci_client_manager - PECI client manager information + * @client; pointer to the PECI client +- * @dev: pointer to the struct device + * @name: PECI client manager name + * @gen_info: CPU generation info of the detected CPU + * +@@ -67,7 +71,6 @@ struct cpu_gen_info { + */ + struct peci_client_manager { + struct peci_client *client; +- struct device *dev; + char name[PECI_NAME_SIZE]; + const struct cpu_gen_info *gen_info; + }; +@@ -93,18 +96,22 @@ peci_client_read_package_config(struct peci_client_manager *priv, + u8 index, u16 param, u8 *data) + { + struct peci_rd_pkg_cfg_msg msg; +- int rc; ++ int ret; + + msg.addr = priv->client->addr; + msg.index = index; + msg.param = param; + msg.rx_len = 4; + +- rc = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); +- if (!rc) +- memcpy(data, msg.pkg_config, 4); ++ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ memcpy(data, msg.pkg_config, 4); + +- return rc; ++ return 0; + } + + #endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */ +diff --git a/include/linux/peci.h b/include/linux/peci.h +index d0e47d45d1d0..6fc424dc2a73 100644 +--- a/include/linux/peci.h ++++ b/include/linux/peci.h +@@ -1,19 +1,18 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __LINUX_PECI_H + #define __LINUX_PECI_H + +-#include <linux/cdev.h> + #include <linux/device.h> ++#include <linux/mutex.h> + #include <linux/peci-ioctl.h> +-#include <linux/rtmutex.h> + + #define PECI_NAME_SIZE 32 + + struct peci_board_info { + char type[PECI_NAME_SIZE]; +- unsigned short addr; /* CPU client address */ ++ u8 addr; /* CPU client address */ + struct device_node *of_node; + }; + +@@ -22,29 +21,29 @@ struct peci_board_info { + * @owner: owner module of the PECI adpater + * @bus_lock: mutex for exclusion of multiple callers + * @dev: device interface to this driver +- * @cdev: character device object to create character device + * @nr: the bus number to map + * @name: name of the adapter + * @userspace_clients_lock: mutex for exclusion of clients handling + * @userspace_clients: list of registered clients + * @xfer: low-level transfer function pointer of the adapter + * @cmd_mask: mask for supportable PECI commands ++ * @use_dma: flag for indicating that adapter uses DMA + * + * Each PECI adapter can communicate with one or more PECI client children. + * These make a small bus, sharing a single wired PECI connection. + */ + struct peci_adapter { + struct module *owner; +- struct rt_mutex bus_lock; ++ struct mutex bus_lock; + struct device dev; +- struct cdev cdev; + int nr; + char name[PECI_NAME_SIZE]; + struct mutex userspace_clients_lock; /* clients list mutex */ + struct list_head userspace_clients; + int (*xfer)(struct peci_adapter *adapter, + struct peci_xfer_msg *msg); +- uint cmd_mask; ++ u32 cmd_mask; ++ bool use_dma; + }; + + static inline struct peci_adapter *to_peci_adapter(void *d) +@@ -87,8 +86,8 @@ static inline struct peci_client *to_peci_client(void *d) + } + + struct peci_device_id { +- char name[PECI_NAME_SIZE]; +- unsigned long driver_data; /* Data private to the driver */ ++ char name[PECI_NAME_SIZE]; ++ ulong driver_data; /* Data private to the driver */ + }; + + /** +@@ -129,13 +128,22 @@ static inline struct peci_driver *to_peci_driver(void *d) + /* use a define to avoid include chaining to get THIS_MODULE */ + #define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver) + ++extern struct bus_type peci_bus_type; ++extern struct device_type peci_adapter_type; ++extern struct device_type peci_client_type; ++ + int peci_register_driver(struct module *owner, struct peci_driver *drv); + void peci_del_driver(struct peci_driver *driver); + struct peci_client *peci_verify_client(struct device *dev); +-struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size); ++struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size); ++struct peci_adapter *peci_get_adapter(int nr); ++void peci_put_adapter(struct peci_adapter *adapter); + int peci_add_adapter(struct peci_adapter *adapter); + void peci_del_adapter(struct peci_adapter *adapter); + struct peci_adapter *peci_verify_adapter(struct device *dev); ++int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)); ++struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len); ++void peci_put_xfer_msg(struct peci_xfer_msg *msg); + int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg); + int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id); + +diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h +index a6dae71cbff5..253fb42e38b7 100644 +--- a/include/uapi/linux/peci-ioctl.h ++++ b/include/uapi/linux/peci-ioctl.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __PECI_IOCTL_H + #define __PECI_IOCTL_H +@@ -7,136 +7,35 @@ + #include <linux/ioctl.h> + #include <linux/types.h> + +-/* Base Address of 48d */ +-#define PECI_BASE_ADDR 0x30 /* The PECI client's default address of 0x30 */ +-#define PECI_OFFSET_MAX 8 /* Max numver of CPU clients */ +- +-/* PCI Access */ +-#define MAX_PCI_READ_LEN 24 /* Number of bytes of the PCI Space read */ +- +-#define PCI_BUS0_CPU0 0x00 +-#define PCI_BUS0_CPU1 0x80 +-#define PCI_CPUBUSNO_BUS 0x00 +-#define PCI_CPUBUSNO_DEV 0x08 +-#define PCI_CPUBUSNO_FUNC 0x02 +-#define PCI_CPUBUSNO 0xcc +-#define PCI_CPUBUSNO_1 0xd0 +-#define PCI_CPUBUSNO_VALID 0xd4 +- +-/* Package Identifier Read Parameter Value */ +-#define PKG_ID_CPU_ID 0x0000 /* CPUID Info */ +-#define PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ +-#define PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ +-#define PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ +-#define PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ +-#define PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ +- +-/* RdPkgConfig Index */ +-#define MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ +-#define MBX_INDEX_VR_DEBUG 1 /* VR Debug */ +-#define MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ +-#define MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ +-#define MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ +-#define MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ +-#define MBX_INDEX_EPI 6 /* Efficient Performance Indication */ +-#define MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ +-#define MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ +-#define MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ +-#define MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ +-#define MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ +-#define MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ +-#define MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ +-#define MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ +-#define MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ +-#define MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ +-#define MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ +-#define MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ +-#define MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ +-#define MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ +-#define MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ +-#define MBX_INDEX_TDP 28 /* Thermal design power minimum */ +-#define MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ +-#define MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ +-#define MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ +-#define MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ +-#define MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ +-#define MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ +-#define MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ +-#define MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ +-#define MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ +-#define MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ +-#define MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ +-#define MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ +-#define MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ +-#define MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ +-#define MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ +-#define MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ +-#define MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ +-#define MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ +-#define MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ +-#define MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ +- +-/* WrPkgConfig Index */ +-#define MBX_INDEX_DIMM_AMBIENT 19 +-#define MBX_INDEX_DIMM_TEMP 24 ++/* The PECI client's default address of 0x30 */ ++#define PECI_BASE_ADDR 0x30 ++ ++/* Max number of CPU clients */ ++#define PECI_OFFSET_MAX 8 ++ ++/* PECI read/write data buffer size max */ ++#define PECI_BUFFER_SIZE 255 + + /* Device Specific Completion Code (CC) Definition */ +-#define DEV_PECI_CC_SUCCESS 0x40 +-#define DEV_PECI_CC_TIMEOUT 0x80 +-#define DEV_PECI_CC_OUT_OF_RESOURCE 0x81 +-#define DEV_PECI_CC_UNAVAIL_RESOURCE 0x82 +-#define DEV_PECI_CC_INVALID_REQ 0x90 ++#define PECI_DEV_CC_SUCCESS 0x40 ++#define PECI_DEV_CC_NEED_RETRY 0x80 ++#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81 ++#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82 ++#define PECI_DEV_CC_INVALID_REQ 0x90 ++#define PECI_DEV_CC_MCA_ERROR 0x91 ++#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93 ++#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94 ++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98 ++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B ++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C + + /* Completion Code mask to check retry needs */ +-#define DEV_PECI_CC_RETRY_CHECK_MASK 0xf0 +-#define DEV_PECI_CC_NEED_RETRY 0x80 ++#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0 + + /* Skylake EDS says to retry for 250ms */ +-#define DEV_PECI_RETRY_TIME_MS 250 +-#define DEV_PECI_RETRY_INTERVAL_USEC 10000 +-#define DEV_PECI_RETRY_BIT 0x01 +- +-#define GET_TEMP_WR_LEN 1 +-#define GET_TEMP_RD_LEN 2 +-#define GET_TEMP_PECI_CMD 0x01 +- +-#define GET_DIB_WR_LEN 1 +-#define GET_DIB_RD_LEN 8 +-#define GET_DIB_PECI_CMD 0xf7 +- +-#define RDPKGCFG_WRITE_LEN 5 +-#define RDPKGCFG_READ_LEN_BASE 1 +-#define RDPKGCFG_PECI_CMD 0xa1 +- +-#define WRPKGCFG_WRITE_LEN_BASE 6 +-#define WRPKGCFG_READ_LEN 1 +-#define WRPKGCFG_PECI_CMD 0xa5 +- +-#define RDIAMSR_WRITE_LEN 5 +-#define RDIAMSR_READ_LEN 9 +-#define RDIAMSR_PECI_CMD 0xb1 +- +-#define WRIAMSR_PECI_CMD 0xb5 +- +-#define RDPCICFG_WRITE_LEN 6 +-#define RDPCICFG_READ_LEN 5 +-#define RDPCICFG_PECI_CMD 0x61 +- +-#define WRPCICFG_PECI_CMD 0x65 +- +-#define RDPCICFGLOCAL_WRITE_LEN 5 +-#define RDPCICFGLOCAL_READ_LEN_BASE 1 +-#define RDPCICFGLOCAL_PECI_CMD 0xe1 +- +-#define WRPCICFGLOCAL_WRITE_LEN_BASE 6 +-#define WRPCICFGLOCAL_READ_LEN 1 +-#define WRPCICFGLOCAL_PECI_CMD 0xe5 +- +-#define PECI_BUFFER_SIZE 32 ++#define PECI_DEV_RETRY_TIME_MS 250 ++#define PECI_DEV_RETRY_INTERVAL_USEC 10000 ++#define PECI_DEV_RETRY_BIT 0x01 + + /** + * enum peci_cmd - PECI client commands +@@ -186,11 +85,12 @@ enum peci_cmd { + * raw PECI transfer + */ + struct peci_xfer_msg { +- __u8 addr; +- __u8 tx_len; +- __u8 rx_len; +- __u8 tx_buf[PECI_BUFFER_SIZE]; +- __u8 rx_buf[PECI_BUFFER_SIZE]; ++ __u8 addr; ++ __u8 tx_len; ++ __u8 rx_len; ++ __u8 padding; ++ __u8 *tx_buf; ++ __u8 *rx_buf; + } __attribute__((__packed__)); + + /** +@@ -202,7 +102,8 @@ struct peci_xfer_msg { + * powered-off, etc. + */ + struct peci_ping_msg { +- __u8 addr; ++ __u8 addr; ++ __u8 padding[3]; + } __attribute__((__packed__)); + + /** +@@ -216,8 +117,13 @@ struct peci_ping_msg { + * command. + */ + struct peci_get_dib_msg { +- __u8 addr; +- __u64 dib; ++#define PECI_GET_DIB_WR_LEN 1 ++#define PECI_GET_DIB_RD_LEN 8 ++#define PECI_GET_DIB_CMD 0xf7 ++ ++ __u8 addr; ++ __u8 padding[3]; ++ __u64 dib; + } __attribute__((__packed__)); + + /** +@@ -232,8 +138,13 @@ struct peci_get_dib_msg { + * below the maximum processor junction temperature. + */ + struct peci_get_temp_msg { +- __u8 addr; +- __s16 temp_raw; ++#define PECI_GET_TEMP_WR_LEN 1 ++#define PECI_GET_TEMP_RD_LEN 2 ++#define PECI_GET_TEMP_CMD 0x01 ++ ++ __u8 addr; ++ __u8 padding; ++ __s16 temp_raw; + } __attribute__((__packed__)); + + /** +@@ -242,6 +153,7 @@ struct peci_get_temp_msg { + * @index: encoding index for the requested service + * @param: specific data being requested + * @rx_len: number of data to be read in bytes ++ * @cc: completion code + * @pkg_config: package config data to be read + * + * The RdPkgConfig() command provides read access to the Package Configuration +@@ -251,11 +163,73 @@ struct peci_get_temp_msg { + * DIMM temperatures and so on. + */ + struct peci_rd_pkg_cfg_msg { +- __u8 addr; +- __u8 index; +- __u16 param; +- __u8 rx_len; +- __u8 pkg_config[4]; ++#define PECI_RDPKGCFG_WRITE_LEN 5 ++#define PECI_RDPKGCFG_READ_LEN_BASE 1 ++#define PECI_RDPKGCFG_CMD 0xa1 ++ ++ __u8 addr; ++ __u8 index; ++#define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ ++#define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */ ++#define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ ++#define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ ++#define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ ++#define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ ++#define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */ ++#define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ ++#define PECI_MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ ++#define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ ++#define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ ++#define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ ++#define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ ++#define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ ++#define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ ++#define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ ++#define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ ++#define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ ++#define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ ++#define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ ++#define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ ++#define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ ++#define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */ ++#define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ ++#define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ ++#define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ ++#define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ ++#define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ ++#define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ ++#define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ ++#define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ ++#define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ ++#define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ ++#define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ ++#define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ ++#define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ ++#define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ ++#define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ ++#define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ ++#define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ ++#define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ ++#define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ ++#define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ ++ ++ __u16 param; ++/* When index is PECI_MBX_INDEX_CPU_ID */ ++#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */ ++#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ ++#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ ++#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ ++#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ ++#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ ++ ++ __u8 rx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u8 pkg_config[4]; + } __attribute__((__packed__)); + + /** +@@ -264,6 +238,7 @@ struct peci_rd_pkg_cfg_msg { + * @index: encoding index for the requested service + * @param: specific data being requested + * @tx_len: number of data to be written in bytes ++ * @cc: completion code + * @value: package config data to be written + * + * The WrPkgConfig() command provides write access to the Package Configuration +@@ -272,11 +247,20 @@ struct peci_rd_pkg_cfg_msg { + * may include power limiting, thermal averaging constant programming and so on. + */ + struct peci_wr_pkg_cfg_msg { +- __u8 addr; +- __u8 index; +- __u16 param; +- __u8 tx_len; +- __u32 value; ++#define PECI_WRPKGCFG_WRITE_LEN_BASE 6 ++#define PECI_WRPKGCFG_READ_LEN 1 ++#define PECI_WRPKGCFG_CMD 0xa5 ++ ++ __u8 addr; ++ __u8 index; ++#define PECI_MBX_INDEX_DIMM_AMBIENT 19 ++#define PECI_MBX_INDEX_DIMM_TEMP 24 ++ ++ __u16 param; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u32 value; + } __attribute__((__packed__)); + + /** +@@ -284,16 +268,47 @@ struct peci_wr_pkg_cfg_msg { + * @addr: address of the client + * @thread_id: ID of the specific logical processor + * @address: address of MSR to read from ++ * @cc: completion code + * @value: data to be read + * + * The RdIAMSR() PECI command provides read access to Model Specific Registers + * (MSRs) defined in the processor's Intel Architecture (IA). + */ + struct peci_rd_ia_msr_msg { +- __u8 addr; +- __u8 thread_id; +- __u16 address; +- __u64 value; ++#define PECI_RDIAMSR_WRITE_LEN 5 ++#define PECI_RDIAMSR_READ_LEN 9 ++#define PECI_RDIAMSR_CMD 0xb1 ++ ++ __u8 addr; ++ __u8 thread_id; ++ __u16 address; ++ __u8 cc; ++ __u8 padding[3]; ++ __u64 value; ++} __attribute__((__packed__)); ++ ++/** ++ * struct peci_wr_ia_msr_msg - WrIAMSR command ++ * @addr: address of the client ++ * @thread_id: ID of the specific logical processor ++ * @address: address of MSR to write to ++ * @tx_len: number of data to be written in bytes ++ * @cc: completion code ++ * @value: data to be written ++ * ++ * The WrIAMSR() PECI command provides write access to Model Specific Registers ++ * (MSRs) defined in the processor's Intel Architecture (IA). ++ */ ++struct peci_wr_ia_msr_msg { ++#define PECI_WRIAMSR_CMD 0xb5 ++ ++ __u8 addr; ++ __u8 thread_id; ++ __u16 address; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u64 value; + } __attribute__((__packed__)); + + /** +@@ -303,6 +318,7 @@ struct peci_rd_ia_msr_msg { + * @device: PCI device number + * @function: specific function to read from + * @reg: specific register to read from ++ * @cc: completion code + * @pci_config: config data to be read + * + * The RdPCIConfig() command provides sideband read access to the PCI +@@ -310,12 +326,56 @@ struct peci_rd_ia_msr_msg { + * processor. + */ + struct peci_rd_pci_cfg_msg { +- __u8 addr; +- __u8 bus; +- __u8 device; +- __u8 function; +- __u16 reg; +- __u8 pci_config[4]; ++#define PECI_RDPCICFG_WRITE_LEN 6 ++#define PECI_RDPCICFG_READ_LEN 5 ++#define PECI_RDPCICFG_READ_LEN_MAX 24 ++#define PECI_RDPCICFG_CMD 0x61 ++ ++ __u8 addr; ++ __u8 bus; ++#define PECI_PCI_BUS0_CPU0 0x00 ++#define PECI_PCI_BUS0_CPU1 0x80 ++#define PECI_PCI_CPUBUSNO_BUS 0x00 ++#define PECI_PCI_CPUBUSNO_DEV 0x08 ++#define PECI_PCI_CPUBUSNO_FUNC 0x02 ++#define PECI_PCI_CPUBUSNO 0xcc ++#define PECI_PCI_CPUBUSNO_1 0xd0 ++#define PECI_PCI_CPUBUSNO_VALID 0xd4 ++ ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 cc; ++ __u8 padding[1]; ++ __u8 pci_config[4]; ++} __attribute__((__packed__)); ++ ++/** ++ * struct peci_wr_pci_cfg_msg - WrPCIConfig command ++ * @addr: address of the client ++ * @bus: PCI bus number ++ * @device: PCI device number ++ * @function: specific function to write to ++ * @reg: specific register to write to ++ * @tx_len: number of data to be written in bytes ++ * @cc: completion code ++ * @pci_config: config data to be written ++ * ++ * The RdPCIConfig() command provides sideband write access to the PCI ++ * configuration space maintained in downstream devices external to the ++ * processor. ++ */ ++struct peci_wr_pci_cfg_msg { ++#define PECI_WRPCICFG_CMD 0x65 ++ ++ __u8 addr; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 pci_config[4]; + } __attribute__((__packed__)); + + /** +@@ -326,6 +386,7 @@ struct peci_rd_pci_cfg_msg { + * @function: specific function to read from + * @reg: specific register to read from + * @rx_len: number of data to be read in bytes ++ * @cc: completion code + * @pci_config: config data to be read + * + * The RdPCIConfigLocal() command provides sideband read access to the PCI +@@ -333,13 +394,18 @@ struct peci_rd_pci_cfg_msg { + * processor IIO and uncore registers within the PCI configuration space. + */ + struct peci_rd_pci_cfg_local_msg { +- __u8 addr; +- __u8 bus; +- __u8 device; +- __u8 function; +- __u16 reg; +- __u8 rx_len; +- __u8 pci_config[4]; ++#define PECI_RDPCICFGLOCAL_WRITE_LEN 5 ++#define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1 ++#define PECI_RDPCICFGLOCAL_CMD 0xe1 ++ ++ __u8 addr; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 rx_len; ++ __u8 cc; ++ __u8 pci_config[4]; + } __attribute__((__packed__)); + + /** +@@ -350,6 +416,7 @@ struct peci_rd_pci_cfg_local_msg { + * @function: specific function to read from + * @reg: specific register to read from + * @tx_len: number of data to be written in bytes ++ * @cc: completion code + * @value: config data to be written + * + * The WrPCIConfigLocal() command provides sideband write access to the PCI +@@ -357,13 +424,18 @@ struct peci_rd_pci_cfg_local_msg { + * access this space even before BIOS enumeration of the system buses. + */ + struct peci_wr_pci_cfg_local_msg { +- __u8 addr; +- __u8 bus; +- __u8 device; +- __u8 function; +- __u16 reg; +- __u8 tx_len; +- __u32 value; ++#define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6 ++#define PECI_WRPCICFGLOCAL_READ_LEN 1 ++#define PECI_WRPCICFGLOCAL_CMD 0xe5 ++ ++ __u8 addr; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 tx_len; ++ __u8 cc; ++ __u32 value; + } __attribute__((__packed__)); + + #define PECI_IOC_BASE 0xb7 +@@ -389,9 +461,15 @@ struct peci_wr_pci_cfg_local_msg { + #define PECI_IOC_RD_IA_MSR \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg) + ++#define PECI_IOC_WR_IA_MSR \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg) ++ + #define PECI_IOC_RD_PCI_CFG \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg) + ++#define PECI_IOC_WR_PCI_CFG \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg) ++ + #define PECI_IOC_RD_PCI_CFG_LOCAL \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \ + struct peci_rd_pci_cfg_local_msg) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch new file mode 100644 index 000000000..675125322 --- /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] i2c: slave-mqueue: add mqueue driver to receive ipmi message + +Some protocols over I2C are designed for bi-directional transferring +messages by using I2C Master Write protocol. Like the MCTP (Management +Component Transport Protocol) and IPMB (Intelligent Platform Management +Bus), they both require that the userspace can receive messages from +I2C dirvers under slave mode. + +This new slave mqueue backend is used to receive and queue messages, it +will exposes these messages to userspace by sysfs bin file. + +Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com> +--- + Documentation/i2c/slave-mqueue-backend.rst | 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..884a7018c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch @@ -0,0 +1,475 @@ +From efa7ad95db45494b2c3685c0688f00174e517e34 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> +--- + arch/arm/boot/dts/aspeed-g4.dtsi | 9 + + arch/arm/boot/dts/aspeed-g5.dtsi | 9 + + drivers/soc/aspeed/Kconfig | 7 + + drivers/soc/aspeed/Makefile | 1 + + drivers/soc/aspeed/aspeed-lpc-mbox.c | 376 +++++++++++++++++++++++++++++++++++ + 5 files changed, 402 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 00848693f455..4b8b0be22cd4 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -344,6 +344,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 8406da6f62a5..9f3bd5bafab5 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -473,6 +473,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/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig +index 78dd74c49ddb..a4be8e566bc7 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 e631b23d519b..f3ff29b874ed 100644 +--- a/drivers/soc/aspeed/Makefile ++++ b/drivers/soc/aspeed/Makefile +@@ -1,5 +1,6 @@ + # 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 +diff --git a/drivers/soc/aspeed/aspeed-lpc-mbox.c b/drivers/soc/aspeed/aspeed-lpc-mbox.c +new file mode 100644 +index 000000000000..795107206022 +--- /dev/null ++++ b/drivers/soc/aspeed/aspeed-lpc-mbox.c +@@ -0,0 +1,376 @@ ++// 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" }, ++ { }, ++}; ++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.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch new file mode 100644 index 000000000..b347894be --- /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,619 @@ +From 3d1ddeb903f6eaeb06ddc1d6cfbed6374ef31f36 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 | 450 +++++++++++++++++++++ + include/uapi/linux/aspeed-lpc-sio.h | 44 ++ + 7 files changed, 533 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 07758c9b900b..3df43f925848 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -345,6 +345,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 2387e2d1ff9e..2d6f730a7101 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -474,6 +474,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..c717a3182320 +--- /dev/null ++++ b/drivers/soc/aspeed/aspeed-lpc-sio.c +@@ -0,0 +1,450 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) 2012-2017 ASPEED Technology Inc. ++// Copyright (c) 2017-2019 Intel Corporation ++ ++#include <linux/clk.h> ++#include <linux/mfd/syscon.h> ++#include <linux/miscdevice.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/poll.h> ++#include <linux/regmap.h> ++ ++#include <linux/aspeed-lpc-sio.h> ++ ++#define SOC_NAME "aspeed" ++#define DEVICE_NAME "lpc-sio" ++ ++#define AST_LPC_SWCR0300 0x0 ++#define LPC_PWRGD_STS (1 << 30) ++#define LPC_PWRGD_RISING_EVT_STS (1 << 29) ++#define LPC_PWRGD_FALLING_EVT_STS (1 << 28) ++#define LPC_PWRBTN_STS (1 << 27) ++#define LPC_PWRBTN_RISING_EVT_STS (1 << 26) ++#define LPC_PWRBTN_FALLING_EVT_STS (1 << 25) ++#define LPC_S5N_STS (1 << 21) ++#define LPC_S5N_RISING_EVT_STS (1 << 20) ++#define LPC_S5N_FALLING_EVT_STS (1 << 19) ++#define LPC_S3N_STS (1 << 18) ++#define LPC_S3N_RISING_EVT_STS (1 << 17) ++#define LPC_S3N_FALLING_EVT_STS (1 << 16) ++#define LPC_PWBTO_RAW_STS (1 << 15) ++#define LPC_LAST_ONCTL_STS (1 << 14) ++#define LPC_WAS_PFAIL_STS (1 << 13) ++#define LPC_POWER_UP_FAIL_STS (1 << 12) /* Crowbar */ ++#define LPC_PWRBTN_OVERRIDE_STS (1 << 11) ++ ++#define AST_LPC_SWCR0704 0x4 ++ ++#define AST_LPC_SWCR0B08 0x8 ++#define LPC_PWREQ_OUTPUT_LEVEL (1 << 25) ++#define LPC_PWBTO_OUTPUT_LEVEL (1 << 24) ++#define LPC_ONCTL_STS (1 << 15) ++#define LPC_ONCTL_GPIO_LEVEL (1 << 14) ++#define LPC_ONCTL_EN_GPIO_OUTPUT (1 << 13) ++#define LPC_ONCTL_EN_GPIO_MODE (1 << 12) ++ ++#define AST_LPC_SWCR0F0C 0xC ++#define AST_LPC_SWCR1310 0x10 ++#define AST_LPC_SWCR1714 0x14 ++#define AST_LPC_SWCR1B18 0x18 ++#define AST_LPC_SWCR1F1C 0x1C ++#define AST_LPC_ACPIE3E0 0x20 ++#define AST_LPC_ACPIC1C0 0x24 ++#define AST_LPC_ACPIB3B0 0x28 ++#define AST_LPC_ACPIB7B4 0x2C ++ ++struct aspeed_lpc_sio { ++ struct miscdevice miscdev; ++ struct regmap *regmap; ++ struct clk *clk; ++ struct semaphore lock; ++ unsigned int reg_base; ++}; ++ ++static struct aspeed_lpc_sio *file_aspeed_lpc_sio(struct file *file) ++{ ++ return container_of(file->private_data, struct aspeed_lpc_sio, ++ miscdev); ++} ++ ++static int aspeed_lpc_sio_open(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++#define LPC_SLP3N5N_EVENT_STATUS (\ ++ LPC_S5N_RISING_EVT_STS | \ ++ LPC_S5N_FALLING_EVT_STS | \ ++ LPC_S3N_RISING_EVT_STS | \ ++ LPC_S3N_FALLING_EVT_STS) ++/************************************* ++ * SLPS3n SLPS5n State ++ * --------------------------------- ++ * 1 1 S12 ++ * 0 1 S3I ++ * x 0 S45 ++ ************************************* ++ */ ++ ++static long sio_get_acpi_state(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ u32 val; ++ int rc; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ rc = regmap_read(lpc_sio->regmap, reg, &val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ ++ /* update the ACPI state event status */ ++ if (sio_data->param != 0) { ++ if (val & LPC_SLP3N5N_EVENT_STATUS) { ++ sio_data->param = 1; ++ rc = regmap_write(lpc_sio->regmap, reg, ++ LPC_SLP3N5N_EVENT_STATUS); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_write() failed with %d(reg:0x%x)\n", ++ rc, reg); ++ return rc; ++ } ++ } else { ++ sio_data->param = 0; ++ } ++ } ++ ++ if ((val & LPC_S3N_STS) && (val & LPC_S5N_STS)) ++ sio_data->data = ACPI_STATE_S12; ++ else if ((val & LPC_S3N_STS) == 0 && (val & LPC_S5N_STS)) ++ sio_data->data = ACPI_STATE_S3I; ++ else ++ sio_data->data = ACPI_STATE_S45; ++ ++ return 0; ++} ++ ++#define LPC_PWRGD_EVENT_STATUS ( \ ++ LPC_PWRGD_RISING_EVT_STS | \ ++ LPC_PWRGD_FALLING_EVT_STS) ++ ++static long sio_get_pwrgd_status(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ u32 val; ++ int rc; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ rc = regmap_read(lpc_sio->regmap, reg, &val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ ++ /* update the PWRGD event status */ ++ if (sio_data->param != 0) { ++ if (val & LPC_PWRGD_EVENT_STATUS) { ++ sio_data->param = 1; ++ rc = regmap_write(lpc_sio->regmap, reg, ++ LPC_PWRGD_EVENT_STATUS); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_write() failed with %d(reg:0x%x)\n", ++ rc, reg); ++ return rc; ++ } ++ } else { ++ sio_data->param = 0; ++ } ++ } ++ ++ sio_data->data = (val & LPC_PWRGD_STS) != 0 ? 1 : 0; ++ ++ return 0; ++} ++ ++static long sio_get_onctl_status(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ u32 val; ++ int rc; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08; ++ rc = regmap_read(lpc_sio->regmap, reg, &val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ ++ sio_data->data = (val & LPC_ONCTL_STS) != 0 ? 1 : 0; ++ ++ return 0; ++} ++ ++static long sio_set_onctl_gpio(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ u32 val; ++ int rc; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08; ++ rc = regmap_read(lpc_sio->regmap, reg, &val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ ++ /* Enable ONCTL GPIO mode */ ++ if (sio_data->param != 0) { ++ val |= LPC_ONCTL_EN_GPIO_MODE; ++ val |= LPC_ONCTL_EN_GPIO_OUTPUT; ++ ++ if (sio_data->data != 0) ++ val |= LPC_ONCTL_GPIO_LEVEL; ++ else ++ val &= ~LPC_ONCTL_GPIO_LEVEL; ++ ++ rc = regmap_write(lpc_sio->regmap, reg, val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_write() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ } else { ++ val &= ~LPC_ONCTL_EN_GPIO_MODE; ++ rc = regmap_write(lpc_sio->regmap, reg, val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_write() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ } ++ ++ return 0; ++} ++ ++static long sio_get_pwrbtn_override(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ u32 val; ++ int rc; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ rc = regmap_read(lpc_sio->regmap, reg, &val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ ++ /* clear the PWRBTN OVERRIDE status */ ++ if (sio_data->param != 0) { ++ if (val & LPC_PWRBTN_OVERRIDE_STS) { ++ rc = regmap_write(lpc_sio->regmap, reg, ++ LPC_PWRBTN_OVERRIDE_STS); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_write() failed with %d(reg:0x%x)\n", ++ rc, reg); ++ return rc; ++ } ++ } ++ } ++ ++ sio_data->data = (val & LPC_PWRBTN_OVERRIDE_STS) != 0 ? 1 : 0; ++ ++ return 0; ++} ++ ++static long sio_get_pfail_status(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ u32 val; ++ int rc; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ rc = regmap_read(lpc_sio->regmap, reg, &val); ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ ++ /* [ASPEED]: SWCR_03_00[13] (Was_pfail: default 1) is used to identify ++ * this current booting is from AC loss (not DC loss) if FW cleans this ++ * bit after booting successfully every time. ++ **********************************************************************/ ++ if (val & LPC_WAS_PFAIL_STS) { ++ rc = regmap_write(lpc_sio->regmap, reg, 0); /* W0C */ ++ if (rc) { ++ dev_err(lpc_sio->miscdev.parent, ++ "regmap_write() failed with %d(reg:0x%x)\n", rc, reg); ++ return rc; ++ } ++ sio_data->data = 1; ++ } else { ++ sio_data->data = 0; ++ } ++ ++ return 0; ++} ++ ++typedef long (*sio_cmd_fn) (struct aspeed_lpc_sio *sio_dev, ++ struct sio_ioctl_data *sio_data); ++static sio_cmd_fn sio_cmd_handle[SIO_MAX_CMD] = { ++ [SIO_GET_ACPI_STATE] = sio_get_acpi_state, ++ [SIO_GET_PWRGD_STATUS] = sio_get_pwrgd_status, ++ [SIO_GET_ONCTL_STATUS] = sio_get_onctl_status, ++ [SIO_SET_ONCTL_GPIO] = sio_set_onctl_gpio, ++ [SIO_GET_PWRBTN_OVERRIDE] = sio_get_pwrbtn_override, ++ [SIO_GET_PFAIL_STATUS] = sio_get_pfail_status, ++}; ++ ++static long aspeed_lpc_sio_ioctl(struct file *file, unsigned int cmd, ++ unsigned long param) ++{ ++ struct aspeed_lpc_sio *lpc_sio = file_aspeed_lpc_sio(file); ++ long ret; ++ sio_cmd_fn cmd_fn; ++ struct sio_ioctl_data sio_data; ++ ++ ++ if (copy_from_user(&sio_data, (void __user *)param, sizeof(sio_data))) ++ return -EFAULT; ++ ++ if (cmd != SIO_IOC_COMMAND || sio_data.sio_cmd >= SIO_MAX_CMD) ++ return -EINVAL; ++ ++ cmd_fn = sio_cmd_handle[sio_data.sio_cmd]; ++ if (cmd_fn == NULL) ++ return -EINVAL; ++ ++ if (down_interruptible(&lpc_sio->lock) != 0) ++ return -ERESTARTSYS; ++ ++ ret = cmd_fn(lpc_sio, &sio_data); ++ if (ret == 0) { ++ if (copy_to_user((void __user *)param, &sio_data, ++ sizeof(sio_data))) ++ ret = -EFAULT; ++ } ++ ++ up(&lpc_sio->lock); ++ ++ return ret; ++} ++ ++static const struct file_operations aspeed_lpc_sio_fops = { ++ .owner = THIS_MODULE, ++ .open = aspeed_lpc_sio_open, ++ .unlocked_ioctl = aspeed_lpc_sio_ioctl, ++}; ++ ++static int aspeed_lpc_sio_probe(struct platform_device *pdev) ++{ ++ struct aspeed_lpc_sio *lpc_sio; ++ struct device *dev; ++ int rc; ++ ++ dev = &pdev->dev; ++ ++ lpc_sio = devm_kzalloc(dev, sizeof(*lpc_sio), GFP_KERNEL); ++ if (!lpc_sio) ++ return -ENOMEM; ++ ++ dev_set_drvdata(&pdev->dev, lpc_sio); ++ ++ rc = of_property_read_u32(dev->of_node, "reg", &lpc_sio->reg_base); ++ if (rc) { ++ dev_err(dev, "Couldn't read reg device-tree property\n"); ++ return rc; ++ } ++ ++ lpc_sio->regmap = syscon_node_to_regmap( ++ pdev->dev.parent->of_node); ++ if (IS_ERR(lpc_sio->regmap)) { ++ dev_err(dev, "Couldn't get regmap\n"); ++ return -ENODEV; ++ } ++ ++ sema_init(&lpc_sio->lock, 1); ++ ++ lpc_sio->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(lpc_sio->clk)) { ++ rc = PTR_ERR(lpc_sio->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; ++ } ++ rc = clk_prepare_enable(lpc_sio->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ ++ lpc_sio->miscdev.minor = MISC_DYNAMIC_MINOR; ++ lpc_sio->miscdev.name = DEVICE_NAME; ++ lpc_sio->miscdev.fops = &aspeed_lpc_sio_fops; ++ lpc_sio->miscdev.parent = dev; ++ rc = misc_register(&lpc_sio->miscdev); ++ if (rc) { ++ dev_err(dev, "Unable to register device\n"); ++ goto err; ++ } ++ ++ dev_info(dev, "Loaded at %pap (0x%08x)\n", &lpc_sio->regmap, ++ lpc_sio->reg_base); ++ ++ return 0; ++ ++err: ++ clk_disable_unprepare(lpc_sio->clk); ++ ++ return rc; ++} ++ ++static int aspeed_lpc_sio_remove(struct platform_device *pdev) ++{ ++ struct aspeed_lpc_sio *lpc_sio = dev_get_drvdata(&pdev->dev); ++ ++ misc_deregister(&lpc_sio->miscdev); ++ clk_disable_unprepare(lpc_sio->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id aspeed_lpc_sio_match[] = { ++ { .compatible = "aspeed,ast2500-lpc-sio" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, aspeed_lpc_sio_match); ++ ++static struct platform_driver aspeed_lpc_sio_driver = { ++ .driver = { ++ .name = SOC_NAME "-" DEVICE_NAME, ++ .of_match_table = aspeed_lpc_sio_match, ++ }, ++ .probe = aspeed_lpc_sio_probe, ++ .remove = aspeed_lpc_sio_remove, ++}; ++module_platform_driver(aspeed_lpc_sio_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); ++MODULE_AUTHOR("Yong Li <yong.blli@linux.intel.com>"); ++MODULE_DESCRIPTION("ASPEED AST LPC SIO device driver"); +diff --git a/include/uapi/linux/aspeed-lpc-sio.h b/include/uapi/linux/aspeed-lpc-sio.h +new file mode 100644 +index 000000000000..5dc1efd4a426 +--- /dev/null ++++ b/include/uapi/linux/aspeed-lpc-sio.h +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (C) 2012-2020 ASPEED Technology Inc. ++ * Copyright (c) 2017 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ */ ++ ++#ifndef _UAPI_LINUX_ASPEED_LPC_SIO_H ++#define _UAPI_LINUX_ASPEED_LPC_SIO_H ++ ++#include <linux/ioctl.h> ++ ++enum ACPI_SLP_STATE { ++ ACPI_STATE_S12 = 1, ++ ACPI_STATE_S3I, ++ ACPI_STATE_S45 ++}; ++ ++/* SWC & ACPI for SuperIO IOCTL */ ++enum SIO_CMD { ++ SIO_GET_ACPI_STATE = 0, ++ SIO_GET_PWRGD_STATUS, ++ SIO_GET_ONCTL_STATUS, ++ SIO_SET_ONCTL_GPIO, ++ SIO_GET_PWRBTN_OVERRIDE, ++ SIO_GET_PFAIL_STATUS, /* Start from AC Loss */ ++ ++ SIO_MAX_CMD ++}; ++ ++struct sio_ioctl_data { ++ unsigned short sio_cmd; ++ unsigned short param; ++ unsigned int data; ++}; ++ ++#define SIO_IOC_BASE 'P' ++#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data) ++ ++#endif /* _UAPI_LINUX_ASPEED_LPC_SIO_H */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch new file mode 100644 index 000000000..a44667436 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch @@ -0,0 +1,595 @@ +From 0f0e0a03218f6a7bdcdd78d319959e6bb974502c Mon Sep 17 00:00:00 2001 +From: Haiyue Wang <haiyue.wang@linux.intel.com> +Date: Sat, 24 Feb 2018 11:12:32 +0800 +Subject: [PATCH] eSPI: add ASPEED AST2500 eSPI driver to boot a host with PCH + runs on eSPI + +When PCH works under eSPI mode, the PMC (Power Management Controller) in +PCH is waiting for SUS_ACK from BMC after it alerts SUS_WARN. It is in +dead loop if no SUS_ACK assert. This is the basic requirement for the BMC +works as eSPI slave. + +Also for the host power on / off actions, from BMC side, the following VW +(Virtual Wire) messages are done in firmware: +1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS +2. SUS_ACK +3. OOB_RESET_ACK +4. HOST_RESET_ACK + +Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com> +--- + .../devicetree/bindings/misc/aspeed,espi-slave.txt | 19 ++ + Documentation/misc-devices/espi-slave.rst | 118 +++++++ + arch/arm/boot/dts/aspeed-g5.dtsi | 4 + + drivers/misc/Kconfig | 8 + + drivers/misc/Makefile | 1 + + drivers/misc/aspeed-espi-slave.c | 353 +++++++++++++++++++++ + 6 files changed, 503 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..8660e2ffbb89 +--- /dev/null ++++ b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt +@@ -0,0 +1,19 @@ ++ASPEED eSPI Slave Controller ++ ++Required properties: ++ - compatible: must be one of: ++ - "aspeed,ast2500-espi-slave" ++ ++ - reg: physical base address of the controller and length of memory mapped ++ region ++ ++ - interrupts: interrupt generated by the controller ++ ++Example: ++ ++ espi: espi@1e6ee000 { ++ compatible = "aspeed,ast2500-espi-slave"; ++ reg = <0x1e6ee000 0x100>; ++ interrupts = <23>; ++ status = "disabled"; ++}; +diff --git a/Documentation/misc-devices/espi-slave.rst b/Documentation/misc-devices/espi-slave.rst +new file mode 100644 +index 000000000000..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 2d6f730a7101..0e7f1d2fa08e 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -289,6 +289,7 @@ + clocks = <&syscon ASPEED_CLK_APB>; + interrupt-controller; + #interrupt-cells = <2>; ++ status = "disabled"; + }; + + sgpio: sgpio@1e780200 { +@@ -383,6 +384,9 @@ + reg = <0x1e6ee000 0x100>; + interrupts = <23>; + status = "disabled"; ++ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_espi_default>; + }; + + lpc: lpc@1e789000 { +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 9d96469fb41c..b6acddaa9421 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -473,6 +473,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 e13de4f0798f..f91f66a15484 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -54,6 +54,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..36ae867ca6f9 +--- /dev/null ++++ b/drivers/misc/aspeed-espi-slave.c +@@ -0,0 +1,353 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2012-2015, ASPEED Technology Inc. ++ * Copyright (c) 2015-2018, Intel Corporation. ++ */ ++ ++#include <linux/atomic.h> ++#include <linux/clk.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/poll.h> ++#include <linux/regmap.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/timer.h> ++ ++#define DEVICE_NAME "aspeed-espi-slave" ++ ++#define ESPI_CTRL 0x00 ++#define ESPI_CTRL_SW_RESET GENMASK(31, 24) ++#define ESPI_CTRL_OOB_CHRDY BIT(4) ++#define ESPI_ISR 0x08 ++#define ESPI_ISR_HW_RESET BIT(31) ++#define ESPI_ISR_VW_SYS_EVT1 BIT(22) ++#define ESPI_ISR_VW_SYS_EVT BIT(8) ++#define ESPI_IER 0x0C ++#define ESPI_DATA_PORT 0x28 ++#define ESPI_DATA_PORT_ASPEED 0xa8 ++#define ESPI_SYS_IER 0x94 ++#define ESPI_SYS_EVENT 0x98 ++#define ESPI_SYS_INT_T0 0x110 ++#define ESPI_SYS_INT_T1 0x114 ++#define ESPI_SYS_INT_T2 0x118 ++#define ESPI_SYS_ISR 0x11C ++#define ESPI_SYSEVT_HOST_RST_ACK BIT(27) ++#define ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23) ++#define ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20) ++#define ESPI_SYSEVT_OOB_RST_ACK BIT(16) ++#define ESPI_SYSEVT_HOST_RST_WARN BIT(8) ++#define ESPI_SYSEVT_OOB_RST_WARN BIT(6) ++#define ESPI_SYSEVT_PLT_RST_N BIT(5) ++#define ESPI_SYS1_IER 0x100 ++#define ESPI_SYS1_EVENT 0x104 ++#define ESPI_SYS1_INT_T0 0x120 ++#define ESPI_SYS1_INT_T1 0x124 ++#define ESPI_SYS1_INT_T2 0x128 ++#define ESPI_SYS1_ISR 0x12C ++#define ESPI_SYSEVT1_SUS_ACK BIT(20) ++#define ESPI_SYSEVT1_SUS_WARN BIT(0) ++ ++struct aspeed_espi_slave_data { ++ struct regmap *map; ++ struct clk *clk; ++}; ++ ++static void aspeed_espi_slave_sys_event(struct platform_device *pdev) ++{ ++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 sts, evt; ++ ++ if (regmap_read(priv->map, ESPI_SYS_ISR, &sts) != 0 || ++ regmap_read(priv->map, ESPI_SYS_EVENT, &evt) != 0) { ++ dev_err(dev, "regmap_read failed\n"); ++ return; ++ } ++ ++ dev_dbg(dev, "sys: sts = %08x, evt = %08x\n", sts, evt); ++ ++ if ((evt & ESPI_SYSEVT_SLAVE_BOOT_STATUS) == 0) { ++ dev_info(dev, "Setting espi slave boot done\n"); ++ regmap_write(priv->map, ESPI_SYS_EVENT, ++ evt | ESPI_SYSEVT_SLAVE_BOOT_STATUS | ++ ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ } ++#if 0 ++ if (sts & ESPI_SYSEVT_HOST_RST_WARN) { ++ dev_info(dev, "ESPI_SYSEVT_HOST_RST_WARN; %s ack\n", ++ (evt & ESPI_SYSEVT_HOST_RST_WARN ? "send" : "clr")); ++ regmap_write_bits(priv->map, ESPI_SYS_EVENT, ++ ESPI_SYSEVT_HOST_RST_ACK, ++ evt & ESPI_SYSEVT_HOST_RST_WARN ? ++ ESPI_SYSEVT_HOST_RST_ACK : 0); ++ } ++ if (sts & ESPI_SYSEVT_OOB_RST_WARN) { ++ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; %s ack\n", ++ (evt & ESPI_SYSEVT_OOB_RST_WARN ? "send" : "clr")); ++ regmap_write_bits(priv->map, ESPI_SYS_EVENT, ++ ESPI_SYSEVT_OOB_RST_ACK, ++ evt & ESPI_SYSEVT_OOB_RST_WARN ? ++ ESPI_SYSEVT_OOB_RST_ACK : 0); ++ } ++#else ++ if (sts & ESPI_SYSEVT_HOST_RST_WARN) { ++ if (evt & ESPI_SYSEVT_HOST_RST_WARN) { ++ dev_info(dev, "ESPI_SYSEVT_HOST_RST_WARN; send ack\n"); ++ regmap_write_bits(priv->map, ESPI_SYS_EVENT, ++ ESPI_SYSEVT_HOST_RST_ACK, ESPI_SYSEVT_HOST_RST_ACK); ++ } ++ } ++ if (sts & ESPI_SYSEVT_OOB_RST_WARN) { ++ if (evt & ESPI_SYSEVT_OOB_RST_WARN) { ++ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; send ack\n"); ++ regmap_write_bits(priv->map, ESPI_SYS_EVENT, ++ ESPI_SYSEVT_OOB_RST_ACK, ESPI_SYSEVT_OOB_RST_ACK); ++ } ++ } ++#endif ++ regmap_write(priv->map, ESPI_SYS_ISR, sts); ++} ++ ++static void aspeed_espi_slave_sys1_event(struct platform_device *pdev) ++{ ++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 sts, evt; ++ ++ if (regmap_read(priv->map, ESPI_SYS1_ISR, &sts) != 0 || ++ regmap_read(priv->map, ESPI_SYS1_EVENT, &evt) != 0) { ++ dev_err(dev, "regmap_read failed\n"); ++ return; ++ } ++ dev_dbg(dev, "sys1: sts = %08x, evt = %08x\n", sts, evt); ++ ++#if 0 ++ if (sts & ESPI_SYSEVT1_SUS_WARN) { ++ dev_info(dev, "ESPI_SYSEVT1_SUS_WARN; %s ack\n", ++ (evt & ESPI_SYSEVT1_SUS_WARN ? "send" : "clr")); ++ regmap_write_bits(priv->map, ESPI_SYS1_EVENT, ++ ESPI_SYSEVT1_SUS_ACK, ++ evt & ESPI_SYSEVT1_SUS_WARN ? ++ ESPI_SYSEVT1_SUS_ACK : 0); ++ } ++#else ++ if (sts & ESPI_SYSEVT1_SUS_WARN) { ++ if (evt & ESPI_SYSEVT1_SUS_WARN) { ++ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; send ack\n"); ++ regmap_write_bits(priv->map, ESPI_SYS1_EVENT, ++ ESPI_SYSEVT1_SUS_ACK, ESPI_SYSEVT1_SUS_ACK); ++ } ++ } ++#endif ++ regmap_write(priv->map, ESPI_SYS1_ISR, sts); ++} ++ ++static void aspeed_espi_slave_boot_ack(struct platform_device *pdev) ++{ ++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 evt; ++ ++ if (regmap_read(priv->map, ESPI_SYS_EVENT, &evt) == 0 && ++ (evt & ESPI_SYSEVT_SLAVE_BOOT_STATUS) == 0) { ++ dev_info(dev, "Setting espi slave boot done\n"); ++ regmap_write(priv->map, ESPI_SYS_EVENT, ++ evt | ESPI_SYSEVT_SLAVE_BOOT_STATUS | ++ ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ } ++ ++ if (regmap_read(priv->map, ESPI_SYS1_EVENT, &evt) == 0 && ++ (evt & ESPI_SYSEVT1_SUS_WARN) != 0 && ++ (evt & ESPI_SYSEVT1_SUS_ACK) == 0) { ++ dev_info(dev, "Boot SUS WARN set; send ack\n"); ++ regmap_write(priv->map, ESPI_SYS1_EVENT, ++ evt | ESPI_SYSEVT1_SUS_ACK); ++ } ++} ++ ++static irqreturn_t aspeed_espi_slave_irq(int irq, void *arg) ++{ ++ struct platform_device *pdev = arg; ++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ u32 sts; ++ ++ if (regmap_read(priv->map, ESPI_ISR, &sts) != 0) { ++ dev_err(dev, "regmap_read failed\n"); ++ return IRQ_NONE; ++ } ++ ++ dev_dbg(dev, "ESPI_ISR: %08x\n", sts); ++ ++ if (sts & ESPI_ISR_VW_SYS_EVT) ++ aspeed_espi_slave_sys_event(pdev); ++ ++ if (sts & ESPI_ISR_VW_SYS_EVT1) ++ aspeed_espi_slave_sys1_event(pdev); ++ ++ /* ++ if (sts & ESPI_ISR_HW_RESET) { ++ regmap_write_bits(priv->map, ESPI_CTRL, ++ ESPI_CTRL_SW_RESET, 0); ++ regmap_write_bits(priv->map, ESPI_CTRL, ++ ESPI_CTRL_SW_RESET, ESPI_CTRL_SW_RESET); ++ ++ aspeed_espi_slave_boot_ack(pdev); ++ } ++ */ ++ ++ regmap_write(priv->map, ESPI_ISR, sts); ++ ++ return IRQ_HANDLED; ++} ++ ++/* Setup Interrupt Type/Enable of System Event from Master ++ * T2 T1 T0 ++ * 1). HOST_RST_WARN : Dual Edge 1 0 0 ++ * 2). OOB_RST_WARN : Dual Edge 1 0 0 ++ * 3). PLTRST_N : Dual Edge 1 0 0 ++ */ ++#define ESPI_SYS_INT_T0_SET 0x00000000 ++#define ESPI_SYS_INT_T1_SET 0x00000000 ++#define ESPI_SYS_INT_T2_SET \ ++(ESPI_SYSEVT_HOST_RST_WARN | ESPI_SYSEVT_OOB_RST_WARN | ESPI_SYSEVT_PLT_RST_N) ++#define ESPI_SYS_INT_SET \ ++(ESPI_SYSEVT_HOST_RST_WARN | ESPI_SYSEVT_OOB_RST_WARN | ESPI_SYSEVT_PLT_RST_N) ++ ++/* Setup Interrupt Type/Enable of System Event 1 from Master ++ * T2 T1 T0 ++ * 1). SUS_WARN : Rising Edge 0 0 1 ++ */ ++#define ESPI_SYS1_INT_T0_SET ESPI_SYSEVT1_SUS_WARN ++#define ESPI_SYS1_INT_T1_SET 0x00000000 ++#define ESPI_SYS1_INT_T2_SET 0x00000000 ++#define ESPI_SYS1_INT_SET ESPI_SYSEVT1_SUS_WARN ++ ++static int aspeed_espi_slave_config_irq(struct platform_device *pdev) ++{ ++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int irq; ++ int rc; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ regmap_write_bits(priv->map, ESPI_CTRL, ESPI_CTRL_OOB_CHRDY, ++ ESPI_CTRL_OOB_CHRDY); ++ ++ regmap_write(priv->map, ESPI_SYS_INT_T0, ESPI_SYS_INT_T0_SET); ++ regmap_write(priv->map, ESPI_SYS_INT_T1, ESPI_SYS_INT_T1_SET); ++ regmap_write(priv->map, ESPI_SYS_INT_T2, ESPI_SYS_INT_T2_SET); ++ regmap_write(priv->map, ESPI_SYS_IER, ESPI_SYS_INT_SET); ++ ++ regmap_write(priv->map, ESPI_SYS1_INT_T0, ESPI_SYS1_INT_T0_SET); ++ regmap_write(priv->map, ESPI_SYS1_INT_T1, ESPI_SYS1_INT_T1_SET); ++ regmap_write(priv->map, ESPI_SYS1_INT_T2, ESPI_SYS1_INT_T2_SET); ++ regmap_write(priv->map, ESPI_SYS1_IER, ESPI_SYS1_INT_SET); ++ ++ regmap_write(priv->map, ESPI_IER, 0xFFFFFFFF); ++ ++ aspeed_espi_slave_boot_ack(pdev); ++ ++ rc = devm_request_irq(dev, irq, aspeed_espi_slave_irq, IRQF_SHARED, ++ dev_name(dev), pdev); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static const struct regmap_config espi_slave_regmap_cfg = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = ESPI_SYS1_ISR, ++}; ++ ++static int aspeed_espi_slave_probe(struct platform_device *pdev) ++{ ++ struct aspeed_espi_slave_data *priv; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ void __iomem *regs; ++ int rc; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->map = devm_regmap_init_mmio(dev, regs, &espi_slave_regmap_cfg); ++ if (IS_ERR(priv->map)) ++ return PTR_ERR(priv->map); ++ ++ priv->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(dev, "couldn't get clock\n"); ++ return PTR_ERR(priv->clk); ++ } ++ rc = clk_prepare_enable(priv->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ ++ dev_set_name(dev, DEVICE_NAME); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ rc = aspeed_espi_slave_config_irq(pdev); ++ if (rc) { ++ platform_set_drvdata(pdev, NULL); ++ goto err; ++ } ++ ++ dev_info(dev, "aspeed,ast2500-espi-slave probe complete\n"); ++ return 0; ++ ++err: ++ clk_disable_unprepare(priv->clk); ++ return rc; ++} ++ ++ ++static int aspeed_espi_slave_remove(struct platform_device *pdev) ++{ ++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id of_espi_slave_match_table[] = { ++ { .compatible = "aspeed,ast2500-espi-slave" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, of_espi_slave_match_table); ++ ++static struct platform_driver aspeed_espi_slave_driver = { ++ .driver = { ++ .name = DEVICE_NAME, ++ .of_match_table = of_match_ptr(of_espi_slave_match_table), ++ }, ++ .probe = aspeed_espi_slave_probe, ++ .remove = aspeed_espi_slave_remove, ++}; ++module_platform_driver(aspeed_espi_slave_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>"); ++MODULE_DESCRIPTION("Linux device interface to the eSPI slave"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch new file mode 100644 index 000000000..53060daf7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch @@ -0,0 +1,605 @@ +From 8d5f080b38d1b652eb5fdd3a7b74164906680ab7 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@intel.com> +Date: Wed, 4 Apr 2018 13:52:39 -0700 +Subject: [PATCH] Add support for new PECI commands + +Signed-off-by: Jason M. Bills <jason.m.bills@intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/peci/peci-core.c | 396 ++++++++++++++++++++++++++++++++++++++++ + include/uapi/linux/peci-ioctl.h | 146 +++++++++++++++ + 2 files changed, 542 insertions(+) + +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index d1f0df8b139a..b99ba788a032 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -318,6 +318,12 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) + * See PECI Spec Table 3-1. + */ + revision = FIELD_GET(REVISION_NUM_MASK, dib); ++ if (revision >= 0x40) { /* Rev. 4.0 */ ++ adapter->cmd_mask |= BIT(PECI_CMD_RD_END_PT_CFG); ++ adapter->cmd_mask |= BIT(PECI_CMD_WR_END_PT_CFG); ++ adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_DISC); ++ adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_GET_FRAME); ++ } + if (revision >= 0x36) /* Rev. 3.6 */ + adapter->cmd_mask |= BIT(PECI_CMD_WR_IA_MSR); + if (revision >= 0x35) /* Rev. 3.5 */ +@@ -687,6 +693,392 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + return ret; + } + ++static int peci_cmd_rd_end_pt_cfg(struct peci_adapter *adapter, void *vmsg) ++{ ++ struct peci_rd_end_pt_cfg_msg *umsg = vmsg; ++ struct peci_xfer_msg *msg = NULL; ++ u32 address; ++ u8 tx_size; ++ int ret; ++ ++ switch (umsg->msg_type) { ++ case PECI_ENDPTCFG_TYPE_LOCAL_PCI: ++ case PECI_ENDPTCFG_TYPE_PCI: ++ /* ++ * Per the PECI spec, the read length must be a byte, word, ++ * or dword ++ */ ++ if (umsg->rx_len != 1 && umsg->rx_len != 2 && ++ umsg->rx_len != 4) { ++ dev_dbg(&adapter->dev, ++ "Invalid read length, rx_len: %d\n", ++ umsg->rx_len); ++ return -EINVAL; ++ } ++ ++ msg = peci_get_xfer_msg(PECI_RDENDPTCFG_PCI_WRITE_LEN, ++ PECI_RDENDPTCFG_READ_LEN_BASE + ++ umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ ++ address = umsg->params.pci_cfg.reg; /* [11:0] - Register */ ++ address |= (u32)umsg->params.pci_cfg.function ++ << 12; /* [14:12] - Function */ ++ address |= (u32)umsg->params.pci_cfg.device ++ << 15; /* [19:15] - Device */ ++ address |= (u32)umsg->params.pci_cfg.bus ++ << 20; /* [27:20] - Bus */ ++ /* [31:28] - Reserved */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDENDPTCFG_CMD; ++ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */ ++ msg->tx_buf[2] = umsg->msg_type; /* Message Type */ ++ msg->tx_buf[3] = 0x00; /* Endpoint ID */ ++ msg->tx_buf[4] = 0x00; /* Reserved */ ++ msg->tx_buf[5] = 0x00; /* Reserved */ ++ msg->tx_buf[6] = PECI_ENDPTCFG_ADDR_TYPE_PCI; /* Addr Type */ ++ msg->tx_buf[7] = umsg->params.pci_cfg.seg; /* PCI Segment */ ++ msg->tx_buf[8] = (u8)address; /* LSB - PCI Config Address */ ++ msg->tx_buf[9] = (u8)(address >> 8); /* PCI Config Address */ ++ msg->tx_buf[10] = (u8)(address >> 16); /* PCI Config Address */ ++ msg->tx_buf[11] = ++ (u8)(address >> 24); /* MSB - PCI Config Address */ ++ break; ++ ++ case PECI_ENDPTCFG_TYPE_MMIO: ++ /* ++ * Per the PECI spec, the read length must be a byte, word, ++ * dword, or qword ++ */ ++ if (umsg->rx_len != 1 && umsg->rx_len != 2 && ++ umsg->rx_len != 4 && umsg->rx_len != 8) { ++ dev_dbg(&adapter->dev, ++ "Invalid read length, rx_len: %d\n", ++ umsg->rx_len); ++ return -EINVAL; ++ } ++ /* ++ * Per the PECI spec, the address type must specify either DWORD ++ * or QWORD ++ */ ++ if (umsg->params.mmio.addr_type != ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D && ++ umsg->params.mmio.addr_type != ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) { ++ dev_dbg(&adapter->dev, ++ "Invalid address type, addr_type: %d\n", ++ umsg->params.mmio.addr_type); ++ return -EINVAL; ++ } ++ ++ if (umsg->params.mmio.addr_type == ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D) ++ tx_size = PECI_RDENDPTCFG_MMIO_D_WRITE_LEN; ++ else ++ tx_size = PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN; ++ msg = peci_get_xfer_msg(tx_size, ++ PECI_RDENDPTCFG_READ_LEN_BASE + ++ umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ ++ address = umsg->params.mmio.function; /* [2:0] - Function */ ++ address |= (u32)umsg->params.mmio.device ++ << 3; /* [7:3] - Device */ ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDENDPTCFG_CMD; ++ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */ ++ msg->tx_buf[2] = umsg->msg_type; /* Message Type */ ++ msg->tx_buf[3] = 0x00; /* Endpoint ID */ ++ msg->tx_buf[4] = 0x00; /* Reserved */ ++ msg->tx_buf[5] = umsg->params.mmio.bar; /* BAR # */ ++ msg->tx_buf[6] = umsg->params.mmio.addr_type; /* Address Type */ ++ msg->tx_buf[7] = umsg->params.mmio.seg; /* PCI Segment */ ++ msg->tx_buf[8] = (u8)address; /* Function/Device */ ++ msg->tx_buf[9] = umsg->params.mmio.bus; /* PCI Bus */ ++ msg->tx_buf[10] = (u8)umsg->params.mmio ++ .offset; /* LSB - Register Offset */ ++ msg->tx_buf[11] = (u8)(umsg->params.mmio.offset ++ >> 8); /* Register Offset */ ++ msg->tx_buf[12] = (u8)(umsg->params.mmio.offset ++ >> 16); /* Register Offset */ ++ msg->tx_buf[13] = (u8)(umsg->params.mmio.offset ++ >> 24); /* MSB - DWORD Register Offset */ ++ if (umsg->params.mmio.addr_type == ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) { ++ msg->tx_buf[14] = (u8)(umsg->params.mmio.offset ++ >> 32); /* Register Offset */ ++ msg->tx_buf[15] = (u8)(umsg->params.mmio.offset ++ >> 40); /* Register Offset */ ++ msg->tx_buf[16] = (u8)(umsg->params.mmio.offset ++ >> 48); /* Register Offset */ ++ msg->tx_buf[17] = ++ (u8)(umsg->params.mmio.offset ++ >> 56); /* MSB - QWORD Register Offset */ ++ } ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; ++} ++ ++static int peci_cmd_wr_end_pt_cfg(struct peci_adapter *adapter, void *vmsg) ++{ ++ struct peci_wr_end_pt_cfg_msg *umsg = vmsg; ++ struct peci_xfer_msg *msg = NULL; ++ u8 tx_size, aw_fcs; ++ int ret, i, idx; ++ u32 address; ++ ++ switch (umsg->msg_type) { ++ case PECI_ENDPTCFG_TYPE_LOCAL_PCI: ++ case PECI_ENDPTCFG_TYPE_PCI: ++ /* ++ * Per the PECI spec, the write length must be a byte, word, ++ * or dword ++ */ ++ if (umsg->tx_len != 1 && umsg->tx_len != 2 && ++ umsg->tx_len != 4) { ++ dev_dbg(&adapter->dev, ++ "Invalid write length, tx_len: %d\n", ++ umsg->tx_len); ++ return -EINVAL; ++ } ++ ++ msg = peci_get_xfer_msg(PECI_WRENDPTCFG_PCI_WRITE_LEN_BASE + ++ umsg->tx_len, PECI_WRENDPTCFG_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ address = umsg->params.pci_cfg.reg; /* [11:0] - Register */ ++ address |= (u32)umsg->params.pci_cfg.function ++ << 12; /* [14:12] - Function */ ++ address |= (u32)umsg->params.pci_cfg.device ++ << 15; /* [19:15] - Device */ ++ address |= (u32)umsg->params.pci_cfg.bus ++ << 20; /* [27:20] - Bus */ ++ /* [31:28] - Reserved */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_WRENDPTCFG_CMD; ++ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */ ++ msg->tx_buf[2] = umsg->msg_type; /* Message Type */ ++ msg->tx_buf[3] = 0x00; /* Endpoint ID */ ++ msg->tx_buf[4] = 0x00; /* Reserved */ ++ msg->tx_buf[5] = 0x00; /* Reserved */ ++ msg->tx_buf[6] = PECI_ENDPTCFG_ADDR_TYPE_PCI; /* Addr Type */ ++ msg->tx_buf[7] = umsg->params.pci_cfg.seg; /* PCI Segment */ ++ msg->tx_buf[8] = (u8)address; /* LSB - PCI Config Address */ ++ msg->tx_buf[9] = (u8)(address >> 8); /* PCI Config Address */ ++ msg->tx_buf[10] = (u8)(address >> 16); /* PCI Config Address */ ++ msg->tx_buf[11] = ++ (u8)(address >> 24); /* MSB - PCI Config Address */ ++ for (i = 0; i < umsg->tx_len; i++) ++ msg->tx_buf[12 + i] = (u8)(umsg->value >> (i << 3)); ++ ++ /* Add an Assured Write Frame Check Sequence byte */ ++ ret = peci_aw_fcs(msg, 15 + umsg->tx_len, &aw_fcs); ++ if (ret) ++ goto out; ++ ++ msg->tx_buf[12 + i] = 0x80 ^ aw_fcs; ++ break; ++ ++ case PECI_ENDPTCFG_TYPE_MMIO: ++ /* ++ * Per the PECI spec, the write length must be a byte, word, ++ * dword, or qword ++ */ ++ if (umsg->tx_len != 1 && umsg->tx_len != 2 && ++ umsg->tx_len != 4 && umsg->tx_len != 8) { ++ dev_dbg(&adapter->dev, ++ "Invalid write length, tx_len: %d\n", ++ umsg->tx_len); ++ return -EINVAL; ++ } ++ /* ++ * Per the PECI spec, the address type must specify either DWORD ++ * or QWORD ++ */ ++ if (umsg->params.mmio.addr_type != ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D && ++ umsg->params.mmio.addr_type != ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) { ++ dev_dbg(&adapter->dev, ++ "Invalid address type, addr_type: %d\n", ++ umsg->params.mmio.addr_type); ++ return -EINVAL; ++ } ++ ++ if (umsg->params.mmio.addr_type == ++ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D) ++ tx_size = PECI_WRENDPTCFG_MMIO_D_WRITE_LEN_BASE + ++ umsg->tx_len; ++ else ++ tx_size = PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE + ++ umsg->tx_len; ++ msg = peci_get_xfer_msg(tx_size, PECI_WRENDPTCFG_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ address = umsg->params.mmio.function; /* [2:0] - Function */ ++ address |= (u32)umsg->params.mmio.device ++ << 3; /* [7:3] - Device */ ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_WRENDPTCFG_CMD; ++ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */ ++ msg->tx_buf[2] = umsg->msg_type; /* Message Type */ ++ msg->tx_buf[3] = 0x00; /* Endpoint ID */ ++ msg->tx_buf[4] = 0x00; /* Reserved */ ++ msg->tx_buf[5] = umsg->params.mmio.bar; /* BAR # */ ++ msg->tx_buf[6] = umsg->params.mmio.addr_type; /* Address Type */ ++ msg->tx_buf[7] = umsg->params.mmio.seg; /* PCI Segment */ ++ msg->tx_buf[8] = (u8)address; /* Function/Device */ ++ msg->tx_buf[9] = umsg->params.mmio.bus; /* PCI Bus */ ++ msg->tx_buf[10] = (u8)umsg->params.mmio ++ .offset; /* LSB - Register Offset */ ++ msg->tx_buf[11] = (u8)(umsg->params.mmio.offset ++ >> 8); /* Register Offset */ ++ msg->tx_buf[12] = (u8)(umsg->params.mmio.offset ++ >> 16); /* Register Offset */ ++ msg->tx_buf[13] = (u8)(umsg->params.mmio.offset ++ >> 24); /* MSB - DWORD Register Offset */ ++ if (umsg->params.mmio.addr_type == ++ PECI_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 ++ >> 40); /* Register Offset */ ++ msg->tx_buf[16] = (u8)(umsg->params.mmio.offset ++ >> 48); /* Register Offset */ ++ msg->tx_buf[17] = ++ (u8)(umsg->params.mmio.offset ++ >> 56); /* MSB - QWORD Register Offset */ ++ idx = 18; ++ } else { ++ idx = 14; ++ } ++ for (i = 0; i < umsg->tx_len; i++) ++ msg->tx_buf[idx + i] = (u8)(umsg->value >> (i << 3)); ++ ++ /* Add an Assured Write Frame Check Sequence byte */ ++ ret = peci_aw_fcs(msg, idx + 3 + umsg->tx_len, &aw_fcs); ++ if (ret) ++ goto out; ++ ++ msg->tx_buf[idx + i] = 0x80 ^ aw_fcs; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ ++out: ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; ++} ++ ++static int peci_cmd_crashdump_disc(struct peci_adapter *adapter, void *vmsg) ++{ ++ struct peci_crashdump_disc_msg *umsg = vmsg; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ /* Per the EDS, the read length must be a byte, word, or qword */ ++ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 8) { ++ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n", ++ umsg->rx_len); ++ return -EINVAL; ++ } ++ ++ msg = peci_get_xfer_msg(PECI_CRASHDUMP_DISC_WRITE_LEN, ++ PECI_CRASHDUMP_DISC_READ_LEN_BASE + ++ umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_CRASHDUMP_CMD; ++ msg->tx_buf[1] = 0x00; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = PECI_CRASHDUMP_DISC_VERSION; ++ msg->tx_buf[3] = PECI_CRASHDUMP_DISC_OPCODE; ++ msg->tx_buf[4] = umsg->subopcode; ++ msg->tx_buf[5] = umsg->param0; ++ msg->tx_buf[6] = (u8)umsg->param1; ++ msg->tx_buf[7] = (u8)(umsg->param1 >> 8); ++ msg->tx_buf[8] = umsg->param2; ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; ++} ++ ++static int peci_cmd_crashdump_get_frame(struct peci_adapter *adapter, ++ void *vmsg) ++{ ++ struct peci_crashdump_get_frame_msg *umsg = vmsg; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ /* Per the EDS, the read length must be a qword or dqword */ ++ if (umsg->rx_len != 8 && umsg->rx_len != 16) { ++ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n", ++ umsg->rx_len); ++ return -EINVAL; ++ } ++ ++ msg = peci_get_xfer_msg(PECI_CRASHDUMP_GET_FRAME_WRITE_LEN, ++ PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE + ++ umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_CRASHDUMP_CMD; ++ msg->tx_buf[1] = 0x00; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = PECI_CRASHDUMP_GET_FRAME_VERSION; ++ msg->tx_buf[3] = PECI_CRASHDUMP_GET_FRAME_OPCODE; ++ msg->tx_buf[4] = (u8)umsg->param0; ++ msg->tx_buf[5] = (u8)(umsg->param0 >> 8); ++ msg->tx_buf[6] = (u8)umsg->param1; ++ msg->tx_buf[7] = (u8)(umsg->param1 >> 8); ++ msg->tx_buf[8] = (u8)umsg->param2; ++ msg->tx_buf[8] = (u8)(umsg->param2 >> 8); ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; ++} ++ + typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *); + + static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { +@@ -702,6 +1094,10 @@ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { + peci_cmd_wr_pci_cfg, + peci_cmd_rd_pci_cfg_local, + peci_cmd_wr_pci_cfg_local, ++ peci_cmd_rd_end_pt_cfg, ++ peci_cmd_wr_end_pt_cfg, ++ peci_cmd_crashdump_disc, ++ peci_cmd_crashdump_get_frame, + }; + + /** +diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h +index 253fb42e38b7..405cd8edbcbf 100644 +--- a/include/uapi/linux/peci-ioctl.h ++++ b/include/uapi/linux/peci-ioctl.h +@@ -71,6 +71,10 @@ enum peci_cmd { + PECI_CMD_WR_PCI_CFG, + PECI_CMD_RD_PCI_CFG_LOCAL, + PECI_CMD_WR_PCI_CFG_LOCAL, ++ PECI_CMD_RD_END_PT_CFG, ++ PECI_CMD_WR_END_PT_CFG, ++ PECI_CMD_CRASHDUMP_DISC, ++ PECI_CMD_CRASHDUMP_GET_FRAME, + PECI_CMD_MAX + }; + +@@ -438,6 +442,132 @@ struct peci_wr_pci_cfg_local_msg { + __u32 value; + } __attribute__((__packed__)); + ++struct peci_rd_end_pt_cfg_msg { ++#define PECI_RDENDPTCFG_PCI_WRITE_LEN 12 ++#define PECI_RDENDPTCFG_MMIO_D_WRITE_LEN 14 ++#define PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN 18 ++#define PECI_RDENDPTCFG_READ_LEN_BASE 1 ++#define PECI_RDENDPTCFG_CMD 0xc1 ++ ++ __u8 addr; ++ __u8 msg_type; ++#define PECI_ENDPTCFG_TYPE_LOCAL_PCI 0x03 ++#define PECI_ENDPTCFG_TYPE_PCI 0x04 ++#define PECI_ENDPTCFG_TYPE_MMIO 0x05 ++ ++ union { ++ struct { ++ __u8 seg; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ } pci_cfg; ++ struct { ++ __u8 seg; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u8 bar; ++ __u8 addr_type; ++#define PECI_ENDPTCFG_ADDR_TYPE_PCI 0x04 ++#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_D 0x05 ++#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q 0x06 ++ ++ __u64 offset; ++ } mmio; ++ } params; ++ __u8 rx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u8 data[8]; ++} __attribute__((__packed__)); ++ ++struct peci_wr_end_pt_cfg_msg { ++#define PECI_WRENDPTCFG_PCI_WRITE_LEN_BASE 13 ++#define PECI_WRENDPTCFG_MMIO_D_WRITE_LEN_BASE 15 ++#define PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE 19 ++#define PECI_WRENDPTCFG_READ_LEN 1 ++#define PECI_WRENDPTCFG_CMD 0xc5 ++ ++ __u8 addr; ++ __u8 msg_type; ++ /* See msg_type in struct peci_rd_end_pt_cfg_msg */ ++ ++ union { ++ struct { ++ __u8 seg; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ } pci_cfg; ++ struct { ++ __u8 seg; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u8 bar; ++ __u8 addr_type; ++ /* See addr_type in struct peci_rd_end_pt_cfg_msg */ ++ ++ __u64 offset; ++ } mmio; ++ } params; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u64 value; ++} __attribute__((__packed__)); ++ ++/* Crashdump Agent */ ++#define PECI_CRASHDUMP_CORE 0x00 ++#define PECI_CRASHDUMP_TOR 0x01 ++ ++/* Crashdump Agent Param */ ++#define PECI_CRASHDUMP_PAYLOAD_SIZE 0x00 ++ ++/* Crashdump Agent Data Param */ ++#define PECI_CRASHDUMP_AGENT_ID 0x00 ++#define PECI_CRASHDUMP_AGENT_PARAM 0x01 ++ ++struct peci_crashdump_disc_msg { ++ __u8 addr; ++ __u8 subopcode; ++#define PECI_CRASHDUMP_ENABLED 0x00 ++#define PECI_CRASHDUMP_NUM_AGENTS 0x01 ++#define PECI_CRASHDUMP_AGENT_DATA 0x02 ++ ++ __u8 cc; ++ __u8 param0; ++ __u16 param1; ++ __u8 param2; ++ __u8 rx_len; ++ __u8 data[8]; ++} __attribute__((__packed__)); ++ ++struct peci_crashdump_get_frame_msg { ++#define PECI_CRASHDUMP_DISC_WRITE_LEN 9 ++#define PECI_CRASHDUMP_DISC_READ_LEN_BASE 1 ++#define PECI_CRASHDUMP_DISC_VERSION 0 ++#define PECI_CRASHDUMP_DISC_OPCODE 1 ++#define PECI_CRASHDUMP_GET_FRAME_WRITE_LEN 10 ++#define PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE 1 ++#define PECI_CRASHDUMP_GET_FRAME_VERSION 0 ++#define PECI_CRASHDUMP_GET_FRAME_OPCODE 3 ++#define PECI_CRASHDUMP_CMD 0x71 ++ ++ __u8 addr; ++ __u8 padding0; ++ __u16 param0; ++ __u16 param1; ++ __u16 param2; ++ __u8 rx_len; ++ __u8 cc; ++ __u8 padding1[2]; ++ __u8 data[16]; ++} __attribute__((__packed__)); ++ + #define PECI_IOC_BASE 0xb7 + + #define PECI_IOC_XFER \ +@@ -478,4 +608,20 @@ struct peci_wr_pci_cfg_local_msg { + _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG_LOCAL, \ + struct peci_wr_pci_cfg_local_msg) + ++#define PECI_IOC_RD_END_PT_CFG \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_END_PT_CFG, \ ++ struct peci_rd_end_pt_cfg_msg) ++ ++#define PECI_IOC_WR_END_PT_CFG \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_END_PT_CFG, \ ++ struct peci_wr_end_pt_cfg_msg) ++ ++#define PECI_IOC_CRASHDUMP_DISC \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_DISC, \ ++ struct peci_crashdump_disc_msg) ++ ++#define PECI_IOC_CRASHDUMP_GET_FRAME \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_GET_FRAME, \ ++ struct peci_crashdump_get_frame_msg) ++ + #endif /* __PECI_IOCTL_H */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch new file mode 100644 index 000000000..28bc8d36c --- /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] Update AST2500d JTAG driver. Step 1 + +Update AST2500d 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..d828233fe --- /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 38c04788647a95e3951674eb802f1f99ecdde164 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 fa66951b05d0..434b753def3b 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -163,6 +163,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) +@@ -652,6 +667,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; +@@ -694,6 +710,11 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, + return -ETIMEDOUT; + } + ++ for (i = 0; i < num; i++) { ++ I2C_HEX_DUMP(bus, msgs[i].addr, msgs[i].flags, ++ msgs[i].buf, msgs[i].len); ++ } ++ + return bus->master_xfer_result; + } + +@@ -1061,6 +1082,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..803701286 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch @@ -0,0 +1,132 @@ +From 01c8d6a5146cd39c2286f659e21f1a1042aa741a Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Wed, 2 Jan 2019 15:06:43 +0800 +Subject: [PATCH] Add high speed baud rate support for UART + +In order to support high speed baud rate(921600 bps), +the default UART clock(24MHz) needs to be switched +to 192MHz(from USB2.0 port1 PHY). + +Create a new 192M Hz clock and assign it to uart, +based on uart clock source configuration in SCU4C. + +bootloader(u-boot) will set SCU4C based on the environment configuration + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + drivers/clk/clk-aspeed.c | 41 +++++++++++++++++++++++++++----- + include/dt-bindings/clock/aspeed-clock.h | 2 ++ + 2 files changed, 37 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c +index 42b4df6ba249..97c27820db3e 100644 +--- a/drivers/clk/clk-aspeed.c ++++ b/drivers/clk/clk-aspeed.c +@@ -14,7 +14,9 @@ + + #include <dt-bindings/clock/aspeed-clock.h> + +-#define ASPEED_NUM_CLKS 36 ++#define ASPEED_NUM_CLKS ASPEED_CLK_MAX ++#define UART_HIGH_SPEED_CLK 192000000 ++#define UART_LOW_SPEED_CLK 24000000 + + #define ASPEED_RESET2_OFFSET 32 + +@@ -28,6 +30,12 @@ + #define AST2400_HPLL_BYPASS_EN BIT(17) + #define ASPEED_MISC_CTRL 0x2c + #define UART_DIV13_EN BIT(12) ++#define ASPEED_MISC2_CTRL 0x4c ++#define UART1_HS_CLK_EN BIT(24) ++#define UART2_HS_CLK_EN BIT(25) ++#define UART3_HS_CLK_EN BIT(26) ++#define UART4_HS_CLK_EN BIT(27) ++#define UART5_HS_CLK_EN BIT(28) + #define ASPEED_STRAP 0x70 + #define CLKIN_25MHZ_EN BIT(23) + #define AST2400_CLK_SOURCE_SEL BIT(18) +@@ -446,7 +454,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) + struct aspeed_reset *ar; + struct regmap *map; + struct clk_hw *hw; +- u32 val, rate; ++ u32 val, uart_clock_div; + int i, ret; + + map = syscon_node_to_regmap(dev->of_node); +@@ -481,15 +489,23 @@ static int aspeed_clk_probe(struct platform_device *pdev) + /* UART clock div13 setting */ + regmap_read(map, ASPEED_MISC_CTRL, &val); + if (val & UART_DIV13_EN) +- rate = 24000000 / 13; ++ uart_clock_div = 13; + else +- rate = 24000000; ++ uart_clock_div = 1; ++ + /* TODO: Find the parent data for the uart clock */ +- hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); ++ hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, ++ UART_LOW_SPEED_CLK / uart_clock_div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_UART] = hw; + ++ hw = clk_hw_register_fixed_rate(dev, "uart-hs", "usb-port1-gate", 0, ++ UART_HIGH_SPEED_CLK / uart_clock_div); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ aspeed_clk_data->hws[ASPEED_CLK_UART_HS] = hw; ++ + /* + * Memory controller (M-PLL) PLL. This clock is configured by the + * bootloader, and is exposed to Linux as a read-only clock rate. +@@ -570,9 +586,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. +@@ -580,7 +609,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 f43738607d77..335879505a72 100644 +--- a/include/dt-bindings/clock/aspeed-clock.h ++++ b/include/dt-bindings/clock/aspeed-clock.h +@@ -39,6 +39,8 @@ + #define ASPEED_CLK_BCLK 33 + #define ASPEED_CLK_MPLL 34 + #define ASPEED_CLK_24M 35 ++#define ASPEED_CLK_UART_HS 36 ++#define ASPEED_CLK_MAX 37 + + #define ASPEED_RESET_XDMA 0 + #define ASPEED_RESET_MCTP 1 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch new file mode 100644 index 000000000..8c18e87ef --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch @@ -0,0 +1,556 @@ +From 0928704f3b593217662f980221406fcf6db39377 Mon Sep 17 00:00:00 2001 +From: Oskar Senft <osk@google.com> +Date: Wed, 8 Aug 2018 10:15:05 -0400 +Subject: [PATCH] misc: aspeed: Add Aspeed UART routing control driver. + +This driver adds sysfs files that allow the BMC userspace to configure +how UARTs and physical serial I/O ports are routed. + +Tested: Checked correct behavior (both read & write) on TYAN S7106 +board by manually changing routing settings and confirming that bits +flow as expected. Tested for UART1 and UART3 as this board doesn't have +the other UARTs wired up in a testable way. + +Signed-off-by: Oskar Senft <osk@google.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + .../ABI/stable/sysfs-driver-aspeed-uart-routing | 14 + + Documentation/misc-devices/aspeed-uart-routing.txt | 49 +++ + arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 4 + + arch/arm/boot/dts/aspeed-g5.dtsi | 6 + + drivers/misc/Kconfig | 6 + + drivers/misc/Makefile | 1 + + drivers/misc/aspeed-uart-routing.c | 383 +++++++++++++++++++++ + 7 files changed, 463 insertions(+) + create mode 100644 Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing + create mode 100644 Documentation/misc-devices/aspeed-uart-routing.txt + create mode 100644 drivers/misc/aspeed-uart-routing.c + +diff --git a/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing +new file mode 100644 +index 000000000000..5068737d9c12 +--- /dev/null ++++ b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing +@@ -0,0 +1,14 @@ ++What: /sys/bus/platform/drivers/aspeed-uart-routing/*/io* ++Date: August 2018 ++Contact: Oskar Senft <osk@google.com> ++Description: Configures the input source for the specific physical ++ serial I/O port. ++Users: OpenBMC. Proposed changes should be mailed to ++ openbmc@lists.ozlabs.org ++ ++What: /sys/bus/platform/drivers/aspeed-uart-routing/*/uart* ++Date: August 2018 ++Contact: Oskar Senft <osk@google.com> ++Description: Configures the input source for the specific UART. ++Users: OpenBMC. Proposed changes should be mailed to ++ openbmc@lists.ozlabs.org +diff --git a/Documentation/misc-devices/aspeed-uart-routing.txt b/Documentation/misc-devices/aspeed-uart-routing.txt +new file mode 100644 +index 000000000000..afaf17cb7eda +--- /dev/null ++++ b/Documentation/misc-devices/aspeed-uart-routing.txt +@@ -0,0 +1,49 @@ ++Kernel driver aspeed-uart-routing ++================================= ++ ++Supported chips: ++ASPEED AST2500 ++ ++Author: ++Google LLC ++ ++Description ++----------- ++ ++The Aspeed AST2500 allows to dynamically route the inputs for the built-in ++UARTS and physical serial I/O ports. ++ ++This allows, for example, to connect the output of UART to another UART. ++This can be used to enable host<->BMC communication via UARTs, e.g. to allow ++access to the host's serial console. ++ ++This driver is for the BMC side. The sysfs files allow the BMC userspace ++which owns the system configuration policy, to configure how UARTs and ++physical serial I/O ports are routed. ++ ++The driver provides the following files in sysfs: ++uart1 Configure the input signal to UART1. ++uart2 Configure the input signal to UART2. ++uart3 Configure the input signal to UART3. ++uart4 Configure the input signal to UART4. ++uart5 Configure the input signal to UART5. ++io1 Configure the input signal to physical serial port 1. ++io2 Configure the input signal to physical serial port 2. ++io3 Configure the input signal to physical serial port 3. ++io4 Configure the input signal to physical serial port 4. ++io5 Configure the input signal to physical serial port 5. ++ ++When read, each file shows the list of available options with the currently ++selected option marked by square brackets "[]". The list of available options ++depends on the selected file. ++ ++Example: ++$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 ++[io1] io2 io3 io4 uart2 uart3 uart4 io6 ++ ++In this case, UART1 gets its input signal from IO1 (physical serial port 1). ++ ++$ echo -n "uart3" \ ++ >/sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 ++$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 ++io1 io2 io3 io4 uart2 [uart3] uart4 io6 +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +index 4815104459f1..3094e90c9def 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +@@ -233,6 +233,10 @@ + status = "okay"; + }; + ++&uart_routing { ++ status = "okay"; ++}; ++ + &mac1 { + status = "okay"; + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 0e7f1d2fa08e..6e0b40eb939f 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -493,6 +493,12 @@ + status = "disabled"; + }; + }; ++ ++ uart_routing: uart_routing@9c { ++ compatible = "aspeed,ast2500-uart-routing"; ++ reg = <0x9c 0x4>; ++ status = "disabled"; ++ }; + }; + + peci: bus@1e78b000 { +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index b6acddaa9421..78e8fc892209 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -481,6 +481,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 f91f66a15484..7337b8bcd0a3 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -55,6 +55,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..7f556de64 --- /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 fcea191a6e0eb869c62b5d1ea8a6e914a540fcfb 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 3df43f925848..618abeab539b 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -101,14 +101,6 @@ + reg = <0x1e6c2000 0x80>; + }; + +- mac0: ethernet@1e660000 { +- compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; +- reg = <0x1e660000 0x180>; +- interrupts = <2>; +- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; +- status = "disabled"; +- }; +- + mac1: ethernet@1e680000 { + compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; + reg = <0x1e680000 0x180>; +@@ -117,6 +109,14 @@ + status = "disabled"; + }; + ++ mac0: ethernet@1e660000 { ++ compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; ++ reg = <0x1e660000 0x180>; ++ interrupts = <2>; ++ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; ++ status = "disabled"; ++ }; ++ + ehci0: usb@1e6a1000 { + compatible = "aspeed,ast2400-ehci", "generic-ehci"; + reg = <0x1e6a1000 0x100>; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 6e0b40eb939f..b8c85fad2a39 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -149,14 +149,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>; +@@ -165,6 +157,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..798038a8e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch @@ -0,0 +1,246 @@ +From 5ccf8e3e397edf195aa65e91af6e9ea16ed88882 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 285c19042c65..59f25d16d6e7 100644 +--- a/drivers/soc/aspeed/Kconfig ++++ b/drivers/soc/aspeed/Kconfig +@@ -51,4 +51,13 @@ config ASPEED_P2A_CTRL + ioctl()s, the driver also provides an interface for userspace mappings to + a pre-defined region. + ++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 2e547cc47e62..ae4ef10914be 100644 +--- a/drivers/soc/aspeed/Makefile ++++ b/drivers/soc/aspeed/Makefile +@@ -5,3 +5,4 @@ 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 ++obj-$(CONFIG_ASPEED_VGA_SHAREDMEM) += aspeed-vga-sharedmem.o +\ No newline at end of file +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..c115d23d0 --- /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 7ac4709dd92c608ca4c8ff0046a434c8f465a80c 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 b8c85fad2a39..88ac8e08b6ae 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -312,7 +312,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 dff5a93f7daa..5759439a3947 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 c368599d36c0..937d212bb02a 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..4c929a25e27c +--- /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 = chip->variant.chan_min; i < chip->variant.chan_max; i++) { ++ struct pwm_device *pwm = &chip->pwms[i]; ++ struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm); ++ ++ if (!chan) ++ continue; ++ ++ if (chan->period_ns) { ++ pwm_fttmr010_config(chip, pwm, chan->duty_ns, ++ chan->period_ns); ++ } ++ ++ if (priv->disabled_mask & BIT(i)) ++ pwm_fttmr010_disable(chip, pwm); ++ else ++ pwm_fttmr010_enable(chip, pwm); ++ } ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(pwm_fttmr010_pm_ops, NULL, pwm_fttmr010_resume); ++ ++static struct platform_driver pwm_fttmr010_driver = { ++ .driver = { ++ .name = "fttmr010-timer-pwm", ++ .pm = &pwm_fttmr010_pm_ops, ++ .of_match_table = of_match_ptr(pwm_fttmr010_matches), ++ }, ++ .probe = pwm_fttmr010_probe, ++ .remove = pwm_fttmr010_remove, ++}; ++module_platform_driver(pwm_fttmr010_driver); ++ ++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); ++MODULE_DESCRIPTION("FTTMR010 PWM Driver for timer pulse outputs"); ++MODULE_LICENSE("GPL v2"); +-- +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..b2057d247 --- /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 ed13e7eb07e6cb8bdc1eb4563de30b469a9beb26 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 9e43508d4567..8a480d269542 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -1299,6 +1299,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; +@@ -1381,6 +1400,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: +@@ -1601,6 +1623,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)); +@@ -1950,7 +1974,9 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, + */ + int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + { ++ enum i2c_hold_msg_type hold_msg; + unsigned long orig_jiffies; ++ unsigned long timeout; + int ret, try; + + if (WARN_ON(!msgs || num < 1)) +@@ -1963,6 +1989,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 +@@ -1999,6 +2044,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); +@@ -2017,6 +2065,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) { +@@ -2040,12 +2089,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 603252fa1284..d3f55243e701 100644 +--- a/drivers/i2c/i2c-mux.c ++++ b/drivers/i2c/i2c-mux.c +@@ -26,6 +26,7 @@ + #include <linux/module.h> + #include <linux/of.h> + #include <linux/slab.h> ++#include <linux/timer.h> + + /* multiplexer per channel data */ + struct i2c_mux_priv { +@@ -35,21 +36,57 @@ struct i2c_mux_priv { + u32 chan_id; + }; + ++static void i2c_mux_hold(struct i2c_mux_core *muxc, unsigned long timeout) ++{ ++ mutex_lock(&muxc->hold_lock); ++ mod_timer(&muxc->hold_timer, jiffies + timeout); ++} ++ ++static void i2c_mux_unhold(struct i2c_mux_core *muxc) ++{ ++ del_timer_sync(&muxc->hold_timer); ++ mutex_unlock(&muxc->hold_lock); ++} ++ ++static void i2c_mux_hold_timer_callback(struct timer_list *t) ++{ ++ struct i2c_mux_core *muxc = from_timer(muxc, t, hold_timer); ++ ++ i2c_mux_unhold(muxc); ++} ++ + static int __i2c_mux_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) + { + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Switch to the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags, ++ msgs[num - 1].len, ++ (u16 *)msgs[num - 1].buf); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = __i2c_transfer(parent, msgs, num); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -60,15 +97,32 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap, + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Switch to the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags, ++ msgs[num - 1].len, ++ (u16 *)msgs[num - 1].buf); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = i2c_transfer(parent, msgs, num); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -81,16 +135,33 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Select the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(flags, ++ size == I2C_SMBUS_WORD_DATA ? 2 : 0, ++ &data->word); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(data->word); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = __i2c_smbus_xfer(parent, addr, flags, + read_write, command, size, data); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -103,16 +174,33 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap, + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Select the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(flags, ++ size == I2C_SMBUS_WORD_DATA ? 2 : 0, ++ &data->word); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(data->word); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = i2c_smbus_xfer(parent, addr, flags, + read_write, command, size, data); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -263,6 +351,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, + muxc->deselect = deselect; + muxc->max_adapters = max_adapters; + ++ mutex_init(&muxc->hold_lock); ++ timer_setup(&muxc->hold_timer, i2c_mux_hold_timer_callback, 0); ++ + return muxc; + } + EXPORT_SYMBOL_GPL(i2c_mux_alloc); +@@ -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 1308126fc384..3ee92c6a442d 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -699,6 +699,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) + +@@ -998,4 +1005,22 @@ static inline struct i2c_client *i2c_acpi_new_device(struct device *dev, + } + #endif /* CONFIG_ACPI */ + ++enum i2c_hold_msg_type { ++ I2C_HOLD_MSG_NONE, ++ I2C_HOLD_MSG_SET, ++ I2C_HOLD_MSG_RESET ++}; ++ ++static inline enum i2c_hold_msg_type i2c_check_hold_msg(u16 flags, u16 len, u16 *buf) ++{ ++ if (flags & I2C_M_HOLD && len == sizeof(u16)) { ++ if (*buf) ++ return I2C_HOLD_MSG_SET; ++ ++ return I2C_HOLD_MSG_RESET; ++ } ++ ++ return I2C_HOLD_MSG_NONE; ++} ++ + #endif /* _LINUX_I2C_H */ +diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h +index f71a1751cacf..a1db9b17ed36 100644 +--- a/include/uapi/linux/i2c.h ++++ b/include/uapi/linux/i2c.h +@@ -72,6 +72,7 @@ struct i2c_msg { + #define I2C_M_RD 0x0001 /* read data, from slave to master */ + /* I2C_M_RD is guaranteed to be 0x0001! */ + #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ ++#define I2C_M_HOLD 0x0100 /* for holding a mux path */ + #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */ + /* makes only sense in kernelspace */ + /* userspace buffers are copied anyway */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/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..25f494652 --- /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 c55d6bb49cfbd39a7c0848076c84166def65936e 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 434b753def3b..99bd30953531 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -1014,7 +1014,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 8a480d269542..69b798a2d31e 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -1320,6 +1320,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 */ +@@ -1347,8 +1348,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..035945cf3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch @@ -0,0 +1,140 @@ +From c4e7b89ee20dc28e10fae7eb0859e4fa9d3e8643 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:04:16 -0700 +Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC BT driver + +If LPC BT driver is registered ahead of lpc-ctrl module, LPC BT +block will be enabled without heart beating of LCLK until lpc-ctrl +enables the LCLK. This issue causes improper handling on host +interrupts when the host sends interrupt in that time frame. Then +kernel eventually forcibly disables the interrupt with dumping +stack and printing a 'nobody cared this irq' message out. + +To prevent this issue, all LPC sub-nodes should enable LCLK +individually so this patch adds clock control logic into the LPC +BT driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../bindings/ipmi/aspeed,ast2400-ibt-bmc.txt | 3 +++ + arch/arm/boot/dts/aspeed-g4.dtsi | 1 + + arch/arm/boot/dts/aspeed-g5.dtsi | 1 + + drivers/char/ipmi/bt-bmc.c | 24 +++++++++++++++++++++- + 4 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt +index 028268fd99ee..d13887d60f19 100644 +--- a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt ++++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt +@@ -10,6 +10,8 @@ Required properties: + "aspeed,ast2400-ibt-bmc" + "aspeed,ast2500-ibt-bmc" + - reg: physical address and size of the registers ++- clocks: contains a phandle to the syscon node describing the clocks. ++ There should then be one cell representing the clock to use. + + Optional properties: + +@@ -22,4 +24,5 @@ Example: + compatible = "aspeed,ast2400-ibt-bmc"; + reg = <0x1e789140 0x18>; + interrupts = <8>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + }; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index 618abeab539b..c2388bb7c678 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -337,6 +337,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 88ac8e08b6ae..88b318fd287b 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -470,6 +470,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/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c +index 40b9927c072c..a4ec9d1743d7 100644 +--- a/drivers/char/ipmi/bt-bmc.c ++++ b/drivers/char/ipmi/bt-bmc.c +@@ -5,6 +5,7 @@ + + #include <linux/atomic.h> + #include <linux/bt-bmc.h> ++#include <linux/clk.h> + #include <linux/errno.h> + #include <linux/interrupt.h> + #include <linux/io.h> +@@ -60,6 +61,7 @@ struct bt_bmc { + struct device dev; + struct miscdevice miscdev; + struct regmap *map; ++ struct clk *clk; + int offset; + int irq; + wait_queue_head_t queue; +@@ -467,6 +469,19 @@ static int bt_bmc_probe(struct platform_device *pdev) + mutex_init(&bt_bmc->mutex); + init_waitqueue_head(&bt_bmc->queue); + ++ bt_bmc->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(bt_bmc->clk)) { ++ rc = PTR_ERR(bt_bmc->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; ++ } ++ rc = clk_prepare_enable(bt_bmc->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ + bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR, + bt_bmc->miscdev.name = DEVICE_NAME, + bt_bmc->miscdev.fops = &bt_bmc_fops, +@@ -474,7 +489,7 @@ static int bt_bmc_probe(struct platform_device *pdev) + rc = misc_register(&bt_bmc->miscdev); + if (rc) { + dev_err(dev, "Unable to register misc device\n"); +- return rc; ++ goto err; + } + + bt_bmc_config_irq(bt_bmc, pdev); +@@ -498,6 +513,11 @@ static int bt_bmc_probe(struct platform_device *pdev) + clr_b_busy(bt_bmc); + + return 0; ++ ++err: ++ clk_disable_unprepare(bt_bmc->clk); ++ ++ return rc; + } + + static int bt_bmc_remove(struct platform_device *pdev) +@@ -507,6 +527,8 @@ static int bt_bmc_remove(struct platform_device *pdev) + misc_deregister(&bt_bmc->miscdev); + if (!bt_bmc->irq) + del_timer_sync(&bt_bmc->poll_timer); ++ clk_disable_unprepare(bt_bmc->clk); ++ + return 0; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch new file mode 100644 index 000000000..c335fb3ec --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch @@ -0,0 +1,125 @@ +From a5bbf0f5943d3a6be6e58a4b78d6d18694ceb859 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:27:48 -0700 +Subject: [PATCH] misc: Add clock control logic into Aspeed LPC SNOOP driver + +If LPC SNOOP driver is registered ahead of lpc-ctrl module, LPC +SNOOP block will be enabled without heart beating of LCLK until +lpc-ctrl enables the LCLK. This issue causes improper handling on +host interrupts when the host sends interrupt in that time frame. +Then kernel eventually forcibly disables the interrupt with +dumping stack and printing a 'nobody cared this irq' message out. + +To prevent this issue, all LPC sub-nodes should enable LCLK +individually so this patch adds clock control logic into the LPC +SNOOP driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/boot/dts/aspeed-g4.dtsi | 1 + + arch/arm/boot/dts/aspeed-g5.dtsi | 1 + + drivers/soc/aspeed/aspeed-lpc-snoop.c | 30 +++++++++++++++++++++++++++--- + 3 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index c2388bb7c678..70aca75d65e0 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -320,6 +320,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 88b318fd287b..f4a5d06f1000 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -453,6 +453,7 @@ + compatible = "aspeed,ast2500-lpc-snoop"; + reg = <0x0 0x80>; + interrupts = <8>; ++ 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 48f7ac238861..96ea52db25be 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..499662ac3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch @@ -0,0 +1,235 @@ +From 27675470115548612cee9153903aaffffb68177b Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:36:34 -0700 +Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC KCS + driver + +If LPC KCS driver is registered ahead of lpc-ctrl module, LPC KCS +block will be enabled without heart beating of LCLK until lpc-ctrl +enables the LCLK. This issue causes improper handling on host +interrupts when the host sends interrupt in that time frame. Then +kernel eventually forcibly disables the interrupt with dumping +stack and printing a 'nobody cared this irq' message out. + +To prevent this issue, all LPC sub-nodes should enable LCLK +individually so this patch adds clock control logic into the LPC +KCS driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt | 3 ++ + arch/arm/boot/dts/aspeed-g4.dtsi | 35 ++++++++++++++++++++ + arch/arm/boot/dts/aspeed-g5.dtsi | 6 +++- + drivers/char/ipmi/kcs_bmc_aspeed.c | 37 ++++++++++++++++++---- + 4 files changed, 73 insertions(+), 8 deletions(-) + +diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt +index d98a9bf45d6c..3453eb0bf8f2 100644 +--- a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt ++++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt +@@ -9,6 +9,8 @@ Required properties: + "aspeed,ast2400-kcs-bmc" + "aspeed,ast2500-kcs-bmc" + - interrupts : interrupt generated by the controller ++- clocks: contains a phandle to the syscon node describing the clocks. ++ There should then be one cell representing the clock to use. + - kcs_chan : The LPC channel number in the controller + - kcs_addr : The host CPU IO map address + +@@ -19,6 +21,7 @@ Example: + compatible = "aspeed,ast2500-kcs-bmc"; + reg = <0x0 0x80>; + interrupts = <8>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + kcs_chan = <3>; + kcs_addr = <0xCA2>; + status = "okay"; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index 1c00828da913..f04006f4cd27 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -298,6 +298,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 { +@@ -309,6 +336,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 f2292bdfef91..d46b9ffc79de 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -135,7 +135,7 @@ + }; + + vic: interrupt-controller@1e6c0080 { +- compatible = "aspeed,ast2400-vic"; ++ compatible = "aspeed,ast2500-vic"; + interrupt-controller; + #interrupt-cells = <1>; + valid-sources = <0xfefff7ff 0x0807ffff>; +@@ -410,18 +410,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"; + }; + }; +@@ -439,6 +442,7 @@ + compatible = "aspeed,ast2500-kcs-bmc"; + interrupts = <8>; + kcs_chan = <4>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + +diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c +index 3c955946e647..bd1912dc5a21 100644 +--- a/drivers/char/ipmi/kcs_bmc_aspeed.c ++++ b/drivers/char/ipmi/kcs_bmc_aspeed.c +@@ -1,11 +1,10 @@ + // SPDX-License-Identifier: GPL-2.0 +-/* +- * Copyright (c) 2015-2018, Intel Corporation. +- */ ++// Copyright (c) 2015-2019, Intel Corporation. + + #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt + + #include <linux/atomic.h> ++#include <linux/clk.h> + #include <linux/errno.h> + #include <linux/interrupt.h> + #include <linux/io.h> +@@ -63,6 +62,7 @@ + + struct aspeed_kcs_bmc { + struct regmap *map; ++ struct clk *clk; + }; + + +@@ -264,36 +264,59 @@ static int aspeed_kcs_probe(struct platform_device *pdev) + return -ENODEV; + } + ++ priv->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ rc = PTR_ERR(priv->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; ++ } ++ rc = clk_prepare_enable(priv->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ + kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1]; + kcs_bmc->io_inputb = aspeed_kcs_inb; + kcs_bmc->io_outputb = aspeed_kcs_outb; + + dev_set_drvdata(dev, kcs_bmc); + +- aspeed_kcs_set_address(kcs_bmc, addr); +- aspeed_kcs_enable_channel(kcs_bmc, true); + rc = aspeed_kcs_config_irq(kcs_bmc, pdev); + if (rc) +- return rc; ++ goto err; + + rc = misc_register(&kcs_bmc->miscdev); + if (rc) { + dev_err(dev, "Unable to register device\n"); +- return rc; ++ goto err; + } + ++ aspeed_kcs_set_address(kcs_bmc, addr); ++ aspeed_kcs_enable_channel(kcs_bmc, true); ++ + pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n", + chan, addr, + kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str); + + return 0; ++ ++err: ++ aspeed_kcs_enable_channel(kcs_bmc, false); ++ clk_disable_unprepare(priv->clk); ++ ++ return rc; + } + + static int aspeed_kcs_remove(struct platform_device *pdev) + { + struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev); ++ struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc); + + misc_deregister(&kcs_bmc->miscdev); ++ aspeed_kcs_enable_channel(kcs_bmc, false); ++ clk_disable_unprepare(priv->clk); + + return 0; + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/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..c3d1f4e8d --- /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 108b39883e73f822b8f03e0d3fe3818b85b29b41 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 01ed21e8bfee..ae08419834a3 100644 +--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c ++++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c +@@ -252,8 +252,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) { +@@ -275,6 +277,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..d0f98b9c1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch @@ -0,0 +1,43 @@ +From 7dd0a7c62e5885bb726ef2bd5007e79a50932c38 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 | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c +index f3816a5c861e..3a94584a9dbc 100644 +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -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..d9379f565 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch @@ -0,0 +1,35 @@ +From 278740d23c1eac792c64608af4bfa3fae640965f 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 AST2500d JTAG driver + +Adding aspeed jtag device + +Signed-off-by: Hunt, Bryan <bryan.hunt@intel.com> +--- + arch/arm/boot/dts/aspeed-g5.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index ed0b7217f55f..89a9febf6f14 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -389,6 +389,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>; +-- +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..3047746ca --- /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 520416545a47cffe66815f31bc1465eab8864554 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 339ac306ded6..fb970bbe6b03 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -234,4 +234,5 @@ source "drivers/counter/Kconfig" + + source "drivers/peci/Kconfig" + ++source "drivers/jtag/Kconfig" + endmenu +diff --git a/drivers/Makefile b/drivers/Makefile +index 18d91cd5ac0f..b4d21c963923 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -189,3 +189,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..94722d6c4 --- /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,1294 @@ +From 817a43d1b1e197e7eff43492599469bbc23bf0fd Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Mon, 3 Jun 2019 08:22:09 -0800 +Subject: [PATCH v29 2/6] Add Aspeed SoC 24xx and 25xx families JTAG master + driver + +Driver adds support of Aspeed 2500/2400 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. + +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> +--- +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 | 1050 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1065 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..1d41a66 +--- /dev/null ++++ b/drivers/jtag/jtag-aspeed.c +@@ -0,0 +1,1050 @@ ++// 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 */ ++#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_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_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 ++ ++/*#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", ++}; ++ ++#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; ++}; ++ ++/* ++ * 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(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(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_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_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_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 int aspeed_jtag_probe(struct platform_device *pdev) ++{ ++ struct aspeed_jtag *aspeed_jtag; ++ struct jtag *jtag; ++ int err; ++ ++ jtag = jtag_alloc(&pdev->dev, sizeof(*aspeed_jtag), &aspeed_jtag_ops); ++ if (!jtag) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, jtag); ++ aspeed_jtag = jtag_priv(jtag); ++ aspeed_jtag->dev = &pdev->dev; ++ ++ /* 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 const struct of_device_id aspeed_jtag_of_match[] = { ++ { .compatible = "aspeed,ast2400-jtag", }, ++ { .compatible = "aspeed,ast2500-jtag", }, ++ {} ++}; ++ ++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..f17bdcd68 --- /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,108 @@ +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 v29 3/6] Documentation: jtag: Add bindings for Aspeed SoC + 24xx and 25xx families JTAG master driver + +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..a7dccc4b6 --- /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 ba0c35ae070cffcb384fc76e23a38e00142b128d Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Wed, 10 Mar 2019 11:48:18 -0800 +Subject: [PATCH v29 5/6] 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.txt | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt +index c955814..f732118 100644 +--- a/Documentation/ioctl/ioctl-number.txt ++++ b/Documentation/ioctl/ioctl-number.txt +@@ -323,6 +323,8 @@ Code Seq#(hex) Include File Comments + 0xB0 all RATIO devices in development: + <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..47a532590 --- /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 8598b57423967f5851484533a1b09a04bafa235b 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 v29 6/6] 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 e0925f221e25..2cd0a46f9a1a 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -8521,6 +8521,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/0058-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch new file mode 100644 index 000000000..7d5e006d1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch @@ -0,0 +1,180 @@ +From f5b6d42c1710a4c1314bc0160f904aa01f501e96 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 7da7e813b2b0..724ee9f35c10 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -16,6 +16,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 99bd30953531..8f26060bd685 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -47,6 +47,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) + +@@ -71,6 +72,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) +@@ -130,6 +132,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, + }; + +@@ -160,6 +164,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 */ + }; + +@@ -266,6 +272,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; +@@ -284,6 +296,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; + } +@@ -326,11 +353,16 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + case ASPEED_I2C_SLAVE_WRITE_RECEIVED: + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &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: +@@ -738,6 +770,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); + } + +@@ -776,6 +810,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; +@@ -920,6 +956,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 3ee92c6a442d..dfdccb2acb24 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -359,6 +359,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/0065-i2c-aspeed-fix-master-pending-state-handling.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch new file mode 100644 index 000000000..003a96c8d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch @@ -0,0 +1,55 @@ +From 4a05d2506e7cb7fb3ad323a16861f09279b4da39 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 11 Jun 2019 14:59:53 -0700 +Subject: [PATCH] i2c: aspeed: fix master pending state handling + +In case of a master pending state, it should not trigger the master +command because this H/W is sharing the same byte buffer for slave +and master operation, so this commit fixes the issue with making +the master command triggering happens when the state goes to active +state. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 8f26060bd685..d8143c24d3a7 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -383,18 +383,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; + u8 slave_addr = i2c_8bit_addr_from_msg(msg); + +- bus->master_state = ASPEED_I2C_MASTER_START; +- + #if IS_ENABLED(CONFIG_I2C_SLAVE) + /* + * If it's requested in the middle of a slave session, set the master + * state to 'pending' then H/W will continue handling this master + * command when the bus comes back to the idle state. + */ +- if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) ++ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) { + bus->master_state = ASPEED_I2C_MASTER_PENDING; ++ return; ++ } + #endif /* CONFIG_I2C_SLAVE */ + ++ bus->master_state = ASPEED_I2C_MASTER_START; + bus->buf_index = 0; + + if (msg->flags & I2C_M_RD) { +@@ -479,7 +480,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) + goto out_no_complete; + +- bus->master_state = ASPEED_I2C_MASTER_START; ++ aspeed_i2c_do_start(bus); + } + #endif /* CONFIG_I2C_SLAVE */ + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch new file mode 100644 index 000000000..9b96b400b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch @@ -0,0 +1,886 @@ +From 36128aacdc8b642b9ee080e493abbc00de345f1d 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 ++-- + drivers/i2c/busses/i2c-aspeed.c | 294 ++++++++++++++++++--- + 4 files changed, 349 insertions(+), 79 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index 724ee9f35c10..e1a0ae7a8c08 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 +@@ -29,12 +32,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 { +@@ -42,11 +54,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 47a5029f5bdb..052b1b6b4dc7 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -469,12 +469,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 { +@@ -482,7 +491,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>; +@@ -498,7 +507,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>; +@@ -514,7 +523,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>; +@@ -531,7 +540,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>; +@@ -548,7 +557,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>; +@@ -565,7 +574,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>; +@@ -582,7 +591,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>; +@@ -599,7 +608,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>; +@@ -616,7 +625,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>; +@@ -633,7 +642,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>; +@@ -650,7 +659,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>; +@@ -667,7 +676,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>; +@@ -684,7 +693,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>; +@@ -701,7 +710,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 89a9febf6f14..2d2173d598e4 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -586,12 +586,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 { +@@ -599,7 +608,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>; +@@ -615,7 +624,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>; +@@ -631,7 +640,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>; +@@ -648,7 +657,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>; +@@ -665,7 +674,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>; +@@ -682,7 +691,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>; +@@ -699,7 +708,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>; +@@ -716,7 +725,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>; +@@ -733,7 +742,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>; +@@ -750,7 +759,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>; +@@ -767,7 +776,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>; +@@ -784,7 +793,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>; +@@ -801,7 +810,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>; +@@ -818,7 +827,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/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index d8143c24d3a7..b721fb1d6d4c 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) +@@ -104,6 +112,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) +@@ -114,6 +124,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, +@@ -161,6 +178,11 @@ struct aspeed_i2c_bus { + int master_xfer_result; + /* Multi-master */ + bool multi_master; ++ /* Buffer mode */ ++ void __iomem *buf_base; ++ size_t buf_size; ++ u8 buf_offset; ++ u8 buf_page; + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; +@@ -259,6 +281,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + { + u32 command, irq_handled = 0; + struct i2c_client *slave = bus->slave; ++ int i, len; + u8 value; + + if (!slave) +@@ -287,7 +310,12 @@ 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; ++ 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; + /* Handle address frame. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_START) { + if (value & 0x1) +@@ -317,6 +345,20 @@ 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) { ++ 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(slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ &value); ++ } ++ } ++ } + irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; + bus->slave_state = ASPEED_I2C_SLAVE_STOP; + } +@@ -349,9 +391,36 @@ 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); ++ 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); ++ } + break; + case ASPEED_I2C_SLAVE_WRITE_RECEIVED: + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); ++ 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(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); ++ } + break; + case ASPEED_I2C_SLAVE_GCALL_REQUESTED: + bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; +@@ -382,6 +451,8 @@ 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); ++ u8 wbuf[4]; ++ int len; + + #if IS_ENABLED(CONFIG_I2C_SLAVE) + /* +@@ -400,12 +471,66 @@ 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 (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ if (msg->len > bus->buf_size) { ++ len = bus->buf_size; ++ } else { ++ len = msg->len; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ 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); ++ } else { ++ /* 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; ++ } ++ } else { ++ if (bus->buf_base) { ++ int i; ++ ++ command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ ++ if (msg->len + 1 > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len + 1; ++ ++ /* ++ * Yeah, it looks clumsy but byte writings on a remapped ++ * I2C SRAM cause corruptions 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)); ++ ++ bus->buf_index = len - 1; ++ ++ 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(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); ++ if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) ++ writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } + +@@ -445,7 +570,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + u32 irq_handled = 0, command = 0; + struct i2c_msg *msg; + u8 recv_byte; +- int ret; ++ int ret, len; + + if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) { + bus->master_state = ASPEED_I2C_MASTER_INACTIVE; +@@ -558,11 +683,43 @@ 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; ++ ++ if (bus->buf_base) { ++ 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 - (i % 4)); ++ ++ bus->buf_index += len; ++ ++ 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); ++ } else { ++ writel(msg->buf[bus->buf_index++], ++ bus->base + ASPEED_I2C_BYTE_BUF_REG); ++ } ++ 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); + } +@@ -579,25 +736,56 @@ 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) { +- if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { +- bus->cmd_err = -EPROTO; +- aspeed_i2c_do_stop(bus); +- goto out_no_complete; ++ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ 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; ++ ++ if (msg->flags & I2C_M_RECV_LEN) { ++ 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->flags &= ~I2C_M_RECV_LEN; + } +- msg->len = recv_byte + +- ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); +- msg->flags &= ~I2C_M_RECV_LEN; + } + + 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; ++ bus->master_state = ASPEED_I2C_MASTER_RX; ++ if (bus->buf_base) { ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ 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; ++ } ++ ++ 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; ++ } + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } else { + aspeed_i2c_next_msg_or_stop(bus); +@@ -947,6 +1135,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 +@@ -1007,16 +1198,15 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + { + const struct of_device_id *match; + struct aspeed_i2c_bus *bus; ++ bool sram_enabled = true; + 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); + +@@ -1050,6 +1240,42 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + bus->get_clk_reg_val = (u32 (*)(struct device *, u32)) + match->data; + ++ /* Enable I2C SRAM in case of AST2500 */ ++ 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); ++ ++ bus->buf_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(bus->buf_base) || resource_size(res) < 2) { ++ bus->buf_base = NULL; ++ } else { ++ 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; ++ } ++ } ++ } ++ + /* Initialize the I2C adapter */ + spin_lock_init(&bus->lock); + init_completion(&bus->cmd_complete); +@@ -1085,8 +1311,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/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch new file mode 100644 index 000000000..a051dbc4d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch @@ -0,0 +1,442 @@ +From 7defe387ea07af3d48feb4daec78d54a284105f1 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 | 231 +++++++++++++++++++-- + 2 files changed, 241 insertions(+), 15 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index e1a0ae7a8c08..97142516399a 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -19,6 +19,16 @@ 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. ++- 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. + - general-call : enables general call receiving. + - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not + specified. +@@ -75,4 +85,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 b721fb1d6d4c..127bc69952ca 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 */ +@@ -112,6 +116,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) +@@ -131,6 +137,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, +@@ -183,6 +197,12 @@ struct aspeed_i2c_bus { + size_t buf_size; + u8 buf_offset; + u8 buf_page; ++ /* DMA mode */ ++ struct dma_pool *dma_pool; ++ dma_addr_t dma_handle; ++ u8 *dma_buf; ++ size_t dma_buf_size; ++ size_t dma_len; + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; +@@ -310,9 +330,13 @@ 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) { +- 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); + else + value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; +@@ -347,7 +371,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { + 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->dma_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(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)); +@@ -391,7 +426,15 @@ 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); +- 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->dma_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, +@@ -403,7 +446,25 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + break; + case ASPEED_I2C_SLAVE_WRITE_RECEIVED: + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ len = bus->dma_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(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->dma_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)); +@@ -472,7 +533,23 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + if (msg->flags & I2C_M_RD) { + command |= ASPEED_I2CD_M_RX_CMD; + +- if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ if (bus->dma_buf && !(msg->flags & I2C_M_RECV_LEN)) { ++ command |= ASPEED_I2CD_RX_DMA_ENABLE; ++ ++ if (msg->len > bus->dma_buf_size) { ++ len = bus->dma_buf_size; ++ } else { ++ len = msg->len; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ 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 if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { + command |= ASPEED_I2CD_RX_BUFF_ENABLE; + + if (msg->len > bus->buf_size) { +@@ -493,7 +570,26 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + command |= ASPEED_I2CD_M_S_RX_CMD_LAST; + } + } else { +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_TX_DMA_ENABLE; ++ ++ if (msg->len + 1 > bus->dma_buf_size) ++ len = bus->dma_buf_size; ++ else ++ len = msg->len + 1; ++ ++ bus->dma_buf[0] = slave_addr; ++ memcpy(bus->dma_buf + 1, msg->buf, len); ++ ++ bus->buf_index = len - 1; ++ ++ 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 if (bus->buf_base) { + int i; + + command |= ASPEED_I2CD_TX_BUFF_ENABLE; +@@ -529,7 +625,8 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + } + } + +- if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) ++ if (!(command & (ASPEED_I2CD_TX_BUFF_ENABLE | ++ ASPEED_I2CD_TX_DMA_ENABLE))) + writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } +@@ -685,7 +782,28 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (bus->buf_index < msg->len) { + command = ASPEED_I2CD_M_TX_CMD; + +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_TX_DMA_ENABLE; ++ ++ if (msg->len - bus->buf_index > ++ bus->dma_buf_size) ++ len = bus->dma_buf_size; ++ else ++ len = msg->len - bus->buf_index; ++ ++ memcpy(bus->dma_buf, msg->buf + bus->buf_index, ++ len); ++ ++ bus->buf_index += 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 if (bus->buf_base) { + u8 wbuf[4]; + int i; + +@@ -736,7 +854,15 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + +- if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ if (bus->dma_buf && !(msg->flags & I2C_M_RECV_LEN)) { ++ 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 && !(msg->flags & I2C_M_RECV_LEN)) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + + ASPEED_I2C_BUF_CTRL_REG)); +@@ -764,7 +890,25 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (bus->buf_index < msg->len) { + command = ASPEED_I2CD_M_RX_CMD; + bus->master_state = ASPEED_I2C_MASTER_RX; +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_RX_DMA_ENABLE; ++ ++ if (msg->len - bus->buf_index > ++ bus->dma_buf_size) { ++ len = bus->dma_buf_size; ++ } else { ++ len = msg->len - bus->buf_index; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ 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 if (bus->buf_base) { + command |= ASPEED_I2CD_RX_BUFF_ENABLE; + + if (msg->len - bus->buf_index > +@@ -1257,7 +1401,51 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + sram_enabled = false; + } + +- if (sram_enabled) { ++ /* ++ * 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 (sram_enabled && !IS_ENABLED(CONFIG_USB_UHCI_ASPEED) && ++ of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2500-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->dma_buf_size); ++ if (!ret && bus->dma_buf_size > dma_len_max) ++ bus->dma_buf_size = dma_len_max; ++ } ++ ++ if (bus->dma_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->dma_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); + +@@ -1297,24 +1485,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) +@@ -1332,6 +1529,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/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..f4dfd6cfa --- /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,181 @@ +From 9a43b47fb794fd195912c6956783b021a46307f8 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 | 79 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 73 insertions(+), 6 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 0ed9a27850e6..ecb5793036cc 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -71,10 +71,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 +86,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 +103,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 | \ +@@ -180,6 +188,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; +@@ -297,6 +306,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 u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + { + u32 command, irq_handled = 0; +@@ -307,6 +324,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. */ +@@ -649,7 +674,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; +@@ -680,9 +705,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) { +@@ -1251,6 +1276,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); +@@ -1259,8 +1285,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; + } +@@ -1464,6 +1528,9 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + } + } + ++ device_property_read_u32(&pdev->dev, "aspeed,hw-timeout-ms", ++ &bus->hw_timeout_ms); ++ + /* Initialize the I2C adapter */ + spin_lock_init(&bus->lock); + init_completion(&bus->cmd_complete); +-- +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..dc38c81f3 --- /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 085bde1e91d85435c44a752bd59d38cf31465518 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 d41f377de9dc..46de9a01a0eb 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -86,6 +86,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) +@@ -353,6 +354,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) { + if (bus->dma_buf && +-- +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..4af5be95d --- /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 9195eef3fec7022ca52ac9791c19de2362ed042e 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 e426452a28f7..d4aaf7fa8e4b 100644 +--- a/drivers/gpio/gpio-aspeed.c ++++ b/drivers/gpio/gpio-aspeed.c +@@ -1189,7 +1189,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; + gpio->chip.irq.need_valid_mask = true; + + /* Allocate a cache of the output registers */ +diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c +index 6fb402a3f74d..2f4c0aab0bf2 100644 +--- a/drivers/gpio/sgpio-aspeed.c ++++ b/drivers/gpio/sgpio-aspeed.c +@@ -675,7 +675,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; + gpio->chip.irq.need_valid_mask = true; + + /* Allocate a cache of the output registers */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch new file mode 100644 index 000000000..e32ec54ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch @@ -0,0 +1,101 @@ +From 3394fabbd17ad7263feeb0f4ae593056237f0647 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 30 Jul 2019 13:01:58 -0700 +Subject: [PATCH] peci: add a temporary workaround + +To cover a PECI issue, this commit makes PECI driver block all PECI +commands when PLTRST_N signal is 0. + +Also, it adds 'use_wa' module parameter for platforms that don't have +the PLTRST_N gpio input so that the WA can be disabled through the +module parameter. + +This is a temporary workaround. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/peci/busses/peci-aspeed.c | 11 +++++++++++ + drivers/peci/peci-core.c | 11 +++++++++++ + include/linux/peci.h | 1 + + 3 files changed, 23 insertions(+) + +diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c +index 8a0dd40730cc..76394ab32854 100644 +--- a/drivers/peci/busses/peci-aspeed.c ++++ b/drivers/peci/busses/peci-aspeed.c +@@ -10,6 +10,7 @@ + #include <linux/jiffies.h> + #include <linux/module.h> + #include <linux/of.h> ++#include <linux/of_gpio.h> + #include <linux/peci.h> + #include <linux/platform_device.h> + #include <linux/reset.h> +@@ -445,6 +446,16 @@ static int aspeed_peci_probe(struct platform_device *pdev) + if (ret) + goto err_put_adapter_dev; + ++ priv->adapter->pltrst_pin = of_get_gpio(pdev->dev.of_node, 0); ++ if (gpio_is_valid(priv->adapter->pltrst_pin)) { ++ ret = devm_gpio_request(&pdev->dev, priv->adapter->pltrst_pin, ++ "peci-aspeed"); ++ if (ret < 0) { ++ priv->adapter->pltrst_pin = -1; ++ dev_err(&pdev->dev, "error requesting pltrst gpio\n"); ++ } ++ } ++ + ret = peci_add_adapter(priv->adapter); + if (ret) + goto err_put_adapter_dev; +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index b99ba788a032..2e3b9a0c83e9 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -5,6 +5,7 @@ + #include <linux/crc8.h> + #include <linux/delay.h> + #include <linux/mm.h> ++#include <linux/gpio.h> + #include <linux/module.h> + #include <linux/of_device.h> + #include <linux/peci.h> +@@ -190,6 +191,11 @@ static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs) + return 0; + } + ++/* Temporary WA */ ++static bool use_wa __read_mostly = true; ++module_param_named(use_wa, use_wa, bool, 0644); ++MODULE_PARM_DESC(use_wa, "flag for enabling of WA"); ++ + static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + bool do_retry, bool has_aw_fcs) + { +@@ -197,6 +203,11 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + u8 aw_fcs; + int ret; + ++ /* Temporary WA */ ++ if (use_wa && gpio_is_valid(adapter->pltrst_pin) && ++ gpio_get_value(adapter->pltrst_pin) == 0) ++ return -EAGAIN; ++ + /* + * In case if adapter uses DMA, check at here whether tx and rx buffers + * are DMA capable or not. +diff --git a/include/linux/peci.h b/include/linux/peci.h +index 6fc424dc2a73..e589cb258a2a 100644 +--- a/include/linux/peci.h ++++ b/include/linux/peci.h +@@ -44,6 +44,7 @@ struct peci_adapter { + struct peci_xfer_msg *msg); + u32 cmd_mask; + bool use_dma; ++ int pltrst_pin; + }; + + static inline struct peci_adapter *to_peci_adapter(void *d) +-- +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/intel.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg new file mode 100644 index 000000000..41530dd6e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg @@ -0,0 +1 @@ +CONFIG_BLK_DEV_RAM=y diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend new file mode 100644 index 000000000..8ff89685b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -0,0 +1,51 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +do_compile_prepend(){ + # device tree compiler flags + export DTC_FLAGS=-@ +} + +SRC_URI += " \ + file://intel.cfg \ + file://0005-arm-dts-aspeed-g5-add-espi.patch \ + file://0007-New-flash-map-for-intel.patch \ + file://0008-Add-ASPEED-SGPIO-driver.patch \ + file://0009-SGPIO-DT-and-pinctrl-fixup.patch \ + file://0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch \ + file://0019-Add-I2C-IPMB-support.patch \ + file://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://0026-Add-support-for-new-PECI-commands.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://0058-i2c-aspeed-add-general-call-support.patch \ + file://0065-i2c-aspeed-fix-master-pending-state-handling.patch \ + file://0066-i2c-aspeed-add-buffer-mode-transfer-support.patch \ + file://0067-i2c-aspeed-add-DMA-mode-transfer-support.patch \ + file://0001-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://0071-peci-add-a-temporary-workaround.patch \ + file://0072-pmbus-add-fault-and-beep-attributes.patch \ + " 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..79e8d96cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch @@ -0,0 +1,404 @@ +From f28e3694f4b15c6eee58733f57213d360fc5ac7a Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 5 Sep 2018 14:16:54 +0530 +Subject: [PATCH 2/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 | 116 +++++++++++++++++++++++++++++++++++++++++ + ethernet_interface.hpp | 39 +++++++++++++- + network_manager.cpp | 104 ++++++++++++++++++++++++++++++++++++ + network_manager.hpp | 9 ++++ + 4 files changed, 267 insertions(+), 1 deletion(-) + +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index aa1c895..e3ea33c 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -35,6 +35,9 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + using Argument = xyz::openbmc_project::Common::InvalidArgument; + ++static constexpr const char* networkChannelCfgFile = ++ "/var/channel_intf_data.json"; ++static constexpr const char* defaultChannelPriv = "priv-admin"; + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + const std::string& objPath, + bool dhcpEnabled, Manager& parent, +@@ -51,6 +54,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + MacAddressIntf::mACAddress(getMACAddress(intfName)); + EthernetInterfaceIntf::nTPServers(getNTPServersFromConf()); + EthernetInterfaceIntf::nameservers(getNameServerFromConf()); ++ getChannelPrivilege(intfName); + + // Emit deferred signal. + if (emitSignal) +@@ -837,5 +841,117 @@ void EthernetInterface::deleteAll() + manager.writeToConfigurationFile(); + } + ++nlohmann::json EthernetInterface::readJsonFile(const std::string& configFile) ++{ ++ std::ifstream jsonFile(configFile); ++ if (!jsonFile.good()) ++ { ++ log<level::ERR>("JSON file not found"); ++ return nullptr; ++ } ++ ++ nlohmann::json data = nullptr; ++ try ++ { ++ data = nlohmann::json::parse(jsonFile, nullptr, false); ++ } ++ catch (nlohmann::json::parse_error& e) ++ { ++ log<level::DEBUG>("Corrupted channel config.", ++ entry("MSG: %s", e.what())); ++ throw std::runtime_error("Corrupted channel config file"); ++ } ++ ++ return data; ++} ++ ++int EthernetInterface::writeJsonFile(const std::string& configFile, ++ const nlohmann::json& jsonData) ++{ ++ std::ofstream jsonFile(configFile); ++ if (!jsonFile.good()) ++ { ++ log<level::ERR>("JSON file open failed", ++ entry("FILE=%s", networkChannelCfgFile)); ++ return -1; ++ } ++ ++ // Write JSON to file ++ jsonFile << jsonData; ++ ++ jsonFile.flush(); ++ return 0; ++} ++ ++std::string ++ EthernetInterface::getChannelPrivilege(const std::string& interfaceName) ++{ ++ std::string priv(defaultChannelPriv); ++ std::string retPriv; ++ ++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile); ++ if (jsonData != nullptr) ++ { ++ try ++ { ++ priv = jsonData[interfaceName].get<std::string>(); ++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv)); ++ return retPriv; ++ } ++ catch (const nlohmann::json::exception& e) ++ { ++ jsonData[interfaceName] = priv; ++ } ++ } ++ else ++ { ++ jsonData[interfaceName] = priv; ++ } ++ ++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0) ++ { ++ log<level::DEBUG>("Error in write JSON data to file", ++ entry("FILE=%s", networkChannelCfgFile)); ++ elog<InternalFailure>(); ++ } ++ ++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv)); ++ ++ return retPriv; ++} ++ ++std::string EthernetInterface::maxPrivilege(std::string priv) ++{ ++ std::string intfName = interfaceName(); ++ ++ if (!priv.empty() && (std::find(manager.supportedPrivList.begin(), ++ manager.supportedPrivList.end(), ++ priv) == manager.supportedPrivList.end())) ++ { ++ log<level::ERR>("Invalid privilege"); ++ elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"), ++ Argument::ARGUMENT_VALUE(priv.c_str())); ++ } ++ ++ if (ChannelAccessIntf::maxPrivilege() == priv) ++ { ++ // No change in privilege so just return. ++ return priv; ++ } ++ ++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile); ++ jsonData[intfName] = priv; ++ ++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0) ++ { ++ log<level::DEBUG>("Error in write JSON data to file", ++ entry("FILE=%s", networkChannelCfgFile)); ++ elog<InternalFailure>(); ++ } ++ ++ // Property change signal will be sent ++ return ChannelAccessIntf::maxPrivilege(std::move(priv)); ++} ++ + } // namespace network + } // namespace phosphor +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index 55fd7d9..7bf93a6 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -2,10 +2,13 @@ + + #include "types.hpp" + #include "util.hpp" ++#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp" + #include "xyz/openbmc_project/Network/IP/Create/server.hpp" + + #include <experimental/filesystem> ++#include <nlohmann/json.hpp> + #include <sdbusplus/bus.hpp> ++#include <sdbusplus/bus/match.hpp> + #include <sdbusplus/server/object.hpp> + #include <string> + #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp> +@@ -21,7 +24,8 @@ using Ifaces = sdbusplus::server::object::object< + sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface, + sdbusplus::xyz::openbmc_project::Network::server::MACAddress, + sdbusplus::xyz::openbmc_project::Network::IP::server::Create, +- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>; ++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll, ++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess>; + + using IP = sdbusplus::xyz::openbmc_project::Network::server::IP; + +@@ -29,10 +33,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. +@@ -153,6 +162,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 MacAddressIntf::mACAddress; +@@ -256,6 +273,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 fa5da0f..a5020f0 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..e16b205 100644 +--- a/network_manager.hpp ++++ b/network_manager.hpp +@@ -137,6 +137,9 @@ class Manager : public details::VLANCreateIface + return (interfaces.find(intf) != interfaces.end()); + } + ++ /** supported privilege list **/ ++ std::vector<std::string> supportedPrivList; ++ + protected: + /** @brief Persistent sdbusplus DBus bus connection. */ + sdbusplus::bus::bus& bus; +@@ -159,6 +162,12 @@ class Manager : public details::VLANCreateIface + + /** @brief Network Configuration directory. */ + fs::path confDir; ++ ++ /** Get the user management service name dynamically **/ ++ std::string getUserServiceName(); ++ ++ /** @brief initializes the supportedPrivilege List */ ++ void initSupportedPrivilges(); + }; + + } // namespace network +-- +2.17.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..ee0d78d57 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += "nlohmann-json" + +SRC_URI += "file://0003-Adding-channel-specific-privilege-to-network.patch \ + " +SRCREV = "f273d2b5629d2a7d96802dc7a7ddb92e303ac8de" + 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..67b8afd5e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check @@ -0,0 +1,78 @@ +#!/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 +} + +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..347ba7cdd --- /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://${PHOSPHORBASE}/LICENSE;md5=19407077e42b1ba3d653da313f1f5b4e" + +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..080ae9f58 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend @@ -0,0 +1,8 @@ +# this is here just to bump faster than upstream +SRC_URI = "git://github.com/openbmc/entity-manager.git" +SRCREV = "fff050a355041d2848b8a126a19a6cb81daebe6b" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +EXTRA_OECMAKE = "-DYOCTO=1 -DUSE_OVERLAYS=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..7568f8ce9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch @@ -0,0 +1,120 @@ +From a30a09f58b9ebfb267c0b9cce9ae25994ea025ca Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Tue, 17 Jul 2018 16:04:58 +0800 +Subject: [PATCH] Add DBUS interface of CPU and Memory's properties Feature + Support: SMBIOS service interface. CPU DIMM information redfish + interface. Base on smbios spec DSP0134_3.0.0 + +Signed-off-by: cyang29 <cheng.c.yang@intel.com> +--- + .../Inventory/Item/Cpu.interface.yaml | 41 +++++++++++++++++++ + .../Inventory/Item/Dimm.interface.yaml | 46 +++++++++++++++++++++- + 2 files changed, 86 insertions(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +index ab29cf3..313eada 100644 +--- a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +@@ -1,4 +1,45 @@ + description: > + Implement to provide CPU attributes. ++properties: ++ - name: ProcessorSocket ++ type: string ++ description: > ++ Processor Socket on MotherBoard ++ - name: ProcessorType ++ type: string ++ description: > ++ Processor Type of CPU ++ - name: ProcessorFamily ++ type: string ++ description: > ++ Processor Family of CPU ++ - name: ProcessorManufacturer ++ type: string ++ description: > ++ Processor Manufacturer of CPU ++ - name: ProcessorId ++ type: uint32 ++ description: > ++ Processor ID of CPU ++ - name: ProcessorVersion ++ type: string ++ description: > ++ Processor Version of CPU ++ - name: ProcessorMaxSpeed ++ type: uint16 ++ description: > ++ Max Speed CPU Can Support ++ - name: ProcessorCharacteristics ++ type: string ++ description: > ++ The Characteristics CPU Has ++ - name: ProcessorCoreCount ++ type: uint16 ++ description: > ++ The Count of Core in CPU ++ - name: ProcessorThreadCount ++ type: uint16 ++ description: > ++ The Count of Thread CPU Can Support + + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +diff --git a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml +index d85326d..b750320 100644 +--- a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml +@@ -1,4 +1,48 @@ + description: > + Implement to provide DIMM attributes. +- ++properties: ++ - name: MemoryDataWidth ++ type: uint16 ++ description: > ++ Data width of Memory. ++ - name: MemorySizeInKB ++ type: uint32 ++ description: > ++ Memory size of DIMM in Kilobyte. ++ - name: MemoryDeviceLocator ++ type: string ++ description: > ++ Socket on base board where Memory located. ++ - name: MemoryType ++ type: string ++ description: > ++ Type of memory. ++ - name: MemoryTypeDetail ++ type: string ++ description: > ++ Additional detail on Memory. ++ - name: MemorySpeed ++ type: uint16 ++ description: > ++ The maximun capable speed of Memory. ++ - name: MemoryManufacturer ++ type: string ++ description: > ++ Manufacturer of memory. ++ - name: MemorySerialNum ++ type: string ++ description: > ++ Memory Serial Number. ++ - name: MemoryPartNum ++ type: string ++ description: > ++ Memory Part Number. ++ - name: MemoryAttributes ++ type: byte ++ description: > ++ Rank attributes of Memory. ++ - name: MemoryConfClockSpeed ++ type: uint16 ++ description: > ++ Configured clock speed to Memory. + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/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/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch new file mode 100644 index 000000000..576bae81a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch @@ -0,0 +1,227 @@ +From 9490574667485cd407193ff9f0d6a96f8c2c87d3 Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Wed, 12 Sep 2018 00:27:23 +0800 +Subject: [PATCH] Add DBUS interface of SMBIOS MDR V2 + +Support: + SMBIOS MDR V2 service interface. + SMBIOS MDR V2 IPMI Command + SMBIOS MDR V2 Redfish interface. +Base on SMBIOS spec DSP0134_3.0.0 and Managed Data Region +Specification Revision 4 +--- + xyz/openbmc_project/Smbios/MDR_V2.errors.yaml | 9 + + xyz/openbmc_project/Smbios/MDR_V2.interface.yaml | 158 +++++++++++++++++++++++ + xyz/openbmc_project/Smbios/README.md | 21 +++ + 3 files changed, 188 insertions(+) + create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.errors.yaml + create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.interface.yaml + create mode 100644 xyz/openbmc_project/Smbios/README.md + +diff --git a/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml +new file mode 100644 +index 0000000..88bd6db +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml +@@ -0,0 +1,9 @@ ++- name: InvalidParameter ++ description: > ++ An invalid parameter is attempted. ++- name: UpdateInProgress ++ description: > ++ Update is in progress. ++- name: InvalidId ++ description: > ++ An invalid Id is attempted. +diff --git a/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml +new file mode 100644 +index 0000000..f97700a +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml +@@ -0,0 +1,158 @@ ++description: > ++ SMBIOS MDR V2 service ++methods: ++ - name: GetDirectoryInformation ++ description: > ++ Get the directory with directory index. ++ parameters: ++ - name: dirIndex ++ type: byte ++ description: > ++ Directory index of SMBIOS. ++ returns: ++ - name: dir ++ type: array[byte] ++ description: > ++ Directory of agent. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: GetDataInformation ++ description: > ++ Get the data info with id index and data set ID. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ returns: ++ - name: dataInfo ++ type: array[byte] ++ description: > ++ Data information of SMBIOS. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: SendDirectoryInformation ++ description: > ++ Send directory information to SMBIOS directory. ++ parameters: ++ - name: dirVersion ++ type: byte ++ description: > ++ A counter which increments each time directory updated. ++ - name: dirIndex ++ type: byte ++ description: > ++ Directory index of SMBIOS. ++ - name: returnedEntries ++ type: byte ++ description: > ++ Indicates number of directory entries. ++ - name: remainingEntries ++ type: byte ++ description: > ++ Remaining entries which are higher than index in this transfer. ++ - name: dirEntry ++ type: array[byte] ++ description: > ++ Data set ID of SMBIOS table. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Need to continue directory transmisson or not. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: GetDataOffer ++ description: > ++ Get data set ID. ++ returns: ++ - name: offer ++ type: array[byte] ++ description: > ++ Data set ID. ++ errors: ++ - self.Error.UpdateInProgress ++ ++ - name: SendDataInformation ++ description: > ++ Send data information with directory index. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ - name: flag ++ type: byte ++ description: > ++ Valid flag to set dir entry status. ++ - name: dataLen ++ type: uint32 ++ description: > ++ The length of the data in bytes. ++ - name: dataVer ++ type: uint32 ++ description: > ++ The version number of this data. ++ - name: timeStamp ++ type: uint32 ++ description: > ++ Timestamp determinded by the agent. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Whether data changes. ++ errors: ++ - self.Error.InvalidParameter ++ ++ - name: FindIdIndex ++ description: > ++ Find id index by data info. ++ parameters: ++ - name: dataInfo ++ type: array[byte] ++ description: > ++ Data info of data entry. ++ returns: ++ - name: idIndex ++ type: int32 ++ description: > ++ Id index of data entry. ++ errors: ++ - self.Error.InvalidId ++ ++ - name: AgentSynchronizeData ++ description: > ++ Synchronize SMBIOS data from file. ++ returns: ++ - name: status ++ type: boolean ++ description: > ++ Whether synchronization succeed or not. ++ ++ - name: SynchronizeDirectoryCommonData ++ description: > ++ Synchronize directory common data. ++ parameters: ++ - name: idIndex ++ type: byte ++ description: > ++ Index of SMBIOS directory. ++ - name: size ++ type: uint32 ++ description: > ++ Size of data that BIOS prepare to transfer. ++ returns: ++ - name: commonData ++ type: array[uint32] ++ description: > ++ Directory common data includes data size, version and timestamp. ++ ++properties: ++ - name: DirectoryEntries ++ type: byte ++ description: > ++ Numbers of directory entries. +diff --git a/xyz/openbmc_project/Smbios/README.md b/xyz/openbmc_project/Smbios/README.md +new file mode 100644 +index 0000000..415ac52 +--- /dev/null ++++ b/xyz/openbmc_project/Smbios/README.md +@@ -0,0 +1,22 @@ ++# SMBIOS MDR V2 ++ ++## Overview ++SMBIOS MDR V2 service exposes D-Bus methods for SMBIOS Version 2 operations. ++ ++### SMBIOS MDR V2 Interface ++SMBIOS MDR V2 interface `xyz.openbmc_project.Smbios.MDR_V2` provides following ++methods. ++#### methods ++* GetDirectoryInformation - Get the directory with directory index. ++* GetDataInformation - Get the data information with id index and data set ID. ++* SendDirectoryInformation - Send directory information to SMBIOS directory. ++* GetDataOffer - Get data set ID. ++* SendDataInformation - Send data information with directory index. ++* FindIdIndex - Find id index by data info. ++* SynchronizeDirectoryCommonData - Synchronize directory common data before ++SMBIOS data start to transfer. ++* AgentSynchronizeData - Synchronize SMBIOS data from file after data transfer ++complete. ++ ++#### properties ++* DirEntries - Numbers of directory entries. Default: 0 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch new file mode 100644 index 000000000..ce23c222b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch @@ -0,0 +1,64 @@ +From f88cac8364d5312e29208018909827d2da4a0f87 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 19 Feb 2019 16:52:51 +0800 +Subject: [PATCH] Define post code interfaces for post code manager + +It includes one method and 2 properties. +properties: + - name: CurrentBootCycleIndex + description: > + It is used to indicate current boot cycle index. + - name: MaxBootCycleNum + description: > + The max cached boot cycles for post code. +methods: + - name: GetPostCodes + description: > + Method to get the cached post code for each boot cycle. +TestBy: bitbake build + +Signeoff-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../State/Boot/PostCode.interface.yaml | 30 ++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + create mode 100644 xyz/openbmc_project/State/Boot/PostCode.interface.yaml + +diff --git a/xyz/openbmc_project/State/Boot/PostCode.interface.yaml b/xyz/openbmc_project/State/Boot/PostCode.interface.yaml +new file mode 100644 +index 0000000..711749d +--- /dev/null ++++ b/xyz/openbmc_project/State/Boot/PostCode.interface.yaml +@@ -0,0 +1,30 @@ ++description: > ++ Monitor Post code coming and buffer all of them based on boot cycle ++ into file system. ++ ++properties: ++ - name: CurrentBootCycleIndex ++ type: uint16 ++ description: > ++ It is used to indicate current boot cycle index. ++ - name: MaxBootCycleNum ++ type: uint16 ++ description: > ++ The max cached boot cycles for post code. ++methods: ++ - name: GetPostCodes ++ description: > ++ Method to get the cached post code for each boot cycle. ++ parameters: ++ - name: Index ++ type: uint16 ++ description: > ++ Index indicates which boot cycle of post codes is requested. ++ returns: ++ - name: codes ++ type: array[uint64] ++ description: > ++ An array of post codes of one boot cycle. ++ errors: ++ - xyz.openbmc_project.Common.Error.InternalFailure ++ - xyz.openbmc_project.Common.Error.InvalidArgument +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch new file mode 100644 index 000000000..68d2c92b7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch @@ -0,0 +1,76 @@ +From 2820ca36ab21c52341cdbde477756f960eaeb68b Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 13 Mar 2019 11:19:07 +0800 +Subject: [PATCH] Create dbus interface for SOL commands + +Create dbus properties for Set/Get SOL config parameter command. +Some platforms need to call Set/Get SOL config parameter command +through KCS, and since sol manager in net-ipmid cannot be accessed +by commands in host-ipmid, need to create a dbus interface in +phospher-settings to transfer properties from host-ipmid to +net-ipmid. + +TestedBy: +With the related code change in net-ipmid, busctl introspect +xyz.openbmc_project.Ipmi.SOL /xyz/openbmc_project/SOL +can show all the properties needed. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + xyz/openbmc_project/Ipmi/SOL.interface.yaml | 44 ++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + create mode 100644 xyz/openbmc_project/Ipmi/SOL.interface.yaml + +diff --git a/xyz/openbmc_project/Ipmi/SOL.interface.yaml b/xyz/openbmc_project/Ipmi/SOL.interface.yaml +new file mode 100644 +index 0000000..94db59f +--- /dev/null ++++ b/xyz/openbmc_project/Ipmi/SOL.interface.yaml +@@ -0,0 +1,44 @@ ++description: > ++ SOL properties use for Get/Set SOL config parameter command in host-ipmid ++ sending config to SOL process in net-ipmid. ++ Since some platforms need to access Get/Set SOL config parameter command ++ through KCS, and current sol manager is implemented in net-ipmid and ++ cannot be accessed by host-ipmid, add a dbus interface for host-ipmid ++ command to transfer properties to net-ipmid. ++ This interface will be implemented in phosphor-settings. ++properties: ++ - name: Progress ++ type: byte ++ description: > ++ Set In Progress property, indicate when any parameters are being ++ updated. ++ - name: Enable ++ type: boolean ++ description: > ++ SOL Enable property, this controls whether the SOL payload type ++ can be activated. ++ - name: Authentication ++ type: byte ++ description: > ++ If SOL enable Force Payload Encryption and Authenticaton. ++ And the minimun operating privilege level SOL required. ++ - name: AccumulateIntervalMS ++ type: byte ++ description: > ++ Character Accumulate Interval in 5ms increments. ++ BMC will wait this time before transmitting a packet. ++ - name: Threshold ++ type: byte ++ description: > ++ BMC will automatically send an SOL character data packet containing ++ this number of characters as soon as this number of characters ++ (or greater) has been accepted from the baseboard serial controller. ++ - name: RetryCount ++ type: byte ++ description: > ++ Packet will be dropped if no ACK/NACK received by time retries ++ expire. ++ - name: RetryIntervalMS ++ type: byte ++ description: > ++ Retry Interval in 10ms increments. +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0021-D-Bus-Intf-Security-modes-property-intf-update.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0021-D-Bus-Intf-Security-modes-property-intf-update.patch new file mode 100644 index 000000000..62d5376d6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0021-D-Bus-Intf-Security-modes-property-intf-update.patch @@ -0,0 +1,80 @@ +From 9b0630f40c7fb1143901f7d114c376426cc03501 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Sat, 15 Jun 2019 01:04:41 +0530 +Subject: [PATCH] [D-Bus Intf] Security modes property & intf update + +Defined new values for RestrictionMode property and defined +SpecialMode interfaces to handle special cases like manufacturing +and validation mode in OpenBMC. + +Note: Please refer Security mode design doc under review for more +details +https://gerrit.openbmc-project.xyz/#/c/openbmc/docs/+/21195/ + +Change-Id: I270e7d23ca2ed260f2d121e3844c2ca79150070e +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + .../Security/RestrictionMode.interface.yaml | 16 +++++++++++++ + .../Control/Security/SpecialMode.interface.yaml | 26 ++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Security/SpecialMode.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Security/RestrictionMode.interface.yaml b/xyz/openbmc_project/Control/Security/RestrictionMode.interface.yaml +index 8e4fd8d..afd2279 100644 +--- a/xyz/openbmc_project/Control/Security/RestrictionMode.interface.yaml ++++ b/xyz/openbmc_project/Control/Security/RestrictionMode.interface.yaml +@@ -21,3 +21,19 @@ enumerations: + - name: Blacklist + description: > + Prevent, if in the blacklist. ++ - name: Provisioning ++ description: > ++ Indicate that system is in provisioning mode ++ and all commands are allowed in system inteface ++ in both pre and post BIOS boot. ++ - name: ProvisionedHostWhitelist ++ description: > ++ Commands in the whitelist will only be executed ++ through system interface after BIOS POST complete. ++ All KCS commands are supported before POST complete. ++ - name: ProvisionedHostDisabled ++ description: > ++ Commands through system interface are executed only ++ till BIOS POST complete notification, after ++ which no system interface commands will be executed(other ++ than BIOS SMI based ones). +diff --git a/xyz/openbmc_project/Control/Security/SpecialMode.interface.yaml b/xyz/openbmc_project/Control/Security/SpecialMode.interface.yaml +new file mode 100644 +index 0000000..6760076 +--- /dev/null ++++ b/xyz/openbmc_project/Control/Security/SpecialMode.interface.yaml +@@ -0,0 +1,26 @@ ++description: > ++ Implement to specify a special mode of operation ++ ++properties: ++ - name: SpecialMode ++ type: enum[self.Modes] ++ description: > ++ The special mode. ++ ++enumerations: ++ - name: Modes ++ description: > ++ Possible modes available. ++ values: ++ - name: None ++ description: > ++ BMC is under normal working condition. ++ - name: Manufacturing ++ description: > ++ Indicate that BMC is in manufacturing mode ++ and is allowed to perform any manufacturing related ++ activity ++ - name: ValidationUnsecure ++ description: > ++ Indicate that BMC is in validation mode, and can ++ execute any special validation related commands +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch new file mode 100644 index 000000000..181d12428 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch @@ -0,0 +1,40 @@ +From b55c6847b18fdee5a72d601b871d73085481e4d9 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 3 Jun 2019 16:31:29 -0700 +Subject: [PATCH] Add chassis power-cycle and reset to Chassis State + +This adds chassis PowerCycle and Reset as possible Transition +values for the Chassis State. These are to support chassis +power cycle and a chassis reset button, respectively. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + xyz/openbmc_project/State/Chassis.interface.yaml | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/State/Chassis.interface.yaml b/xyz/openbmc_project/State/Chassis.interface.yaml +index 4ae6274..470a3a2 100644 +--- a/xyz/openbmc_project/State/Chassis.interface.yaml ++++ b/xyz/openbmc_project/State/Chassis.interface.yaml +@@ -31,10 +31,17 @@ enumerations: + values: + - name: 'Off' + description: > +- Chassis power should be off ++ Chassis power should be off + - name: 'On' + description: > + Chassis power should be on ++ - name: 'PowerCycle' ++ description: > ++ Chassis power should be cycled ++ - name: 'Reset' ++ description: > ++ Chassis should be reset ++ + + - name: PowerState + description: > +-- +2.7.4 + 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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend new file mode 100644 index 000000000..79a67ee79 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend @@ -0,0 +1,17 @@ +SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git" +SRCREV = "ddc9e9f9d6ed0282ec6c1421a706b45f3c09ebcc" + +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://0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch \ + file://0018-Define-post-code-interfaces-for-post-code-manager.patch \ + file://0021-D-Bus-Intf-Security-modes-property-intf-update.patch \ + file://0022-Add-chassis-power-cycle-and-reset-to-Chassis-State.patch \ + file://0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch \ + file://0025-Add-PreInterruptFlag-properity-in-DBUS.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..30044eb6e --- /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 = "a7ec8350d17b70153cebe666d3fbe88bddd02a1a" + +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/fwupd@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service new file mode 100644 index 000000000..d51fee312 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service @@ -0,0 +1,8 @@ +[Unit]
+Description=Flash BMC with fwupd script : %I
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/fwupd.sh file:////tmp/images/%i/image-runtime
+SyslogIdentifier=fwupd
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend new file mode 100644 index 000000000..2efe911ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +EXTRA_OECONF += "--enable-fwupd_script" + +SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service" + + +SRC_URI += "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 \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend new file mode 100644 index 000000000..5326680f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend @@ -0,0 +1,6 @@ +SYSTEMD_LINK_${PN}_remove += "../op-start-host@.service:obmc-host-startmin@0.target.requires/op-start-host@0.service" +SYSTEMD_LINK_${PN}_remove += "../op-init-pnor@.service:obmc-host-startmin@0.target.requires/op-init-pnor@0.service" + +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-start-host@0.service" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-init-pnor@0.service"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket new file mode 100644 index 000000000..8782e4dd3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket @@ -0,0 +1,9 @@ +[Unit] +Description=BMC Webserver socket + +[Socket] +ListenStream=443 +ReusePort=true + +[Install] +WantedBy=sockets.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend new file mode 100644 index 000000000..53cd944c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -0,0 +1,17 @@ +SRC_URI = "git://github.com/openbmc/bmcweb.git" +SRCREV = "b76f9ca126d5c1abcd8b833a511d784531dbb3a1" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# add a user called bmcweb for the server to assume +# bmcweb is part of group shadow for non-root pam authentication +USERADD_PARAM_${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb" + +GROUPADD_PARAM_${PN} = "web; redfish " + +# Enable CPU Log and Raw PECI support +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_CPU_LOG=ON" +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_RAW_PECI=ON" + +# Enable Redfish BMC Journal support +EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_BMC_JOURNAL=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend new file mode 100644 index 000000000..616fb9a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://dev_id.json \ + file://channel_access.json \ + file://channel_config.json \ + file://master_write_read_white_list.json \ + " + +FILES_${PN} += " \ + ${datadir}/ipmi-providers/channel_access.json \ + ${datadir}/ipmi-providers/channel_config.json \ + ${datadir}/ipmi-providers/master_write_read_white_list.json \ + " + +do_install_append() { + install -m 0644 -D ${WORKDIR}/channel_access.json \ + ${D}${datadir}/ipmi-providers/channel_access.json + install -m 0644 -D ${WORKDIR}/channel_config.json \ + ${D}${datadir}/ipmi-providers/channel_config.json + install -m 0644 -D ${WORKDIR}/master_write_read_white_list.json \ + ${D}${datadir}/ipmi-providers/master_write_read_white_list.json +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json new file mode 100644 index 000000000..299483121 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json @@ -0,0 +1,23 @@ +{ + "1" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "2" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "3" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json new file mode 100644 index 000000000..92731f439 --- /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" : "EMP", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "5" : { + "name" : "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/0009-IPv6-Network-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch new file mode 100644 index 000000000..b54b22213 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch @@ -0,0 +1,899 @@ +From c20bc8eb6a08d177d951012eb91b37398b15d81d Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Tue, 27 Nov 2018 11:01:15 -0800 +Subject: [PATCH] IPv6 Network changes + +Allow IPv6 IPMI set/get commands + +Signed-off-by: David Cobbley <david.j.cobbley@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> + +Change-Id: If5528d3b7294c5f8c17db5919439235d0fad0446 +--- + include/ipmid/types.hpp | 9 + + include/ipmid/utils.hpp | 1 + + transporthandler.cpp | 654 +++++++++++++++++++++++++++++++++++++++- + transporthandler.hpp | 50 +++ + 4 files changed, 713 insertions(+), 1 deletion(-) + +diff --git a/include/ipmid/types.hpp b/include/ipmid/types.hpp +index 57c5873..c06fd8c 100644 +--- a/include/ipmid/types.hpp ++++ b/include/ipmid/types.hpp +@@ -224,6 +224,7 @@ constexpr auto ADDR_TYPE_FORMAT = "%hhx"; + + constexpr auto IPV4_ADDRESS_SIZE_BYTE = 4; + constexpr auto IPV6_ADDRESS_SIZE_BYTE = 16; ++constexpr auto IPV6_ADDRESS_STATUS_SIZE = 22; + + constexpr auto DEFAULT_MAC_ADDRESS = "00:00:00:00:00:00"; + constexpr auto DEFAULT_ADDRESS = "0.0.0.0"; +@@ -235,6 +236,7 @@ constexpr auto BITS_32 = 32; + constexpr auto MASK_32_BIT = 0xFFFFFFFF; + constexpr auto VLAN_ID_MASK = 0x00000FFF; + constexpr auto VLAN_ENABLE_MASK = 0x8000; ++constexpr auto IPV6_DUID_SIZE = 18; + + enum class IPOrigin : uint8_t + { +@@ -243,5 +245,12 @@ enum class IPOrigin : uint8_t + DHCP = 2, + }; + ++enum class AddressingEnables : uint8_t ++{ ++ IPv4Only = 0, ++ IPv6Only = 1, ++ IPv4AndIPv6 = 2, ++}; ++ + } // namespace network + } // namespace ipmi +diff --git a/include/ipmid/utils.hpp b/include/ipmid/utils.hpp +index 9ef1488..8b91b12 100644 +--- a/include/ipmid/utils.hpp ++++ b/include/ipmid/utils.hpp +@@ -256,6 +256,7 @@ namespace network + constexpr auto ROOT = "/xyz/openbmc_project/network"; + constexpr auto SERVICE = "xyz.openbmc_project.Network"; + constexpr auto IP_TYPE = "ipv4"; ++constexpr auto IPV6_TYPE = "ipv6"; + constexpr auto IPV4_PREFIX = "169.254"; + constexpr auto IPV6_PREFIX = "fe80"; + constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 8172cc4..12d224a 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -30,6 +30,12 @@ std::unique_ptr<phosphor::Timer> networkTimer = nullptr; + + const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx + constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; ++constexpr auto ipv6Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; ++ ++static const std::array<std::string, 3> ipAddressEnablesType = { ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only", ++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"}; + + std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; + +@@ -389,7 +395,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_context_t context) + { + ipmi_ret_t rc = IPMI_CC_OK; +- *data_len = 0; + + using namespace std::chrono_literals; + +@@ -403,6 +408,9 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + auto reqptr = reinterpret_cast<const set_lan_t*>(request); + sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); + ++ size_t reqLen = *data_len; ++ *data_len = 0; ++ + // channel number is the lower nibble + int channel = reqptr->channel & CHANNEL_MASK; + auto ethdevice = ipmi::getChannelName(channel); +@@ -426,6 +434,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::IPSRC: + { ++ if (reqLen != LAN_PARAM_IPSRC_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint8_t ipsrc{}; + std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); + channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); +@@ -434,6 +447,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::MAC: + { ++ if (reqLen != LAN_PARAM_MAC_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + char mac[SIZE_MAC]; + + std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, +@@ -454,6 +472,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::SUBNET: + { ++ if (reqLen != LAN_PARAM_SUBNET_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(netmask, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -463,6 +486,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::GATEWAY: + { ++ if (reqLen != LAN_PARAM_GATEWAY_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + std::snprintf(gateway, INET_ADDRSTRLEN, + ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], + reqptr->data[1], reqptr->data[2], reqptr->data[3]); +@@ -472,6 +500,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::VLAN: + { ++ if (reqLen != LAN_PARAM_VLAN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + uint16_t vlan{}; + std::memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); + // We are not storing the enable bit +@@ -484,6 +517,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + case LanParam::INPROGRESS: + { ++ if (reqLen != LAN_PARAM_INPROGRESS_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ + if (reqptr->data[0] == SET_COMPLETE) + { + channelConf->lan_set_in_progress = SET_COMPLETE; +@@ -512,6 +550,122 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + } + break; + ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ if (reqLen != LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressingEnables = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6AddressSource = ++ reqptr->data[1] & 0x81; // Looking at bit 0 and bit 7 ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, &reqptr->data[2], tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6Addr.assign(tmpIPV6); ++ channelConf->ipv6Prefix = reqptr->data[19]; ++ break; ++ } ++ ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6RouterAddressConfigControl = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6GatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6GatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayAddr.assign(tmpIPV6); ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ channelConf->ipv6BackupGatewayPrefixLength = reqptr->data[0]; ++ break; ++ } ++ ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE) ++ { ++ return IPMI_CC_REQ_DATA_LEN_INVALID; ++ } ++ ++ char tmpIPV6[INET6_ADDRSTRLEN]; ++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data), ++ tmpIPV6, INET6_ADDRSTRLEN); ++ channelConf->ipv6BackupGatewayPrefixValue.assign(tmpIPV6); ++ break; ++ } ++ + default: + { + rc = IPMI_CC_PARM_NOT_SUPPORTED; +@@ -538,6 +692,7 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_ret_t rc = IPMI_CC_OK; + *data_len = 0; + const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 ++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; + + get_lan_t* reqptr = (get_lan_t*)request; + // channel number is the lower nibble +@@ -676,6 +831,476 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + static_cast<uint8_t>(cipherList.size()); + break; + } ++ case LanParam::IPV6_AND_IPV4_SUPPORTED: ++ { ++ uint8_t addressSupport = ++ 0x1; // Allow both IPv4 & IPv6 simultaneously ++ std::array<uint8_t, 2> buf = {current_revision, addressSupport}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_AND_IPV4_ENABLES: ++ { ++ // If DHCP, check if you have an ipv6 and ipv4 address. If static ++ // return not supported ++ ++ // 00h check if conf DHCP == ipv4 or off ++ // 01h check if conf DHCP == ipv6 ++ // 02h check if DHCP == true ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t ipVAddressEnables = 0; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system has an ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ ipmi::Value ipEnablesProp = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables"); ++ std::string ipEnables = std::get<std::string>(ipEnablesProp); ++ ++ // check if on off ipv4 ipv6, etc. ++ bool found = false; ++ for (uint8_t ii = 0; ii < ipAddressEnablesType.size(); ii++) ++ { ++ if (ipEnables == ipAddressEnablesType[ii]) ++ { ++ ipVAddressEnables = ii; ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ { ++ return IPMI_CC_PARM_NOT_SUPPORTED; ++ } ++ } ++ else ++ { ++ ipVAddressEnables = channelConf->ipv6AddressingEnables; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, ipVAddressEnables}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATUS: ++ { ++ // Number of IPV6 addresses that are supported ++ constexpr std::array<uint8_t, 3> statusData = {1, 1, 3}; ++ ++ std::array<uint8_t, 4> buf = {current_revision, statusData[0], ++ statusData[1], statusData[2]}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ADDRESSES: ++ { ++ // Only return set selector 0 ++ uint8_t ipv6SetSelector = 0; ++ std::string ipaddress; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (std::get<std::string>(properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ++ { ++ ipaddress = ++ std::get<std::string>(properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ std::get<uint8_t>(properties["PrefixLength"]); ++ status = 0; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ ipaddress = channelConf->ipv6Addr.c_str(); ++ prefixLength = channelConf->ipv6Prefix; ++ status = 1; ++ } ++ ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_STATUS_SIZE> buf = { ++ current_revision, ipv6SetSelector, ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUID_STORAGE_LENGTH: ++ { ++ // DHCP unique identified ++ // Only 1 read-only 16-byte Block needed ++ uint8_t duidLength = 1; ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_STATIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = std::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DYNAMIC_ADDRESSES: ++ { ++ std::string ipaddress; ++ uint8_t ipv6AddressSource = 0; ++ uint8_t prefixLength = 0; ++ uint8_t status = 0; ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ try ++ { ++ auto ipObjectInfo = ++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ auto properties = ipmi::getAllDbusProperties( ++ bus, ipObjectInfo.second, ipObjectInfo.first, ++ ipmi::network::IP_INTERFACE); ++ ++ if (std::get<std::string>(properties["Origin"]) == ++ "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") ++ { ++ ipaddress = ++ std::get<std::string>(properties["Address"]); ++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7 ++ prefixLength = ++ std::get<uint8_t>(properties["PrefixLength"]); ++ status = 0; ++ } ++ else ++ { ++ status = 1; ++ } ++ } ++ // ignore the exception, as it is a valid condition that ++ // the system is not configured with any IP. ++ catch (InternalFailure& e) ++ { ++ // nothing to do. ++ } ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ ipaddress = channelConf->ipv6Addr; ++ ipv6AddressSource = channelConf->ipv6AddressSource; ++ prefixLength = channelConf->ipv6Prefix; ++ status = channelConf->ipv6AddressStatus; ++ } ++ ++ uint8_t ipv6SetSelector = 0; ++ std::array<uint8_t, 22> buf = {current_revision, ipv6SetSelector, ++ ipv6AddressSource}; ++ inet_pton(AF_INET6, ipaddress.c_str(), ++ reinterpret_cast<void*>(&buf[3])); ++ buf[20] = prefixLength; ++ buf[21] = status; ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUID_STOR_LEN: ++ { ++ uint8_t duidLength = 0; ++ // Only 1 read-only 16-byte Block needed ++ duidLength = 1; ++ ++ std::array<uint8_t, 2> buf = {current_revision, duidLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUIDS: ++ { ++ std::string macAddress; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ auto macObjectInfo = ++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, macObjectInfo.second, macObjectInfo.first, ++ ipmi::network::MAC_INTERFACE, "MACAddress"); ++ ++ macAddress = std::get<std::string>(variant); ++ } ++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) ++ { ++ macAddress = channelConf->macAddress; ++ } ++ ++ std::array<uint8_t, ++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)> ++ buf; ++ buf = {current_revision, ++ reqptr->parameter_set, ++ reqptr->parameter_block, ++ DUID_LEN, ++ 0, // Filler byte ++ DUID_LL_TYPE, ++ 0, // Filler byte ++ DUIC_ETH_HW_TYPE}; ++ ++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, ++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]), ++ (&buf[13])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL: ++ { ++ // Determine if automated router discovery occurs when static ++ // addresses are used for the bmc ++ ++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE; ++ std::string networkInterfacePath; ++ uint8_t dynamicRA; ++ if (channelConf->lan_set_in_progress == SET_COMPLETE) ++ { ++ ++ try ++ { ++ ipmi::ObjectTree ancestorMap; ++ // if the system is having ip object,then ++ // get the IP object. ++ auto ipObject = ++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE, ++ ipmi::network::ROOT, ethIP); ++ ++ // Get the parent interface of the IP object. ++ try ++ { ++ ipmi::InterfaceList interfaces; ++ interfaces.emplace_back( ++ ipmi::network::ETHERNET_INTERFACE); ++ ++ ancestorMap = ipmi::getAllAncestors( ++ bus, ipObject.first, std::move(interfaces)); ++ } ++ catch (InternalFailure& e) ++ { ++ // if unable to get the parent interface ++ // then commit the error and return. ++ log<level::ERR>( ++ "Unable to get the parent interface", ++ entry("PATH=%s", ipObject.first.c_str()), ++ entry("INTERFACE=%s", ++ ipmi::network::ETHERNET_INTERFACE)); ++ return IPMI_CC_UNSPECIFIED_ERROR; ++ } ++ // for an ip object there would be single parent ++ // interface. ++ networkInterfacePath = ancestorMap.begin()->first; ++ } ++ catch (InternalFailure& e) ++ { ++ // if there is no ip configured on the system,then ++ // get the network interface object. ++ auto networkInterfaceObject = ipmi::getDbusObject( ++ bus, ipmi::network::ETHERNET_INTERFACE, ++ ipmi::network::ROOT, ethdevice); ++ ++ networkInterfacePath = networkInterfaceObject.first; ++ } ++ ++ auto variant = ipmi::getDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfacePath, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA"); ++ dynamicRA = std::get<bool>(variant); ++ } ++ else ++ { ++ dynamicRA = channelConf->ipv6RouterAddressConfigControl; ++ } ++ ++ std::array<uint8_t, 2> buf = {current_revision, dynamicRA}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6GatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = {current_revision, ++ channelConf->ipv6GatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL: ++ { ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ ++ inet_pton(AF_INET6, channelConf->ipv6GatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR: ++ { ++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision}; ++ inet_pton(AF_INET6, channelConf->ipv6BackupGatewayAddr.c_str(), ++ reinterpret_cast<void*>(&buf[1])); ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN: ++ { ++ std::array<uint8_t, 2> buf = { ++ current_revision, channelConf->ipv6BackupGatewayPrefixLength}; ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } ++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL: ++ { ++ ++ constexpr uint8_t setSelector = 0; ++ std::array<uint8_t, sizeof(setSelector) + ++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE + ++ sizeof(current_revision)> ++ buf = {current_revision, setSelector}; ++ inet_pton(AF_INET6, ++ channelConf->ipv6BackupGatewayPrefixValue.c_str(), ++ reinterpret_cast<void*>(&buf[2])); ++ ++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response)); ++ *data_len = buf.size(); ++ break; ++ } + default: + log<level::ERR>("Unsupported parameter", + entry("PARAMETER=0x%x", reqptr->parameter)); +@@ -921,6 +1546,16 @@ void applyChanges(int channel) + ipaddress, prefix); + } + ++ if (!channelConf->ipv6Addr.empty() && ++ channelConf->ipv6AddressSource == ++ 0x80) // Check if IPv6 static addresses are enabled ++ { ++ ipmi::network::createIP(bus, ipmi::network::SERVICE, ++ networkInterfacePath, ipv6Protocol, ++ channelConf->ipv6Addr, ++ channelConf->ipv6Prefix); ++ } ++ + if (!gateway.empty()) + { + ipmi::setDbusProperty(bus, systemObject.second, +@@ -928,7 +1563,24 @@ void applyChanges(int channel) + ipmi::network::SYSTEMCONFIG_INTERFACE, + "DefaultGateway", std::string(gateway)); + } ++ else if (!channelConf->ipv6GatewayAddr.empty()) ++ { ++ ipmi::setDbusProperty( ++ bus, systemObject.second, systemObject.first, ++ ipmi::network::SYSTEMCONFIG_INTERFACE, "DefaultGateway", ++ std::string(channelConf->ipv6GatewayAddr)); ++ } + } ++ // set IPAddress Enables ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables", ++ ipAddressEnablesType[channelConf->ipv6AddressingEnables]); ++ ++ ipmi::setDbusProperty( ++ bus, ipmi::network::SERVICE, networkInterfaceObject.first, ++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA", ++ (bool)channelConf->ipv6RouterAddressConfigControl); + } + catch (InternalFailure& e) + { +diff --git a/transporthandler.hpp b/transporthandler.hpp +index 04d4673..bd23391 100644 +--- a/transporthandler.hpp ++++ b/transporthandler.hpp +@@ -79,6 +79,28 @@ enum class LanParam : uint8_t + IPV6_NEIGHBOR_TIMING_CONFIGURATION = 80, + }; + ++// Data length of parameters ++constexpr size_t LAN_PARAM_INPROGRESS_SIZE = 3; ++constexpr size_t LAN_PARAM_IP_SIZE = 6; ++constexpr size_t LAN_PARAM_IPSRC_SIZE = 3; ++constexpr size_t LAN_PARAM_MAC_SIZE = 8; ++constexpr size_t LAN_PARAM_SUBNET_SIZE = 6; ++constexpr size_t LAN_PARAM_GATEWAY_SIZE = 6; ++constexpr size_t LAN_PARAM_VLAN_SIZE = 4; ++constexpr size_t LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE = 23; ++constexpr size_t LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE = 18; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE = 19; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE = 18; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE = 3; ++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE = 19; ++ ++constexpr uint8_t DUID_LEN = 10; ++constexpr uint8_t DUID_LL_TYPE = 3; ++constexpr uint8_t DUIC_ETH_HW_TYPE = 1; ++ + constexpr uint8_t SET_COMPLETE = 0; + constexpr uint8_t SET_IN_PROGRESS = 1; + constexpr uint8_t SET_COMMIT_WRITE = 2; // Optional +@@ -101,6 +123,20 @@ struct ChannelConfig_t + uint8_t lan_set_in_progress = SET_COMPLETE; + bool flush = false; + ++ // IPV6 parameters ++ uint8_t ipv6AddressSource = 0x0; ++ uint8_t ipv6AddressingEnables = 0x2; ++ std::string ipv6Addr; ++ uint8_t ipv6Prefix = 32; ++ uint8_t ipv6AddressStatus = 0x0; ++ uint8_t ipv6RouterAddressConfigControl = 0x0; ++ std::string ipv6GatewayAddr; ++ std::string ipv6BackupGatewayAddr; ++ uint8_t ipv6GatewayPrefixLength; ++ std::string ipv6GatewayPrefixValue; ++ uint8_t ipv6BackupGatewayPrefixLength = 0x0; ++ std::string ipv6BackupGatewayPrefixValue; ++ + void clear() + { + ipaddr.clear(); +@@ -111,6 +147,20 @@ struct ChannelConfig_t + ipsrc = ipmi::network::IPOrigin::UNSPECIFIED; + lan_set_in_progress = SET_COMPLETE; + flush = false; ++ ++ // IPv6 ++ ipv6Addr.clear(); ++ ipv6GatewayAddr.clear(); ++ ipv6BackupGatewayAddr.clear(); ++ ipv6AddressingEnables = 0x2; ++ ipv6AddressSource = 0x0; ++ ipv6Prefix = 32; ++ ipv6AddressStatus = 0x0; ++ ipv6RouterAddressConfigControl = 0x0; ++ ipv6GatewayPrefixLength = 0x0; ++ ipv6GatewayPrefixValue.clear(); ++ ipv6BackupGatewayPrefixLength = 0x0; ++ ipv6BackupGatewayPrefixValue.clear(); + } + }; + +-- +2.17.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..efee7cc26 --- /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,36 @@ +commit 72e6573f36fd3b9ce018e71b07bc1be63275d1f8 +Author: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri Jun 21 12:27:20 2019 -0700 + + 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> + +diff --git a/apphandler.cpp b/apphandler.cpp +index 280d0db..25af6bb 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -799,8 +799,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"; + +@@ -809,7 +807,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 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch new file mode 100644 index 000000000..396d2e949 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch @@ -0,0 +1,22 @@ +From ad7276f3aedb6f5aed315db57406c98f2bf71a09 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 13:21:52 +0800 +Subject: [PATCH] [ipmi] add set bios id to whitelist + +Add "SetBIOSId" and "GetDeviceInfo" 2 OEM commands into whitelist + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 2 ++ + 1 file changed, 2 insertions(+) + +Index: phosphor-host-ipmid/host-ipmid-whitelist.conf +=================================================================== +--- phosphor-host-ipmid.orig/host-ipmid-whitelist.conf ++++ phosphor-host-ipmid/host-ipmid-whitelist.conf +@@ -47,3 +47,5 @@ + 0x2C:0x06 //<Group Extension>:<Get Asset Tag> + 0x2C:0x07 //<Group Extension>:<Get Sensor Info> + 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> ++0x30:0x26 //<OEM>:<Set BIOS ID> ++0x30:0x27 //<OEM>:<Get Device Info> diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch new file mode 100644 index 000000000..fdaa91085 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch @@ -0,0 +1,25 @@ +From cf466ba2c66a95825ae0014d7c378ad63b050d2f Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Wed, 15 Aug 2018 14:50:04 +0800 +Subject: [PATCH] [ipmi] add oem command "get AIC FRU" to whitelist + +Intel BIOS requires this oem command to get addon card FRU info. +Add to whitelist to unblock. + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + host-ipmid-whitelist.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index db54a49..49746a2 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -43,3 +43,4 @@ + 0x30:0x41 //<OEM>:<Set System GUID> + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> ++0x30:0x31 //<OEM>:<Get AIC card FRU> +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch new file mode 100644 index 000000000..b800632cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch @@ -0,0 +1,15 @@ +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 22a2a3c..5d71698 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -49,3 +49,10 @@ + 0x30:0x26 //<OEM>:<Set BIOS ID> + 0x30:0x27 //<OEM>:<Get Device Info> + 0x30:0x31 //<OEM>:<Get AIC card FRU> ++0x30:0x54 //<OEM>:<Set Power Restore Delay> ++0x30:0x55 //<OEM>:<Get Power Restore Delay> ++0x30:0x9A //<OEM>:<Get Processor Error Config> ++0x30:0x9B //<OEM>:<Set Processor Error Config> ++0x30:0xB0 //<OEM>:<Get LED Status> ++0x30:0xE9 //<OEM>:<Get BIOS Post Codes> ++ diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/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/0054-Fix-User-commands-require-channel-layer-lib.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch new file mode 100644 index 000000000..bf6f672cf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch @@ -0,0 +1,37 @@ +From 5d0c9d2217dbe369daffb8a92d7b5e7d7d34d566 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Sat, 2 Mar 2019 20:08:32 +0530 +Subject: [PATCH] Fix: User commands require channel layer lib + +As channel layer is separated out from user layer lib, it +has to be manually included in libusercommands, as user +command handlers use channel layer API's + +Tested-by: +1. Made sure that libusercommands are loaded on it's own +without any undefined symbol error. +2. ipmitool user list 1 works on host interface + +Change-Id: I6652ad248e01afc1349e3a9612754dbdb84b96ad +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index bb7bdbf..4e9101e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -120,7 +120,8 @@ libipmi20_la_CXXFLAGS = $(COMMON_CXX) + providers_LTLIBRARIES += libusercmds.la + libusercmds_la_LIBADD = \ + libipmid/libipmid.la \ +- user_channel/libuserlayer.la ++ user_channel/libuserlayer.la \ ++ user_channel/libchannellayer.la + libusercmds_la_SOURCES = \ + user_channel/usercommands.cpp + libusercmds_la_LDFLAGS = \ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch new file mode 100644 index 000000000..3a77887a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch @@ -0,0 +1,102 @@ +From 949db3a985719335d3df77db368eb2b296756749 Mon Sep 17 00:00:00 2001 +From: "Jia, chunhui" <chunhui.jia@linux.intel.com> +Date: Tue, 19 Mar 2019 16:09:06 +0800 +Subject: [PATCH] add SetInProgress to get/set boot option cmd + +It is required by BIOS. BIOS will check setinprogress first. +If this flag is not supported, BIOS will bypass all boot +option flow. + +Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f +Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com> +--- + chassishandler.cpp | 26 +++++++++++++++++++++++++- + chassishandler.hpp | 3 +++ + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 6d14d1b..553afa8 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1351,6 +1351,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + return IPMI_CC_OK; + } + ++static constexpr uint8_t setComplete = 0x0; ++static constexpr uint8_t setInProgress = 0x1; ++static uint8_t transferStatus = setComplete; ++ + ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -1365,11 +1369,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; + IpmiValue bootOption = ipmiDefault; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ *data_len = ++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS); ++ resp->version = SET_PARM_VERSION; ++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS); ++ resp->data[0] = transferStatus; ++ return IPMI_CC_OK; ++ } ++ + std::memset(resp, 0, sizeof(*resp)); + resp->version = SET_PARM_VERSION; + resp->parm = 5; + resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; +- + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +@@ -1505,6 +1519,16 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // This IPMI command does not have any resposne data + *data_len = 0; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ if (transferStatus == setInProgress) { ++ return IPMI_CC_FAIL_SET_IN_PROGRESS; ++ } ++ transferStatus = reqptr->data[0]; ++ return IPMI_CC_OK; ++ } ++ + /* 000101 + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +diff --git a/chassishandler.hpp b/chassishandler.hpp +index 2c42b11..6a24507 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -28,6 +28,7 @@ enum ipmi_chassis_return_codes + { + IPMI_OK = 0x0, + IPMI_CC_PARM_NOT_SUPPORTED = 0x80, ++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81, + }; + + // Generic completion codes, +@@ -49,6 +50,7 @@ enum ipmi_chassis_control_cmds : uint8_t + }; + enum class BootOptionParameter : size_t + { ++ SET_IN_PROGRESS = 0x0, + BOOT_INFO = 0x4, + BOOT_FLAGS = 0x5, + OPAL_NETWORK_SETTINGS = 0x61 +@@ -56,6 +58,7 @@ enum class BootOptionParameter : size_t + + enum class BootOptionResponseSize : size_t + { ++ SET_IN_PROGRESS = 3, + BOOT_FLAGS = 5, + OPAL_NETWORK_SETTINGS = 50 + }; +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch new file mode 100644 index 000000000..a96707d44 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch @@ -0,0 +1,195 @@ +From 6e37e02a4f200507627a82f6dba00a9c9d877cb2 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Mon, 18 Mar 2019 23:05:16 +0800 +Subject: [PATCH] Add timer use/actions support + +Based on IPMI spec, add timer use/actions support, +and add input data checking + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + app/watchdog.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++----- + app/watchdog_service.cpp | 8 +++++++ + app/watchdog_service.hpp | 8 +++++++ + 3 files changed, 72 insertions(+), 6 deletions(-) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 1a5d19c..3b61055 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -89,6 +89,13 @@ static constexpr uint8_t wd_dont_stop = 0x1 << 6; + static constexpr uint8_t wd_timeout_action_mask = 0x3; + + static constexpr uint8_t wdTimerUseMask = 0x7; ++static constexpr uint8_t wdTimerUseResTimer1 = 0x0; ++static constexpr uint8_t wdTimerUseResTimer2 = 0x6; ++static constexpr uint8_t wdTimerUseResTimer3 = 0x7; ++static constexpr uint8_t wdTimerUseRes = 0x38; ++ ++static constexpr uint8_t wdTimerActionMask = 0xcc; ++static constexpr uint8_t wdTimerUseExpMask = 0xc1; + + enum class IpmiAction : uint8_t + { +@@ -186,6 +193,11 @@ static_assert(sizeof(wd_set_req) == 6, "wd_set_req has invalid size."); + static_assert(sizeof(wd_set_req) <= MAX_IPMI_BUFFER, + "wd_get_res can't fit in request buffer."); + ++static uint8_t timerLogFlags = 0; ++static uint8_t timerActions = 0; ++ ++static uint8_t timerUseExpirationFlags = 0; ++ + ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -203,6 +215,24 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + req.initial_countdown = le16toh(req.initial_countdown); + *data_len = 0; + ++ if (((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer1) || ++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer2) || ++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer3) || ++ (req.timer_use & wdTimerUseRes) || ++ (req.timer_action & wdTimerActionMask) || ++ (req.expire_flags & wdTimerUseExpMask)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ if (req.pretimeout > (req.initial_countdown / 10)) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } ++ ++ timerLogFlags = req.timer_use & 0x80; ++ timerActions = req.timer_action; ++ + try + { + WatchdogService wd_service; +@@ -221,6 +251,10 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + static_cast<IpmiTimerUse>(req.timer_use & wdTimerUseMask); + wd_service.setTimerUse(ipmiTimerUseToWdTimerUse(ipmiTimerUse)); + ++ wd_service.setExpiredTimerUse(WatchdogService::TimerUse::Reserved); ++ ++ timerUseExpirationFlags &= ~req.expire_flags; ++ + // Set the new interval and the time remaining deci -> mill seconds + const uint64_t interval = req.initial_countdown * 100; + wd_service.setInterval(interval); +@@ -339,7 +373,6 @@ static_assert(sizeof(wd_get_res) == 8, "wd_get_res has invalid size."); + static_assert(sizeof(wd_get_res) <= MAX_IPMI_BUFFER, + "wd_get_res can't fit in response buffer."); + +-static constexpr uint8_t wd_dont_log = 0x1 << 7; + static constexpr uint8_t wd_running = 0x1 << 6; + + ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, +@@ -358,20 +391,37 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // Build and return the response + wd_get_res res; +- res.timer_use = wd_dont_log; +- res.timer_action = +- static_cast<uint8_t>(wdActionToIpmiAction(wd_prop.expireAction)); ++ res.timer_use |= timerLogFlags; ++ res.timer_action = timerActions; + + // Interval and timeRemaining need converted from milli -> deci seconds + res.initial_countdown = htole16(wd_prop.interval / 100); ++ ++ if (wd_prop.expiredTimerUse != WatchdogService::TimerUse::Reserved) ++ { ++ timerUseExpirationFlags |= ++ 1 << static_cast<uint8_t>( ++ wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)); ++ } ++ + if (wd_prop.enabled) + { + res.timer_use |= wd_running; + res.present_countdown = htole16(wd_prop.timeRemaining / 100); ++ res.expire_flags = 0; + } + else + { +- res.present_countdown = res.initial_countdown; ++ if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved) ++ { ++ res.present_countdown = res.initial_countdown; ++ res.expire_flags = 0; ++ } ++ else ++ { ++ res.present_countdown = 0; ++ res.expire_flags = timerUseExpirationFlags; ++ } + } + + res.timer_use |= +@@ -379,7 +429,7 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + + // TODO: Do something about having pretimeout support + res.pretimeout = 0; +- res.expire_flags = 0; ++ + memcpy(response, &res, sizeof(res)); + *data_len = sizeof(res); + lastCallSuccessful = true; +diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp +index e65ea63..8b1aa47 100644 +--- a/app/watchdog_service.cpp ++++ b/app/watchdog_service.cpp +@@ -83,6 +83,9 @@ WatchdogService::Properties WatchdogService::getProperties() + wd_prop.timerUse = Watchdog::convertTimerUseFromString( + std::get<std::string>(properties.at("CurrentTimerUse"))); + ++ wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString( ++ std::get<std::string>(properties.at("ExpiredTimerUse"))); ++ + wd_prop.interval = std::get<uint64_t>(properties.at("Interval")); + wd_prop.timeRemaining = + std::get<uint64_t>(properties.at("TimeRemaining")); +@@ -187,6 +190,11 @@ void WatchdogService::setTimerUse(TimerUse timerUse) + setProperty("CurrentTimerUse", convertForMessage(timerUse)); + } + ++void WatchdogService::setExpiredTimerUse(TimerUse timerUse) ++{ ++ setProperty("ExpiredTimerUse", convertForMessage(timerUse)); ++} ++ + void WatchdogService::setInterval(uint64_t interval) + { + setProperty("Interval", interval); +diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp +index 75afc1e..d0cc1a8 100644 +--- a/app/watchdog_service.hpp ++++ b/app/watchdog_service.hpp +@@ -36,6 +36,7 @@ class WatchdogService + bool enabled; + Action expireAction; + TimerUse timerUse; ++ TimerUse expiredTimerUse; + uint64_t interval; + uint64_t timeRemaining; + }; +@@ -79,6 +80,13 @@ class WatchdogService + */ + void setTimerUse(TimerUse timerUse); + ++ /** @brief Sets the value of the ExpiredTimerUse property on the host ++ * watchdog ++ * ++ * @param[in] timerUse - The new timerUse value ++ */ ++ void setExpiredTimerUse(TimerUse timerUse); ++ + /** @brief Sets the value of the interval property on the host watchdog + * + * @param[in] interval - The new interval value +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/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..5623d246d --- /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,411 @@ +From 55db62a92dff4bfc3d34c590b33d9da4e7706b9d Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 3 Jul 2019 06:12:55 +0800 +Subject: [PATCH] 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> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 289 ++++++++++++++++++++++++++++++++++++++++++++++ + transporthandler.hpp | 33 ++++++ + 3 files changed, 323 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 2b72d23..856588e 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -42,6 +42,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 bb624c4..25062ae 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -36,6 +36,9 @@ static const std::array<std::string, 3> ipAddressEnablesType = { + "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only", + "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"}; + ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; ++ + std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; + + using namespace phosphor::logging; +@@ -1631,6 +1634,285 @@ void createNetworkTimer() + } + } + ++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; ++} ++ ++void initializeSOLInProgress() ++{ ++ ipmi::ChannelInfo chInfo; ++ for (int chNum = 0; chNum < ipmi::maxIpmiChannels; chNum++) ++ { ++ if (!ipmi::isValidChannel(static_cast<uint8_t>(chNum))) ++ { ++ continue; ++ } ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(chNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ continue; ++ } ++ if (setSOLParameter("Progress", static_cast<uint8_t>(0), chNum) < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error initialize sol progress"); ++ } ++ } ++} ++ ++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 ++ ++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", (configParamData1 & 0x7), ++ 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() + { + // As this timer is only for transport handler +@@ -1648,5 +1930,12 @@ void register_netfn_transport_functions() + ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, + ipmi_transport_get_lan, PRIVILEGE_OPERATOR); + ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdSetSolConfigParameters, ++ ipmi::Privilege::Admin, setSOLConfParams); ++ ++ // Initialize dbus property progress to 0 every time sol manager restart. ++ initializeSOLInProgress(); ++ + return; + } +diff --git a/transporthandler.hpp b/transporthandler.hpp +index bd23391..1237658 100644 +--- a/transporthandler.hpp ++++ b/transporthandler.hpp +@@ -1,5 +1,6 @@ + #pragma once + ++#include <ipmid/api-types.hpp> + #include <ipmid/types.hpp> + #include <string> + // IPMI commands for Transport net functions. +@@ -8,6 +9,8 @@ enum ipmi_netfn_storage_cmds + // Get capability bits + IPMI_CMD_SET_LAN = 0x01, + IPMI_CMD_GET_LAN = 0x02, ++ IPMI_CMD_SET_SOL_CONF_PARAMS = 0x21, ++ IPMI_CMD_GET_SOL_CONF_PARAMS = 0x22, + }; + + // Command specific completion codes +@@ -186,3 +189,33 @@ void commitNetworkChanges(); + * @param[in] channel: channel number. + */ + void applyChanges(int channel); ++ ++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; +-- +2.7.4 + 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..01a3e49b8 --- /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,260 @@ +From e8ad148601fc3b45fac9092fdd45c537433e662f 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] 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> +--- + 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 44c2181..0fcac4e 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,6 +41,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 25062ae..9ba2868 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1719,6 +1719,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; ++} ++ + void initializeSOLInProgress() + { + ipmi::ChannelInfo chInfo; +@@ -1913,6 +1935,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() + { + // As this timer is only for transport handler +@@ -1934,6 +2121,10 @@ void register_netfn_transport_functions() + ipmi::transport::cmdSetSolConfigParameters, + ipmi::Privilege::Admin, setSOLConfParams); + ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdGetSolConfigParameters, ++ ipmi::Privilege::User, getSOLConfParams); ++ + // Initialize dbus property progress to 0 every time sol manager restart. + initializeSOLInProgress(); + +-- +2.7.4 + 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..f29111758 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch @@ -0,0 +1,289 @@ +From 00fb92edcb4229eeb5b46c4eb206ba7d70e241fc 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 +chassis state transitions. This allows each chassis control action +to more closely follow the behavior defined in the IPMI spec. + +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, 52 insertions(+), 154 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 88bf84b..ad564e2 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> + +@@ -712,59 +713,63 @@ ipmi_ret_t ipmi_set_chassis_cap(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + //------------------------------------------ + // 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) ++ try + { +- log<level::ERR>("Failed to initiate transition", +- entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str())); ++ 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; + } + + namespace power_policy +@@ -1033,76 +1038,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 +@@ -1115,61 +1050,24 @@ 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 = initiateChassisStateTransition( ++ State::Chassis::Transition::Reset); ++ 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 = initiateChassisStateTransition( ++ State::Chassis::Transition::PowerCycle); + 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: + break; + + default: +-- +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..685e7c39d --- /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>((req.timer_action >> 4) & ++ wdPreTimeoutInterruptMask); ++ 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/0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch new file mode 100644 index 000000000..6a7b056ab --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch @@ -0,0 +1,29 @@ +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 2938d23..bc5df29 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -445,23 +445,21 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse)); + } + ++ res.expire_flags = timerUseExpirationFlags; + if (wd_prop.enabled) + { + res.timer_use |= wd_running; + res.present_countdown = htole16(wd_prop.timeRemaining / 100); +- res.expire_flags = 0; + } + else + { + if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved) + { + res.present_countdown = res.initial_countdown; +- res.expire_flags = 0; + } + else + { + res.present_countdown = 0; +- res.expire_flags = timerUseExpirationFlags; + } + } + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch new file mode 100644 index 000000000..57a31c991 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0064-Update-provisioning-mode-filter-logic.patch @@ -0,0 +1,286 @@ +From 3279300bb9afd1f169b35b7830d7f054045ab35f Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Tue, 18 Jun 2019 19:42:30 +0530 +Subject: [PATCH] Update provisioning mode filter logic + +Updated provisioning mode filtering logic support. Based on the +RestrictionMode property, Host (system) interface commands will be +filtered as per the allowed list in ProvisionedHostWhitelist once +POST complete is achieved. No commands will be allowed in +ProvisionedHostDisabled after POST complete and in all other cases +filterning logic will not be applied. + +Tested +1. Verified the filtering logic through EFI shell and made sure +filtering logic is applied when RestrictionMode is in +ProvisionedHostWhitelist mode +2. Verified no filtering logic is applied in normal modes +3. Made sure BIOS is able to execute commands, which are not in +whitelist (Note: New whitelist conf is under review). + +Change-Id: I7a14e827d70e2d8d6975e600a0fd00e2a790bc22 +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + whitelist-filter.cpp | 155 ++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 122 insertions(+), 33 deletions(-) + +diff --git a/whitelist-filter.cpp b/whitelist-filter.cpp +index 9f1e7c8..2c56087 100644 +--- a/whitelist-filter.cpp ++++ b/whitelist-filter.cpp +@@ -25,6 +25,7 @@ namespace + */ + class WhitelistFilter + { ++ + public: + WhitelistFilter(); + ~WhitelistFilter() = default; +@@ -35,17 +36,26 @@ class WhitelistFilter + + private: + void postInit(); +- void cacheRestrictedMode(); ++ void cacheRestrictedAndPostCompleteMode(); + void handleRestrictedModeChange(sdbusplus::message::message& m); ++ void handlePostCompleteChange(sdbusplus::message::message& m); + ipmi::Cc filterMessage(ipmi::message::Request::ptr request); + +- bool restrictedMode = true; ++ sdbusplus::xyz::openbmc_project::Control::Security::server:: ++ RestrictionMode::Modes restrictionMode = ++ sdbusplus::xyz::openbmc_project::Control::Security::server:: ++ RestrictionMode::Modes::ProvisionedHostWhitelist; ++ bool postCompleted = false; + std::shared_ptr<sdbusplus::asio::connection> bus; + std::unique_ptr<settings::Objects> objects; ++ std::unique_ptr<settings::Objects> postCompleteObj; + std::unique_ptr<sdbusplus::bus::match::match> modeChangeMatch; ++ std::unique_ptr<sdbusplus::bus::match::match> postCompleteMatch; + + static constexpr const char restrictionModeIntf[] = + "xyz.openbmc_project.Control.Security.RestrictionMode"; ++ static constexpr const char* systemOsStatusIntf = ++ "xyz.openbmc_project.State.OperatingSystem.Status"; + }; + + WhitelistFilter::WhitelistFilter() +@@ -63,16 +73,22 @@ WhitelistFilter::WhitelistFilter() + post_work([this]() { postInit(); }); + } + +-void WhitelistFilter::cacheRestrictedMode() ++void WhitelistFilter::cacheRestrictedAndPostCompleteMode() + { + using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; + std::string restrictionModeSetting; + std::string restrictionModeService; ++ std::string systemOsStatusPath; ++ std::string systemOsStatusService; + try + { + restrictionModeSetting = objects->map.at(restrictionModeIntf).at(0); + restrictionModeService = + objects->service(restrictionModeSetting, restrictionModeIntf); ++ ++ systemOsStatusPath = postCompleteObj->map.at(systemOsStatusIntf).at(0); ++ systemOsStatusService = ++ postCompleteObj->service(systemOsStatusPath, systemOsStatusIntf); + } + catch (const std::out_of_range& e) + { +@@ -80,26 +96,50 @@ void WhitelistFilter::cacheRestrictedMode() + "Could not look up restriction mode interface from cache"); + return; + } ++ + bus->async_method_call( + [this](boost::system::error_code ec, ipmi::Value v) { + if (ec) + { + log<level::ERR>("Error in RestrictionMode Get"); + // Fail-safe to true. +- restrictedMode = true; ++ restrictionMode = ++ RestrictionMode::Modes::ProvisionedHostWhitelist; + return; + } + auto mode = std::get<std::string>(v); +- auto restrictionMode = +- RestrictionMode::convertModesFromString(mode); +- restrictedMode = +- (restrictionMode == RestrictionMode::Modes::Whitelist); +- log<level::INFO>((restrictedMode ? "Set restrictedMode = true" +- : "Set restrictedMode = false")); ++ restrictionMode = RestrictionMode::convertModesFromString(mode); ++ log<level::INFO>( ++ "Read restriction mode", ++ entry("VALUE=%d", static_cast<int>(restrictionMode))); + }, + restrictionModeService, restrictionModeSetting, + "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf, + "RestrictionMode"); ++ ++ bus->async_method_call( ++ [this](boost::system::error_code ec, const ipmi::Value& v) { ++ if (ec) ++ { ++ log<level::ERR>("Error in OperatingSystemState Get"); ++ postCompleted = true; ++ return; ++ } ++ auto value = std::get<std::string>(v); ++ if (value == "Standby") ++ { ++ postCompleted = true; ++ } ++ else ++ { ++ postCompleted = false; ++ } ++ log<level::INFO>("Read POST complete value", ++ entry("VALUE=%d", postCompleted)); ++ }, ++ systemOsStatusService, systemOsStatusPath, ++ "org.freedesktop.DBus.Properties", "Get", systemOsStatusIntf, ++ "OperatingSystemState"); + } + + void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) +@@ -112,23 +152,44 @@ void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m) + { + if (property.first == "RestrictionMode") + { +- RestrictionMode::Modes restrictionMode = +- RestrictionMode::convertModesFromString( +- std::get<std::string>(property.second)); +- restrictedMode = +- (restrictionMode == RestrictionMode::Modes::Whitelist); +- log<level::INFO>((restrictedMode +- ? "Updated restrictedMode = true" +- : "Updated restrictedMode = false")); ++ restrictionMode = RestrictionMode::convertModesFromString( ++ std::get<std::string>(property.second)); ++ log<level::INFO>( ++ "Updated restriction mode", ++ entry("VALUE=%d", static_cast<int>(restrictionMode))); ++ } ++ } ++} ++void WhitelistFilter::handlePostCompleteChange(sdbusplus::message::message& m) ++{ ++ std::string intf; ++ std::vector<std::pair<std::string, ipmi::Value>> propertyList; ++ m.read(intf, propertyList); ++ for (const auto& property : propertyList) ++ { ++ if (property.first == "OperatingSystemState") ++ { ++ std::string value = std::get<std::string>(property.second); ++ if (value == "Standby") ++ { ++ postCompleted = true; ++ } ++ else ++ { ++ postCompleted = false; ++ } ++ log<level::INFO>(postCompleted ? "Updated to POST Complete" ++ : "Updated to !POST Complete"); + } + } + } +- + void WhitelistFilter::postInit() + { + objects = std::make_unique<settings::Objects>( + *bus, std::vector<settings::Interface>({restrictionModeIntf})); +- if (!objects) ++ postCompleteObj = std::make_unique<settings::Objects>( ++ *bus, std::vector<settings::Interface>({systemOsStatusIntf})); ++ if (!objects || !postCompleteObj) + { + log<level::ERR>( + "Failed to create settings object; defaulting to restricted mode"); +@@ -136,37 +197,65 @@ void WhitelistFilter::postInit() + } + + // Initialize restricted mode +- cacheRestrictedMode(); ++ cacheRestrictedAndPostCompleteMode(); + // Wait for changes on Restricted mode +- std::string filterStr; ++ std::string filterStrModeChange; ++ std::string filterStrPostComplete; + try + { +- filterStr = sdbusplus::bus::match::rules::propertiesChanged( ++ filterStrModeChange = sdbusplus::bus::match::rules::propertiesChanged( + objects->map.at(restrictionModeIntf).at(0), restrictionModeIntf); ++ filterStrPostComplete = sdbusplus::bus::match::rules::propertiesChanged( ++ postCompleteObj->map.at(systemOsStatusIntf).at(0), ++ systemOsStatusIntf); + } + catch (const std::out_of_range& e) + { +- log<level::ERR>("Failed to determine restriction mode filter string"); ++ log<level::ERR>("Failed to determine restriction mode / POST complete " ++ "filter string"); + return; + } + modeChangeMatch = std::make_unique<sdbusplus::bus::match::match>( +- *bus, filterStr, [this](sdbusplus::message::message& m) { ++ *bus, filterStrModeChange, [this](sdbusplus::message::message& m) { + handleRestrictedModeChange(m); + }); ++ postCompleteMatch = std::make_unique<sdbusplus::bus::match::match>( ++ *bus, filterStrPostComplete, [this](sdbusplus::message::message& m) { ++ handlePostCompleteChange(m); ++ }); + } + + ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request) + { +- if (request->ctx->channel == ipmi::channelSystemIface && restrictedMode) ++ using namespace sdbusplus::xyz::openbmc_project::Control::Security::server; ++ ++ if (request->ctx->channel == ipmi::channelSystemIface && ++ (restrictionMode != RestrictionMode::Modes::None && ++ restrictionMode != RestrictionMode::Modes::Provisioning)) + { +- if (!std::binary_search( +- whitelist.cbegin(), whitelist.cend(), +- std::make_pair(request->ctx->netFn, request->ctx->cmd))) ++ if (!postCompleted) + { +- log<level::ERR>("Net function not whitelisted", +- entry("NETFN=0x%X", int(request->ctx->netFn)), +- entry("CMD=0x%X", int(request->ctx->cmd))); +- return ipmi::ccInsufficientPrivilege; ++ // Allow all commands, till POST is not completed ++ return ipmi::ccSuccess; ++ } ++ switch (restrictionMode) ++ { ++ case RestrictionMode::Modes::ProvisionedHostWhitelist: ++ { ++ if (!std::binary_search( ++ whitelist.cbegin(), whitelist.cend(), ++ std::make_pair(request->ctx->netFn, request->ctx->cmd))) ++ { ++ log<level::ERR>( ++ "Net function not whitelisted", ++ entry("NETFN=0x%X", int(request->ctx->netFn)), ++ entry("CMD=0x%X", int(request->ctx->cmd))); ++ return ipmi::ccInsufficientPrivilege; ++ } ++ break; ++ } ++ default: // for whitelist, blacklist & HostDisabled ++ return ipmi::ccInsufficientPrivilege; + } + } + return ipmi::ccSuccess; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-Valid-VLANID-should-be-1-4095-as-in-802.1VLAN-spec.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-Valid-VLANID-should-be-1-4095-as-in-802.1VLAN-spec.patch new file mode 100644 index 000000000..f8f71338a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0066-Valid-VLANID-should-be-1-4095-as-in-802.1VLAN-spec.patch @@ -0,0 +1,44 @@ +From 07caf4cc516601c93d12bbe89b4afb0284201dff Mon Sep 17 00:00:00 2001 +From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +Date: Fri, 2 Aug 2019 14:18:31 +0530 +Subject: [PATCH] Valid VLANID should be 1-4095 as in 802.1VLAN spec + +Added the VLAN ID checking condition in Set LAN configuration + +Unit test: +Verified VLAN ID 1-4095 is allowed and CC returns for 0 & > 4095 + +Change-Id: I1737986ed7adb727758dedb84b851ba2c208cea3 +Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com> +--- + transporthandler.cpp | 4 ++++ + transporthandler.hpp | 1 + + 2 files changed, 5 insertions(+) + +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 44ddcef..ede6472 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -536,6 +536,10 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // We assume that ipmitool always send enable + // bit as 1. + vlan = le16toh(vlan); ++ if (vlan == 0 || vlan > maxValidVLANIDValue) ++ { ++ return IPMI_CC_INVALID_FIELD_REQUEST; ++ } + channelConf->vlanID = vlan; + } + break; +diff --git a/transporthandler.hpp b/transporthandler.hpp +index 1237658..d8805e1 100644 +--- a/transporthandler.hpp ++++ b/transporthandler.hpp +@@ -219,3 +219,4 @@ enum class Privilege : uint8_t + + constexpr uint8_t progressMask = 0x03; + constexpr uint8_t enableMask = 0x01; ++constexpr uint16_t maxValidVLANIDValue = 4095; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/host-ipmid-whitelist.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/host-ipmid-whitelist.conf new file mode 100644 index 000000000..deed53b0b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/host-ipmid-whitelist.conf @@ -0,0 +1,50 @@ +#<NetFn>:<Command +0x00:0x00 //<Chassis>:<Chassis Capabiliti> +0x00:0x01 //<Chassis>:<Get Chassis Status> +0x00:0x07 //<Chassis>:<Get System Restart Cause> +0x00:0x09 //<Chassis>:<Get System Boot Options> +0x00:0x0F //<Chassis>:<Get POH Counter Command> +0x04:0x02 //<Sensor/Event>:<Platform event> +0x04:0x2D //<Sensor/Event>:<Get Sensor Reading> +0x04:0x2F //<Sensor/Event>:<Get Sensor Type> +0x06:0x01 //<App>:<Get Device ID> +0x06:0x04 //<App>:<Get Self Test Results> +0x06:0x07 //<App>:<Get ACPI Power State> +0x06:0x08 //<App>:<Get Device GUID> +0x06:0x22 //<App>:<Reset Watchdog Timer> +0x06:0x24 //<App>:<Set Watchdog Timer> +0x06:0x25 //<App>:<Get Watchdog Timer> +0x06:0x2F //<App>:<Get BMC Global Enables> +0x06:0x31 //<App>:<Get Message Flags> +0x06:0x35 //<App>:<Read Event Message Buffer> +0x06:0x36 //<App>:<Get BT Interface Capabilities> +0x06:0x37 //<App>:<Get System GUID> +0x06:0x42 //<App>:<Get Channel Info Command> +0x06:0x4E //<App>:<Get Channel Payload Support> +0x06:0x54 //<App>:<Get Channel Cipher Suites> +0x0A:0x10 //<Storage>:<Get FRU Inventory Area Info> +0x0A:0x11 //<Storage>:<Read FRU Data> +0x0A:0x20 //<Storage>:<Get SDR Repository Info> +0x0A:0x22 //<Storage>:<Reserve SDR Repository> +0x0A:0x23 //<Storage>:<Get SDR> +0x0A:0x40 //<Storage>:<Get SEL Info> +0x0A:0x42 //<Storage>:<Reserve SEL> +0x0A:0x44 //<Storage>:<Add SEL Entry> +0x0A:0x48 //<Storage>:<Get SEL Time> +0x0A:0x49 //<Storage>:<Set SEL Time> +0x0C:0x02 //<Transport>:<Get LAN 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> +0x2C:0x03 //<Group Extension>:<Get Power Limit> +0x2C:0x06 //<Group Extension>:<Get Asset Tag> +0x2C:0x07 //<Group Extension>:<Get Sensor Info> +0x2C:0x10 //<Group Extension>:<Get Temperature Readings> +0x30:0x27 //<OEM>:<Get Device Info> +0x30:0x31 //<OEM>:<Get AIC card FRU> +0x30:0x55 //<OEM>:<Get Power Restore Delay> +0x30:0x9A //<OEM>:<Get Processor Error Config> +0x30:0xB0 //<OEM>:<Get LED Status> +0x30:0xE9 //<OEM>:<Get BIOS Post Codes> + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/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..b09bbf890 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service @@ -0,0 +1,28 @@ +[Unit] +Description=Phosphor Inband IPMI +# TODO openbmc/openbmc#2059 - The wants/after below should be based on providers +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +After=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service +Wants=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +After=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service +Wants=mapper-wait@-xyz-openbmc_project-control-security-restriction_mode.service +After=mapper-wait@-xyz-openbmc_project-control-security-restriction_mode.service +Wants=mapper-wait@-xyz-openbmc_project-state-os.service +After=mapper-wait@-xyz-openbmc_project-state-os.service +Wants=clear-once.service +After=clear-once.service + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env ipmid +SyslogIdentifier=ipmid +RuntimeDirectory = ipmi +RuntimeDirectoryPreserve = yes +StateDirectory = ipmi + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend new file mode 100644 index 000000000..16bd9f757 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -0,0 +1,44 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# TODO: This should be removed, once up-stream bump up +# issue is resolved +#SRC_URI = "git://github.com/openbmc/phosphor-host-ipmid" +SRCREV = "9da3a75091e0bf0849e2555447e64a70f1dc3bfb" + +SRC_URI += "file://phosphor-ipmi-host.service \ + file://host-ipmid-whitelist.conf \ + file://0009-IPv6-Network-changes.patch \ + file://0010-fix-get-system-GUID-ipmi-command.patch \ + file://0013-ipmi-add-set-bios-id-to-whitelist.patch \ + file://0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch \ + file://0050-enable-6-oem-commands.patch \ + file://0053-Fix-keep-looping-issue-when-entering-OS.patch \ + file://0056-add-SetInProgress-to-get-set-boot-option-cmd.patch \ + file://0057-Add-timer-use-actions-support.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://0064-Enable-watchdog-to-save-useflag-after-host-power-off.patch \ + file://0064-Update-provisioning-mode-filter-logic.patch \ + file://0066-Valid-VLANID-should-be-1-4095-as-in-802.1VLAN-spec.patch \ + " + +# 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_configure_append(){ + cp -f ${WORKDIR}/host-ipmid-whitelist.conf ${S} +} + +do_install_append(){ + rm -f ${D}/${bindir}/phosphor-softpoweroff +} 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..f33be5760 --- /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 = "bbfd00abdbc6d2f7c0389eae91cc055a1d4fe0c3" 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..140d1b302 --- /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 = "2cdc49585235a6557c9cbb6c8b75c064fc02681a" + +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..24037a4cb --- /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 = "35ca150beb7d5faf2fe0ca44c87bc7b0ade0aee7" + +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..b27961109 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb @@ -0,0 +1,19 @@ +SUMMARY = "Node Manager Proxy" +DESCRIPTION = "The Node Manager Proxy provides a simple interface for communicating \ +with Management Engine via IPMB" + +SRC_URI = "git://git@github.com/Intel-BMC/node-manager;protocol=ssh" +SRCREV = "06e8a1072b05d42e63cf70e2ceac7390578c051d" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} = "node-manager-proxy.service" + +DEPENDS = "sdbusplus \ + phosphor-logging \ + boost" + +S = "${WORKDIR}/git/" +inherit cmake systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb new file mode 100644 index 000000000..dd48df0c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb @@ -0,0 +1,21 @@ +SUMMARY = "Phosphor LED Group Management for Intel" +PR = "r1" + +inherit native +inherit obmc-phosphor-utils + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES += "virtual/phosphor-led-manager-config-native" + +SRC_URI += "file://led.yaml" +S = "${WORKDIR}" + +# Overwrite the example led layout yaml file prior +# to building the phosphor-led-manager package +do_install() { + SRC=${S} + DEST=${D}${datadir}/phosphor-led-manager + install -D ${SRC}/led.yaml ${DEST}/led.yaml +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml new file mode 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..177f5c98f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb @@ -0,0 +1,15 @@ +SUMMARY = "Multi node manager" +DESCRIPTION = "Daemon to handle chassis level shared resources on multi-node platform" + +SRC_URI = "git://git@github.com/Intel-BMC/multi-node-manager.git;protocol=ssh" +SRCREV = "34d959285a3ca12c4bfefa4040d82d571c78843b" + +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +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/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..d20da7b35 --- /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/phosphor-u-boot-env-mgr" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +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/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..e97c40c1c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init @@ -0,0 +1,217 @@ +#!/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 +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 + +if grep -q debug-init /proc/cmdline; then + exec > /tmp/init.log 2>&1 + set -x +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 real ubifs backing store +RWFS_MNT=/tmp/.rwfs + +if grep -q "$RWFS_MNT" /proc/mounts; then + # quit - we have already run + exit 0 +fi +mkdir -p "$RWFS_MNT" + +mtd_by_name() { + local name="$1" + local mtd="/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)" + echo "$mtd" +} + +mtdnum_by_name() { + local name="$1" + local mtdnum="$(grep "$name" /proc/mtd | cut -c 4)" + echo "$mtdnum" +} + +NV_MTD=rwfs +NV_MTD_DEV="$(mtd_by_name ${NV_MTD})" +NV_MTD_NUM="$(mtdnum_by_name ${NV_MTD})" + +nvrw() { + local p="$1" + # Clear the work dir doing overlay mount + rm -rf "${RWFS_MNT}${p}.work" + mkdir -p "${RWFS_MNT}${p}" "${RWFS_MNT}${p}.work" + local mname=$(echo "rwnv${p}" | sed 's,/,,g') + local opts="lowerdir=${p},upperdir=${RWFS_MNT}${p},workdir=${RWFS_MNT}${p}.work,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 "${RWFS_MNT}/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 "${RWFS_MNT}/etc.work" + + # clean everything out of /home + rm -rf "${RWFS_MNT}/home" "${RWFS_MNT}/home.work" + + # clean everything out of /var + rm -rf "${RWFS_MNT}/var" "${RWFS_MNT}/var.work" + + echo "Files remaining: $(find $RWFS_MNT/)" + sync +} + +full_clean() { + log "restore-defaults: full_clean" + local OVL='' + for OVL in $NV_OVERLAYS; do + rm -rf "${RWFS_MNT}${OVL}" "${RWFS_MNT}${OVL}.work" + done + sync +} +# attach a UBI device to the MTD device +prepare_ubi_volume() { + local nv_num="$1" + local mtd="/dev/mtd${nv_num}" + local ubi="/dev/ubi${nv_num}" + if [ ! -e $ubi ]; then + if ! ubiattach -m "$nv_num" -d "$nv_num"; then + # the attach failed, so format the MTD device and try again + log "Warning! Failed to attach $ubi to $mtd." + log "UBI-formatting $mtd to attach again. Data on this device will be lost." + ubiformat -y "$mtd" + ubiattach -m "$nv_num" -d "$nv_num" + fi + fi + + # make a UBI volume on the UBI device + local vol="${ubi}_0" + if [ ! -e $vol ]; then + ubimkvol "$ubi" -N "$mtd" -m + fi +} + +reformat_ubi_volume() { + local nv_num="$1" + local mnt="$2" + local ubi="/dev/ubi${nv_num}" + local vol="${ubi}_0" + # unmount the volume to reformat it + umount -f "$mnt" + ubidetach -m $nv_num + ubiformat -y "$ubi" + prepare_ubi_volume $nv_num + # remount the UBIFS on the UBI volume + mount -t ubifs "$vol" "$mnt" + if [ $? -ne 0 ]; then + log "Failed to mount reformatted NV volume; system unstable" + fi +} + +# mount a UBIFS on the UBI volume +prepare_ubi_volume $NV_MTD_NUM +mount -t ubifs "/dev/ubi${NV_MTD_NUM}_0" "$RWFS_MNT" +if [ $? -ne 0 ]; then + log "Failed to mount NV volume; attempting recovery" + reformat_ubi_volume $NV_MTD_NUM $RWFS_MNT +fi + +# check for full factory reset: if so, ubiformat $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 +elif [ $restore_op -eq 3 ]; then + log "restore-defaults: reformat" + reformat_ubi_volume $NV_MTD_NUM $RWFS_MNT +fi +rm -f $RESTORE_FLAG + +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 "$RWFS_MNT$MACHINE_ID" ]; then + umount "/etc" + rm -f "$RWFS_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 UBIFS on the UBI volume + prepare_ubi_volume $SOFS_MTD_NUM + mount -t ubifs "/dev/ubi${SOFS_MTD_NUM}_0" "$SOFS_MNT" + if [ $? -ne 0 ]; then + log "Failed to mount SOFS volume; attempting recovery" + reformat_ubi_volume $SOFS_MTD_NUM $SOFS_MNT + fi +fi + +log "Finished mounting non-volatile overlays" + +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..53f42dbdf --- /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/prov-mode-mgr" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +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/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..fcdef4e02 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend @@ -0,0 +1,7 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git" +SRCREV = "3d300fca24b30864b3e9a4f5768cfe5e769458ae" + +# Enable threshold monitoring +EXTRA_OECMAKE += "-DSEL_LOGGER_MONITOR_THRESHOLD_EVENTS=ON" +EXTRA_OECMAKE += "-DREDFISH_LOG_MONITOR_PULSE_EVENTS=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service new file mode 100644 index 000000000..b8c3554ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service @@ -0,0 +1,10 @@ +[Unit] +Description= BMC Self-Test + +[Service] +Restart=always +ExecStart=/usr/bin/env selftest +SyslogIdentifier=selftest + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb new file mode 100644 index 000000000..da1d74207 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb @@ -0,0 +1,38 @@ +SUMMARY = "BMC Self Test service" +DESCRIPTION = "BMC Self Test service for subsystem diagnosis failure info" + +SRC_URI = "git://git@github.com/Intel-BMC/intel-self-test;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "d039998ad2c55aeae4191af30e15bbd3032508c1" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=fa818a259cbed7ce8bc2a22d35a464fc" + +inherit cmake +inherit obmc-phosphor-dbus-service +inherit obmc-phosphor-systemd +inherit pkgconfig pythonnative + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.selftest.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " + +EXTRA_OECMAKE = " -DENABLE_GTEST=OFF -DCMAKE_SKIP_RPATH=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-WA-enable-disable-control-code-into-cpusensor.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-WA-enable-disable-control-code-into-cpusensor.patch new file mode 100644 index 000000000..1e1fc9625 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors/0001-Add-WA-enable-disable-control-code-into-cpusensor.patch @@ -0,0 +1,50 @@ +From f9b4545af42fc673f81d043a8512db8ebfe58660 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +Date: Fri, 2 Aug 2019 12:02:58 -0700 +Subject: [PATCH] Add WA enable/disable control code into cpusensor + +This commit adds a PECI WA enable/disable control code. If 'UseWA' +isn't in CPU configuration or the setting is 0, the WA will be +disabled by writing 'N' on the peci_core module parameter. + +This is a temporary WA. + +Change-Id: I73ae9ac49c9382f3ebdc800c360e078418b124e9 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +--- + src/CPUSensorMain.cpp | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp +index 2a3ff16f8294..b4085fd1038d 100644 +--- a/src/CPUSensorMain.cpp ++++ b/src/CPUSensorMain.cpp +@@ -629,6 +629,25 @@ bool getCpuConfig( + std::cout << "type: " << type << "\n"; + } + ++ // Temporary WA ++ uint64_t useWA = 0; ++ auto findUseWA = config.second.find("UseWA"); ++ if (findUseWA != config.second.end()) ++ { ++ useWA = std::visit(VariantToUnsignedIntVisitor(), ++ findUseWA->second); ++ } ++ if (useWA == 0) ++ { ++ std::ofstream deviceFile( ++ "/sys/module/peci_core/parameters/use_wa"); ++ if (deviceFile.good()) ++ { ++ deviceFile << 'N'; ++ } ++ deviceFile.close(); ++ } ++ + cpuConfigs.emplace(bus, addr, name, State::OFF); + } + } +-- +2.7.4 + 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..082c87055 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -0,0 +1,10 @@ +SRCREV = "7fa475d3f27ec6c37503ff7ec0496acc2215da29" +SRC_URI = "git://github.com/openbmc/dbus-sensors.git" + +DEPENDS_append = " libgpiod" + +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" +SRC_URI += "file://0001-Add-WA-enable-disable-control-code-into-cpusensor.patch" + +#todo(cheng) remove this when synced upstream +SYSTEMD_SERVICE_${PN} += " xyz.openbmc_project.mcutempsensor.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..1a34e2478 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb @@ -0,0 +1,20 @@ +SUMMARY = "Settings" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} = "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..d6d9d2d20 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "Special mode manager daemon to handle manufacturing modes" +DESCRIPTION = "Daemon exposes the manufacturing mode property" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/special-mode-mgr" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "specialmodemgr.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/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..12fd75226 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "Service configuration manager daemon to control service properties" +DESCRIPTION = "Daemon controls service properies like port, channels, state etc.." + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/srvcfg-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +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/post-code-manager/0001-Implement-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch new file mode 100644 index 000000000..8915484cd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch @@ -0,0 +1,499 @@ +From 7d78e70735e1bce51ef34cfe128be68758de3447 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 19 Feb 2019 15:00:11 +0800 +Subject: [PATCH] Implement post code manager + +Implement method and properties defined in PostCode.interface.yaml +under phosphor-dbus-interfaces/xyz/openbmc_project/State/Boot +1. Method: std::vector<uint64_t> PostCode::getPostCodes(uint16_t index) +2. Properties: CurrentBootCycleIndex/MaxBootCycleNum + +Test-By: + Every cycle post codes is saved in "/var/lib/phosphor-post-code-manager" + "1" file is saved all post codes for cycle 1 + "2" file is saved all post codes for cycle 2 + "CurrentBootCycleIndex" file is saved the current boot cycle number. + root@wolfpass:/var/lib/phosphor-post-code-manager# ls + 1 2 CurrentBootCycleIndex + +Change-Id: Ia89b9121983261fef5573092d890beb84626ceeb +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + CMakeLists.txt | 45 ++++++ + MAINTAINERS | 45 ++++++ + inc/post_code.hpp | 152 ++++++++++++++++++ + ...penbmc_project.State.Boot.PostCode.service | 11 ++ + src/main.cpp | 61 +++++++ + src/post_code.cpp | 109 +++++++++++++ + 6 files changed, 423 insertions(+) + create mode 100644 CMakeLists.txt + create mode 100644 MAINTAINERS + create mode 100644 inc/post_code.hpp + create mode 100644 service_files/xyz.openbmc_project.State.Boot.PostCode.service + create mode 100644 src/main.cpp + create mode 100644 src/post_code.cpp + +diff --git a/CMakeLists.txt b/CMakeLists.txt +new file mode 100644 +index 0000000..594d839 +--- /dev/null ++++ b/CMakeLists.txt +@@ -0,0 +1,45 @@ ++cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) ++project(post-code-manager CXX) ++set(CMAKE_CXX_STANDARD 17) ++set(CMAKE_CXX_STANDARD_REQUIRED ON) ++ ++set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) ++include(GNUInstallDirs) ++include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc) ++include_directories(${CMAKE_CURRENT_BINARY_DIR}) ++ ++set(DBUS_OBJECT_NAME "xyz/openbmc_project/State/Boot/PostCode") ++set(DBUS_INTF_NAME "xyz.openbmc_project.State.Boot.PostCode") ++ ++add_definitions(-DDBUS_OBJECT_NAME="/${DBUS_OBJECT_NAME}") ++add_definitions(-DDBUS_INTF_NAME="${DBUS_INTF_NAME}") ++set(SRC_FILES src/post_code.cpp ++ src/main.cpp ) ++set ( SERVICE_FILES ++ service_files/xyz.openbmc_project.State.Boot.PostCode.service ) ++ ++# import sdbusplus ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(SDBUSPLUSPLUS sdbusplus REQUIRED) ++include_directories(${SDBUSPLUSPLUS_INCLUDE_DIRS}) ++link_directories(${SDBUSPLUSPLUS_LIBRARY_DIRS}) ++find_program(SDBUSPLUSPLUS sdbus++) ++ ++# import phosphor-logging ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(LOGGING phosphor-logging REQUIRED) ++include_directories(${LOGGING_INCLUDE_DIRS}) ++link_directories(${LOGGING_LIBRARY_DIRS}) ++ ++# phosphor-dbus-interfaces ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(DBUSINTERFACE phosphor-dbus-interfaces REQUIRED) ++include_directories(${DBUSINTERFACE_INCLUDE_DIRS}) ++link_directories(${DBUSINTERFACE_LIBRARY_DIRS}) ++ ++add_executable(${PROJECT_NAME} ${SRC_FILES}) ++target_link_libraries(${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} ) ++target_link_libraries(${PROJECT_NAME} "${SDBUSPLUSPLUS_LIBRARIES} -lstdc++fs -lphosphor_dbus") ++ ++install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) ++install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/) +\ No newline at end of file +diff --git a/MAINTAINERS b/MAINTAINERS +new file mode 100644 +index 0000000..de6cc54 +--- /dev/null ++++ b/MAINTAINERS +@@ -0,0 +1,45 @@ ++How to use this list: ++ Find the most specific section entry (described below) that matches where ++ your change lives and add the reviewers (R) and maintainers (M) as ++ reviewers. You can use the same method to track down who knows a particular ++ code base best. ++ ++ Your change/query may span multiple entries; that is okay. ++ ++ If you do not find an entry that describes your request at all, someone ++ forgot to update this list; please at least file an issue or send an email ++ to a maintainer, but preferably you should just update this document. ++ ++Description of section entries: ++ ++ Section entries are structured according to the following scheme: ++ ++ X: NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!> ++ X: ... ++ . ++ . ++ . ++ ++ Where REPO_NAME is the name of the repository within the OpenBMC GitHub ++ organization; FILE_PATH is a file path within the repository, possibly with ++ wildcards; X is a tag of one of the following types: ++ ++ M: Denotes maintainer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; ++ if omitted from an entry, assume one of the maintainers from the ++ MAINTAINERS entry. ++ R: Denotes reviewer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>; ++ these people are to be added as reviewers for a change matching the repo ++ path. ++ F: Denotes forked from an external repository; has fields URL. ++ ++ Line comments are to be denoted "# SOME COMMENT" (typical shell style ++ comment); it is important to follow the correct syntax and semantics as we ++ may want to use automated tools with this file in the future. ++ ++ A change cannot be added to an OpenBMC repository without a MAINTAINER's ++ approval; thus, a MAINTAINER should always be listed as a reviewer. ++ ++START OF MAINTAINERS LIST ++------------------------- ++ ++M: Kuiying Wang <kuiying.wang@intel.com> <kuiyingw> +\ No newline at end of file +diff --git a/inc/post_code.hpp b/inc/post_code.hpp +new file mode 100644 +index 0000000..84c8b3e +--- /dev/null ++++ b/inc/post_code.hpp +@@ -0,0 +1,152 @@ ++/* ++// Copyright (c) 2019 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++#pragma once ++#include <fcntl.h> ++#include <unistd.h> ++#include <cereal/cereal.hpp> ++#include <experimental/filesystem> ++#include <cereal/access.hpp> ++#include <cereal/archives/json.hpp> ++#include <iostream> ++#include <fstream> ++#include <cereal/types/vector.hpp> ++ ++#include <xyz/openbmc_project/State/Boot/PostCode/server.hpp> ++#include <xyz/openbmc_project/Common/error.hpp> ++#include <phosphor-logging/elog-errors.hpp> ++#include <xyz/openbmc_project/State/Host/server.hpp> ++ ++#define MaxPostCodeCycles 100 ++ ++const static constexpr char *PostCodePath = ++ "/xyz/openbmc_project/state/boot/raw"; ++const static constexpr char *PropertiesIntf = ++ "org.freedesktop.DBus.Properties"; ++const static constexpr char *PostCodeListPath = ++ "/var/lib/phosphor-post-code-manager/"; ++const static constexpr char *CurrentBootCycleIndexName = ++ "CurrentBootCycleIndex"; ++const static constexpr char *HostStatePath = ++ "/xyz/openbmc_project/state/host0"; ++ ++ ++struct EventDeleter ++{ ++ void operator()(sd_event *event) const ++ { ++ event = sd_event_unref(event); ++ } ++}; ++using EventPtr = std::unique_ptr<sd_event, EventDeleter>; ++namespace fs = std::experimental::filesystem; ++namespace StateServer = sdbusplus::xyz::openbmc_project::State::server; ++ ++using post_code = ++ sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode; ++ ++struct PostCode : sdbusplus::server::object_t<post_code> ++{ ++ PostCode(sdbusplus::bus::bus& bus, const char* path, ++ EventPtr &event) : ++ sdbusplus::server::object_t<post_code>(bus, path), ++ bus(bus), ++ propertiesChangedSignalRaw( ++ bus, ++ sdbusplus::bus::match::rules::type::signal() + ++ sdbusplus::bus::match::rules::member("PropertiesChanged") + ++ sdbusplus::bus::match::rules::path(PostCodePath) + ++ sdbusplus::bus::match::rules::interface(PropertiesIntf), ++ [this](sdbusplus::message::message &msg) { ++ std::string objectName; ++ std::map<std::string, sdbusplus::message::variant<uint64_t>> msgData; ++ msg.read(objectName, msgData); ++ // Check if it was the Value property that changed. ++ auto valPropMap = msgData.find("Value"); ++ { ++ if (valPropMap != msgData.end()) ++ { ++ this->savePostCodes(sdbusplus::message::variant_ns::get<uint64_t>(valPropMap->second)); ++ } ++ } ++ }), ++ propertiesChangedSignalCurrentHostState( ++ bus, ++ sdbusplus::bus::match::rules::type::signal() + ++ sdbusplus::bus::match::rules::member("PropertiesChanged") + ++ sdbusplus::bus::match::rules::path(HostStatePath) + ++ sdbusplus::bus::match::rules::interface(PropertiesIntf), ++ [this](sdbusplus::message::message &msg) { ++ std::string objectName; ++ std::map<std::string, sdbusplus::message::variant<std::string>> msgData; ++ msg.read(objectName, msgData); ++ // Check if it was the Value property that changed. ++ auto valPropMap = msgData.find("CurrentHostState"); ++ { ++ if (valPropMap != msgData.end()) ++ { ++ StateServer::Host::HostState currentHostState = ++ StateServer::Host::convertHostStateFromString( ++ sdbusplus::message::variant_ns::get<std::string>(valPropMap->second)); ++ if (currentHostState == StateServer::Host::HostState::Off) ++ { ++ if (this->currentBootCycleIndex() >= this->maxBootCycleNum()) ++ { ++ this->currentBootCycleIndex(1); ++ } else{ ++ this->currentBootCycleIndex(this->currentBootCycleIndex() + 1); ++ } ++ this->postCodes.clear(); ++ } ++ } ++ } ++ }) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "PostCode is created"); ++ auto dir = fs::path(PostCodeListPath); ++ fs::create_directories(dir); ++ strPostCodeListPath = PostCodeListPath; ++ strCurrentBootCycleIndexName = CurrentBootCycleIndexName; ++ uint16_t index = 0; ++ deserialize(fs::path(strPostCodeListPath + strCurrentBootCycleIndexName), index); ++ currentBootCycleIndex(index); ++ maxBootCycleNum(MaxPostCodeCycles); ++ if (currentBootCycleIndex() >= maxBootCycleNum()) ++ { ++ currentBootCycleIndex(1); ++ } else{ ++ currentBootCycleIndex(currentBootCycleIndex() + 1); ++ } ++ } ++ ~PostCode() ++ { ++ ++ } ++ ++ std::vector<uint64_t> getPostCodes(uint16_t index) override; ++ ++ private: ++ sdbusplus::bus::bus& bus; ++ std::vector<uint64_t> postCodes; ++ std::string strPostCodeListPath; ++ std::string strCurrentBootCycleIndexName; ++ void savePostCodes(uint64_t code); ++ sdbusplus::bus::match_t propertiesChangedSignalRaw; ++ sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState; ++ fs::path serialize(const std::string& path); ++ bool deserialize(const fs::path& path, uint16_t& index); ++ bool deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes); ++}; +diff --git a/service_files/xyz.openbmc_project.State.Boot.PostCode.service b/service_files/xyz.openbmc_project.State.Boot.PostCode.service +new file mode 100644 +index 0000000..67bc43f +--- /dev/null ++++ b/service_files/xyz.openbmc_project.State.Boot.PostCode.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Post code manager ++ ++[Service] ++ExecStart=/usr/bin/env post-code-manager ++SyslogIdentifier=post-code-manager ++Type=dbus ++BusName=xyz.openbmc_project.State.Boot.PostCode ++ ++[Install] ++WantedBy=obmc-standby.target +diff --git a/src/main.cpp b/src/main.cpp +new file mode 100644 +index 0000000..4a74b29 +--- /dev/null ++++ b/src/main.cpp +@@ -0,0 +1,61 @@ ++/* ++// Copyright (c) 2019 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++#include "post_code.hpp" ++ ++int main(int argc, char* argv[]) ++{ ++ int ret = 0; ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Start post code manager service..."); ++ ++ sd_event* event = nullptr; ++ ret = sd_event_default(&event); ++ if (ret < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error creating a default sd_event handler"); ++ return ret; ++ } ++ EventPtr eventP{event}; ++ event = nullptr; ++ ++ sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); ++ sdbusplus::server::manager_t m{bus, DBUS_OBJECT_NAME}; ++ ++ bus.request_name(DBUS_INTF_NAME); ++ ++ PostCode postCode{bus, DBUS_OBJECT_NAME, eventP}; ++ ++ try ++ { ++ bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL); ++ ret = sd_event_loop(eventP.get()); ++ if (ret < 0) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error occurred during the sd_event_loop", ++ phosphor::logging::entry("RET=%d", ret)); ++ } ++ } ++ catch (std::exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return -1; ++ } ++ return 0; ++ ++} +diff --git a/src/post_code.cpp b/src/post_code.cpp +new file mode 100644 +index 0000000..983eeee +--- /dev/null ++++ b/src/post_code.cpp +@@ -0,0 +1,109 @@ ++/* ++// Copyright (c) 2019 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++#include "post_code.hpp" ++std::vector<uint64_t> PostCode::getPostCodes(uint16_t index) ++{ ++ std::vector<uint64_t> codes; ++ ++ if (currentBootCycleIndex() == index) ++ return postCodes; ++ deserializePostCodes(fs::path(strPostCodeListPath + std::to_string(index)), codes); ++ return codes; ++} ++void PostCode::savePostCodes(uint64_t code) ++{ ++ postCodes.push_back(code); ++ serialize(fs::path(PostCodeListPath)); ++ return; ++} ++ ++fs::path PostCode::serialize(const std::string& path) ++{ ++ try ++ { ++ uint16_t index = currentBootCycleIndex(); ++ fs::path fullPath(path + strCurrentBootCycleIndexName); ++ std::ofstream os(fullPath.c_str(), std::ios::binary); ++ cereal::JSONOutputArchive oarchive(os); ++ oarchive(index); ++ ++ std::ofstream osPostCodes((path + std::to_string(currentBootCycleIndex())).c_str(), std::ios::binary); ++ cereal::JSONOutputArchive oarchivePostCodes(osPostCodes); ++ oarchivePostCodes(postCodes); ++ ++ return path; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ } ++} ++ ++bool PostCode::deserialize(const fs::path& path, uint16_t& index) ++{ ++ try ++ { ++ if (fs::exists(path)) ++ { ++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); ++ cereal::JSONInputArchive iarchive(is); ++ iarchive(index); ++ return true; ++ } ++ return false; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return false; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ return false; ++ } ++ ++ return false; ++} ++ ++bool PostCode::deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes) ++{ ++ try ++ { ++ if (fs::exists(path)) ++ { ++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); ++ cereal::JSONInputArchive iarchive(is); ++ iarchive(codes); ++ return true; ++ } ++ return false; ++ } ++ catch (cereal::Exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return false; ++ } ++ catch (const fs::filesystem_error& e) ++ { ++ return false; ++ } ++ ++ return false; ++} +-- +2.19.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb new file mode 100644 index 000000000..8f2ead18a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb @@ -0,0 +1,34 @@ +SUMMARY = "Phosphor post code manager" +DESCRIPTION = "Post Code Manager" + +SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git" +SRCREV = "7f50dcaa6feb66cf5307b8a0e4742a36a50eed29" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +inherit cmake pkgconfig systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.State.Boot.PostCode.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += "file://0001-Implement-post-code-manager.patch" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb new file mode 100644 index 000000000..921352a5b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb @@ -0,0 +1,19 @@ +SUMMARY = "Callback Manager" +DESCRIPTION = "D-Bus daemon that registers matches that trigger method calls" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground;protocol=ssh" + +inherit cmake systemd +DEPENDS = "boost sdbusplus" + +PV = "0.1+git${SRCPV}" +SRCREV = "226ca2842e0a14ad56b4ebeedfd82ac2ea7e145e" + +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..0af64698a --- /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,1645 @@ +From a519a128b9a44b1798419bf3a653d58e266c60fb 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 | 290 ++------------------- + user_mgr.hpp | 9 +- + user_service.cpp | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + user_service.hpp | 233 +++++++++++++++++ + 6 files changed, 1139 insertions(+), 268 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 17146e6..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,49 +570,8 @@ bool UserMgr::userLockedForFailedAttempt(const std::string &userName, + + UserSSHLists UserMgr::getUserAndSshGrpList() + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- +- std::vector<std::string> userList; +- std::vector<std::string> sshUsersList; +- struct passwd pw, *pwp = nullptr; +- std::array<char, 1024> buffer{}; +- +- phosphor::user::File passwd(passwdFileName, "r"); +- if ((passwd)() == NULL) +- { +- log<level::ERR>("Error opening the passwd file"); +- elog<InternalFailure>(); +- } +- +- while (true) +- { +- auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(), +- &pwp); +- if ((r != 0) || (pwp == NULL)) +- { +- // Any error, break the loop. +- break; +- } +- // Add all users whose UID >= 1000 and < 65534 +- // and special UID 0. +- if ((pwp->pw_uid == 0) || +- ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) +- { +- std::string userName(pwp->pw_name); +- userList.emplace_back(userName); +- +- // ssh doesn't have separate group. Check login shell entry to +- // get all users list which are member of ssh group. +- std::string loginShell(pwp->pw_shell); +- if (loginShell == "/bin/sh") +- { +- sshUsersList.emplace_back(userName); +- } +- } +- } +- endpwent(); +- return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ // Call The User Service to get the User and SSUsers lists ++ return std::move(userSrvc->getUserAndSshGrpList()); + } + + size_t UserMgr::getIpmiUsersCount() +@@ -781,49 +582,14 @@ size_t UserMgr::getIpmiUsersCount() + + bool UserMgr::isUserEnabled(const std::string &userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- std::array<char, 4096> buffer{}; +- struct spwd spwd; +- struct spwd *resultPtr = nullptr; +- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), +- buffer.max_size(), &resultPtr); +- if (!status && (&spwd == resultPtr)) +- { +- if (resultPtr->sp_expire >= 0) +- { +- return false; // user locked out +- } +- return true; +- } +- return false; // assume user is disabled for any error. ++ // Call The User Service to verify if user is enabled ++ return userSrvc->isUserEnabled(userName); + } + + std::vector<std::string> UserMgr::getUsersInGroup(const std::string &groupName) + { +- std::vector<std::string> usersInGroup; +- // Should be more than enough to get the pwd structure. +- std::array<char, 4096> buffer{}; +- struct group grp; +- struct group *resultPtr = nullptr; +- +- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(), +- buffer.max_size(), &resultPtr); +- +- if (!status && (&grp == resultPtr)) +- { +- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) +- { +- usersInGroup.emplace_back(*(grp.gr_mem)); +- } +- } +- else +- { +- log<level::ERR>("Group not found", +- entry("GROUP=%s", groupName.c_str())); +- // Don't throw error, just return empty userList - fallback +- } +- return usersInGroup; ++ // Call The User Service to get the users that belong to a group ++ return std::move(userSrvc->getUsersInGroup(groupName)); + } + + DbusUserObj UserMgr::getPrivilegeMapperObject(void) +@@ -1052,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()) + { +@@ -1111,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); +@@ -1220,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..9bb602c +--- /dev/null ++++ b/user_service.cpp +@@ -0,0 +1,781 @@ ++/* ++// Copyright (c) 2018 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#include <grp.h> ++#include <pwd.h> ++#include <numeric> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++#include <boost/algorithm/string/split.hpp> ++#include "shadowlock.hpp" ++#include "file.hpp" ++#include "user_service.hpp" ++ ++/* anonymous namespace for User Service interface implementations. ++// Each class inside this namespace implements a special service ++// to be used for the User Manager class. This can be extended to use ++// other user management services and it should be as simple as ++// adding a new class which inherits from phosphor::user::UserServiceInterface ++*/ ++ ++namespace ++{ ++ ++std::string getCSVFromVector(std::vector<std::string> vec) ++{ ++ switch (vec.size()) ++ { ++ case 0: ++ { ++ return ""; ++ } ++ break; ++ ++ case 1: ++ { ++ return std::string{vec[0]}; ++ } ++ break; ++ ++ default: ++ { ++ return std::accumulate( ++ std::next(vec.begin()), vec.end(), vec[0], ++ [](std::string a, std::string b) { return a + ',' + b; }); ++ } ++ } ++} ++ ++bool removeStringFromCSV(std::string &csvStr, const std::string &delStr) ++{ ++ std::string::size_type delStrPos = csvStr.find(delStr); ++ if (delStrPos != std::string::npos) ++ { ++ // need to also delete the comma char ++ if (delStrPos == 0) ++ { ++ csvStr.erase(delStrPos, delStr.size() + 1); ++ } ++ else ++ { ++ csvStr.erase(delStrPos - 1, delStr.size() + 1); ++ } ++ return true; ++ } ++ return false; ++} ++ ++class ShadowService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ ShadowService() = default; ++ ++ ~ShadowService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::vector<std::string> userList; ++ std::vector<std::string> sshUsersList; ++ ++ struct passwd pw, *pwp = nullptr; ++ std::array<char, 1024> buffer{}; ++ ++ phosphor::user::File passwd(passwdFileName, "r"); ++ if ((passwd)() == NULL) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error opening the passwd file"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ while (true) ++ { ++ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), ++ buffer.max_size(), &pwp); ++ if ((r != 0) || (pwp == NULL)) ++ { ++ // Any error, break the loop. ++ break; ++ } ++ // Add all users whose UID >= 1000 and < 65534 ++ // and special UID 0. ++ if ((pwp->pw_uid == 0) || ++ ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) ++ { ++ std::string userName(pwp->pw_name); ++ userList.emplace_back(userName); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ std::string loginShell(pwp->pw_shell); ++ if (loginShell == "/bin/sh") ++ { ++ sshUsersList.emplace_back(userName); ++ } ++ } ++ } ++ endpwent(); ++ return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const override ++ { ++ std::vector<std::string> usersInGroup; ++ // Should be more than enough to get the pwd structure. ++ std::array<char, 4096> buffer{}; ++ struct group grp; ++ struct group *grpPtr = &grp; ++ struct group *resultPtr; ++ ++ int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ ++ if (!status && (grpPtr == resultPtr)) ++ { ++ for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) ++ { ++ usersInGroup.emplace_back(*(grp.gr_mem)); ++ } ++ } ++ else ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Group not found", ++ phosphor::logging::entry("GROUP=%s", groupName.c_str())); ++ // Don't throw error, just return empty usersInGroup - fallback ++ } ++ return usersInGroup; ++ } ++ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups.append(","); ++ } ++ groups.append(priv); ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), ++ "-m", "-N", "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ std::string newHomeDir = "/home/" + newUserName; ++ phosphor::user::executeCmd("/usr/sbin/usermod", "-l", ++ newUserName.c_str(), userName.c_str(), ++ "-d", newHomeDir.c_str(), "-m"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User rename failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void deleteUser(const std::string &userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/userdel", userName.c_str(), ++ "-r"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User delete failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same. ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), ++ "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user privilege / groups"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/usermod", userName.c_str(), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user enabled state"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string &userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ std::array<char, 4096> buffer{}; ++ struct spwd spwd; ++ struct spwd *resultPtr = nullptr; ++ int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ if (!status && (&spwd == resultPtr)) ++ { ++ if (resultPtr->sp_expire >= 0) ++ { ++ return false; // user locked out ++ } ++ return true; ++ } ++ return false; // assume user is disabled for any error. ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string &userName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::getUserGroups not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ return std::vector<std::string>(); ++ } ++ ++ void createGroup(const std::string &groupName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::createGroup not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ private: ++ static constexpr const char *passwdFileName = "/etc/passwd"; ++}; ++ ++class SSSDService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ SSSDService(const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++ { ++ ++ createGroup(lockedGrp); ++ for (const auto &g : groups) ++ { ++ createGroup(g); ++ } ++ for (const auto &p : privs) ++ { ++ createGroup(p); ++ } ++ } ++ ++ ~SSSDService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ std::vector<std::string> users; ++ std::vector<std::string> sshGroup; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/bin/getent", "-s", ++ "sss", "passwd"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get users information " ++ "from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ for (const auto &userLine : exeOutput) ++ { ++ std::vector<std::string> userInfo; ++ boost::algorithm::split(userInfo, userLine, ++ boost::algorithm::is_any_of(":")); ++ // At this point userInfo is a vector containing the passwd ++ // info for the user, so we know the correct positions: ++ // 0: User name. ++ // 1: Encrypted password. ++ // 2: User ID number (UID) ++ // 3: User's group ID number (GID) ++ // 4: Full name of the user (GECOS) ++ // 5: User home directory. ++ // 6: Login shell. ++ users.emplace_back(userInfo[0]); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ if (userInfo[6] == "/bin/sh") ++ { ++ sshGroup.emplace_back(userInfo[0]); ++ } ++ } ++ ++ return std::make_pair(std::move(users), std::move(sshGroup)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const override ++ { ++ std::vector<std::string> userList; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get group users from sssd service"); ++ // Don't throw error, just return empty usersInGroup - return ++ return userList; ++ } ++ // exeOutput should have 5 entries ++ // 0: Group ++ // 1: GID number ++ // 2: Member users ++ // 3: Is a member of ++ // 4: Member groups ++ exeOutput[2].erase( ++ exeOutput[2].begin(), ++ std::find(exeOutput[2].begin(), exeOutput[2].end(), ':')); ++ boost::algorithm::trim_left(exeOutput[2]); ++ boost::algorithm::split(userList, exeOutput[2], ++ boost::algorithm::is_any_of(",")); ++ return userList; ++ } ++ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const override ++ { ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_useradd", "-m", "-G", groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user in sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ // Sometimes the SSSD service needs some time to actually ++ // reflect the changes to the local DB to the NSS service, ++ // that is why we have this sleep here ... ++ std::this_thread::sleep_for(std::chrono::seconds(1)); ++ // update user status (locked/unlocked) ++ updateUserStatus(userName, enabled); ++ } ++ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const override ++ { ++ std::vector<std::string> exeOutput; ++ // Local Domain for sssd doesn't have a rename feature ++ // so we need to first create a new user and then delete ++ // the old one. ++ // The only issue with this is that the password for the ++ // user will have to be reseted since it is a new user being created. ++ ++ // Get original user groups ++ std::vector<std::string> groups = getUserGroups(userName); ++ // Check if it has a "ssh" group by looking for the shell login ++ try ++ { ++ exeOutput = phosphor::user::executeCmd( ++ "/usr/bin/getent", "-s", "sss", "passwd", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get information for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ if (exeOutput[0].find("/bin/sh")) ++ { ++ groups.emplace_back(phosphor::user::grpSsh); ++ } ++ // Call create user with the new user names and previous groups ++ // Priv is already part of the groups so that can be empty. ++ createUser(newUserName, groups, "", isUserEnabled(userName)); ++ ++ // Now delete original user ++ deleteUser(userName); ++ } ++ ++ void deleteUser(const std::string &userName) const override ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_userdel", "-r", ++ userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to delete user from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const override ++ { ++ // local domain sssd do not allow to update all list of groups, ++ // so we will remove all groups first (except for the user one) ++ // and then all all the ones that were passed ++ std::string oldGroups = getCSVFromVector(getUserGroups(userName)); ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_usermod", "-r", oldGroups.c_str(), "-a", ++ groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user groups and " ++ "priv from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const override ++ { ++ std::string enabledStr; ++ std::string lockedStr; ++ if (isUserEnabled(userName) == enabled) ++ { ++ return; ++ } ++ if (enabled) ++ { ++ enabledStr = "-r"; ++ lockedStr = "-U"; ++ } ++ else ++ { ++ enabledStr = "-a"; ++ lockedStr = "-L"; ++ } ++ try ++ { ++ // We will add a special locked group to identify the users ++ // that have been locked out of the system. ++ // TODO: sss_usermod is not locking user accounts for the ++ // LOCAL domain, need to find the correct PAM configuration ++ // to actually lockout users for SSSD. ++ // As a workaround we are using the pam module pam_listfile.so ++ // to lockout all users that belong to the locked group. ++ phosphor::user::executeCmd("/usr/sbin/sss_usermod", ++ enabledStr.c_str(), lockedGrp.c_str(), ++ lockedStr.c_str(), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user status from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string &userName) const override ++ { ++ std::vector<std::string> userGrps = getUserGroups(userName); ++ return std::find(userGrps.begin(), userGrps.end(), lockedGrp) == ++ userGrps.end(); ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string &userName) const override ++ { ++ std::vector<std::string> exeOutput; ++ try ++ { ++ exeOutput = ++ phosphor::user::executeCmd("/usr/bin/groups", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get groups for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ std::vector<std::string> groups; ++ boost::algorithm::split(groups, exeOutput[0], ++ boost::algorithm::is_any_of(" ")); ++ // Delete group that equals user name if it exists ++ auto userNameGroup = std::find(groups.begin(), groups.end(), userName); ++ if (userNameGroup != groups.end()) ++ { ++ groups.erase(userNameGroup); ++ } ++ return groups; ++ } ++ ++ void createGroup(const std::string &groupName) const override ++ { ++ try ++ { ++ if (!groupExists(groupName)) ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupadd", ++ groupName.c_str()); ++ } ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create group"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ private: ++ static const std::string lockedGrp; ++ ++ bool groupExists(const std::string &groupName) const ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ return false; ++ } ++ return true; ++ } ++}; ++ ++const std::string SSSDService::lockedGrp = "sssd_locked"; ++} // anonymous namespace ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++UserService::UserService(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::updateServiceType(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ usrSrvcImpl.reset(); ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::setServiceImpl(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ switch (srvcType) ++ { ++ case ServiceType::shadow: ++ { ++ usrSrvcImpl = std::make_unique<ShadowService>(); ++ } ++ break; ++ ++ case ServiceType::sssd: ++ { ++ usrSrvcImpl = std::make_unique<SSSDService>(groups, privs); ++ } ++ break; ++ ++ case ServiceType::none: ++ default: ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Invalid service type initialization!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ break; ++ } ++} ++ ++UserService::~UserService() ++{ ++} ++ ++phosphor::user::UserSSHLists UserService::getUserAndSshGrpList() const ++{ ++ return usrSrvcImpl->getUserAndSshGrpList(); ++} ++ ++std::vector<std::string> ++ UserService::getUsersInGroup(const std::string &groupName) const ++{ ++ return usrSrvcImpl->getUsersInGroup(groupName); ++} ++ ++void UserService::createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const ++{ ++ usrSrvcImpl->createUser(userName, groupNames, priv, enabled); ++} ++ ++void UserService::renameUser(const std::string &userName, ++ const std::string &newUserName) const ++{ ++ usrSrvcImpl->renameUser(userName, newUserName); ++} ++ ++void UserService::deleteUser(const std::string &userName) const ++{ ++ usrSrvcImpl->deleteUser(userName); ++} ++ ++void UserService::updateGroupsAndPriv( ++ const std::string &userName, const std::vector<std::string> &groupNames, ++ const std::string &priv) const ++{ ++ usrSrvcImpl->updateGroupsAndPriv(userName, groupNames, priv); ++} ++ ++void UserService::updateUserStatus(const std::string &userName, ++ const bool &enabled) const ++{ ++ usrSrvcImpl->updateUserStatus(userName, enabled); ++} ++ ++bool UserService::isUserEnabled(const std::string &userName) const ++{ ++ return usrSrvcImpl->isUserEnabled(userName); ++} ++ ++std::vector<std::string> ++ UserService::getUserGroups(const std::string &userName) const ++{ ++ return usrSrvcImpl->getUserGroups(userName); ++} ++ ++} // namespace user ++} // namespace phosphor +diff --git a/user_service.hpp b/user_service.hpp +new file mode 100644 +index 0000000..97a049b +--- /dev/null ++++ b/user_service.hpp +@@ -0,0 +1,233 @@ ++/* ++// Copyright (c) 2018 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++#include <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/User/Common/error.hpp> ++#include <phosphor-logging/log.hpp> ++#include <phosphor-logging/elog.hpp> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++using UserSSHLists = ++ std::pair<std::vector<std::string>, std::vector<std::string>>; ++using InternalFailure = ++ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; ++using InsufficientPermission = ++ sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission; ++ ++const std::string grpSsh = "ssh"; ++ ++template <typename... ArgTypes> ++std::vector<std::string> executeCmd(const char *path, ArgTypes &&... tArgs) ++{ ++ std::vector<std::string> stdOutput; ++ boost::process::ipstream stdOutStream; ++ boost::process::child execProg(path, const_cast<char *>(tArgs)..., ++ boost::process::std_out > stdOutStream); ++ std::string stdOutLine; ++ ++ while (stdOutStream && std::getline(stdOutStream, stdOutLine) && ++ !stdOutLine.empty()) ++ { ++ stdOutput.emplace_back(stdOutLine); ++ } ++ ++ execProg.wait(); ++ ++ int retCode = execProg.exit_code(); ++ if (retCode) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Command execution failed", ++ phosphor::logging::entry("PATH=%d", path), ++ phosphor::logging::entry("RETURN_CODE:%d", retCode)); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ return stdOutput; ++} ++ ++/** @class UserServiceInterface ++ * @brief Interface class for methods provided by the implemmentations ++ * of the user service. Provides the same methods as the UserService ++ * class. ++ */ ++class UserServiceInterface ++{ ++ public: ++ UserServiceInterface() = default; ++ virtual ~UserServiceInterface() = default; ++ virtual UserSSHLists getUserAndSshGrpList() const = 0; ++ virtual std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const = 0; ++ virtual void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, ++ const bool &enabled) const = 0; ++ virtual void renameUser(const std::string &userName, ++ const std::string &newUserName) const = 0; ++ virtual void deleteUser(const std::string &userName) const = 0; ++ virtual void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const = 0; ++ virtual void updateUserStatus(const std::string &userName, ++ const bool &enabled) const = 0; ++ virtual bool isUserEnabled(const std::string &userName) const = 0; ++ virtual std::vector<std::string> ++ getUserGroups(const std::string &userName) const = 0; ++ virtual void createGroup(const std::string &groupName) const = 0; ++}; ++ ++/** @class UserService ++ * @brief Responsible for managing the user service for the user manager. ++ * This service is the one responsible to actually change the user information ++ * of the application. It can support sevaral services, currently the ones ++ * supported are: ++ * ++ * 1) Shadow: Which uses the /etc/shadow file for updating the users ++ * 2) SSSD: Which uses the sssd service for a LOCAL domain only right now. ++ */ ++class UserService ++{ ++ public: ++ UserService() = delete; ++ UserService(const UserService &) = delete; ++ UserService &operator=(const UserService &) = delete; ++ UserService(UserService &&) = delete; ++ UserService &operator=(UserService &&) = delete; ++ ++ // Service Types implemented. None is used to validate. ++ enum class ServiceType ++ { ++ none, ++ shadow, ++ sssd ++ }; ++ ++ UserService(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ ~UserService(); ++ ++ /** @brief update the current Service type of the instance. ++ * This function is used to update in real time the service ++ * being used for the user management without restarting the ++ * whole service. ++ * ++ * @param[in] srvcType ++ * @param[in] groups ++ * @param[in] privs ++ */ ++ void updateServiceType(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ ++ /** @brief get user list and SSH group members list ++ * This method gets the list of users from the service. ++ * If the userlist reference is empty, all the users will be added ++ * and DBus notified about them. If the list is not empty, the function ++ * will only update list adding the missing ones to it. It will not remove ++ * any extra users on the list that are not part of the service! ++ * ++ */ ++ UserSSHLists getUserAndSshGrpList() const; ++ ++ /** @brief Get users in group. ++ * This method creates a new user as requested ++ * ++ * @param[in] groupName - Name of the group which has to be queried ++ */ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const; ++ ++ /** @brief create user method. ++ * This method creates a new user as requested ++ * ++ * @param[in] userName - Name of the user which has to be created ++ * @param[in] groupNames - Group names list, to which user has to be added. ++ * @param[in] priv - Privilege of the user. ++ * @param[in] enabled - State of the user enabled / disabled. ++ */ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const; ++ ++ /** @brief rename user method. ++ * This method renames the user as requested ++ * ++ * @param[in] userName - current name of the user ++ * @param[in] userName - user name to which it has to be renamed. ++ */ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const; ++ ++ /** @brief delete user method. ++ * This method deletes the user as requested ++ * ++ * @param[in] userName - Name of the user which has to be deleted ++ */ ++ void deleteUser(const std::string &userName) const; ++ ++ /** @brief Updates user Groups and Privilege. ++ * ++ * @param[in] userName - Name of the user which has to be modified ++ * @param[in] groupNames - Group names list for user. ++ * @param[in] priv - Privilege of the user. ++ */ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const; ++ ++ /** @brief Updates user status ++ * If enabled = false: User will be disabled ++ * If enabled = true : User will be enabled ++ * ++ * @param[in] userName - Name of the user ++ * @param[in] enabled - Status of the user: enabled / disabled? ++ */ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const; ++ ++ /** @brief Verify if user is enabled or not ++ * If enabled returns true ++ * If not enabled returns false ++ * ++ * @param[in] userName - Name of the user ++ */ ++ bool isUserEnabled(const std::string &userName) const; ++ ++ /** @brief Get the list of groups a user belongs to ++ * ++ * @param[in] userName - Name of the user ++ */ ++ std::vector<std::string> getUserGroups(const std::string &userName) const; ++ ++ private: ++ // User service implementation. ++ void setServiceImpl(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ std::unique_ptr<UserServiceInterface> usrSrvcImpl; ++}; ++ ++} // namespace user ++} // namespace phosphor +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend new file mode 100644 index 000000000..327be045d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SRC_URI = "git://github.com/openbmc/phosphor-user-manager;nobranch=1" +SRCREV = "1af1223304dbf7aaecd5f238227abee95cce8b39" + + +SRC_URI += " \ + file://0005-Added-suport-for-multiple-user-manager-services.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..f50ec86d1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb @@ -0,0 +1,21 @@ +SUMMARY = "Virtual Media Service" +DESCRIPTION = "Virtual Media Service" + +SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh;nobranch=1" +SRCREV = "0de77d616866a6251ce7e36db3285fda76b13873" + +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" + +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..950f4932d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb @@ -0,0 +1,35 @@ + +SUMMARY = "FRB2 timer service" +DESCRIPTION = "The FRB2 timer service will monitor the mailbox register 0\ +and start a watchdog for FRB2 if the data is 1(BIOS will write this value)" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://frb2-watchdog.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${PHOSPHORBASE}/LICENSE;md5=19407077e42b1ba3d653da313f1f5b4e" + +S = "${WORKDIR}" + +inherit cmake +inherit pkgconfig pythonnative + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + boost \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt new file mode 100644 index 000000000..bd5567d31 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (frb2-watchdog CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import libsystemd +find_package (PkgConfig REQUIRED) +pkg_check_modules (SYSTEMD libsystemd REQUIRED) +include_directories (${SYSTEMD_INCLUDE_DIRS}) +link_directories (${SYSTEMD_LIBRARY_DIRS}) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +# import phosphor-dbus-interfaces +find_package (PkgConfig REQUIRED) +pkg_check_modules (DBUSINTERFACE phosphor-dbus-interfaces REQUIRED) +include_directories (${DBUSINTERFACE_INCLUDE_DIRS}) +link_directories (${DBUSINTERFACE_LIBRARY_DIRS}) + +add_executable (frb2-watchdog frb2-watchdog.cpp) + +target_link_libraries (${PROJECT_NAME} systemd) +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} + phosphor_logging) +install (TARGETS frb2-watchdog DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp new file mode 100644 index 000000000..5356e95db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp @@ -0,0 +1,258 @@ +/* Copyright 2018 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <boost/container/flat_set.hpp> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <optional> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> +#include <sdbusplus/bus.hpp> +#include <sdbusplus/bus/match.hpp> +#include <sdbusplus/message.hpp> +#include <sdbusplus/timer.hpp> +#include <vector> +#include <xyz/openbmc_project/State/Watchdog/server.hpp> + +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred); + +static int mailboxDevFd = -1; + +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); +boost::asio::ip::tcp::socket mailBoxDevSocket(io); +boost::asio::deadline_timer pollTimer(io); +boost::asio::posix::stream_descriptor inputDevice(io); + +// mailbox registre data[0:0] for FRB2 enable bit +boost::asio::streambuf readBuf(1); +std::string dataRead; + +// FRB2 watchdog timeout is 6 minutes +static constexpr unsigned int frb2TimerIntervalMs = 360 * 1000; + +// mailbox device polling time interval is 2 seconds +static constexpr unsigned int pollMs = 2000; + +static constexpr unsigned int frb2Started = 1; +static constexpr unsigned int frb2Stopped = 0; + +// FRB2 status +static uint8_t frb2Status = frb2Stopped; + +static constexpr const char *mailboxDevName = "/dev/aspeed-mbox"; + +static constexpr const char frb2Bus[] = "xyz.openbmc_project.FRB2"; +static constexpr const char frb2Obj[] = "/xyz/openbmc_project/FRB2"; +static constexpr const char frb2Intf[] = "xyz.openbmc_project.FRB2"; + +static constexpr char powerBus[] = "xyz.openbmc_project.Chassis.Control.Power"; +static constexpr char powerPath[] = + "/xyz/openbmc_project/Chassis/Control/Power0"; +static constexpr char powerIntf[] = "xyz.openbmc_project.Chassis.Control.Power"; + +static constexpr char wdBus[] = "xyz.openbmc_project.Watchdog"; +static constexpr char wdPath[] = "/xyz/openbmc_project/watchdog/host0"; +static constexpr char wdIntf[] = "xyz.openbmc_project.State.Watchdog"; +static constexpr char propIntf[] = "org.freedesktop.DBus.Properties"; + +typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator; + +// check if FRB2 bit is 0x1 +std::pair<iterator, bool> matchFRB2(iterator begin, iterator end) +{ + unsigned char ch = 0; + iterator i = begin; + + while (i != end) + { + ch = static_cast<unsigned char>(*i); + if (ch & 0x1) + { + return std::make_pair(i, true); + } + i++; + } + + return std::make_pair(i, false); +} + +static void startRead() +{ + boost::asio::async_read_until(inputDevice, readBuf, matchFRB2, + [&](const boost::system::error_code &ec, + std::size_t bytes_transferred) { + handleResponse(ec, bytes_transferred); + }); +} + +template <typename T> void setProperty(const std::string &key, const T &val) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "setProperty", phosphor::logging::entry("KEY=%s", key.c_str())); + + try + { + conn->async_method_call( + [](const boost::system::error_code &err) { + if (err) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "async_method_call error!", + phosphor::logging::entry( + "ERROR=%s", + boost::system::system_error(err).what())); + } + }, + wdBus, wdPath, propIntf, "Set", wdIntf, key, + sdbusplus::message::variant_ns::variant<T>(val)); + } + catch (sdbusplus::exception::SdBusError &e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Dbus error!", phosphor::logging::entry("ERROR=%s", e.what())); + } +} +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred) +{ + std::istream responseStream(&readBuf); + std::string response; + int n = 0; + uint64_t interval = frb2TimerIntervalMs; + + std::getline(responseStream, response); + responseStream.clear(); + + if (err == boost::system::errc::bad_file_descriptor) + { + + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "bad file descriptor"); + return; // we're being destroyed + } + + if (!err) + { + // FRB2 is set by BIOS + if (frb2Stopped == frb2Status) + { + // start FRB2 watchdog + frb2Status = frb2Started; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 enable, start FRB2 watchdog"); + setProperty( + "ExpireAction", + std::string( + "xyz.openbmc_project.State.Watchdog.Action.HardReset")); + setProperty("Interval", interval); + setProperty("TimeRemaining", interval); + setProperty("Initialized", true); + setProperty("Enabled", true); + } + } + else if (err == boost::asio::error::misc_errors::not_found) + { + // FRB2 is clear, stop FRB2 watchdog if it is started + if (frb2Started == frb2Status) + { + frb2Status = frb2Stopped; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 is unset, stop FRB2 watchdog"); + setProperty("Enabled", false); + } + } + else + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "handleResponse error!", + phosphor::logging::entry("ERROR=%s", + boost::system::system_error(err).what())); + } + + pollTimer.expires_from_now(boost::posix_time::milliseconds(pollMs)); + pollTimer.async_wait( + [](const boost::system::error_code &ec) { startRead(); }); +} + +int main(int argc, char **argv) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "Monitor FRB2 signal"); + + sdbusplus::bus::match_t biosPostSignal( + static_cast<sdbusplus::bus::bus &>(*conn), + sdbusplus::bus::match::rules::type::signal() + + sdbusplus::bus::match::rules::member("PostCompleted") + + sdbusplus::bus::match::rules::path(powerPath) + + sdbusplus::bus::match::rules::interface(powerIntf), + [](sdbusplus::message::message &msg) { + uint8_t value = 0; + ssize_t rc = 0; + phosphor::logging::log<phosphor::logging::level::INFO>( + "BIOS post completed signal"); + // stop FRB2 and clean mailbox + value = 0; + rc = ::pwrite(mailboxDevFd, &value, 1, 0); + if (rc != 1) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox write error!"); + } + setProperty("Enabled", false); + frb2Status = frb2Stopped; + return; + }); + + conn->request_name(frb2Bus); + + auto server = sdbusplus::asio::object_server(conn); + + std::shared_ptr<sdbusplus::asio::dbus_interface> frb2Iface = + server.add_interface(frb2Obj, frb2Intf); + + frb2Iface->register_property("frb2Status", frb2Status); + + frb2Iface->initialize(); + + mailboxDevFd = ::open(mailboxDevName, O_RDWR | O_CLOEXEC); + if (mailboxDevFd < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox device open fail!"); + return -1; + } + + inputDevice.assign(mailboxDevFd); + + startRead(); + + io.run(); + + ::close(mailboxDevFd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Move-Phosphor-Watchdog-to-Not-Use-Service-Files.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Move-Phosphor-Watchdog-to-Not-Use-Service-Files.patch new file mode 100644 index 000000000..627dacef1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Move-Phosphor-Watchdog-to-Not-Use-Service-Files.patch @@ -0,0 +1,198 @@ +From d15cf914ad51207021451b12863d4b7585f4666c 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] Move Phosphor-Watchdog to Not Use Service Files + +Our power control does not use service files, update it +so that it calls properties directly. + +According to EPS, change the messageArgs in redfish about watchdog +action and pre-interrupt action. + +Tested: used ipmi to create watchdog event and system +was restarted. + +Set a watchdog (Timer action and pre-interrupt action both are none). + ipmitool raw 0x06 0x24 0x05 0x00 0x00 0x00 0x30 0x00 +Get the watchdog. + ipmitool mc watchdog get +Start the watchdog. + ipmitool mc watchdog reset +When timer expired, check messageArgs in Redfish with below url: +https://IP/redfish/v1/Systems/system/LogServices/EventLog/Entries. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + watchdog.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 108 insertions(+), 8 deletions(-) + +diff --git a/watchdog.cpp b/watchdog.cpp +index 9090760..4c8e480 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,44 @@ 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* powerActionHardReset = ++ "xyz.openbmc_project.State.Watchdog.Action.HardReset"; ++const static constexpr char* powerActionOff = ++ "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; ++const static constexpr char* powerActionPowerCycle = ++ "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; ++const static constexpr char* powerActionNone = ++ "xyz.openbmc_project.State.Watchdog.Action.None"; ++const static constexpr char* preInterruptNoAction = ++ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None"; ++ ++const static constexpr char* hardResteDescription = ++ "Hard Reset - System reset due to Watchdog timeout"; ++const static constexpr char* powerOffDescription = ++ "Power Down - System power down due to Watchdog timeout"; ++const static constexpr char* powerCycleDescription = ++ "Power Cycle - System power cycle due to Watchdog timeout"; ++const static constexpr char* timerExpiredDescription = "Timer expired"; ++const static constexpr char* preInterruptDescription = "Timer interrupt"; ++ ++namespace restart ++{ ++static constexpr const char* busName = "xyz.openbmc_project.Settings"; ++static constexpr const char* path = ++ "/xyz/openbmc_project/control/host0/restart_cause"; ++static constexpr const char* interface = ++ "xyz.openbmc_project.Common.RestartCause"; ++static constexpr const char* property = "RestartCause"; ++} // 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 + + void Watchdog::resetTimeRemaining(bool enableWatchdog) + { +@@ -102,12 +139,51 @@ uint64_t Watchdog::interval(uint64_t value) + // Optional callback function on timer expiration + void Watchdog::timeOutHandler() + { ++ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt(); + Action action = expireAction(); ++ std::string actionMessageArgs{}; ++ + if (!this->enabled()) + { + action = fallback->action; + } + ++ if (convertForMessage(action) == powerActionHardReset) ++ { ++ actionMessageArgs = hardResteDescription; ++ } ++ else if (convertForMessage(action) == powerActionOff) ++ { ++ actionMessageArgs = powerOffDescription; ++ } ++ else if (convertForMessage(action) == powerActionPowerCycle) ++ { ++ actionMessageArgs = powerCycleDescription; ++ } ++ else if (convertForMessage(action) == powerActionNone) ++ { ++ actionMessageArgs = timerExpiredDescription; ++ } ++ else ++ { ++ actionMessageArgs = "Reserved"; ++ } ++ ++ // 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", actionMessageArgs.c_str(), NULL); ++ ++ if (preInterruptNoAction != convertForMessage(preTimeoutInterruptAction)) ++ { ++ 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=%s", ++ preInterruptDescription, NULL); ++ } ++ + expiredTimerUse(currentTimerUse()); + + auto target = actionTargetMap.find(action); +@@ -128,10 +204,11 @@ void Watchdog::timeOutHandler() + + try + { +- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, +- SYSTEMD_INTERFACE, "StartUnit"); +- method.append(target->second); +- method.append("replace"); ++ auto 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 +219,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(); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0002-Stop-the-watchdog-when-the-host-is-going-to-off.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0002-Stop-the-watchdog-when-the-host-is-going-to-off.patch new file mode 100644 index 000000000..016cf063a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0002-Stop-the-watchdog-when-the-host-is-going-to-off.patch @@ -0,0 +1,118 @@ +From b05da90d7023199e23daf8fbb49455138332f241 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Wed, 24 Jul 2019 16:21:13 +0800 +Subject: [PATCH] Stop the watchdog when the host is going to off + +After the host is off, check the WDT status, if it is running, +needs to stop it + +Tested: +Set a watchdog with a long time expiration(Timer action is none, +Timer Use is OEM and Initial Countdown is 435.1 second). + ipmitool raw 0x06 0x24 0x05 0x00 0x00 0x00 0xff 0x10 +Get the watchdog. + ipmitool mc watchdog get +Start the watchdog. + ipmitool mc watchdog reset +Host off. + ipmitool chassis power off +Get the watchdog. + ipmitool mc watchdog get +Check the watchdog status, expect watchdog is stoped. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + watchdog.cpp | 21 +++++++++++++++++++++ + watchdog.hpp | 23 ++++++++++++++++++++++- + 2 files changed, 43 insertions(+), 1 deletion(-) + +diff --git a/watchdog.cpp b/watchdog.cpp +index 4c8e480..fa58ef4 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -21,6 +21,10 @@ using namespace phosphor::logging; + using sdbusplus::exception::SdBusError; + using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; + ++const static constexpr char* currentPowerState = "CurrentPowerState"; ++const static constexpr char* powerStatusOff = ++ "xyz.openbmc_project.State.Chassis.PowerState.Off"; ++ + const static constexpr char* powerActionHardReset = + "xyz.openbmc_project.State.Watchdog.Action.HardReset"; + const static constexpr char* powerActionOff = +@@ -60,6 +64,23 @@ static constexpr const char* interface = "xyz.openbmc_project.State.Chassis"; + static constexpr const char* request = "RequestedPowerTransition"; + } // namespace chassis + ++void Watchdog::powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props) ++{ ++ const auto iter = props.find(currentPowerState); ++ if (iter != props.end()) ++ { ++ const std::string* powerState = std::get_if<std::string>(&iter->second); ++ if (powerState && (*powerState == powerStatusOff)) ++ { ++ if (timerEnabled()) ++ { ++ enabled(false); ++ } ++ } ++ } ++} ++ + void Watchdog::resetTimeRemaining(bool enableWatchdog) + { + timeRemaining(interval()); +diff --git a/watchdog.hpp b/watchdog.hpp +index 7de9bb3..dcbecd1 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/chassis0", ++ "xyz.openbmc_project.State.Chassis"), ++ [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/0003-Set-PreTimeoutInterruptOccurFlag-in-DBUS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0003-Set-PreTimeoutInterruptOccurFlag-in-DBUS.patch new file mode 100644 index 000000000..60b605418 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0003-Set-PreTimeoutInterruptOccurFlag-in-DBUS.patch @@ -0,0 +1,45 @@ +From 41f71ecfa2b8339281a33c260d78102453d4ac97 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Tue, 30 Jul 2019 15:31:09 +0800 +Subject: [PATCH] Set PreTimeoutInterruptOccurFlag in DBUS + +Set preTimeoutInterruptOccurFlag in DBUS as 'true' when +watchdog pre-timeout interrupt occurred. +This property is use for recording PreTimeoutInterruptOccurFlag. +In command get message flag, need verify whether pre-timeout +interrupt occurred by it. + +Tested: +Set watchdog timer +(Pre-timeout interrupt is Messaging, Initial Countdown is 2 second). +ipmitool raw 0x06 0x24 0x5 0x30 0x1 0x3e 0x14 0x00 +Start watchdog timer. +ipmitool mc watchdog reset +Wait watchdog timer expired, log into below: +http://BMC-IP:3000/ +xyz.openbmc_project.Watchdog +/xyz/openbmc_project/watchdog/host0 +xyz.openbmc_project.State.Watchdog +check whether the value of PreTimeoutInterruptOccurFlag is true. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + watchdog.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/watchdog.cpp b/watchdog.cpp +index fa58ef4..bdf65da 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -198,6 +198,8 @@ void Watchdog::timeOutHandler() + + if (preInterruptNoAction != 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", +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0004-Standardize-watchdog-redfish-format-according-to-EPS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0004-Standardize-watchdog-redfish-format-according-to-EPS.patch new file mode 100644 index 000000000..578fa1257 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0004-Standardize-watchdog-redfish-format-according-to-EPS.patch @@ -0,0 +1,211 @@ +From 3bead6316f653f14773e65b2f6b8facb08f200e7 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Fri, 9 Aug 2019 14:54:13 +0800 +Subject: [PATCH] Standardize watchdog redfish format according to EPS + +According to EPS and test requirement, change the messageArgs +in redfish about watchdog action and pre-interrupt action and +add timer user display. + +Tested: +Set a watchdog (Timer action and pre-interrupt action both are none). + ipmitool raw 0x06 0x24 0x05 0x00 0x00 0x00 0x30 0x00 +Get the watchdog. + ipmitool mc watchdog get +Start the watchdog. + ipmitool mc watchdog reset +When timer expired, check messageArgs in Redfish with below url: +https://IP/redfish/v1/Systems/system/LogServices/EventLog/Entries. + + "Message": "Host Watchdog Event: Power Cycle - System power cycle due to Watchdog timeout. timer use: SMS/OS", + "MessageArgs": [ + "Power Cycle - System power cycle due to Watchdog timeout. timer use: SMS/OS" + ], + + "Message": "Host Watchdog Event: Timer interrupt - Messaging Interrupt due to Watchdog timeout. timer use: OEM", + "MessageArgs": [ + "Timer interrupt - Messaging Interrupt due to Watchdog timeout. timer use: OEM" + ], + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + watchdog.cpp | 127 +++++++++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 89 insertions(+), 38 deletions(-) + +diff --git a/watchdog.cpp b/watchdog.cpp +index bdf65da..7cfcc75 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -25,25 +25,28 @@ const static constexpr char* currentPowerState = "CurrentPowerState"; + const static constexpr char* powerStatusOff = + "xyz.openbmc_project.State.Chassis.PowerState.Off"; + +-const static constexpr char* powerActionHardReset = +- "xyz.openbmc_project.State.Watchdog.Action.HardReset"; +-const static constexpr char* powerActionOff = +- "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; +-const static constexpr char* powerActionPowerCycle = +- "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; +-const static constexpr char* powerActionNone = +- "xyz.openbmc_project.State.Watchdog.Action.None"; +-const static constexpr char* preInterruptNoAction = +- "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None"; +- +-const static constexpr char* hardResteDescription = +- "Hard Reset - System reset due to Watchdog timeout"; ++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 due to Watchdog timeout"; ++ "Power Down - System power down"; + const static constexpr char* powerCycleDescription = +- "Power Cycle - System power cycle due to Watchdog timeout"; ++ "Power Cycle - System power cycle"; + const static constexpr char* timerExpiredDescription = "Timer expired"; +-const static constexpr char* preInterruptDescription = "Timer interrupt"; ++ ++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 + { +@@ -161,54 +164,102 @@ uint64_t Watchdog::interval(uint64_t value) + 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; + } + +- if (convertForMessage(action) == powerActionHardReset) +- { +- actionMessageArgs = hardResteDescription; +- } +- else if (convertForMessage(action) == powerActionOff) +- { +- actionMessageArgs = powerOffDescription; +- } +- else if (convertForMessage(action) == powerActionPowerCycle) ++ switch (timeUser) + { +- actionMessageArgs = powerCycleDescription; ++ 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; + } +- else if (convertForMessage(action) == powerActionNone) +- { +- actionMessageArgs = timerExpiredDescription; +- } +- else ++ ++ switch (action) + { +- actionMessageArgs = "Reserved"; ++ 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", actionMessageArgs.c_str(), NULL); ++ "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 (preInterruptNoAction != convertForMessage(preTimeoutInterruptAction)) ++ 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=%s", +- preInterruptDescription, NULL); ++ "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to " ++ "Watchdog timeout. timer use: %s", ++ preInterruptActionMessageArgs.c_str(), ++ timeUserMessage.c_str(), NULL); + } + +- expiredTimerUse(currentTimerUse()); +- + auto target = actionTargetMap.find(action); + if (target == actionTargetMap.end()) + { +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service new file mode 100644 index 000000000..5ef1a4179 --- /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.Chassis.Transition.Reset \ + --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..0e221a6b5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend @@ -0,0 +1,12 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +SRCREV = "c35135d32f9cb84b62de7b72eee3a2e87b4b3d4d" +SRC_URI += "file://0001-Move-Phosphor-Watchdog-to-Not-Use-Service-Files.patch \ + file://0002-Stop-the-watchdog-when-the-host-is-going-to-off.patch \ + file://0003-Set-PreTimeoutInterruptOccurFlag-in-DBUS.patch \ + file://0004-Standardize-watchdog-redfish-format-according-to-EPS.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..2ed120659 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb @@ -0,0 +1,16 @@ +SUMMARY = "System watchdog" +DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \ + when unrecoverable events occurs" + +inherit allarch +inherit obmc-phosphor-systemd + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} += "system-watchdog.service" +SYSTEMD_ENVIRONMENT_FILE_${PN} += "obmc/system-watchdog/system-watchdog.conf" + +SYSTEMD_SERVICE_${PN} += "watchdog-reset.service" +SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.service" +SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.timer" 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..6f33b36d7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service @@ -0,0 +1,8 @@ +[Unit] +Description=Reset BMC Using Hardware Watchdog +Conflicts=system-watchdog.service + +[Service] +ExecStart=/sbin/watchdog -T 0 -F /dev/watchdog1 +Type=oneshot + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0004-Implement-force-boot-to-bios-in-server-power-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0004-Implement-force-boot-to-bios-in-server-power-control.patch new file mode 100644 index 000000000..3885318de --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0004-Implement-force-boot-to-bios-in-server-power-control.patch @@ -0,0 +1,176 @@ +From 5a6e97bdca6db517eabb94a926623e2f662b1315 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Thu, 1 Aug 2019 17:37:17 +0800 +Subject: [PATCH] force to bios fix bump fail + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + app/common/services/api-utils.js | 30 ++++++++++++++++++ + app/common/services/constants.js | 4 +++ + app/common/services/dataService.js | 1 + + .../controllers/power-operations-controller.html | 11 +++++++ + .../controllers/power-operations-controller.js | 36 ++++++++++++++++++++-- + 5 files changed, 80 insertions(+), 2 deletions(-) + +diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js +index d485016..3d64406 100644 +--- a/app/common/services/api-utils.js ++++ b/app/common/services/api-utils.js +@@ -29,12 +29,42 @@ window.angular && (function(angular) { + HOST_STATE_TEXT: Constants.HOST_STATE, + LED_STATE: Constants.LED_STATE, + LED_STATE_TEXT: Constants.LED_STATE_TEXT, ++ FORCE_TO_BIOS_STATE_TEXT: Constants.FORCE_TO_BIOS_STATE_TEXT, + HOST_SESSION_STORAGE_KEY: Constants.API_CREDENTIALS.host_storage_key, + validIPV4IP: function(ip) { + // Checks for [0-255].[0-255].[0-255].[0-255] + return ip.match( + /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/); + }, ++ setForceToBIOSState: function(state) { ++ console.log(state); ++ var data = JSON.stringify({'Boot': ++ { ++ 'BootSourceOverrideTarget': state ++ } ++ }); ++ return $http({ ++ method: 'PATCH', ++ url: DataService.getHost() + '/redfish/v1/Systems/system', ++ withCredentials: true, ++ data: data ++ }); ++ }, ++ getForceToBIOSState: function() { ++ ++ return $http({ ++ method: 'GET', ++ url: DataService.getHost() + '/redfish/v1/Systems/system', ++ withCredentials: true ++ }).then( ++ function(response) { ++ console.log(JSON.stringify(response.data.Boot.BootSourceOverrideTarget)); ++ return response.data.Boot.BootSourceOverrideTarget; ++ }, ++ function(error) { ++ console.log(error); ++ }); ++ }, + getRedfishSysName: function() { + return $http({ + method: 'GET', +diff --git a/app/common/services/constants.js b/app/common/services/constants.js +index ae82e76..e594570 100644 +--- a/app/common/services/constants.js ++++ b/app/common/services/constants.js +@@ -42,6 +42,10 @@ window.angular && (function(angular) { + }, + LED_STATE: {on: true, off: false}, + LED_STATE_TEXT: {on: 'on', off: 'off'}, ++ FORCE_TO_BIOS_STATE_TEXT: { ++ on: 'BiosSetup', ++ off: 'None' ++ }, + SEVERITY_TO_PRIORITY_MAP: { + Emergency: 'High', + Alert: 'High', +diff --git a/app/common/services/dataService.js b/app/common/services/dataService.js +index 87fddba..cc9c0b3 100644 +--- a/app/common/services/dataService.js ++++ b/app/common/services/dataService.js +@@ -16,6 +16,7 @@ window.angular && (function(angular) { + this.server_health = Constants.SERVER_HEALTH.unknown; + this.server_state = 'Unreachable'; + this.LED_state = Constants.LED_STATE_TEXT.off; ++ this.ForceToBIOS_state = Constants.FORCE_TO_BIOS_STATE_TEXT.off; + this.last_updated = new Date(); + + this.loading = false; +diff --git a/app/server-control/controllers/power-operations-controller.html b/app/server-control/controllers/power-operations-controller.html +index ddf8bda..ea46e00 100644 +--- a/app/server-control/controllers/power-operations-controller.html ++++ b/app/server-control/controllers/power-operations-controller.html +@@ -10,6 +10,17 @@ + <div class="row column"> + <div id="power-indicator-bar" class="power__indicator-bar" ng-class="{'power__state-on': dataService.server_state == 'Running', 'power__state-off': dataService.server_state == 'Off', 'power__state-indet': dataService.server_state == 'Standby', 'power__state-error': dataService.server_state == 'Quiesced'}"> + <p class="inline">{{dataService.hostname}} - {{dataService.server_id}}</p> ++ <div class="toggle float-right"> ++ <input id="toggle__switch-round" ++ class="toggle-switch toggle-switch__round-flat" ++ type="checkbox" ++ tabindex="0" ++ ng-click="toggleForceToBIOS()" ++ ng-checked="dataService.ForceToBIOS_state == 'BiosSetup'" ++ ng-disabled="dataService.server_unreachable"> ++ <label for="toggle__switch-round" tabindex="0"> </label> ++ <h3 class="inline">Boot to BIOS</h3> ++ </div> + <h3 class="power__state inline no-margin h3"><span>{{dataService.server_state | quiescedToError}}</span></h3> + </div> + </div> +diff --git a/app/server-control/controllers/power-operations-controller.js b/app/server-control/controllers/power-operations-controller.js +index 986ac3b..2c29093 100644 +--- a/app/server-control/controllers/power-operations-controller.js ++++ b/app/server-control/controllers/power-operations-controller.js +@@ -10,10 +10,10 @@ window.angular && (function(angular) { + 'use strict'; + + angular.module('app.serverControl').controller('powerOperationsController', [ +- '$scope', 'APIUtils', 'dataService', 'Constants', '$interval', '$q', ++ '$route', '$scope', 'APIUtils', 'dataService', 'Constants', '$interval', '$q', + 'toastService', + function( +- $scope, APIUtils, dataService, Constants, $interval, $q, toastService) { ++ $route, $scope, APIUtils, dataService, Constants, $interval, $q, toastService) { + $scope.dataService = dataService; + // Is a || of the other 4 "confirm" variables to ensure only + // one confirm is shown at a time. +@@ -57,6 +57,17 @@ window.angular && (function(angular) { + }, Constants.POLL_INTERVALS.POWER_OP); + return deferred.promise; + }; ++ APIUtils.getForceToBIOSState().then( ++ function(data) { ++ if (data == APIUtils.FORCE_TO_BIOS_STATE_TEXT.on) { ++ dataService.ForceToBIOS_state = APIUtils.FORCE_TO_BIOS_STATE_TEXT.on; ++ } else { ++ dataService.ForceToBIOS_state = APIUtils.FORCE_TO_BIOS_STATE_TEXT.off; ++ } ++ }, ++ function(error) { ++ console.log(JSON.stringify(error)); ++ }); + + APIUtils.getLastPowerTime() + .then( +@@ -74,6 +85,27 @@ window.angular && (function(angular) { + $scope.loading = false; + }); + ++ $scope.toggleForceToBIOS = function() { ++ var toggleState = ++ (dataService.ForceToBIOS_state == APIUtils.FORCE_TO_BIOS_STATE_TEXT.on) ? ++ APIUtils.FORCE_TO_BIOS_STATE_TEXT.off : ++ APIUtils.FORCE_TO_BIOS_STATE_TEXT.on; ++ dataService.ForceToBIOS_state = ++ (dataService.ForceToBIOS_state == APIUtils.FORCE_TO_BIOS_STATE_TEXT.on) ? ++ APIUtils.FORCE_TO_BIOS_STATE_TEXT.off : ++ APIUtils.FORCE_TO_BIOS_STATE_TEXT.on; ++ APIUtils.setForceToBIOSState(toggleState) ++ .then( ++ function(response) {}, ++ function(errors) { ++ toastService.error( ++ 'Failed to set Boot to BIOS '); ++ console.log(JSON.stringify(errors)); ++ // Reload to get correct current state ++ $route.reload(); ++ }) ++ }; ++ + $scope.toggleState = function() { + dataService.server_state = + (dataService.server_state == 'Running') ? 'Off' : 'Running'; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend new file mode 100644 index 000000000..5f18206c8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +#SRC_URI = "git://github.com/openbmc/phosphor-webui.git" +SRCREV = "30d7c6377f70382088436c7a4830663eb522d588" + +SRC_URI += "file://0004-Implement-force-boot-to-bios-in-server-power-control.patch" diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh new file mode 100644 index 000000000..176bfd7ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh @@ -0,0 +1 @@ +export LDB_MODULES_PATH=/usr/lib/ldb diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups new file mode 100644 index 000000000..7c189e231 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups @@ -0,0 +1 @@ +sssd_locked diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf new file mode 100644 index 000000000..d2ffe5ddc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf @@ -0,0 +1,2 @@ +enable-cache passwd no +enable-cache group no
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf new file mode 100644 index 000000000..7a2786bee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf @@ -0,0 +1,16 @@ +[sssd] +domains = LOCAL +services = nss, pam +config_file_version = 2 + +[nss] +enum_cache_timeout = 1 +filter_groups = root +filter_users = root + +[pam] + +[domain/LOCAL] +enumerate = true +id_provider = local +auth_provider = local diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service new file mode 100644 index 000000000..fe2bcf8b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service @@ -0,0 +1,15 @@ +[Unit] +Description=System Security Services Daemon +# SSSD must be running before we permit user sessions +Before=systemd-user-sessions.service nss-user-lookup.target +Wants=nss-user-lookup.target + +[Service] +Environment=LDB_MODULES_PATH=/usr/lib/ldb DEBUG_LOGGER=-f +ExecStart=/usr/sbin/sssd $DEBUG_LOGGER +Type=simple +Restart=always +PIDFile=/var/run/sssd.pid + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend new file mode 100644 index 000000000..03965ce72 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend @@ -0,0 +1,26 @@ +inherit obmc-phosphor-systemd + +FILESEXTRAPATHS_append := "${THISDIR}/files:" +SRC_URI += "file://sssd.conf \ + file://nscd.conf \ + file://locked_groups \ + file://ldb.sh \ + " + +PACKAGECONFIG += " systemd " +SYSTEMD_AUTO_ENABLE = "enable" + +EXTRA_OECONF += " --enable-pammoddir=${base_libdir}/security" + +do_install_append() { + # sssd creates also the /var/run link. Need to remove it to avoid conflicts + # with the one created by base-files recipe. + rm -rf ${D}/var/run + install -m 600 ${WORKDIR}/locked_groups ${D}/${sysconfdir}/${BPN} + install -m 600 ${WORKDIR}/nscd.conf ${D}/${sysconfdir} + install -d ${D}${sysconfdir}/profile.d + install -m 0644 ${WORKDIR}/ldb.sh ${D}${sysconfdir}/profile.d +} + +FILES_${PN} += " /lib/security/pam_sss.so " + diff --git a/meta-openbmc-mods/meta-common/recipes-support/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-utilities/beeper-test/beeper-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb new file mode 100644 index 000000000..51cda82e9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb @@ -0,0 +1,17 @@ +SUMMARY = "Beeper Test App" +DESCRIPTION = "Beeper Test Application for pwm-beeper" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM += "\ + file://beeper-test.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \ + " + +SRC_URI = "\ + file://CMakeLists.txt \ + file://beeper-test.cpp \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format new file mode 100644 index 000000000..ea71ad6e1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format @@ -0,0 +1,99 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt new file mode 100644 index 000000000..81a0c7e81 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(beeper-test CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(beeper-test beeper-test.cpp) +install(TARGETS beeper-test DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp new file mode 100644 index 000000000..31dafdd88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp @@ -0,0 +1,81 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: pwm-beeper test application +// +*/ + +#include <fcntl.h> +#include <linux/input.h> +#include <stdio.h> +#include <unistd.h> + +#include <cstring> +#include <iostream> + +int main(int argc, char** argv) +{ + if (argc < 3) + { + std::cout << "usage: <input device> <sequence of 'tone in " + "Hz','duration in ms' pair>\n"; + std::cout << "example: beeper-test /dev/input/event0 " + "2100,100,0,150,2500,50,0,50,2200,100\n"; + return 1; + } + + int fd; + if ((fd = open(argv[1], O_RDWR | O_CLOEXEC)) < 0) + { + perror("Failed to open input device"); + return -1; + } + + struct input_event event; + event.type = EV_SND; + event.code = SND_TONE; + + char* pch = strtok(argv[2], ","); + while (pch != NULL) + { + event.value = atoi(pch); + + pch = strtok(NULL, ","); + if (!pch) + { + std::cerr << "Invalid tone,duration pair\n"; + close(fd); + return -1; + } + + int durationMs = atoi(pch); + + if (write(fd, &event, sizeof(struct input_event)) != + sizeof(struct input_event)) + { + perror("Failed to write a tone sound event"); + close(fd); + return -1; + } + + usleep(durationMs * 1000); + + pch = strtok(NULL, ","); + } + + close(fd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb new file mode 100644 index 000000000..78240c0f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb @@ -0,0 +1,17 @@ +SUMMARY = "Dimm Sensor" +DESCRIPTION = "Dimm Sensor Executable" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://DimmSensor.cpp \ + " + +LICENSE = "CLOSED" + +S = "${WORKDIR}" + +inherit cmake + +# linux-libc-headers guides this way to include custom uapi headers +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +do_configure[depends] += "virtual/kernel:do_shared_workdir" diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt new file mode 100644 index 000000000..6262f8dee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(dimmsensor CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(dimmsensor DimmSensor.cpp) +install (TARGETS dimmsensor DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp new file mode 100644 index 000000000..9cc13c2a5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp @@ -0,0 +1,143 @@ +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <vector> +#include <linux/aspeed_peci_ioctl.h> + +#define PECI_DIMM_TEMP_REG 0x150 +#define DIMM_DEFAULT_VALUE 0x55 + +class DimmConfig { + public: + uint8_t chanId, bus, device, function, dimmnum; +}; + +#define MAX_BUFFER_SIZE 32 + +// TODO get this from config +auto GetDimmConfig(uint8_t dimm) { + uint8_t chan = dimm / 2; + assert(chan < 6); + + auto ret = std::make_unique<DimmConfig>(); + + ret->chanId = chan; + ret->dimmnum = 2; + ret->bus = 2; + switch (chan) { + case 0: + ret->device = 10; + ret->function = 2; + break; + case 1: + ret->device = 10; + ret->function = 6; + break; + case 2: + ret->device = 11; + ret->function = 2; + break; + case 3: + ret->device = 12; + ret->function = 2; + break; + case 4: + ret->device = 12; + ret->function = 6; + break; + case 5: + ret->device = 13; + ret->function = 2; + break; + default: + assert(0); + break; + } + + return ret; +} + +// returns read vector on success, empty vector on failure +auto peci_config_local(uint8_t u8target, uint8_t u8bus, uint8_t u8device, + uint8_t u8fcn, uint16_t u16reg, uint8_t u8readlen) { + auto msg = std::make_unique<peci_xfer_msg>(); + uint32_t u32Address; + int fd; + std::vector<uint8_t> ret; + + u32Address = u16reg; + u32Address |= u8fcn << 12; + u32Address |= u8device << 15; + u32Address |= u8bus << 20; + + msg->client_addr = u8target; + msg->tx_len = RDPCICFGLOCAL_WRITE_LEN; + msg->rx_len = RDPCICFGLOCAL_READ_LEN_BASE + u8readlen; + + msg->tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; + msg->tx_buf[2] = u32Address & 0xFF; + msg->tx_buf[3] = (u32Address >> 8) & 0xFF; + msg->tx_buf[4] = (u32Address >> 16) & 0xFF; + + fd = open("/dev/peci", O_RDWR | O_CLOEXEC); + if (fd >= 0) { + int success = ioctl(fd, PECI_IOC_XFER, msg.get()); + if (success == 0) { + if (DEV_PECI_CC_SUCCESS == msg->rx_buf[0]) { + ret.resize(RDPCICFGLOCAL_READ_LEN_BASE + u8readlen - 1); + memcpy(ret.data(), &(msg->rx_buf[1]), ret.size()); + } + } + close(fd); + } + return ret; +} + +int main(int argc, char** argv) { + if (argc != 3) { + std::cout << argv[0] << " requires 2 arguments: CPUNum, DimmNum.\n"; + return -1; + } + uint8_t cpunum = atoi(argv[1]); + if (cpunum > 3) { + std::cout << cpunum << " greater than cpu max of 3.\n"; + return -1; + } + uint8_t dimmnum = atoi(argv[2]); + if (dimmnum > 11) { + std::cout << dimmnum << " greater than dimm max of 11.\n"; + return -1; + } + + auto dimm_config = GetDimmConfig(dimmnum); + + uint8_t dimmSelect = dimmnum % 2; // dimm 0 or 1 for each config + + auto val = peci_config_local(PECI_BASE_ADDR + cpunum, dimm_config->bus, + dimm_config->device, dimm_config->function, + PECI_DIMM_TEMP_REG + dimmSelect * 4, 4); + + if (!val.size()) { + std::cout << "Peci Error\n"; + return -1; + } + + // TODO dimm offsets needed? + + if (val[0] == 0) + std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum) + << " not populated.\n"; + else if(val[0] == DIMM_DEFAULT_VALUE) + std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum) + << " in illegal state.\n"; + else + std::cout << unsigned(val[0]) << " degrees C.\n"; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini new file mode 100644 index 000000000..619570dbb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini @@ -0,0 +1,277 @@ +; +; Copyright 2015 Intel Corporation. +; +; The source code, information and material ("Material") contained herein is +; owned by Intel Corporation or its suppliers or licensors, and title to such +; Material remains with Intel Corporation or its suppliers or licensors. The +; Material contains proprietary information of Intel or its suppliers and +; licensors. The Material is protected by worldwide copyright laws and treaty +; provisions. No part of the Material may be used, copied, reproduced, +; modified, published, uploaded, posted, transmitted, distributed or disclosed +; in any way without Intel's prior express written permission. No license under +; any patent, copyright or other intellectual property rights in the Material +; is granted to or conferred upon you, either expressly, by implication, +; inducement, estoppel or otherwise. Any license under such intellectual +; property rights must be express and approved by Intel in writing. + +; +; This file is similar to the config.genimage2 file of previous BMC +; generations but it is not generated. It contains all of the information +; to generate the signed-image variant of the signtool config file. +; + +[GLOBAL] +Major = 0 +Minor = 72 +Output = update.bin +Alloc = 33792K ; 0x2100000 +BlockSize = 64K +Type = 0xffffffff ; generate top level composite image +Locate = 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Factory ROM file generation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +RomOutput = rom-a-only.ima +RomAlloc = 33M +KeyRegion = Certificate +NewKeyRegion = ReplacementCertificate +SecVersion = 0 + + + +; RecoveryOnly items should be place first in the image + +[FRISBEE_ROM] +Major = 1 +Minor = 5 +Type = ROBL +File = frisbee.bin +Locate = 0x00000000 +Alloc = 240K +Compress = 0 +SecVersion = 1 +Unsigned = 1 + +[Certificate] +Locate = 0x3c000 +Type = CERT +Alloc = 8K +Fill = 0xff +Unsigned = 1 +ROMOnly = 1 +SecVersion = 0 + +;[FWPRODUCTID] +;Major = 1 +;Minor = 0 +;Type = FWID +;File = fwproductid.bin +;Locate = 0x0003f000 +;ROMOnly = 1 +;SecVersion = 0 + +[FRISBEE_UPD] +Major = 1 +Minor = 5 +Type = RWBL +File = frisbee.bin +Locate = 0x040000 +Alloc = 256K +Compress = 0 +SecVersion = 1 +IndivSign = 1 +SigOffset = 0x03e000 + +[U-Boot] +Major = 1 +Minor = 5 +Type = UBT\x00 +File = u-boot.bin +Alloc = 256K +Compress = 0 +SecVersion = 1 +IndivSign = 1 +SigOffset = 0x03e000 + +; Linux OS Image +[OSIMAGE] +Major = 1 +Minor = 1 +Type = LKNL +File = uImage +SecVersion = 1 + +[DTB] +Major = 1 +Minor = 1 +Type = DTB\x00 +File = uImage-aspeed-bmc-intel-purley.dtb +SecVersion = 0 + +; Root File System +[ROOT] +Major = 1 +Minor = 1 +Type = RtFS +File = image-rofs.squashfs-xz.u-boot +Load = 0x83000000 +SecVersion = 1 +; +; WWW File System in CRAMFS. +;[WWW] +;Major = 1 +;Minor = 1 +;Type = WWW\x00 +;File = webfs.bin +;BlockDev = 1 +;SecVersion = 1 + +; Replacement certificate for re-keying the BMC +; Will only be added to image if -rk is specified +[ReplacementCertificate] +Major = 1 +Minor = 1 +Type = CRT0 +Alloc = 4K +SecVersion = 0 +Compress = 0 +IndivSign = 1 +Unbound = 1 +Fill = 0xff +SigOffset = 0x800 + +; Manifest goes here +; This gets some special treatment (this needs to match the location +; that Frisbee thinks the manifest is at or it won't boot) +[Manifest] +Major = 0 +Minor = 0 +Type = MFST +Alloc = 4K +Locate = 0x1bff000 +Fill = 0xff +SecVersion = 0 + +; +; NV File System in JFFS2, but it is blank in the ROM version +; and filled in with defaults from the rootfs +[PARAMS] +Major = 1 +Minor = 1 +Type = CONF +Alloc = 4096K +Locate = 0x1c00000 +ROMOnly = 1 +BlockDev = 1 +SecVersion = 1 +Unsigned = 1 + +; notice that these sections have no file +; and are marked as ROMOnly. This forces them +; into the allocation so we don't get overlapping +; sections, but does not actually put anything into +; the rom at build time. + +[UBootEnv] +Major = 1 +Minor = 0 +Type = UENV +; File = ; no file makes this a placeholder +Locate = 0x2000000 +Alloc = 64K +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[FRUData] +Major = 1 +Minor = 0 +Type = FRU\x00 +Alloc = 64K +Locate = 0x2010000 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[SEL] +Major = 1 +Minor = 0 +Type = SEL\x00 +Alloc = 512K +Locate = 0x2020000 +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +; NV filesystem that survives reset mfg defaults. +; OEM Web customization goes here. +[PersistentNV] +Major = 1 +Minor = 0 +Type = PNV\x00 +Alloc = 2048K +Locate = 0x20a0000 +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[RubixLog] +Major = 1 +Minor = 0 +Type = BTLG +Alloc = 4K +Locate = 0x23fe000 +BlockDev = 0 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[BootPointer] +Major = 1 +Minor = 0 +Type = BPTR +Alloc = 4K +Locate = 0x23ff000 +BlockDev = 0 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +; +; Example Section with all possible fields with their default +; values, unless the field is specified mandatory +; +;[EXAMPLE] +;Major = 0 ; Major number of module +;Minor = 0 ; Minor number of module +;Type = TYPE ; four bytes hopefully human readable, +; ; use c-style escapes if non-ascii, \x23\x10\x00\xf3 +; ; or use a number 0xf3001023 +;Alloc = X ; Maximum memory allocated; X = roundup +;File = name ; File containing the module +; ; If Alloc is specified, but no File, a blank +; ; header will be created (only useful for ROMOnly) +;Locate = addr ; Location in Flash; MANDATORY +;ROMOnly = 1 ; if ROMOnly is set and non-zero, this section +; ; will only be present in the ROM image, not the updater image +;RecoveryOnly = 1 ; if RecoveryOnly is set and non-zero, this section +; ; will only be present in the recovery image, not the active image +;BlockDev = 1 ; this will make the signed image code export this +; ; image as a mtd block device at runtime +;Unsigned = 1 ; Do not include this section in signatures (NV data) +;Compress = 1 ; compress image contents (useful for non-compressed items) +;SecVersion = X ; a 16-bit security revision to enforce no downgrades +;IndivSign = 1 ; section is individually signed; do not include in full signature +;Unbound = 1 ; by default, individually signed sections are part of the +; ; full signature too. This makes them independent +;SigOffset = X ; offset within individually-signed section to place signature +;Fill = xx ; fill with pattern xx instead of a file's contents +; +; Note: Numeric values can be represented either by decimal or a +; hexadecimal (Prefixed by 0x) +; Numeric values can either end with K or M to specify in +; KiloBytes or MegaBytes +; diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt new file mode 100644 index 000000000..0c98160b9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(io-app C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +add_executable(io io-app.c) +install (TARGETS io DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c new file mode 100644 index 000000000..a5ffabd88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c @@ -0,0 +1,665 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: map io region to read or write to HW registers +// +*/ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> + +static int quiet = 0; + +static int dump(unsigned long phys, void *addr, size_t len) +{ + const uint32_t *ubuf = addr; + unsigned int wd = 0, l, iv; + unsigned char *h, *a; + char line[256]; + static const char itoh[] = "0123456789abcdef"; + + /* 0 1 2 3 4 5 6 + * 0123456789012345678901234567890123456789012345678901234567890123456789 + * 00000000: 00000000 00000000 00000000 00000000 ................ + */ + while (wd < len) + { + memset(line, ' ', sizeof(line)); + sprintf(line, "%08lx: ", phys + (wd*sizeof(uint32_t))); + a = (unsigned char*)&line[47]; + h = (unsigned char*)&line[10]; + for (l=0; l<4 && (l+wd)<len; l++) + { + uint32_t v = *ubuf++; + for (iv=0; iv<sizeof(v); iv++) + { + uint8_t b = v >> (8*((sizeof(v)-1)-iv)); + *h++ = itoh[b>>4]; + *h++ = itoh[b&0xf]; + if (isprint(b)) + *a++ = (char)b; + else + *a++ = '.'; + } + *h++ = ' '; + } + *a++ = '\n'; + *a = 0; + wd += l; + fputs(line, stdout); + } + return wd; +} + + +struct mapping +{ + unsigned long phys; + void *virt; + size_t len; +}; + +static struct mapping *maps = NULL; +static int nr_maps = 0; + +static void unmap_all(void) +{ + int i; + for (i=0; i<nr_maps; i++) + { + if (maps[i].virt) + munmap(maps[i].virt, maps[i].len); + maps[i].virt = NULL; + } +} + +int add_a_map(unsigned long phys, void *virt, size_t len) +{ + void *new_maps; + new_maps = realloc(maps, (nr_maps + 1) * sizeof(struct mapping)); + if (!new_maps) + { + unmap_all(); + munmap(virt, len); + } + else + { + maps = new_maps; + maps[nr_maps].phys = phys; + maps[nr_maps].virt = virt; + maps[nr_maps].len = len; + nr_maps++; + return 0; + } + return -1; +} + +static void *map_fd(int fd, off_t offset, size_t len, int mode, int flags) +{ + void *mapped_at; + unsigned long phys = -1; + + if (offset != -1) + phys = offset; + else + offset = 0; + + mapped_at = mmap(NULL, len, mode, flags, fd, offset); + if (mapped_at != MAP_FAILED) + { + if (add_a_map(phys, mapped_at, len) != 0) + { + mapped_at = MAP_FAILED; + } + } + + return mapped_at; +} + +static void *map_file(const char *fname, size_t *len, int mode, int flags) +{ + int fd; + struct stat sb; + void *ptr; + int fmode; + + if (mode & PROT_WRITE) + fmode = O_RDWR; + else + fmode = O_RDONLY; + + fd = open(fname, fmode); + if (fd < 0) + return MAP_FAILED; + + if (*len == 0) + { + fstat(fd, &sb); + *len = sb.st_size; + } + ptr = map_fd(fd, -1, *len, mode, flags); + close(fd); + return ptr; +} + +static int load_maps(const char *cmap_str, size_t mlen) +{ + char *tmp_sa = NULL, *tmp_sl = NULL, *endptr = NULL; + const void *mapped = NULL; + int ret = 0; + const char *delim = "\r\n\t ,"; + unsigned long addr; + size_t len; + char *map_str = NULL, *paddr = NULL, *plen = NULL; + int fd; + + fd = open("/dev/mem", O_RDWR); + if (fd < 0) + { + return -1; + } + + len = strlen(cmap_str); + map_str = (char *)malloc(len + 1); + if (!map_str) + { + close(fd); + return -1; + } + strncpy(map_str, cmap_str, len); + map_str[len] = '\0'; + paddr = strtok_r(map_str, delim, &tmp_sa); + while (paddr) + { + /* find the next comma or newline */ + if (!strtok_r(paddr, ":", &tmp_sl)) + { + fprintf(stderr, "malformed map string '%s'\n", paddr); + goto _loop; + } + plen = strtok_r(NULL, ":", &tmp_sl); + if (!plen) + { + goto _loop; + } + addr = strtoul(paddr, &endptr, 16); + if (*endptr) + { + fprintf(stderr, "Failed to parse address from '%s'\n", paddr); + ret = -1; + break; + } + len = strtoul(plen, &endptr, 16); + if (*endptr) + { + fprintf(stderr, "Failed to parse len from '%s'\n", plen); + ret = -1; + break; + } + if (MAP_FAILED == (mapped = map_fd(fd, addr, len, PROT_READ|PROT_WRITE, MAP_SHARED))) + { + fprintf(stderr, "Failed to map %lx +%x\n", addr, len); + ret = -1; + break; + } + if (!quiet) + printf("added map: %p (%lx..%lx)\n", mapped, addr, addr+len); +_loop: + paddr = strtok_r(NULL, delim, &tmp_sa); + } + free(map_str); + close(fd); + return ret; +} + +int md(unsigned long addr, uint32_t unused, size_t len) +{ + int i, j; + + (void)unused; + for (i=0; i<nr_maps; i++) + { + if (-1 == maps[i].phys) + continue; + if (maps[i].phys <= addr && + (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len)) + { + uint32_t *buf, *pv; + + buf = (uint32_t *)malloc(len*sizeof(uint32_t)); + if (!buf) + return 1; + pv = (uint32_t *)(maps[i].virt + (addr - maps[i].phys)); + for (j=0; j<len; j++) + buf[j] = *pv++; + + dump(addr, buf, len); + free(buf); + return 0; + } + } + fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len); + return 1; +} + +int mw(unsigned long addr, uint32_t val, size_t len) +{ + int i, j; + + for (i=0; i<nr_maps; i++) + { + if (-1 == maps[i].phys) + continue; + if (maps[i].phys <= addr && + (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len)) + { + for (j=0; j<len; j++) + { + *((uint32_t*)(maps[i].virt + (addr - maps[i].phys))) = val; + } + return 0; + } + } + fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len); + return 1; +} + +char *readline(char *buf, size_t len, FILE *f) +{ + int raw = 0; + size_t br = 0; + struct termios tios, orig_tios; + + if (!quiet) + { + /* put terminal in raw mode to get unbuffered io */ + if (tcgetattr(fileno(f), &orig_tios) == 0) + { + tios = orig_tios; + tios.c_iflag |= IGNPAR; + tios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); + tios.c_oflag &= ~OPOST; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + tcsetattr(fileno(f), TCSADRAIN, &tios); + raw = 1; + } + } + if (!raw) + { + return fgets(buf, len, f); + } + /* read in bytes one at a time and echo them */ + while (br < (len-1)) + { + int c = fgetc(f); + switch (c) + { + case 3: /* ^C */ + br = 0; + c = '\n'; + break; + case 4: + br = 0; + c = -1; + break; + case '\b': + if (br > 0) + { + fputs("\b \b", stdout); + br--; + } + break; + case '\r': + case '\n': + fputs("\r\n", stdout); + buf[br++] = '\n'; + break; + case ' '...'~': + fputc(c, stdout); + buf[br++] = c; + break; + break; + default: + break; + } + if (c == -1) + { + if (br == 0) + buf = NULL; + break; + } + if (c == '\r' || c == '\n') + break; + } + if (buf) + buf[br] = 0; + + tcsetattr(fileno(f), TCSADRAIN, &orig_tios); + return buf; +} + +#define MAX_LINE_LEN 4096 +int io(void) +{ + const char delim1[] = "\r\n;"; + const char delim2[] = "\t "; + char line[MAX_LINE_LEN]; + char *command, *cmd, *paddr, *pval, *plen, *endptr; + char *tmp_s1, *tmp_s2; + unsigned long addr; + uint32_t val; + size_t len; + int (*fn)(unsigned long, uint32_t, size_t); + + if (!quiet) + fputs("> ", stdout); + while (readline(line, MAX_LINE_LEN, stdin) != NULL && *line) + { + /* read next line or next command (up to newline or ';') */ + command = strtok_r(line, delim1, &tmp_s1); + if (!command || strlen(command) == 0) + goto _command_loop; + while (NULL != command && strlen(command) > 0) + { + cmd = strtok_r(command, delim2, &tmp_s2); + if (!cmd) + goto _cmd_err; + if (cmd[0] == 'q' || cmd[0] == 'Q') + return 0; + paddr = strtok_r(NULL, delim2, &tmp_s2); + if (!paddr) + goto _cmd_err; + addr = strtoul(paddr, &endptr, 16); + if (*endptr) + goto _cmd_err; + fn = NULL; + if (strncmp(cmd, "mw", 3) == 0) + { + fn = mw; + pval = strtok_r(NULL, delim2, &tmp_s2); + if (!pval) + goto _cmd_err; + val = strtoul(pval, &endptr, 16); + if (*endptr) + goto _cmd_err; + len = 1; + } + else if (strncmp(cmd, "md", 3) == 0) + { + fn = md; + len = 0x40; + val = 0; + } + else + { + goto _cmd_err; + } + plen = strtok_r(NULL, delim2, &tmp_s2); + if (plen) + { + len = strtoul(plen, &endptr, 16); + if (*endptr) + goto _cmd_err; + } + + if (fn) + fn(addr, val, len); + + command = strtok_r(NULL, delim1, &tmp_s1); + } +_command_loop: + if (!quiet) + fputs("> ", stderr); + continue; +_cmd_err: + fprintf(stderr, "md addr [len]\nmw addr val [len]\n" + "q[uit] | ctrl-d | ctrl-c to exit\n"); + if (!quiet) + fputs("> ", stderr); + } + return 0; +} + +typedef enum +{ + CPU_NONE = 0, + CPU_PILOT3, + CPU_PILOT4, + CPU_AST2500, + CPU_MAX, +} CPU_TYPE; + +static CPU_TYPE probe_cpu(void) +{ + FILE *f; + char cpuinfo[128]; + static CPU_TYPE this_cpu = CPU_NONE; + + if (CPU_NONE == this_cpu) + { + f = fopen("/sys/firmware/devicetree/base/compatible", "r"); + if (f) { + int br = fread(cpuinfo, 1, sizeof(cpuinfo)-1, f); + if (br > 0) { + cpuinfo[br] = 0; + char *v = cpuinfo; + while (v < (cpuinfo + sizeof(cpuinfo)) && *v) { + if (strncmp("aspeed,ast2500", v, 15) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + } + v += 1 + strnlen(v, sizeof(cpuinfo) - (v - cpuinfo)); + } + } + fclose(f); + } + } + if (CPU_NONE == this_cpu) + { + const char delim[] = "\r\n\t :"; + char *tmp_s; + f = fopen("/proc/cpuinfo", "r"); + if (f != NULL) { + while (fgets(cpuinfo, sizeof(cpuinfo), f)) + { + strtok_r(cpuinfo, delim, &tmp_s); + if (strncmp("Hardware", cpuinfo, 9) == 0) + { + char *v = strtok_r(NULL, delim, &tmp_s); + if (v) + { + if (strncmp("AST2500", v, 8) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + } + else if (strncmp("ASpeed SoC", v, 11) == 0) + { + if (!quiet) + fprintf(stderr, "Found ASpeed SoC\n"); + this_cpu = CPU_AST2500; + } + else if (strncmp("ServerEngines PILOT3", v, 21) == 0) + { + if (!quiet) + fprintf(stderr, "Found PILOT3\n"); + this_cpu = CPU_PILOT3; + } + } + break; + } + } + fclose(f); + } + } + return this_cpu; +} + +static const char *probe_cpu_for_map(void) +{ + switch (probe_cpu()) + { + case CPU_PILOT3: + return "0:2000000,10000000:8000,40000000:43b000"; + case CPU_AST2500: + return "0:4000000,1e600000:1a0000,20000000:4000000"; + default: + return ""; + } +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: io [-c config] [-m map]\n" + " md [-c config] [-m map] <addr> [len]\n" + " mw [-c config] [-m map] <addr> <val> [len]\n\n" + "With: -c config load mappings from file config\n" + " -m map load mappings from string map\n" + " addr, val, len are all hex numbers\n\n" + "When invoked as io, this will start a shell that will\n" + "allow the user to type in md and mw commands much like\n" + "the U-Boot environment. By default, it will map in all\n" + "the addresses for the known processor type.\n\n" + "map string is of the format addr:len[,addr2:len2...]\n" + "config file is of the same format as map string\n" + "but with each mapping on separate lines instead of\n" + "comma separated values\n" + ); + exit(1); +} + +#define shift if (++i >= argc) usage() + +int main(int argc, const char *argv[]) +{ + char *exe_full; + char *exe; + char *endptr; + int i, first_arg = 1; + const char *cfg_file = NULL; + const char *map_str = NULL; + size_t flen = 0; + size_t len = 0; + unsigned long addr; + uint32_t val; + int ret = 0; + + i = 1; + while (i < argc) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'm': + shift; + map_str = argv[i]; + break; + case 'c': + shift; + cfg_file = argv[i]; + break; + default: + usage(); + } + } + else + { + first_arg = i; + break; + } + } + + exe_full = strdup(argv[0]); + if (exe_full != NULL ) + exe = basename(exe_full); + else + return ret; + + if (strncmp(exe, "io", 3) != 0 || !isatty(fileno(stdin))) + quiet = 1; + + if (!map_str) + { + if (!cfg_file) + map_str = probe_cpu_for_map(); + else + map_str = map_file(cfg_file, &flen, PROT_READ, MAP_PRIVATE); + } + else + { + flen = strlen(map_str); + } + if (load_maps(map_str, flen) < 0) + { + fprintf(stderr, "failed to map regions: check map string or config file\n"); + goto _cleanup; + } + + if (strncmp(exe, "md", 3) == 0) + { + len = 0x40; + addr = strtoul(argv[first_arg], &endptr, 16); + if ((first_arg + 1) < argc) + { + len = strtoul(argv[first_arg + 1], &endptr, 16); + } + ret = md(addr, 0, len); + goto _cleanup; + } + + if (strncmp(exe, "mw", 3) == 0) + { + len = 1; + addr = strtoul(argv[first_arg], &endptr, 16); + if ((first_arg + 1) < argc) + { + val = strtoul(argv[first_arg + 1], &endptr, 16); + } + else + { + usage(); + } + if ((first_arg + 2) < argc) + { + len = strtoul(argv[first_arg + 2], &endptr, 16); + } + ret = mw(addr, val, len); + goto _cleanup; + } + + io(); + +_cleanup: + unmap_all(); + free(exe_full); + return ret; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb new file mode 100644 index 000000000..5ac0f0a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb @@ -0,0 +1,17 @@ +SUMMARY = "IO App" +DESCRIPTION = "IO application for accessing memory-mapped IO regions on the BMC" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM += "\ + file://io-app.c;beginline=2;endline=14;md5=639666a0bf40bb717b46b378297eeceb \ + " + +SRC_URI = "\ + file://CMakeLists.txt \ + file://io-app.c \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt new file mode 100644 index 000000000..1cde22b49 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(lpc-cmds C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +add_executable(lpc_cmds lpc_cmds.c) +install (TARGETS lpc_cmds DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c new file mode 100644 index 000000000..467231372 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c @@ -0,0 +1,501 @@ +/* +// 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); +} + +/*********************************************************************************/ + +#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" + "\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(cmd, "kcs") == 0) { + int ifc; + + if (argc < 3) + usage(); + + ifc = atoi(argv[2]); + if (ifc < 1 || ifc > 4) /* ipmi-kcs1 ~ ipmi-kcs4 */ + usage(); + + if (argc == 3) + KCSIfcTask(ifc, 0); + else if (argc == 4 && strcmp(argv[3], "quiet") == 0) + KCSIfcTask(ifc, 1); +#if SUPPORT_KCS_ADDR_CMD + else if (argc == 4 && strcmp(argv[3], "getaddr") == 0) + KCSIfcGetAddr(ifc); + else if (argc == 5 && strcmp(argv[3], "setaddr") == 0) + KCSIfcSetAddr(ifc, strtoul(argv[4], NULL, 16)); +#endif +#if SUPPORT_MAILBOX + } else if (strcmp(cmd, "mailbox") == 0) { + if (argc < 4) + usage(); + + if (strcmp(argv[2], "read") == 0) { + MailBoxRead(atoi(argv[3])); + } else { + if (argc < 5) + usage(); + MailBoxWrite(atoi(argv[3]), strtoul(argv[4], NULL, 16)); + } +#endif +#if SUPPORT_SNOOP + } else if (strcmp(cmd, "snoop") == 0) { + int ifc; + + if (argc < 3) + usage(); + + ifc = atoi(argv[2]); + if (ifc < 0 || ifc > 1) /* snoop0 ~ snoop1 */ + usage(); + + if (strcmp(argv[3], "read") == 0) + ReadBiosPOSTCodes(ifc); + else + usage(); +#endif + } + + return 0; +} + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h new file mode 100644 index 000000000..56c79d1c1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h @@ -0,0 +1,78 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +*/ + +#ifndef __LPC_DRV_H__ +#define __LPC_DRV_H__ + +#define LPC_DEV_MAJOR 250 +#define LPC_DEV_MINOR 0 + +/***********************************************************************************/ + +enum KCS_CMD { + KCS_SET_ADDR = 0, + KCS_GET_ADDR, + KCS_SMS_ATN, + KCS_FORCE_ABORT, +}; + +struct kcs_ioctl_data { + unsigned int cmd; + unsigned int data; +}; + +#define KCS_IOC_BASE 'K' +#define KCS_IOC_COMMAND _IOWR(KCS_IOC_BASE, 1, struct kcs_ioctl_data) + +/***********************************************************************************/ + +enum ACPI_SLP_STATE { + ACPI_STATE_S12 = 1, + ACPI_STATE_S3I, + ACPI_STATE_S45 +}; + +/* SWC & ACPI for SuperIO IOCTL */ +enum SIO_CMD { + SIO_GET_ACPI_STATE = 0, + SIO_GET_PWRGD_STATUS, + SIO_GET_ONCTL_STATUS, + SIO_SET_ONCTL_GPIO, + SIO_GET_PWRBTN_OVERRIDE, + SIO_GET_PFAIL_STATUS, /* Start from AC Loss */ + + SIO_MAX_CMD +}; + +struct sio_ioctl_data { + unsigned short sio_cmd; + unsigned short param; + unsigned int data; +}; + +#define SIO_IOC_BASE 'P' +#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data) + +/***********************************************************************************/ + +#define MAX_MAILBOX_NUM 16 + +/***********************************************************************************/ + +#endif + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb new file mode 100644 index 000000000..2fbb1eb2f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb @@ -0,0 +1,16 @@ +SUMMARY = "LPC tools" +DESCRIPTION = "command tool for LPC interface test on the BMC" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${PHOSPHORBASE}/LICENSE;md5=19407077e42b1ba3d653da313f1f5b4e" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://lpc_drv.h \ + file://lpc_cmds.c \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py new file mode 100755 index 000000000..977fcd3a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py @@ -0,0 +1,144 @@ +#!/usr/bin/python + +import glob +import os +import sys +import time + +if len(sys.argv) == 1: + cpuno = 0 +else: + cpuno = int(sys.argv[1]) + +hwmon_path = '/sys/class/hwmon' +cputemp_name_match = '{}{}'.format('peci_cputemp.cpu', cpuno) +dimmtemp_name_match = '{}{}'.format('peci_dimmtemp.cpu', cpuno) + +dimmtemp_path = '' + +os.chdir(hwmon_path) + +for dirpath, dirnames, files in os.walk(hwmon_path): + for d in dirnames: + try: + with open('{}/{}'.format(d, 'name')) as f: + hwmon_name = f.read().strip() + if hwmon_name == cputemp_name_match: + cputemp_path = os.path.abspath(d) + cputemp_name = hwmon_name + elif hwmon_name == dimmtemp_name_match: + dimmtemp_path = os.path.abspath(d) + dimmtemp_name = hwmon_name + except: + continue + +if not cputemp_path: + print "Can't find the " + cputemp_name_match + quit() + +try: + while True: + os.system('clear') + os.chdir(cputemp_path) + + print '{}/{}: {}'.format(hwmon_path, cputemp_path, cputemp_name) + if dimmtemp_path: + print '{}/{}: {}'.format(hwmon_path, dimmtemp_path, dimmtemp_name) + + print + print 'Package temperature' + for input in glob.glob('temp[1-5]_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print '{:11s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000)) + + print + print 'Core temperature' + count = 0 + for input in glob.glob('temp[!1-5]_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + for input in glob.glob('temp??_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + print + + if dimmtemp_path: + os.chdir(dimmtemp_path) + print + print 'DIMM temperature' + count = 0 + for input in glob.glob('temp*_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + print + else: + os.chdir(hwmon_path) + for dirpath, dirnames, files in os.walk(hwmon_path): + for d in dirnames: + try: + with open('{}/{}'.format(d, 'name')) as f: + hwmon_name = f.read().strip() + if hwmon_name == dimmtemp_name_match: + dimmtemp_path = os.path.abspath(d) + dimmtemp_name = hwmon_name + except: + continue + + time.sleep(1) +except KeyboardInterrupt: + print " exiting..." diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb new file mode 100644 index 000000000..b3b4096a6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb @@ -0,0 +1,20 @@ +SUMMARY = "PECI hwmon test tool" +DESCRIPTION = "command line python tool for testing PECI hwmon" + +SRC_URI = "\ + file://peci-hwmon-test.py \ + " +LICENSE = "CLOSED" + +RDEPENDS_${PN} += "python" + +S = "${WORKDIR}" + +do_compile () { +} + +do_install () { + install -d ${D}/${bindir} + install -m 0755 ${WORKDIR}/peci-hwmon-test.py ${D}/${bindir} +} + diff --git a/meta-openbmc-mods/meta-wht/conf/bblayers.conf.sample b/meta-openbmc-mods/meta-wht/conf/bblayers.conf.sample new file mode 100644 index 000000000..09c2bbc4a --- /dev/null +++ b/meta-openbmc-mods/meta-wht/conf/bblayers.conf.sample @@ -0,0 +1,25 @@ +# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf +# changes incompatibly +LCONF_VERSION = "10" + +BBPATH = "${TOPDIR}" +BBFILES ?= "" + +BBLAYERS ?= " \ + ##OEROOT##/meta \ + ##OEROOT##/meta-poky \ + ##OEROOT##/meta-openembedded/meta-oe \ + ##OEROOT##/meta-openembedded/meta-networking \ + ##OEROOT##/meta-openembedded/meta-perl \ + ##OEROOT##/meta-openembedded/meta-python \ + ##OEROOT##/meta-phosphor \ + ##OEROOT##/meta-aspeed \ + ##OEROOT##/meta-x86 \ + ##OEROOT##/meta-openbmc-mods \ + ##OEROOT##/meta-intel \ + ##OEROOT##/meta-openbmc-mods/meta-common \ + ##OEROOT##/meta-openbmc-mods/meta-common-small \ + ##OEROOT##/meta-openbmc-mods/meta-ast2500 \ + ##OEROOT##/meta-openbmc-mods/meta-wht \ + ##OEROOT##/meta-security \ + " diff --git a/meta-openbmc-mods/meta-wht/conf/conf-notes.txt b/meta-openbmc-mods/meta-wht/conf/conf-notes.txt new file mode 100644 index 000000000..91059a72d --- /dev/null +++ b/meta-openbmc-mods/meta-wht/conf/conf-notes.txt @@ -0,0 +1,6 @@ +Common targets are: + intel-platforms + obmc-phosphor-image + qemu-helper-native + virtual/kernel + phosphor-ipmi-host diff --git a/meta-openbmc-mods/meta-wht/conf/layer.conf b/meta-openbmc-mods/meta-wht/conf/layer.conf new file mode 100644 index 000000000..7f5bc8fa8 --- /dev/null +++ b/meta-openbmc-mods/meta-wht/conf/layer.conf @@ -0,0 +1,14 @@ +LOCALCONF_VERSION = "4" +# 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 += "wht" +BBFILE_PATTERN_wht = "" +BBFILE_PRIORITY_wht = "7" +LAYERSERIES_COMPAT_wht = "warrior" + +PRODUCT_GENERATION = "wht"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-wht/conf/local.conf.sample b/meta-openbmc-mods/meta-wht/conf/local.conf.sample new file mode 100644 index 000000000..f92bf8b33 --- /dev/null +++ b/meta-openbmc-mods/meta-wht/conf/local.conf.sample @@ -0,0 +1,29 @@ +MACHINE ??= "intel-ast2500" +#DL_DIR ?= "/~YoctoDownloads" +#SSTATE_DIR ?= "/~YoctoSstate-cache" +DISTRO ?= "openbmc-phosphor" +PACKAGE_CLASSES ?= "package_rpm" +SANITY_TESTED_DISTROS_append ?= " RedHatEnterpriseWorkstation-6.*" +EXTRA_IMAGE_FEATURES = "debug-tweaks" +USER_CLASSES ?= "buildstats image-mklibs image-prelink" +PATCHRESOLVE = "noop" + +# PFR image Build +# Before exporting the conf, please uncomment the below line +# for building Intel PFR compliant images. +#IMAGE_FSTYPES += "intel-pfr" + +BB_DISKMON_DIRS = "\ + STOPTASKS,${TMPDIR},1G,100K \ + STOPTASKS,${DL_DIR},1G,100K \ + STOPTASKS,${SSTATE_DIR},1G,100K \ + STOPTASKS,/tmp,100M,100K \ + ABORT,${TMPDIR},100M,1K \ + ABORT,${DL_DIR},100M,1K \ + ABORT,${SSTATE_DIR},100M,1K \ + ABORT,/tmp,10M,1K" +CONF_VERSION = "4" +#BB_NUMBER_THREADS = "70" + +FULL_OPTIMIZATION = "-Os -pipe ${DEBUG_FLAGS}" +require conf/distro/include/security_flags.inc diff --git a/meta-openbmc-mods/meta-wht/conf/machine/intel-ast2500.conf b/meta-openbmc-mods/meta-wht/conf/machine/intel-ast2500.conf new file mode 100644 index 000000000..907b9f1e1 --- /dev/null +++ b/meta-openbmc-mods/meta-wht/conf/machine/intel-ast2500.conf @@ -0,0 +1 @@ +require conf/machine/include/intel-ast2500.inc diff --git a/meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample b/meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample new file mode 100644 index 000000000..f3a4bc513 --- /dev/null +++ b/meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample @@ -0,0 +1,25 @@ +# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf +# changes incompatibly +LCONF_VERSION = "10" + +BBPATH = "${TOPDIR}" +BBFILES ?= "" + +BBLAYERS ?= " \ + ##OEROOT##/meta \ + ##OEROOT##/meta-poky \ + ##OEROOT##/meta-openembedded/meta-oe \ + ##OEROOT##/meta-openembedded/meta-networking \ + ##OEROOT##/meta-openembedded/meta-perl \ + ##OEROOT##/meta-openembedded/meta-python \ + ##OEROOT##/meta-phosphor \ + ##OEROOT##/meta-aspeed \ + ##OEROOT##/meta-x86 \ + ##OEROOT##/meta-openbmc-mods \ + ##OEROOT##/meta-intel \ + ##OEROOT##/meta-openbmc-mods/meta-common \ + ##OEROOT##/meta-openbmc-mods/meta-common-small \ + ##OEROOT##/meta-openbmc-mods/meta-ast2500 \ + ##OEROOT##/meta-openbmc-mods/meta-wolfpass \ + ##OEROOT##/meta-security \ + " diff --git a/meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt b/meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt new file mode 100644 index 000000000..91059a72d --- /dev/null +++ b/meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt @@ -0,0 +1,6 @@ +Common targets are: + intel-platforms + obmc-phosphor-image + qemu-helper-native + virtual/kernel + phosphor-ipmi-host diff --git a/meta-openbmc-mods/meta-wolfpass/conf/layer.conf b/meta-openbmc-mods/meta-wolfpass/conf/layer.conf new file mode 100644 index 000000000..db27b43dc --- /dev/null +++ b/meta-openbmc-mods/meta-wolfpass/conf/layer.conf @@ -0,0 +1,14 @@ +LOCALCONF_VERSION = "3" +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "wolfpass" +BBFILE_PATTERN_wolfpass = "" +BBFILE_PRIORITY_wolfpass = "7" +LAYERSERIES_COMPAT_wolfpass = "warrior" + +PRODUCT_GENERATION = "prl" diff --git a/meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample b/meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample new file mode 100644 index 000000000..0d8c780f3 --- /dev/null +++ b/meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample @@ -0,0 +1,23 @@ +MACHINE ??= "intel-ast2500" +#DL_DIR ?= "/~YoctoDownloads" +#SSTATE_DIR ?= "/~YoctoSstate-cache" +DISTRO ?= "openbmc-phosphor" +PACKAGE_CLASSES ?= "package_rpm" +SANITY_TESTED_DISTROS_append ?= " RedHatEnterpriseWorkstation-6.*" +EXTRA_IMAGE_FEATURES = "debug-tweaks" +USER_CLASSES ?= "buildstats image-mklibs image-prelink" +PATCHRESOLVE = "noop" +BB_DISKMON_DIRS = "\ + STOPTASKS,${TMPDIR},1G,100K \ + STOPTASKS,${DL_DIR},1G,100K \ + STOPTASKS,${SSTATE_DIR},1G,100K \ + STOPTASKS,/tmp,100M,100K \ + ABORT,${TMPDIR},100M,1K \ + ABORT,${DL_DIR},100M,1K \ + ABORT,${SSTATE_DIR},100M,1K \ + ABORT,/tmp,10M,1K" +CONF_VERSION = "3" +#BB_NUMBER_THREADS = "70" + +FULL_OPTIMIZATION = "-Os -pipe ${DEBUG_FLAGS}" +require conf/distro/include/security_flags.inc diff --git a/meta-openbmc-mods/meta-wolfpass/conf/machine/intel-ast2500.conf b/meta-openbmc-mods/meta-wolfpass/conf/machine/intel-ast2500.conf new file mode 100644 index 000000000..907b9f1e1 --- /dev/null +++ b/meta-openbmc-mods/meta-wolfpass/conf/machine/intel-ast2500.conf @@ -0,0 +1 @@ +require conf/machine/include/intel-ast2500.inc |