diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common')
381 files changed, 47671 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/COPYING.MIT b/meta-openbmc-mods/meta-common/COPYING.MIT new file mode 100644 index 000000000..89de35479 --- /dev/null +++ b/meta-openbmc-mods/meta-common/COPYING.MIT @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/meta-openbmc-mods/meta-common/README b/meta-openbmc-mods/meta-common/README new file mode 100644 index 000000000..9d4a8a1e6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/README @@ -0,0 +1,64 @@ +This README file contains information on the contents of the +common layer. + +Please see the corresponding sections below for details. + + +Dependencies +============ + +This layer depends on: + + URI: git://git.openembedded.org/bitbake + branch: master + + URI: git://git.openembedded.org/openembedded-core + layers: meta + branch: master + + URI: git://git.yoctoproject.org/xxxx + layers: xxxx + branch: master + + +Patches +======= + +Please submit any patches against the common layer to the +xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer: + +Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com> + + +Table of Contents +================= + + I. Adding the common layer to your build + II. Misc + + +I. Adding the common layer to your build +================================================= + +--- replace with specific instructions for the common layer --- + +In order to use this layer, you need to make the build system aware of +it. + +Assuming the common layer exists at the top-level of your +yocto build tree, you can add it to the build system by adding the +location of the common layer to bblayers.conf, along with any +other layers needed. e.g.: + + BBLAYERS ?= " \ + /path/to/yocto/meta \ + /path/to/yocto/meta-poky \ + /path/to/yocto/meta-yocto-bsp \ + /path/to/yocto/meta-common \ + " + + +II. Misc +======== + +--- replace with specific information about the common layer --- diff --git a/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass new file mode 100644 index 000000000..9563b55cb --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass @@ -0,0 +1,121 @@ + + +inherit obmc-phosphor-full-fitimage +inherit image_types_phosphor_auto +DEPENDS += "obmc-intel-pfr-image-native python3-native intel-blocksign-native" + +require recipes-core/os-release/version-vars.inc + +IMAGE_TYPES += "intel-pfr" + +IMAGE_TYPEDEP_intel-pfr = "mtd-auto" +IMAGE_TYPES_MASKED += "intel-pfr" + +# PFR images directory +PFR_IMAGES_DIR = "${DEPLOY_DIR_IMAGE}/pfr_images" + +# PFR image generation script directory +PFR_SCRIPT_DIR = "${STAGING_DIR_NATIVE}${bindir}" + +# PFR image config directory +PFR_CFG_DIR = "${STAGING_DIR_NATIVE}${datadir}/pfrconfig" + +# Refer flash map in manifest.json for the addresses offset +PFM_OFFSET = "0x80000" + +# 0x80000/1024 = 0x200 or 512, 1K Page size. +PFM_OFFSET_PAGE = "512" + +# RC_IMAGE +RC_IMAGE_OFFSET = "0x02a00000" + +# RC_IMAGE_PAGE= 0x02a00000/1024 = 0xA800 or 43008 +RC_IMAGE_PAGE = "43008" + +do_image_pfr () { + bbplain "Generating Intel PFR compliant BMC image" + + bbplain "Build Version = ${build_version}" + bbplain "Build Number = ${build_number}" + bbplain "Build Hash = ${build_hash}" + + mkdir -p "${PFR_IMAGES_DIR}" + cd "${PFR_IMAGES_DIR}" + + # python script that does the creating PFM, BMC compressed and unsigned images from BMC 128MB raw binary file. + ${PFR_SCRIPT_DIR}/pfr_image.py ${PFR_CFG_DIR}/pfr_manifest.json ${DEPLOY_DIR_IMAGE}/image-mtd ${build_version} ${build_number} ${build_hash} + + # sign the PFM region + ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/pfm_config.xml -o ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm.bin -v + + # Add the signed PFM to rom image + dd bs=1k conv=notrunc seek=${PFM_OFFSET_PAGE} if=${PFR_IMAGES_DIR}/pfm_signed.bin of=${PFR_IMAGES_DIR}/image-mtd-pfr + + # Create unsigned BMC update capsule - append with 1. pfm_signed, 2. pbc, 3. bmc compressed + dd if=${PFR_IMAGES_DIR}/pfm_signed.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin + + dd if=${PFR_IMAGES_DIR}/pbc.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin + + dd if=${PFR_IMAGES_DIR}/bmc_compressed.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin + + # Sign the BMC update capsule + ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/bmc_config.xml -o ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin -v + + # Add the signed bmc update capsule to full rom image @ 0x2a00000 + dd bs=1k conv=notrunc seek=${RC_IMAGE_PAGE} if=${PFR_IMAGES_DIR}/bmc_signed_cap.bin of=${PFR_IMAGES_DIR}/image-mtd-pfr + + # Append date and time to all the PFR images + mv ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm_signed-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/pfm.bin ${PFR_IMAGES_DIR}/pfm-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/pbc.bin ${PFR_IMAGES_DIR}/pbc-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/bmc_compressed.bin ${PFR_IMAGES_DIR}/bmc_compressed-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_signed_cap-${DATETIME}.bin + mv ${PFR_IMAGES_DIR}/image-mtd-pfr ${PFR_IMAGES_DIR}/image-mtd-pfr-${DATETIME}.bin +} + +do_image_pfr[vardepsexclude] += "DATE DATETIME" +do_image_pfr[vardeps] += "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16" +do_image_pfr[depends] += " \ + obmc-intel-pfr-image-native:do_populate_sysroot \ + intel-blocksign-native:do_populate_sysroot \ + " + +python() { + 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..b43933278 --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass @@ -0,0 +1,52 @@ +inherit obmc-phosphor-image +inherit systemd-watchdog + +IMAGE_INSTALL_append = " \ + bmcweb \ + dbus-broker \ + entity-manager \ + ipmitool \ + intel-ipmi-oem \ + phosphor-ipmi-ipmb \ + phosphor-node-manager-proxy \ + dbus-sensors \ + phosphor-webui \ + at-scale-debug \ + phosphor-pid-control \ + phosphor-host-postd \ + phosphor-certificate-manager \ + phosphor-sel-logger \ + smbios-mdrv2 \ + obmc-ikvm \ + system-watchdog \ + frb2-watchdog \ + srvcfg-manager \ + callback-manager \ + post-code-manager \ + preinit-mounts \ + mtd-utils-ubifs \ + special-mode-mgr \ + rsyslog \ + static-mac-addr \ + phosphor-u-boot-mgr \ + prov-mode-mgr \ + ac-boot-check \ + host-error-monitor \ + beepcode-mgr \ + psu-manager \ + kernel-panic-check \ + id-led-off \ + hsbp-manager \ + security-registers-check \ + pch-time-sync \ + nv-sync \ + security-manager \ + multi-node-nl \ + mctpd \ + " + +IMAGE_INSTALL_append = "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'intel-pfr-manager', '', d)}" + +# this package was flagged as a security risk +IMAGE_INSTALL_remove += " lrzsz" + 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..20b77d1be --- /dev/null +++ b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass @@ -0,0 +1,31 @@ +add_watchdog_confs() { + + interval=10 # minutes + count=5 # allowed reboots + + for service in $(ls $D/lib/systemd/system | grep -o ".*service"); do + if [[ "$service" == *"mapper-wait"* ]]; then + continue + fi + + if [ "$service" = "system-watchdog.service" ]; then + continue + fi + + if cat $D/lib/systemd/system/${service} | grep oneshot > /dev/null; then + continue + fi + + folder="$D/etc/systemd/system/${service}.d" + mkdir -p "${folder}" + fname="${folder}/watchdog.conf" + echo "[Unit]" > ${fname} + echo "OnFailure=watchdog-reset.service" >> ${fname} + echo "[Service]" >> "${fname}" + echo "StartLimitInterval=${interval}min" >> "${fname}" + echo "StartLimitBurst=${count}" >> "${fname}" + done + +} + +ROOTFS_POSTINSTALL_COMMAND += "add_watchdog_confs" diff --git a/meta-openbmc-mods/meta-common/conf/layer.conf b/meta-openbmc-mods/meta-common/conf/layer.conf new file mode 100644 index 000000000..4c640e868 --- /dev/null +++ b/meta-openbmc-mods/meta-common/conf/layer.conf @@ -0,0 +1,11 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "common" +BBFILE_PATTERN_common = "^${LAYERDIR}/" +BBFILE_PRIORITY_common = "10" +LAYERSERIES_COMPAT_common = "warrior zeus" diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0000-AST2600-Add-the-latest-chip-initialization-code.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0000-AST2600-Add-the-latest-chip-initialization-code.patch new file mode 100644 index 000000000..2ec774144 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0000-AST2600-Add-the-latest-chip-initialization-code.patch @@ -0,0 +1,265 @@ +From 8c9e2fffa9ea72ddc8734ee74b30cc62ba06fd3a Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 2 Mar 2020 13:54:50 -0800 +Subject: [PATCH] AST2600: Add the latest chip initialization code + +This commit cherry picked the latest chip initialization code from +Aspped SDK v00.05.05 to support AST2600 A1 revision. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/mach-aspeed/ast2600/Makefile | 2 +- + arch/arm/mach-aspeed/ast2600/cache.c | 26 +++++++ + arch/arm/mach-aspeed/ast2600/platform.S | 132 +++++++++++++++++++++++++------- + 3 files changed, 130 insertions(+), 30 deletions(-) + create mode 100644 arch/arm/mach-aspeed/ast2600/cache.c + +diff --git a/arch/arm/mach-aspeed/ast2600/Makefile b/arch/arm/mach-aspeed/ast2600/Makefile +index b074d4b70a14..2889388fab75 100644 +--- a/arch/arm/mach-aspeed/ast2600/Makefile ++++ b/arch/arm/mach-aspeed/ast2600/Makefile +@@ -1,2 +1,2 @@ +-obj-y += platform.o aspeed_scu_info.o ++obj-y += platform.o aspeed_scu_info.o cache.o + obj-$(CONFIG_SPL_BUILD) += spl.o +diff --git a/arch/arm/mach-aspeed/ast2600/cache.c b/arch/arm/mach-aspeed/ast2600/cache.c +new file mode 100644 +index 000000000000..82de0b0fda8a +--- /dev/null ++++ b/arch/arm/mach-aspeed/ast2600/cache.c +@@ -0,0 +1,26 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) ASPEED Technology Inc. ++ * Chia-Wei Wang <chiawei_wang@aspeedtech.com> ++ */ ++ ++#include <common.h> ++#include <asm/system.h> ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++void enable_caches(void) ++{ ++#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) ++ enum dcache_option opt = DCACHE_WRITETHROUGH; ++#else ++ enum dcache_option opt = DCACHE_WRITEBACK; ++#endif ++ /* enable D-cache as well as MMU */ ++ dcache_enable(); ++ ++ /* setup cache attribute for DRAM region */ ++ mmu_set_region_dcache_behaviour(ASPEED_DRAM_BASE, ++ gd->ram_size, ++ opt); ++} +diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S +index de97cccc78b7..f1a1f057c09b 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -26,39 +26,45 @@ + * +----------------------+ AST_SMP_MAILBOX_BASE + */ + +-#define AST_SMP_MAILBOX_BASE 0x1E6E2180 ++#define AST_SMP_MAILBOX_BASE (0x1E6E2180) + #define AST_SMP_MBOX_FIELD_ENTRY (AST_SMP_MAILBOX_BASE + 0x0) + #define AST_SMP_MBOX_FIELD_GOSIGN (AST_SMP_MAILBOX_BASE + 0x4) + #define AST_SMP_MBOX_FIELD_READY (AST_SMP_MAILBOX_BASE + 0x8) + #define AST_SMP_MBOX_FIELD_POLLINSN (AST_SMP_MAILBOX_BASE + 0xc) + + /* AST2600 HW registers */ +-#define AST_SCU_BASE 0x1E6E2000 +-#define AST_SCU_PROT_KEY1 (AST_SCU_BASE) +-#define AST_SCU_PROT_KEY2 (AST_SCU_BASE + 0x010) +-#define AST_SCU_REV_ID (AST_SCU_BASE + 0x014) +-#define AST_SCU_HPLL_PARAM (AST_SCU_BASE + 0x200) +-#define AST_SCU_HPLL_PARAM_EXT (AST_SCU_BASE + 0x204) +-#define AST_SCU_HW_STRAP1 (AST_SCU_BASE + 0x500) +-#define AST_SCU_CA7_PARITY_CHK (AST_SCU_BASE + 0x820) +-#define AST_SCU_CA7_PARITY_CLR (AST_SCU_BASE + 0x824) +- +-#define AST_FMC_BASE 0x1E620000 ++#define AST_SCU_BASE (0x1E6E2000) ++#define AST_SCU_PROT_KEY1 (AST_SCU_BASE) ++#define AST_SCU_PROT_KEY2 (AST_SCU_BASE + 0x010) ++#define AST_SCU_REV_ID (AST_SCU_BASE + 0x014) ++#define AST_SCU_SYSRST_CTRL (AST_SCU_BASE + 0x040) ++#define AST_SCU_SYSRST_CTRL_CLR (AST_SCU_BASE + 0x044) ++#define AST_SCU_DEBUG_CTRL (AST_SCU_BASE + 0x0C8) ++#define AST_SCU_DEBUG_CTRL2 (AST_SCU_BASE + 0x0D8) ++#define AST_SCU_HPLL_PARAM (AST_SCU_BASE + 0x200) ++#define AST_SCU_HPLL_PARAM_EXT (AST_SCU_BASE + 0x204) ++#define AST_SCU_HW_STRAP1 (AST_SCU_BASE + 0x500) ++#define AST_SCU_HW_STRAP1_CLR (AST_SCU_BASE + 0x504) ++#define AST_SCU_HW_STRAP2 (AST_SCU_BASE + 0x510) ++#define AST_SCU_HW_STRAP2_CLR (AST_SCU_BASE + 0x514) ++#define AST_SCU_CA7_CTRL (AST_SCU_BASE + 0x800) ++#define AST_SCU_CA7_AXI_PREFETCH_START (AST_SCU_BASE + 0x808) ++#define AST_SCU_CA7_AXI_PREFETCH_END (AST_SCU_BASE + 0x80C) ++#define AST_SCU_CA7_PARITY_CHK (AST_SCU_BASE + 0x820) ++#define AST_SCU_CA7_PARITY_CLR (AST_SCU_BASE + 0x824) ++#define AST_SCU_MMIO_DEC_SET (AST_SCU_BASE + 0xC24) ++ ++#define AST_FMC_BASE (0x1E620000) ++#define AST_FMC_CE0_CTRL (AST_FMC_BASE + 0x010) + #define AST_FMC_WDT1_CTRL_MODE (AST_FMC_BASE + 0x060) + #define AST_FMC_WDT2_CTRL_MODE (AST_FMC_BASE + 0x064) + ++#define AST_GPIO_BASE (0x1E780000) ++#define AST_GPIOYZ_DATA_VALUE (AST_GPIO_BASE + 0x1E0) ++ + /* Revision ID */ + #define REV_ID_AST2600A0 0x05000303 + +-ENTRY(ast_bootmode) +- ldr r1, =AST_SCU_HW_STRAP1 +- ldr r0, [r1] +- tst r0, #0x4 +- moveq r0, #0x0 @; AST_BOOTMODE_SPI +- movne r0, #0x1 @; AST_BOOTMODE_EMMC +- mov pc, lr +-ENDPROC(ast_bootmode) +- + .macro scu_unlock + movw r0, #0xA8A8 + movt r0, #0x1688 @; magic key to unlock SCU +@@ -71,11 +77,19 @@ ENDPROC(ast_bootmode) + + .macro timer_init + #ifdef CONFIG_FPGA_ASPEED +- movw r0, #0x7840 +- movt r0, #0x17D ++ movw r0, #0xF080 ++ movt r0, #0x2FA + #else +- movw r0, #0x2340 +- movt r0, #0x430E ++ ldr r0, =AST_SCU_REV_ID ++ ldr r0, [r0] ++ ++ ldr r1, =REV_ID_AST2600A0 ++ cmp r0, r1 ++ ++ movweq r0, #0x32C0 ++ movteq r0, #0x4013 ++ movwne r0, #0x8C00 ++ movtne r0, #0x4786 + #endif + mcr p15, 0, r0, c14, c0, 0 @; update CNTFRQ + .endm +@@ -133,7 +147,7 @@ do_primary_core_setup: + /* unlock system control unit */ + scu_unlock + +- /* tune-up CPU clock for AST2600 A0 */ ++ /* identify AST2600 A0/A1 */ + ldr r0, =AST_SCU_REV_ID + ldr r0, [r0] + +@@ -142,7 +156,7 @@ do_primary_core_setup: + + bne 0f + +- /* setup CPU clocks */ ++ /* tune up CPU clocks (A0 only) */ + ldr r0, =AST_SCU_HW_STRAP1 + ldr r1, [r0] + bic r1, #0x1800 +@@ -150,7 +164,7 @@ do_primary_core_setup: + str r1, [r0] + + ldr r0, =AST_SCU_HPLL_PARAM +- movw r1, #0x4087 ++ movw r1, #0x4080 + movt r1, #0x1000 + str r1, [r0] + +@@ -163,13 +177,54 @@ wait_lock: + tst r1, #0x80000000 + beq wait_lock + ++ /* skip A1 only area */ ++ b 1f ++ + 0: ++ /* enable AXI prefetch (A1 only) */ ++ ldr r0, =AST_SCU_CA7_AXI_PREFETCH_START ++ ldr r1, =ASPEED_DRAM_BASE ++ str r1, [r0] ++ ++ ldr r0, =AST_SCU_CA7_AXI_PREFETCH_END ++ ldr r1, =0xFFFFFFFF ++ str r1, [r0] ++ ++ ldr r0, =AST_SCU_CA7_CTRL ++ ldr r1, [r0] ++ orr r1, #0x8000 ++ str r1, [r0] ++ ++ /* LPC/eSPI mode selection (A1 only) */ ++ ldr r0, =AST_GPIOYZ_DATA_VALUE ++ ldr r0, [r0] ++ tst r0, #0x1000 ++ beq 1f ++ ++ /* switch to LPC mode if GPIOZ[4]=1 */ ++ ldr r0, =AST_SCU_HW_STRAP2 ++ ldr r1, [r0] ++ orr r1, #0x40 ++ str r1, [r0] ++ ++1: ++ /* release display port reset */ ++ ldr r0, =AST_SCU_SYSRST_CTRL_CLR ++ movw r1, #0x0000 ++ movt r1, #0x3000 ++ str r1, [r0] ++ ++ /* MMIO decode setting */ ++ ldr r0, =AST_SCU_MMIO_DEC_SET ++ mov r1, #0x2000 ++ str r1, [r0] ++ + /* enable cache & SRAM parity check */ + mov r0, #0 + ldr r1, =AST_SCU_CA7_PARITY_CLR + str r0, [r1] + +- mov r0, #0x11 ++ mov r0, #0x1 + ldr r1, =AST_SCU_CA7_PARITY_CHK + str r0, [r1] + +@@ -177,8 +232,27 @@ wait_lock: + mov r0, #0 + ldr r1, =AST_FMC_WDT1_CTRL_MODE + str r0, [r1] ++#if 0 + ldr r1, =AST_FMC_WDT2_CTRL_MODE + str r0, [r1] ++#endif ++ /* tune up SPI clock */ ++ movw r0, #0x0641 ++ movt r0, #0x203B ++ ldr r1, =AST_FMC_CE0_CTRL ++ str r0, [r1] ++ ++ /* disable UART-based SoC Debug Interface UART5 and P2A bridge*/ ++ ldr r0, =AST_SCU_DEBUG_CTRL ++ ldr r1, [r0] ++ orr r1, #0x03 ++ str r1, [r0] ++ ++ /* disable UART-based SoC Debug Interface UART1 and LPC2AHB bridge */ ++ ldr r0, =AST_SCU_DEBUG_CTRL2 ++ ldr r1, [r0] ++ orr r1, #0x0A ++ str r1, [r0] + + /* relocate mailbox insn. for cpuN polling SMP go signal */ + adrl r0, mailbox_insn +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch new file mode 100644 index 000000000..f1505b8cd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-Add-ast2600-intel-as-a-new-board.patch @@ -0,0 +1,1360 @@ +From efa949f82a1dd32b83eafe3fe58038abc04ecdbf Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Thu, 24 Oct 2019 14:06:33 -0700 +Subject: [PATCH] Add ast2600-intel as a new board + +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + arch/arm/dts/Makefile | 3 + + arch/arm/dts/ast2600-intel.dts | 157 ++++++++++ + arch/arm/lib/interrupts.c | 5 + + arch/arm/mach-aspeed/ast2600/Kconfig | 9 + + arch/arm/mach-aspeed/ast2600/aspeed_scu_info.c | 1 + + board/aspeed/ast2600_intel/Kconfig | 13 + + board/aspeed/ast2600_intel/Makefile | 4 + + board/aspeed/ast2600_intel/ast-espi.c | 298 ++++++++++++++++++ + board/aspeed/ast2600_intel/ast-irq.c | 399 +++++++++++++++++++++++++ + board/aspeed/ast2600_intel/ast-irq.h | 8 + + board/aspeed/ast2600_intel/ast-timer.c | 59 ++++ + board/aspeed/ast2600_intel/intel.c | 176 +++++++++++ + cmd/Kconfig | 2 +- + common/autoboot.c | 10 + + common/board_r.c | 8 +- + include/configs/evb_ast2600.h | 2 +- + 16 files changed, 1148 insertions(+), 6 deletions(-) + create mode 100644 arch/arm/dts/ast2600-intel.dts + create mode 100644 board/aspeed/ast2600_intel/Kconfig + create mode 100644 board/aspeed/ast2600_intel/Makefile + create mode 100644 board/aspeed/ast2600_intel/ast-espi.c + create mode 100644 board/aspeed/ast2600_intel/ast-irq.c + create mode 100644 board/aspeed/ast2600_intel/ast-irq.h + create mode 100644 board/aspeed/ast2600_intel/ast-timer.c + create mode 100644 board/aspeed/ast2600_intel/intel.c + +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile +index d1d4dca340f8..38fe8113469e 100644 +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -680,6 +680,9 @@ dtb-$(CONFIG_TARGET_EVB_AST2500) += \ + dtb-$(CONFIG_TARGET_EVB_AST2600) += \ + ast2600-evb.dtb + ++dtb-$(CONFIG_TARGET_AST2600_INTEL) += \ ++ ast2600-intel.dtb ++ + dtb-$(CONFIG_TARGET_FPGA_AST2600) += \ + ast2600-fpga.dtb + +diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts +new file mode 100644 +index 000000000000..99788b21e444 +--- /dev/null ++++ b/arch/arm/dts/ast2600-intel.dts +@@ -0,0 +1,157 @@ ++/dts-v1/; ++ ++#include "ast2600-u-boot.dtsi" ++ ++/ { ++ memory { ++ device_type = "memory"; ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ chosen { ++ stdout-path = &uart5; ++ }; ++ ++ aliases { ++ spi0 = &fmc; ++ ethernet1 = &mac1; ++ }; ++ ++ cpus { ++ cpu@0 { ++ clock-frequency = <800000000>; ++ }; ++ cpu@1 { ++ clock-frequency = <800000000>; ++ }; ++ }; ++ ++ system-leds { ++ compatible = "gpio-leds"; ++ green-led { ++ label = "green"; ++ gpios = <&gpio0 50 GPIO_ACTIVE_LOW>; ++ default-state = "blink"; ++ }; ++ amber-led { ++ label = "amber"; ++ gpios = <&gpio0 51 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ id-led { ++ label = "id"; ++ gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; ++ default-state = "blink"; ++ }; ++ hb-led { ++ label = "hb"; ++ gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++}; ++ ++&gpio0 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&uart2 { ++ status = "okay"; ++}; ++ ++&uart5 { ++ u-boot,dm-pre-reloc; ++ status = "okay"; ++}; ++ ++&sdrammc { ++ clock-frequency = <400000000>; ++}; ++ ++&wdt1 { ++ u-boot,dm-pre-reloc; ++ status = "okay"; ++}; ++ ++&wdt2 { ++ u-boot,dm-pre-reloc; ++ status = "okay"; ++}; ++ ++&wdt3 { ++ u-boot,dm-pre-reloc; ++ status = "okay"; ++}; ++ ++&mdio { ++ status = "okay"; ++}; ++ ++&mac1 { ++ status = "okay"; ++ ++ phy-mode = "rgmii"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mac2link_default &pinctrl_mdio2_default>; ++}; ++ ++&fmc { ++ status = "okay"; ++#if 0 ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_fmcquad_default>; ++#endif ++ flash@0 { ++ compatible = "spi-flash", "sst,w25q256"; ++ status = "okay"; ++ spi-max-frequency = <40000000>; ++ spi-tx-bus-width = <2>; ++ spi-rx-bus-width = <2>; ++ }; ++}; ++ ++&emmc_slot0 { ++ status = "okay"; ++ bus-width = <4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_emmc_default>; ++}; ++ ++&i2c4 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c5_default>; ++}; ++ ++&i2c5 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c6_default>; ++}; ++ ++&i2c6 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c7_default>; ++}; ++ ++&i2c7 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c8_default>; ++}; ++ ++&i2c8 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c9_default>; ++}; +diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c +index ee775ce5d264..8c985532afb4 100644 +--- a/arch/arm/lib/interrupts.c ++++ b/arch/arm/lib/interrupts.c +@@ -25,6 +25,7 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++int interrupt_init (void) __attribute__((weak)); + int interrupt_init (void) + { + /* +@@ -35,10 +36,13 @@ int interrupt_init (void) + return 0; + } + ++void enable_interrupts (void) __attribute__((weak)); + void enable_interrupts (void) + { + return; + } ++ ++int disable_interrupts (void) __attribute__((weak)); + int disable_interrupts (void) + { + return 0; +@@ -189,6 +193,7 @@ void do_fiq (struct pt_regs *pt_regs) + bad_mode (); + } + ++void do_irq (struct pt_regs *pt_regs) __attribute__((weak)); + void do_irq (struct pt_regs *pt_regs) + { + efi_restore_gd(); +diff --git a/arch/arm/mach-aspeed/ast2600/Kconfig b/arch/arm/mach-aspeed/ast2600/Kconfig +index 3c208ff3da67..a2a2fe0e24a8 100644 +--- a/arch/arm/mach-aspeed/ast2600/Kconfig ++++ b/arch/arm/mach-aspeed/ast2600/Kconfig +@@ -24,9 +24,18 @@ config TARGET_FPGA_AST2600 + FPGA-AST2600 is Aspeed FPGA board for AST2600 chip. + This is mainly for internal development. Note that + most implementation is co-code with EVB-AST2600. ++ ++config TARGET_AST2600_INTEL ++ bool "AST2600-INTEL" ++ depends on ASPEED_AST2600 ++ help ++ AST2600-INTEL is an Intel server board with the AST2600 ++ as the BMC. ++ + endchoice + + source "board/aspeed/evb_ast2600/Kconfig" + source "board/aspeed/fpga_ast2600/Kconfig" ++source "board/aspeed/ast2600_intel/Kconfig" + + endif +diff --git a/arch/arm/mach-aspeed/ast2600/aspeed_scu_info.c b/arch/arm/mach-aspeed/ast2600/aspeed_scu_info.c +index c31e8a3614b0..84ca9f68aee7 100644 +--- a/arch/arm/mach-aspeed/ast2600/aspeed_scu_info.c ++++ b/arch/arm/mach-aspeed/ast2600/aspeed_scu_info.c +@@ -88,6 +88,7 @@ extern void + aspeed_sys_reset_info(void) + { + u32 rest = readl(ASPEED_SYS_RESET_CTRL); ++ printf("RST: %08x\n", rest); + + if (rest & SYS_PWR_RESET_FLAG) { + printf("RST : Power On \n"); +diff --git a/board/aspeed/ast2600_intel/Kconfig b/board/aspeed/ast2600_intel/Kconfig +new file mode 100644 +index 000000000000..b841dab60c76 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/Kconfig +@@ -0,0 +1,13 @@ ++if TARGET_AST2600_INTEL ++ ++config SYS_BOARD ++ default "ast2600_intel" ++ ++config SYS_VENDOR ++ default "aspeed" ++ ++config SYS_CONFIG_NAME ++ string "board configuration name" ++ default "ast2600_intel" ++ ++endif +diff --git a/board/aspeed/ast2600_intel/Makefile b/board/aspeed/ast2600_intel/Makefile +new file mode 100644 +index 000000000000..37d2f0064f38 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/Makefile +@@ -0,0 +1,4 @@ ++obj-y += intel.o ++obj-y += ast-espi.o ++obj-y += ast-irq.o ++obj-y += ast-timer.o +diff --git a/board/aspeed/ast2600_intel/ast-espi.c b/board/aspeed/ast2600_intel/ast-espi.c +new file mode 100644 +index 000000000000..1852dd3d86e2 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ast-espi.c +@@ -0,0 +1,298 @@ ++/* ++ * 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> ++ ++#define AST_LPC_BASE 0x1e6e9000 ++#define AST_ESPI_BASE 0x1e6ee000 ++#define AST_SCU_BASE 0x1e6e2000 ++#define AST_SCU_HW_STRAP2 0x510 ++#define SCU_HW_STRAP_ESPI_ENABLED 0x40 ++ ++#define USE_HW_HANDSHAKE 0 ++#define DEBUG_ESPI_ENABLED 0 ++#if DEBUG_ESPI_ENABLED ++#define DBG_ESPI printf ++#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 ESPI080 0x080 /* Engine Control 2. */ ++#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 BIT(4) ++#define AST_ESPI_FLASH_SW_CHRDY BIT(7) ++#define AST_ESPI_FLASH_SW_READ BIT(10) ++ ++/* ESPI00C bits (Interrupt Enable) */ ++#define AST_ESPI_IEN_HW_RST BIT(31) ++#define AST_ESPI_IEN_SYS1_EV BIT(22) ++#define AST_ESPI_IEN_SYS_EV BIT(8) ++#define AST_ESPI_IEN_GPIO_EV BIT(9) ++ ++/* ESPI008 bits ISR */ ++#define AST_ESPI_VW_SYS_EVT BIT(8) ++#define AST_ESPI_VW_GPIO_EVT BIT(9) ++#define AST_ESPI_VW_SYS_EV1 BIT(22) ++#define AST_ESPI_HW_RST BIT(31) ++ ++/* ESPI080 bits */ ++#define AST_ESPI_AUTO_ACK_HOST_RST_WARN BIT(2) ++#define AST_ESPI_AUTO_ACK_OOB_RST_WARN BIT(1) ++#define AST_ESPI_AUTO_ACK_SUS_WARN BIT(0) ++ ++/* ESPI098 and ESPI11C bits */ ++#define AST_ESPI_OOB_RST_WARN BIT(6) ++#define AST_ESPI_HOST_RST_WARN BIT(8) ++#define AST_ESPI_PLTRSTN BIT(5) ++#define AST_ESPI_OOB_RST_ACK BIT(16) ++#define AST_ESPI_SL_BT_DONE BIT(20) ++#define AST_ESPI_SL_BT_STATUS BIT(23) ++#define AST_ESPI_HOST_RST_ACK BIT(27) ++ ++/* ESPI104 bits */ ++#define AST_ESPI_SUS_WARN BIT(0) ++#define AST_ESPI_SUS_ACK BIT(20) ++ ++/* LPC chip ID */ ++#define SCR0SIO 0x170 ++#define IRQ_SRC_ESPI 74 /* IRQ 74 */ ++ ++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); ++ } ++ ++ uint32_t sys1_event = readl(AST_ESPI_BASE + ESPI104); ++ if (sys1_event & AST_ESPI_SUS_WARN && ++ !(sys1_event & AST_ESPI_SUS_ACK)) { ++ DBG_ESPI("Boot SUS_WARN, evt: 0x%08x\n", sys1_event); ++ writel(sys1_event | AST_ESPI_SUS_ACK, AST_ESPI_BASE + ESPI104); ++ DBG_ESPI("SUS_WARN sent ack\n"); ++ } ++} ++ ++int espi_irq_handler(struct pt_regs *regs) ++{ ++ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008); ++ ++ DBG_ESPI("espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x,\ ++ ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x,\ ++ ESPI12c=0X%x, irq_status=0x%x\n", ++ readl(AST_ESPI_BASE + ESPI008), ++ readl(AST_ESPI_BASE + ESPI00C), ++ readl(AST_ESPI_BASE + ESPI100), ++ readl(AST_ESPI_BASE + ESPI11C), ++ readl(AST_ESPI_BASE + ESPI094), ++ readl(AST_ESPI_BASE + ESPI12C), 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 evt: 0x%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); ++ DBG_ESPI("HOST_RST_WARN sent ack\n"); ++ } ++ } ++ if (sys_status & AST_ESPI_OOB_RST_WARN) { ++ DBG_ESPI("OOB_RST_WARN evt: 0x%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); ++ DBG_ESPI("OOB_RST_WARN sent ack\n"); ++ } ++ } ++ if (sys_status & AST_ESPI_PLTRSTN) { ++ DBG_ESPI("PLTRSTN: %c, evt: 0x%08X\n", ++ (sys_event & AST_ESPI_PLTRSTN) ? '1' : '0', ++ sys_event); ++ } ++ 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 evt: 0x%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); ++ DBG_ESPI("SUS_WARN sent ack\n"); ++ } ++ } ++ writel(sys1_status, AST_ESPI_BASE + ESPI12C); /* clear status */ ++ } ++ ++ if (irq_status & AST_ESPI_HW_RST) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI000) & 0x00ffffffff; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ v |= 0xff000000; ++ writel(v, AST_ESPI_BASE + ESPI000); ++ ++ DBG_ESPI("HW_RESET\n"); ++ ++ espi_handshake_ack(); ++ } ++ ++ writel(irq_status, AST_ESPI_BASE + ESPI008); /* clear irq_status */ ++ ++ DBG_ESPI("end espi_irq_handler, ESPI008=0X%x, ESPI00c=0X%x,\ ++ ESPI100=0X%x, ESPI11c=0X%x, ESPI094=0X%x,\ ++ ESPI12c=0X%x, irq_status=0X%x\n", ++ readl(AST_ESPI_BASE + ESPI008), ++ readl(AST_ESPI_BASE + ESPI00C), ++ readl(AST_ESPI_BASE + ESPI100), ++ readl(AST_ESPI_BASE + ESPI11C), ++ readl(AST_ESPI_BASE + ESPI094), ++ readl(AST_ESPI_BASE + ESPI12C), irq_status); ++ return 0; ++} ++ ++void espi_init(void) ++{ ++ if (!readl(AST_SCU_BASE + AST_SCU_HW_STRAP2) & ++ SCU_HW_STRAP_ESPI_ENABLED) { ++ uint32_t v; ++ ++ DBG_ESPI("espi init\n"); ++ ++ writel(0xff000000, AST_SCU_BASE + 0x454); /* driving strength */ ++ ++ /* 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); ++ ++#if USE_HW_HANDSHAKE ++ v = readl(AST_ESPI_BASE + ESPI098) | ++ AST_ESPI_SL_BT_STATUS | AST_ESPI_SL_BT_DONE; ++ writel(v, AST_ESPI_BASE + ESPI098); ++ ++ return; ++#endif ++ ++ v = readl(AST_ESPI_BASE + ESPI080); ++ v &= ~(AST_ESPI_AUTO_ACK_HOST_RST_WARN | ++ AST_ESPI_AUTO_ACK_OOB_RST_WARN | ++ AST_ESPI_AUTO_ACK_SUS_WARN); ++ writel(v, AST_ESPI_BASE + ESPI080); /* Disable auto H/W ack */ ++ ++ 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_PLTRSTN, AST_ESPI_BASE + ESPI118); ++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN | ++ AST_ESPI_PLTRSTN, 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_HW_RST | AST_ESPI_IEN_SYS1_EV | ++ AST_ESPI_IEN_SYS_EV, AST_ESPI_BASE + ESPI00C); ++ ++ irq_install_handler(IRQ_SRC_ESPI, espi_irq_handler, NULL); ++ } else { ++ DBG_ESPI("No espi strap\n"); ++ } ++} +diff --git a/board/aspeed/ast2600_intel/ast-irq.c b/board/aspeed/ast2600_intel/ast-irq.c +new file mode 100644 +index 000000000000..f817f8cd7c81 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ast-irq.c +@@ -0,0 +1,399 @@ ++/* ++ * 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/io.h> ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define GIC_DISTRIBUTOR_OFFSET 0x1000 ++#define GIC_CPU_OFFSET 0x2000 ++#define GIC_INTERFACE_OFFSET 0x4000 ++#define GIC_VIRT_OFFSET 0x6000 ++ ++#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) ++ ++/* GIC_DISTRIBUTOR_OFFSET register offsets */ ++#define GICD_CTLR 0x000 ++#define GICD_TYPER 0x004 ++#define GICD_IIDR 0x008 ++#define GICD_IGROUPRn 0x080 ++#define GICD_ISENABLERn 0x100 ++#define GICD_ICENABLERn 0x180 ++#define GICD_ISPENDRn 0x200 ++#define GICD_ICPENDRn 0x280 ++#define GICD_ISACTIVERn 0x300 ++#define GICD_ICACTIVERn 0x380 ++#define GICD_IPRIORITYRn 0x400 ++#define GICD_ITARGETSRn 0x800 ++#define GICD_ICFGRn 0xc00 ++#define GICD_PPISR 0xd00 ++#define GICD_SPISRn 0xd04 ++#define GICD_SGIR 0xf00 ++#define GICD_CPENDINGIRn 0xf10 ++#define GICD_SPENDINGIRn 0xf10 ++#define GICD_PIDR4 0xfd0 ++#define GICD_PIDR5 0xfd4 ++#define GICD_PIDR6 0xfd8 ++#define GICD_PIDR7 0xfdc ++#define GICD_PIDR0 0xfe0 ++#define GICD_PIDR1 0xfe4 ++#define GICD_PIDR2 0xfe8 ++#define GICD_PIDR3 0xfec ++#define GICD_CIDR0 0xff0 ++#define GICD_CIDR1 0xff4 ++#define GICD_CIDR2 0xff8 ++#define GICD_CIDR3 0xffc ++ ++#define GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC 0x0100143b ++ ++/* GIC_CPU_OFFSET register offsets */ ++#define GICC_CTLR 0x0000 ++#define GICC_PMRn 0x0004 ++#define GICC_BPR 0x0008 ++#define GICC_IAR 0x000c ++#define GICC_EOIR 0x0010 ++#define GICC_RPR 0x0014 ++#define GICC_HPPIR 0x0018 ++#define GICC_ABPR 0x001c ++#define GICC_AIAR 0x0020 ++#define GICC_AEOIR 0x0024 ++#define GICC_AHPPIR 0x0028 ++#define GICC_APR0 0x00d0 ++#define GICC_NSAPR0 0x00e0 ++#define GICC_IIDR 0x00fc ++#define GICC_DIR 0x1000 ++ ++#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b ++ ++/* GIC_INTERFACE_OFFSET register offsets */ ++#define GICH_HCR 0x000 ++#define GICH_VTR 0x004 ++#define GICH_VMCR 0x008 ++#define GICH_MISR 0x010 ++#define GICH_EISR0 0x020 ++#define GICH_ELSR0 0x020 ++#define GICH_APR0 0x0f0 ++#define GICH_LR0 0x100 ++#define GICH_LR1 0x104 ++#define GICH_LR2 0x108 ++#define GICH_LR3 0x10c ++ ++/* GIC_VIRT_OFFSET register offsets */ ++#define GICV_CTLR 0x0000 ++#define GICV_PMR 0x0004 ++#define GICV_BPR 0x0008 ++#define GICV_IAR 0x000c ++#define GICV_EOIR 0x0010 ++#define GICV_RPR 0x0014 ++#define GICV_HPPIR 0x0018 ++#define GICV_ABPR 0x001c ++#define GICV_AIAR 0x0020 ++#define GICV_AEOIR 0x0024 ++#define GICV_AHPPIR 0x0028 ++#define GICV_APR0 0x00d0 ++#define GICV_NSAPR0 0x00e0 ++#define GICV_IIDR 0x00fc ++#define GICV_DIR 0x1000 ++ ++#define GIC_VIRT_CPU_IMPLEMENTER_MAGIC 0x0102143b ++ ++#define GICD_CTLR_ENABLE 0x03 ++ ++#define GICD_INT_DEF_PRI 0xa0 ++#define GICD_INT_DEF_PRI_X4 (\ ++ (GICD_INT_DEF_PRI << 24) |\ ++ (GICD_INT_DEF_PRI << 16) |\ ++ (GICD_INT_DEF_PRI << 8) |\ ++ GICD_INT_DEF_PRI) ++ ++#define GICD_INT_ACTLOW_LVLTRIG 0 ++#define GICD_INT_EN_CLR_X32 0xffffffff ++#define GICD_INT_EN_CLR_PPI 0xffff0000 ++#define GICD_INT_EN_SET_SGI 0x0000ffff ++ ++#define gicd_readl(OFFSET) readl(gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET)) ++#define gicd_writel(VALUE, OFFSET) \ ++ writel((VALUE), gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET)) ++#define gicc_readl(OFFSET) readl(gbase + GIC_CPU_OFFSET + (OFFSET)) ++#define gich_readl(OFFSET) readl(gbase + GIC_INTERFACE_OFFSET + (OFFSET)) ++#define gicv_readl(OFFSET) readl(gbase + GIC_VIRT_OFFSET + (OFFSET)) ++ ++static size_t max_irq = 0; ++ ++#define ITLINES_MASK 0x1f ++#define ITLINES_SHIFT 5 ++ ++#define GIC_MAX_IRQ 1020 ++static interrupt_handler_t *handlers[GIC_MAX_IRQ] = {NULL}; ++static unsigned long irq_total = 0; ++static unsigned long irq_counts[GIC_MAX_IRQ] = {0}; ++static uint32_t gbase = 0; ++ ++/* TODO: This, hard-coded, or from dts? */ ++static inline uint32_t gic_base(void) ++{ ++ uint32_t base; ++ /* read the base address of the private peripheral space */ ++ __asm__ __volatile__("mrc p15, 4, %r0, c15, c0, 0\n\t" : "=r"(base) : ); ++ return base; ++} ++ ++static void enable_gic(void) ++{ ++ uint32_t gicd_ctlr; ++ ++ /* add GIC offset ref table 1-3 for interrupt distributor address */ ++ gicd_ctlr = gicd_readl(GICD_CTLR); ++ gicd_writel(gicd_ctlr | GICD_CTLR_ENABLE, GICD_CTLR); ++} ++ ++static void disable_gic(void) ++{ ++ uint32_t gicd_ctlr; ++ ++ /* add GIC offset ref table 1-3 for interrupt distributor address */ ++ gicd_ctlr = gicd_readl(GICD_CTLR); ++ gicd_writel(gicd_ctlr & ~GICD_CTLR_ENABLE, GICD_CTLR); ++} ++ ++static void enable_irq_id(unsigned int id) ++{ ++ uint32_t grp = id >> ITLINES_SHIFT; ++ uint32_t grp_bit = 1 << (id & ITLINES_MASK); ++ gicd_writel(grp_bit, GICD_ISENABLERn + grp * sizeof(uint32_t)); ++} ++ ++static void disable_irq_id(unsigned int id) ++{ ++ uint32_t grp = id >> ITLINES_SHIFT; ++ uint32_t grp_bit = 1 << (id & ITLINES_MASK); ++ gicd_writel(grp_bit, GICD_ICENABLERn + grp * sizeof(uint32_t)); ++} ++ ++static int gic_probe(void) ++{ ++ int i; ++ gbase = gic_base(); ++ enable_gic(); ++ ++ if (gicd_readl(GICD_IIDR) != GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC && ++ gicc_readl(GICC_IIDR) != GIC_CPU_IMPLEMENTER_MAGIC && ++ gicv_readl(GICV_IIDR) != GIC_VIRT_CPU_IMPLEMENTER_MAGIC) ++ { ++ return 0; ++ } ++ /* GIC supports up to 1020 lines */ ++ max_irq = ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) << ITLINES_SHIFT; ++ if (max_irq > GIC_MAX_IRQ) ++ max_irq = GIC_MAX_IRQ; ++ /* set all lines to be level triggered N-N */ ++ for (i = 32; i < max_irq; i += 16) ++ gicd_writel(0, GICD_ICFGRn + i / 4); ++ ++ /* Set priority on all interrupts. */ ++ for (i = 0; i < max_irq; i += 4) ++ gicd_writel(GICD_INT_DEF_PRI_X4, GICD_IPRIORITYRn + i); ++ ++ /* Deactivate and disable all SPIs. */ ++ for (i = 32; i < max_irq; i += 32) { ++ gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn + i / 8); ++ gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICENABLERn + i / 8); ++ } ++ gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn); ++ gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn); ++ gicd_writel(GICD_INT_EN_SET_SGI, GICD_ISENABLERn); ++ ++ return 0; ++} ++ ++void irq_free_handler (int irq); ++static void gic_shutdown(void) ++{ ++ int i; ++ for (i = 0; i < max_irq; i++) ++ { ++ irq_free_handler(i); ++ } ++ disable_gic(); ++} ++ ++int arch_interrupt_init_early(void) ++{ ++ return 0; ++} ++ ++int arch_interrupt_init(void) ++{ ++ int i; ++ for (i = 0; i < GIC_MAX_IRQ; i++) ++ { ++ handlers[i] = NULL; ++ irq_counts[i] = 0; ++ } ++ return gic_probe(); ++} ++ ++int arch_interrupt_fini(void) ++{ ++ gic_shutdown(); ++ return 0; ++} ++ ++int interrupt_init (void) ++{ ++ /* ++ * setup up stacks if necessary ++ */ ++ IRQ_STACK_START_IN = gd->irq_sp + 8; ++ ++ printf("%s()\n", __FUNCTION__); ++ return arch_interrupt_init(); ++ ++ return 0; ++} ++ ++int global_interrupts_enabled (void) ++{ ++ unsigned long cpsr; ++ __asm__ __volatile__("mrs %0, cpsr\n" ++ : "=r" (cpsr) ++ : ++ : "memory"); ++ ++ return (cpsr & 0x80) == 0; ++} ++ ++void enable_interrupts (void) ++{ ++ unsigned long cpsr; ++ __asm__ __volatile__("mrs %0, cpsr\n" ++ "bic %0, %0, #0x80\n" ++ "msr cpsr_c, %0" ++ : "=r" (cpsr) ++ : ++ : "memory"); ++ ++ return; ++} ++ ++int disable_interrupts (void) ++{ ++ unsigned long cpsr, temp; ++ __asm__ __volatile__("mrs %0, cpsr\n" ++ "orr %1, %0, #0xc0\n" ++ "msr cpsr_c, %1" ++ : "=r" (cpsr), "=r" (temp) ++ : ++ : "memory"); ++ return (cpsr & 0x80) == 0; ++} ++ ++void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx) ++{ ++ if (irq > max_irq) { ++ printf("irq %d out of range\n", irq); ++ return; ++ } ++ if (handlers[irq]) { ++ printf("irq %d already in use (%p)\n", irq, handlers[irq]); ++ return; ++ } ++ printf("registering handler for irq %d\n", irq); ++ handlers[irq] = handler; ++ enable_irq_id(irq); ++} ++ ++void irq_free_handler (int irq) ++{ ++ if (irq >= max_irq) { ++ printf("irq %d out of range\n", irq); ++ return; ++ } ++ if (handlers[irq]) { ++ handlers[irq] = NULL; ++ disable_irq_id(irq); ++ } ++} ++ ++int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int i; ++ int enabled = global_interrupts_enabled(); ++ printf("GIC base = 0x%x\n", gbase); ++ printf("interrupts %sabled\n", (enabled ? "en" : "dis")); ++ uint32_t grp_en = 0; ++ for (i = 0; i < max_irq; i++) { ++ if ((i & ITLINES_MASK) == 0) ++ grp_en = gicd_readl(GICD_ISENABLERn + ++ (i >> ITLINES_SHIFT) * sizeof(uint32_t)); ++ int irq_enabled = grp_en & (1 << (i & ITLINES_MASK)); ++ if (!irq_enabled) ++ continue; ++ printf("% 2i (% 3s): %lu\n", i, ++ (irq_enabled ? "on" : "off"), irq_counts[i]); ++ } ++ printf("total: %lu\n", irq_total); ++ return 0; ++} ++ ++void do_irq(struct pt_regs *pt_regs) ++{ ++ int i; ++ if (!gbase) { ++ static int printed_msg = 0; ++ if (!printed_msg) ++ { ++ printed_msg = 1; ++ printf("interrupt before configured!\n"); ++ } ++ return; ++ } ++ irq_total++; ++ uint32_t grp_pend = 0; ++ for (i = 0; i < max_irq; i++) { ++ /* limit reads of the pending register to once in 32 */ ++ if ((i & ITLINES_MASK) == 0) ++ grp_pend = gicd_readl(GICD_ISPENDRn + ++ (i >> ITLINES_SHIFT) * sizeof(uint32_t)); ++ uint32_t pending = grp_pend & (1 << (i & ITLINES_MASK)); ++ if (pending) { ++ irq_counts[i]++; ++ /* mask via GICD_ICENABLERn */ ++ gicd_writel(pending, GICD_ICENABLERn + ++ (i >> ITLINES_SHIFT) * sizeof(uint32_t)); ++ if (handlers[i]) { ++ handlers[i](pt_regs); ++ /* unmask via GICD_ISENABLERn */ ++ gicd_writel(pending, GICD_ISENABLERn + ++ (i >> ITLINES_SHIFT) * sizeof(uint32_t)); ++ /* clear pending via GICD_ICPENDRn */ ++ gicd_writel(pending, GICD_ICPENDRn + ++ (i >> ITLINES_SHIFT) * sizeof(uint32_t)); ++ } else { ++ printf("unexpected interrupt %i; masking\n", i); ++ /* clear pending via GICD_ICPENDRn */ ++ gicd_writel(pending, GICD_ISPENDRn + ++ (i >> ITLINES_SHIFT) * sizeof(uint32_t)); ++ } ++ } ++ } ++} +diff --git a/board/aspeed/ast2600_intel/ast-irq.h b/board/aspeed/ast2600_intel/ast-irq.h +new file mode 100644 +index 000000000000..9957f2baa7ff +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ast-irq.h +@@ -0,0 +1,8 @@ ++#ifndef _AST_IRQ_H_ ++#define _AST_IRQ_H_ ++ ++int request_irq(int irq, interrupt_handler_t *handler); ++int release_irq(int irq); ++int arch_interrupt_init_early(void); ++ ++#endif +diff --git a/board/aspeed/ast2600_intel/ast-timer.c b/board/aspeed/ast2600_intel/ast-timer.c +new file mode 100644 +index 000000000000..cf8c69aba5d3 +--- /dev/null ++++ b/board/aspeed/ast2600_intel/ast-timer.c +@@ -0,0 +1,59 @@ ++/* ++ * Copyright 2019 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> ++ ++static const int timer_irqs[] = {48, 49, 50, 51, 52, 53, 54, 55}; ++#define AST_TIMER_BASE 0x1e782000 ++/* 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_RESET_BY_WDT 8 ++#define TIMER_CONTROL 0x30 ++#define TIMER_RELOAD 0x04 ++#define TIMER_CONTROL_CLEAR 0x3c ++ ++void timer_disable(int n) ++{ ++ if (n < 0 || n > 7) { ++ return; ++ } ++ uint32_t tctrl = 0xf << (n * 4); ++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL_CLEAR); ++} ++ ++void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler) ++{ ++ if (n < 0 || n > 7) { ++ return; ++ } ++ if (!freq) ++ return; ++ ++ timer_disable(n); ++ ++ uint32_t v = TIMER_1MHZ_CLK_COUNT / freq; ++ writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD); ++ ++ uint32_t tctrl = ( ++ TIMER_ENABLE | ++ TIMER_1MHZ_CLK_SEL | ++ TIMER_RESET_BY_WDT) << (n * 4); ++ ++ if (handler) { ++ irq_install_handler(timer_irqs[n], handler, NULL); ++ tctrl |= (TIMER_ENABLE_IRQ << (n * 4)); ++ } ++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL); ++} +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +new file mode 100644 +index 000000000000..b5d8dd36d20b +--- /dev/null ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -0,0 +1,176 @@ ++/* Intel customizations of Das U-Boot */ ++#include <common.h> ++#include <asm/gpio.h> ++#include <asm/io.h> ++ ++/* use GPIOC0 on intel boards */ ++#define FFUJ_GPIO "gpio@1e78000016" ++ ++int read_ffuj(void) ++{ ++ struct gpio_desc desc; ++ int ret; ++ ++ ret = dm_gpio_lookup_name(FFUJ_GPIO, &desc); ++ if (ret) ++ return ret; ++ ret = dm_gpio_request(&desc, "ffuj"); ++ if (ret) ++ return ret; ++ ret = dm_gpio_set_dir_flags(&desc, GPIOD_ACTIVE_LOW); ++ if (ret) ++ return ret; ++ ret = dm_gpio_get_value(&desc); ++ dm_gpio_free(desc.dev, &desc); ++ return ret; ++} ++ ++/* gpio_abort is a weak symbol in common/autoboot.c */ ++int gpio_abort(void) ++{ ++ int value; ++ /* check ffuj to abort the autoboot */ ++ value = read_ffuj(); ++ printf("FFUJ: %d\n", value); ++ return value <= 0 ? 0 : 1; ++} ++ ++int misc_init_r(void) ++{ ++ /* This is called near the end of the _r init sequence */ ++ ++ return 0; ++} ++ ++static void gpio_passthru_init(void) ++{ ++ /* FIXME: do this without the hard-coded SCU values */ ++ /* enable passthru gpio (for now) */ ++ writel(0x0f000000, 0x1e6e24bc); ++ writel(0xc0000060, 0x1e6e2418); ++} ++ ++#define AST_LPC_BASE 0x1e789000 ++#define LPC_SNOOP_ADDR 0x80 ++#define HICR5 0x080 /* Host Interface Control Register 5 */ ++#define HICR6 0x084 /* Host Interface Control Register 6 */ ++#define SNPWADR 0x090 /* LPC Snoop Address Register */ ++#define HICRB 0x100 /* Host Interface Control Register B */ ++ ++/* 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 */ ++ ++static void port80h_snoop_init(void) ++{ ++ uint32_t value; ++ /* enable port80h snoop and 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); ++} ++ ++#define AST_GPIO_BASE 0x1e780000 ++ ++static void sgpio_init(void) ++{ ++#define SGPIO_CLK_DIV(N) ((N) << 16) ++#define SGPIO_BYTES(N) ((N) << 6) ++#define SGPIO_ENABLE 1 ++#define GPIO554 0x554 ++#define SCU_414 0x414 /* Multi-function Pin Control #5 */ ++#define SCU_414_SGPM_MASK GENMASK(27, 24) ++ ++ uint32_t value; ++ /* set the sgpio clock to pclk/(2*(5+1)) or ~2 MHz */ ++ value = SGPIO_CLK_DIV(256) | SGPIO_BYTES(10) | SGPIO_ENABLE; ++ writel(value, AST_GPIO_BASE + GPIO554); ++ writel(readl(SCU_BASE | SCU_414) | SCU_414_SGPM_MASK, ++ SCU_BASE | SCU_414); ++} ++ ++void espi_init(void); ++int arch_interrupt_init_early(void); ++ ++static void timer_handler(void *regs) ++{ ++ printf("+"); ++} ++ ++void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler); ++int board_early_init_f(void) ++{ ++ /* This is called before relocation; beware! */ ++ /* initialize running timer? timer_init is next in the list but ++ * I am not sure if it actually does anything... */ ++ arch_interrupt_init_early(); ++ ++ gpio_passthru_init(); ++ ++ port80h_snoop_init(); ++ ++ sgpio_init(); ++ ++ /* TODO: is it too late to enforce HW security registers? */ ++ return 0; ++} ++ ++int board_early_init_r(void) ++{ ++ debug("board_early_init_r\n"); ++ /* timer_enable(0, 1, timer_handler); */ ++ ++ espi_init(); ++ ++ return 0; ++} ++ ++/* aspeed/board.c defines these functions ++int arch_early_init_r(void) ++{ ++ return 0; ++} ++*/ ++ ++/* ++void board_init(void) ++{ ++} ++*/ ++ ++#ifdef CONFIG_WATCHDOG ++/* watchdog stuff */ ++void watchdog_init(void) ++{ ++} ++ ++void watchdog_reset(void) ++{ ++} ++#endif +diff --git a/cmd/Kconfig b/cmd/Kconfig +index 92736f2d6612..f64a2595da65 100644 +--- a/cmd/Kconfig ++++ b/cmd/Kconfig +@@ -1862,7 +1862,7 @@ config CMD_DIAG + + config CMD_IRQ + bool "irq - Show information about interrupts" +- depends on !ARM && !MIPS && !SH ++ depends on !MIPS && !SH + help + This enables two commands: + +diff --git a/common/autoboot.c b/common/autoboot.c +index 94133eaeda78..5e69000b848b 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -255,10 +255,20 @@ static int __abortboot(int bootdelay) + } + # endif /* CONFIG_AUTOBOOT_KEYED */ + ++int gpio_abort(void) __attribute__((weak)); ++int gpio_abort(void) ++{ ++ return 0; ++} ++ + static int abortboot(int bootdelay) + { + int abort = 0; + ++ abort = gpio_abort(); ++ if (abort) ++ return abort; ++ + if (bootdelay >= 0) + abort = __abortboot(bootdelay); + +diff --git a/common/board_r.c b/common/board_r.c +index 472987d5d52f..a7f5371bac71 100644 +--- a/common/board_r.c ++++ b/common/board_r.c +@@ -673,6 +673,10 @@ static init_fnc_t init_sequence_r[] = { + #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \ + defined(CONFIG_SANDBOX) + board_init, /* Setup chipselects */ ++ interrupt_init, ++#ifdef CONFIG_ARM ++ initr_enable_interrupts, ++#endif + #endif + /* + * TODO: printing of the clock inforamtion of the board is now +@@ -771,10 +775,6 @@ static init_fnc_t init_sequence_r[] = { + #ifdef CONFIG_CMD_KGDB + initr_kgdb, + #endif +- interrupt_init, +-#ifdef CONFIG_ARM +- initr_enable_interrupts, +-#endif + #if defined(CONFIG_MICROBLAZE) || defined(CONFIG_M68K) + timer_init, /* initialize timer */ + #endif +diff --git a/include/configs/evb_ast2600.h b/include/configs/evb_ast2600.h +index 3a12f2f0d43c..91a42f2522e2 100644 +--- a/include/configs/evb_ast2600.h ++++ b/include/configs/evb_ast2600.h +@@ -18,7 +18,7 @@ + + /* Environment */ + #define CONFIG_ENV_SIZE 0x10000 +-#define CONFIG_ENV_OFFSET 0x60000 ++#define CONFIG_ENV_OFFSET 0x2400000 + #define CONFIG_ENV_SECT_SIZE (4 << 10) + + #endif /* __CONFIG_H */ +-- +2.7.4 + 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/0003-ast2600-intel-layout-environment-addr.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch new file mode 100644 index 000000000..88d7cd019 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0003-ast2600-intel-layout-environment-addr.patch @@ -0,0 +1,85 @@ +From 2a52808ddd6a6bef40bab9a15bd22b1c7988a798 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Thu, 12 Dec 2019 12:54:18 +0800 +Subject: [PATCH] ast2600: intel-layout-environment-addr + +Tested: +Both kernel and u-boot work at the area /dev/mtd/u-boot-env + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + common/board_r.c | 11 +++++++++-- + include/configs/aspeed-common.h | 12 +++++++++++- + include/configs/evb_ast2600_spl.h | 2 +- + 3 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/common/board_r.c b/common/board_r.c +index a7f5371bac71..492d7f1cbe4c 100644 +--- a/common/board_r.c ++++ b/common/board_r.c +@@ -433,10 +433,17 @@ 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, 0); ++ } + #ifdef CONFIG_OF_CONTROL + env_set_hex("fdtcontroladdr", + (unsigned long)map_to_sysmem(gd->fdt_blob)); +diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h +index d1eb4688e68f..0ece4a1b9440 100644 +--- a/include/configs/aspeed-common.h ++++ b/include/configs/aspeed-common.h +@@ -55,13 +55,23 @@ + #ifndef CONFIG_BOOTCOMMAND + #define CONFIG_BOOTCOMMAND "bootm 20080000" + #endif ++#define CONFIG_SYS_REDUNDAND_ENVIRONMENT ++#define CONFIG_ENV_ADDR_REDUND + #define CONFIG_ENV_OVERWRITE ++#define AST_FMC_CS0_BASE 0x20000000 /* CS0 */ ++#define CONFIG_ENV_OFFSET 0x2400000 ++#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET) ++#define CONFIG_ENV_SIZE 0x10000 ++#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_ENV_SECT_SIZE (4 << 10) + + #define CONFIG_SYS_BOOTM_LEN (0x800000 * 2) + + #define CONFIG_EXTRA_ENV_SETTINGS \ + "verify=yes\0" \ +- "spi_dma=no\0" \ ++ "spi_dma=yes\0" \ + "" + + /* +diff --git a/include/configs/evb_ast2600_spl.h b/include/configs/evb_ast2600_spl.h +index 8bbd6e18727a..8529f46c0b19 100644 +--- a/include/configs/evb_ast2600_spl.h ++++ b/include/configs/evb_ast2600_spl.h +@@ -19,7 +19,7 @@ + + /* Environment */ + #define CONFIG_ENV_SIZE 0x10000 +-#define CONFIG_ENV_OFFSET 0x90000 ++#define CONFIG_ENV_OFFSET 0x2400000 + #define CONFIG_ENV_SECT_SIZE (4 << 10) + + #ifdef CONFIG_SPL_TINY +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Disable-crashdump-trigger-gpio.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Disable-crashdump-trigger-gpio.patch new file mode 100644 index 000000000..d9c40fea0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Disable-crashdump-trigger-gpio.patch @@ -0,0 +1,57 @@ +From b203aee347f6b4104a7dfbc061b195c99795451e Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 3 Jan 2020 15:14:09 -0800 +Subject: [PATCH] Disable crashdump trigger gpio + +This commit disables crashdump trigger gpio (GPIOC3) to prevent +unexpected host failures. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + board/aspeed/ast2600_intel/intel.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index b6a11132448f..f095f1ecd696 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -151,6 +151,27 @@ static void sgpio_init(void) + SCU_BASE | SCU_414); + } + ++static void disable_crashlog_trigger(void) ++{ ++#define SCU_410 0x410 /* Multi-function Pin Control #4 */ ++#define SCU_410_RGMII3TXD1 BIT(19) ++#define GPIO_004 0x004 /* GPIO A/B/C/D Direction */ ++#define GPIO_000 0x000 /* GPIO A/B/C/D Value */ ++#define GPIO_C3 BIT(19) ++ ++ /* ++ * Set FM_BMC_CRASHLOG_TRIG_N (GPIOC3) as an output with value high ++ * explicitly since it doesn't have an external pull up. It uses direct ++ * register access because it's called from board_early_init_f(). ++ */ ++ writel(readl(SCU_BASE | SCU_410) & ~SCU_410_RGMII3TXD1, ++ SCU_BASE | SCU_410); ++ writel(readl(AST_GPIO_BASE | GPIO_004) | GPIO_C3, ++ AST_GPIO_BASE | GPIO_004); ++ writel(readl(AST_GPIO_BASE | GPIO_000) | GPIO_C3, ++ AST_GPIO_BASE | GPIO_000); ++} ++ + void espi_init(void); + int arch_interrupt_init_early(void); + +@@ -167,6 +188,8 @@ int board_early_init_f(void) + * I am not sure if it actually does anything... */ + arch_interrupt_init_early(); + ++ disable_crashlog_trigger(); ++ + gpio_passthru_init(); + + port80h_snoop_init(); +-- +2.7.4 + 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-Ast2600-Enable-interrupt-in-u-boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch new file mode 100644 index 000000000..ce9aa668a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-Ast2600-Enable-interrupt-in-u-boot.patch @@ -0,0 +1,458 @@ +From 959b75b846aa25168fe9e3d04ceb0e0778f89992 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 3 Jan 2020 12:52:29 +0800 +Subject: [PATCH] Enable interrupt in u-boot. + +Ast2600 is Cortex-A7 +GIC V2 is used as the interrupt controller +GIC includes GICD and GICC + +Testedby: +1. Enable interrupt based SW handshake for ESPI +2. Both ArcherCity and Ast2600 EVB are working well. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + arch/arm/lib/vectors.S | 31 ++++++- + board/aspeed/ast2600_intel/ast-irq.c | 154 +++++++++++++++++------------------ + configs/evb-ast2600_defconfig | 1 + + include/configs/evb_ast2600.h | 1 + + 4 files changed, 107 insertions(+), 80 deletions(-) + +diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S +index 2ca6e2494a7a..e2ed04a204de 100644 +--- a/arch/arm/lib/vectors.S ++++ b/arch/arm/lib/vectors.S +@@ -13,7 +13,7 @@ + */ + + #include <config.h> +- ++#define CONFIG_USE_IRQ + /* + * A macro to allow insertion of an ARM exception vector either + * for the non-boot0 case or by a boot0-header. +@@ -145,6 +145,17 @@ fiq: + + #else /* !CONFIG_SPL_BUILD */ + ++#ifdef CONFIG_USE_IRQ ++/* IRQ stack memory (calculated at run-time) */ ++.globl IRQ_STACK_START ++IRQ_STACK_START: ++ .word 0x0badc0de ++/* IRQ stack memory (calculated at run-time) */ ++.globl FIQ_STACK_START ++FIQ_STACK_START: ++ .word 0x0badc0de ++#endif ++ + /* IRQ stack memory (calculated at run-time) + 8 bytes */ + .globl IRQ_STACK_START_IN + IRQ_STACK_START_IN: +@@ -277,17 +288,31 @@ not_used: + bad_save_user_regs + bl do_not_used + ++ .align 5 ++#ifdef CONFIG_USE_IRQ ++irq: ++ get_irq_stack ++ irq_save_user_regs ++ bl do_irq ++ irq_restore_user_regs ++ .align 5 ++fiq: ++ get_fiq_stack ++ /* someone ought to write a more effective fiq_save_user_regs */ ++ irq_save_user_regs ++ bl do_fiq ++ irq_restore_user_regs + + .align 5 ++#else + irq: + get_bad_stack + bad_save_user_regs + bl do_irq +- + .align 5 + fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq +- ++#endif /* CONFIG_USE_IRQ */ + #endif /* CONFIG_SPL_BUILD */ +diff --git a/board/aspeed/ast2600_intel/ast-irq.c b/board/aspeed/ast2600_intel/ast-irq.c +index f817f8cd7c81..6e91b17ab186 100644 +--- a/board/aspeed/ast2600_intel/ast-irq.c ++++ b/board/aspeed/ast2600_intel/ast-irq.c +@@ -18,19 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; + #define GIC_INTERFACE_OFFSET 0x4000 + #define GIC_VIRT_OFFSET 0x6000 + +-#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) +- + /* GIC_DISTRIBUTOR_OFFSET register offsets */ + #define GICD_CTLR 0x000 + #define GICD_TYPER 0x004 +@@ -82,7 +69,9 @@ DECLARE_GLOBAL_DATA_PTR; + #define GICC_IIDR 0x00fc + #define GICC_DIR 0x1000 + +-#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b ++#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b ++#define GICC_IAR_INT_ID_MASK 0x3ff ++#define GIC_CPU_DEACTIVATE 0x1000 + + /* GIC_INTERFACE_OFFSET register offsets */ + #define GICH_HCR 0x000 +@@ -116,9 +105,10 @@ DECLARE_GLOBAL_DATA_PTR; + + #define GIC_VIRT_CPU_IMPLEMENTER_MAGIC 0x0102143b + +-#define GICD_CTLR_ENABLE 0x03 +- +-#define GICD_INT_DEF_PRI 0xa0 ++#define GICD_CTLR_ENABLE 0x03 /*enable group 0 and 1*/ ++#define GICC_CTLR_ENABLE 0x03 ++#define GICD_ITARGET_ALL 0xffffffff ++#define GICD_INT_DEF_PRI 0xa0 + #define GICD_INT_DEF_PRI_X4 (\ + (GICD_INT_DEF_PRI << 24) |\ + (GICD_INT_DEF_PRI << 16) |\ +@@ -129,20 +119,30 @@ DECLARE_GLOBAL_DATA_PTR; + #define GICD_INT_EN_CLR_X32 0xffffffff + #define GICD_INT_EN_CLR_PPI 0xffff0000 + #define GICD_INT_EN_SET_SGI 0x0000ffff ++#define GICD_ICFG_LEVEL_TRIGGER 0x55555555 ++#define GICC_UNMASK_ALL_PRIORITY 0xff + + #define gicd_readl(OFFSET) readl(gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET)) + #define gicd_writel(VALUE, OFFSET) \ + writel((VALUE), gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET)) + #define gicc_readl(OFFSET) readl(gbase + GIC_CPU_OFFSET + (OFFSET)) ++#define gicc_writel(VALUE, OFFSET) \ ++ writel((VALUE), gbase + GIC_CPU_OFFSET + (OFFSET)) + #define gich_readl(OFFSET) readl(gbase + GIC_INTERFACE_OFFSET + (OFFSET)) + #define gicv_readl(OFFSET) readl(gbase + GIC_VIRT_OFFSET + (OFFSET)) +- +-static size_t max_irq = 0; +- + #define ITLINES_MASK 0x1f + #define ITLINES_SHIFT 5 +- + #define GIC_MAX_IRQ 1020 ++#define SPI_INT_NUM_MIN 32 ++#define MAX_IRQ 0xfffffffe ++#define DEBUG_IRQ_ENABLED 0 ++#if DEBUG_IRQ_ENABLED ++#define DBG_IRQ printf ++#else ++#define DBG_IRQ(...) ++#endif ++ ++static size_t max_irq = 0; + static interrupt_handler_t *handlers[GIC_MAX_IRQ] = {NULL}; + static unsigned long irq_total = 0; + static unsigned long irq_counts[GIC_MAX_IRQ] = {0}; +@@ -159,31 +159,40 @@ static inline uint32_t gic_base(void) + + static void enable_gic(void) + { +- uint32_t gicd_ctlr; ++ uint32_t gicd_ctlr, gicc_ctlr; + ++ DBG_IRQ(" %s()\n", __FUNCTION__); + /* add GIC offset ref table 1-3 for interrupt distributor address */ + gicd_ctlr = gicd_readl(GICD_CTLR); ++ gicc_ctlr = gicc_readl(GICC_CTLR); + gicd_writel(gicd_ctlr | GICD_CTLR_ENABLE, GICD_CTLR); ++ gicc_writel(gicc_ctlr | GICC_CTLR_ENABLE, GICC_CTLR); + } + + static void disable_gic(void) + { +- uint32_t gicd_ctlr; +- ++ uint32_t gicd_ctlr, gicc_ctlr; ++ DBG_IRQ(" %s()\n", __FUNCTION__); + /* add GIC offset ref table 1-3 for interrupt distributor address */ + gicd_ctlr = gicd_readl(GICD_CTLR); + gicd_writel(gicd_ctlr & ~GICD_CTLR_ENABLE, GICD_CTLR); ++ gicc_ctlr = gicc_readl(GICC_CTLR); ++ gicc_writel(gicc_ctlr & ~GICC_CTLR_ENABLE, GICC_CTLR); + } + + static void enable_irq_id(unsigned int id) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); ++ + uint32_t grp = id >> ITLINES_SHIFT; + uint32_t grp_bit = 1 << (id & ITLINES_MASK); + gicd_writel(grp_bit, GICD_ISENABLERn + grp * sizeof(uint32_t)); ++ gicd_writel(GICD_ITARGET_ALL, GICD_ITARGETSRn + id / 4 * 4); + } + + static void disable_irq_id(unsigned int id) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); + uint32_t grp = id >> ITLINES_SHIFT; + uint32_t grp_bit = 1 << (id & ITLINES_MASK); + gicd_writel(grp_bit, GICD_ICENABLERn + grp * sizeof(uint32_t)); +@@ -193,22 +202,29 @@ static int gic_probe(void) + { + int i; + gbase = gic_base(); ++ DBG_IRQ("gic_probe GIC base = 0x%x, magicd=0x%x\n", ++ gbase, gicd_readl(GICD_IIDR)); + enable_gic(); + + if (gicd_readl(GICD_IIDR) != GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC && + gicc_readl(GICC_IIDR) != GIC_CPU_IMPLEMENTER_MAGIC && + gicv_readl(GICV_IIDR) != GIC_VIRT_CPU_IMPLEMENTER_MAGIC) + { ++ printf("error: magic check \n"); + return 0; + } + /* GIC supports up to 1020 lines */ +- max_irq = ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) << ITLINES_SHIFT; ++ max_irq = (((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 32) - 1; + if (max_irq > GIC_MAX_IRQ) + max_irq = GIC_MAX_IRQ; + /* set all lines to be level triggered N-N */ + for (i = 32; i < max_irq; i += 16) +- gicd_writel(0, GICD_ICFGRn + i / 4); ++ gicd_writel(GICD_ICFG_LEVEL_TRIGGER, GICD_ICFGRn + i / 4); + ++ DBG_IRQ("max_irq = 0x%x, typer=0x%x, config=0x%x, maxirq=0x%x\n", max_irq, ++ (gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1, ++ gicd_readl(GICD_ICFGRn + 0x8), ++ ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 0x20); + /* Set priority on all interrupts. */ + for (i = 0; i < max_irq; i += 4) + gicd_writel(GICD_INT_DEF_PRI_X4, GICD_IPRIORITYRn + i); +@@ -218,9 +234,11 @@ static int gic_probe(void) + gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn + i / 8); + gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICENABLERn + i / 8); + } +- gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn); +- gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn); ++ gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn); ++ gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn); + gicd_writel(GICD_INT_EN_SET_SGI, GICD_ISENABLERn); ++ /* unmask all priority */ ++ gicc_writel(GICC_UNMASK_ALL_PRIORITY, GICC_PMRn); + + return 0; + } +@@ -228,6 +246,7 @@ static int gic_probe(void) + void irq_free_handler (int irq); + static void gic_shutdown(void) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); + int i; + for (i = 0; i < max_irq; i++) + { +@@ -238,6 +257,7 @@ static void gic_shutdown(void) + + int arch_interrupt_init_early(void) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); + return 0; + } + +@@ -249,11 +269,13 @@ int arch_interrupt_init(void) + handlers[i] = NULL; + irq_counts[i] = 0; + } ++ DBG_IRQ("arch_interrupt_init\n"); + return gic_probe(); + } + + int arch_interrupt_fini(void) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); + gic_shutdown(); + return 0; + } +@@ -261,14 +283,12 @@ int arch_interrupt_fini(void) + int interrupt_init (void) + { + /* +- * setup up stacks if necessary +- */ ++ * setup up stacks if necessary*/ ++ IRQ_STACK_START = gd->irq_sp + 8; + IRQ_STACK_START_IN = gd->irq_sp + 8; + +- printf("%s()\n", __FUNCTION__); ++ DBG_IRQ(" %s()\n", __FUNCTION__); + return arch_interrupt_init(); +- +- return 0; + } + + int global_interrupts_enabled (void) +@@ -286,12 +306,12 @@ void enable_interrupts (void) + { + unsigned long cpsr; + __asm__ __volatile__("mrs %0, cpsr\n" +- "bic %0, %0, #0x80\n" ++ "bic %0, %0, #0x1c0\n" + "msr cpsr_c, %0" + : "=r" (cpsr) + : + : "memory"); +- ++ DBG_IRQ(" %s()\n", __FUNCTION__); + return; + } + +@@ -304,11 +324,13 @@ int disable_interrupts (void) + : "=r" (cpsr), "=r" (temp) + : + : "memory"); ++ DBG_IRQ(" %s()\n", __FUNCTION__); + return (cpsr & 0x80) == 0; + } + + void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); + if (irq > max_irq) { + printf("irq %d out of range\n", irq); + return; +@@ -317,13 +339,14 @@ void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx) + printf("irq %d already in use (%p)\n", irq, handlers[irq]); + return; + } +- printf("registering handler for irq %d\n", irq); ++ DBG_IRQ("registering handler for irq %d\n", irq); + handlers[irq] = handler; + enable_irq_id(irq); + } + + void irq_free_handler (int irq) + { ++ DBG_IRQ(" %s()\n", __FUNCTION__); + if (irq >= max_irq) { + printf("irq %d out of range\n", irq); + return; +@@ -338,9 +361,10 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) + { + int i; + int enabled = global_interrupts_enabled(); +- printf("GIC base = 0x%x\n", gbase); +- printf("interrupts %sabled\n", (enabled ? "en" : "dis")); ++ DBG_IRQ("GIC base = 0x%x\n", gbase); ++ DBG_IRQ("interrupts %sabled\n", (enabled ? "en" : "dis")); + uint32_t grp_en = 0; ++ + for (i = 0; i < max_irq; i++) { + if ((i & ITLINES_MASK) == 0) + grp_en = gicd_readl(GICD_ISENABLERn + +@@ -348,52 +372,28 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) + int irq_enabled = grp_en & (1 << (i & ITLINES_MASK)); + if (!irq_enabled) + continue; +- printf("% 2i (% 3s): %lu\n", i, ++ DBG_IRQ("%2d (%3s): %lu\n", i, + (irq_enabled ? "on" : "off"), irq_counts[i]); + } +- printf("total: %lu\n", irq_total); ++ DBG_IRQ("total: %lu\n", irq_total); + return 0; + } + + void do_irq(struct pt_regs *pt_regs) + { +- int i; +- if (!gbase) { +- static int printed_msg = 0; +- if (!printed_msg) +- { +- printed_msg = 1; +- printf("interrupt before configured!\n"); +- } +- return; +- } +- irq_total++; +- uint32_t grp_pend = 0; +- for (i = 0; i < max_irq; i++) { +- /* limit reads of the pending register to once in 32 */ +- if ((i & ITLINES_MASK) == 0) +- grp_pend = gicd_readl(GICD_ISPENDRn + +- (i >> ITLINES_SHIFT) * sizeof(uint32_t)); +- uint32_t pending = grp_pend & (1 << (i & ITLINES_MASK)); +- if (pending) { +- irq_counts[i]++; +- /* mask via GICD_ICENABLERn */ +- gicd_writel(pending, GICD_ICENABLERn + +- (i >> ITLINES_SHIFT) * sizeof(uint32_t)); +- if (handlers[i]) { +- handlers[i](pt_regs); +- /* unmask via GICD_ISENABLERn */ +- gicd_writel(pending, GICD_ISENABLERn + +- (i >> ITLINES_SHIFT) * sizeof(uint32_t)); +- /* clear pending via GICD_ICPENDRn */ +- gicd_writel(pending, GICD_ICPENDRn + +- (i >> ITLINES_SHIFT) * sizeof(uint32_t)); +- } else { +- printf("unexpected interrupt %i; masking\n", i); +- /* clear pending via GICD_ICPENDRn */ +- gicd_writel(pending, GICD_ISPENDRn + +- (i >> ITLINES_SHIFT) * sizeof(uint32_t)); +- } ++ uint32_t irqstat = 0, irqnr = 0; ++ ++ if (irq_total < MAX_IRQ) ++ irq_total++; ++ irqstat = gicc_readl(GICC_IAR); ++ irqnr = irqstat & GICC_IAR_INT_ID_MASK; ++ ++ if (irqnr > SPI_INT_NUM_MIN && irqnr < GIC_MAX_IRQ) { ++ gicc_writel(irqnr, GICC_EOIR); ++ if (irq_counts[irqnr] < MAX_IRQ) ++ irq_counts[irqnr]++; ++ if (handlers[irqnr]) { ++ handlers[irqnr](NULL); + } + } + } +diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig +index 517d59adaf11..9cd7aea98e8d 100644 +--- a/configs/evb-ast2600_defconfig ++++ b/configs/evb-ast2600_defconfig +@@ -72,3 +72,4 @@ CONFIG_SPI=y + CONFIG_DM_SPI=y + CONFIG_SYSRESET=y + CONFIG_WDT=y ++CONFIG_USE_IRQ=y +diff --git a/include/configs/evb_ast2600.h b/include/configs/evb_ast2600.h +index 91a42f2522e2..15061b25d872 100644 +--- a/include/configs/evb_ast2600.h ++++ b/include/configs/evb_ast2600.h +@@ -8,6 +8,7 @@ + + #include <configs/aspeed-common.h> + ++#define CONFIG_USE_IRQ + #define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + 0x300000) + #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + 0x5000000) + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch new file mode 100644 index 000000000..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/0006-SPI-Quad-IO-Mode.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch new file mode 100644 index 000000000..ca5846416 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-SPI-Quad-IO-Mode.patch @@ -0,0 +1,158 @@ +From 8c953c7f1d512cf4acd9ce000d65e46094d61597 Mon Sep 17 00:00:00 2001 +From: arun-pm <arun.p.m@linux.intel.com> +Date: Fri, 29 Nov 2019 00:19:09 +0530 +Subject: [PATCH] SPI Quad IO Mode + +This commit adds quad IO mode in SPI driver for AST2600. + +Note:- Removed n25q00 Quad I/O support for the time being due to clock issue + with chip 'Micron 8UA15 - rw182 (128MB)' while enabling Quad I/O mode. +--- + arch/arm/dts/ast2600-intel.dts | 6 ++--- + drivers/mtd/spi/spi-nor-ids.c | 7 +++++- + drivers/spi/aspeed_spi.c | 46 ++++++++++++++++++++++++---------- + 3 files changed, 41 insertions(+), 18 deletions(-) + +diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts +index 0d362ac7c1..2a74bbd30a 100644 +--- a/arch/arm/dts/ast2600-intel.dts ++++ b/arch/arm/dts/ast2600-intel.dts +@@ -101,16 +101,14 @@ + + &fmc { + status = "okay"; +-#if 0 + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fmcquad_default>; +-#endif + flash@0 { + compatible = "spi-flash", "sst,w25q256"; + status = "okay"; + spi-max-frequency = <40000000>; +- spi-tx-bus-width = <2>; +- spi-rx-bus-width = <2>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; + }; + }; + +diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c +index c77987f1ff..d679238562 100644 +--- a/drivers/mtd/spi/spi-nor-ids.c ++++ b/drivers/mtd/spi/spi-nor-ids.c +@@ -164,7 +164,12 @@ const struct flash_info spi_nor_ids[] = { + { INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, +- { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, ++ /* Removed n25q00 Quad I/O support for the time being due to clock issue with chip 'Micron 8UA15 - rw182 (128MB)' ++ * while enabling Quad I/O mode. As this chip is default shipped in platforms, marking it ++ * as Not supported for the time being. Once all chips are replaced with the new model, this can be enabled ++ * back(Note:- Certain other chips having same name(n25q00) but different part number has no issues). ++ */ ++ { INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | NO_CHIP_ERASE) }, + { INFO("n25q00a", 0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + #endif +diff --git a/drivers/spi/aspeed_spi.c b/drivers/spi/aspeed_spi.c +index a8c2b3de2b..ae5edaee9f 100644 +--- a/drivers/spi/aspeed_spi.c ++++ b/drivers/spi/aspeed_spi.c +@@ -16,6 +16,9 @@ + #include <linux/ioport.h> + + #define ASPEED_SPI_MAX_CS 3 ++#define AST2600A0 0x05000303 ++#define AST2600A0_MAX_FREQ 40000000 ++#define AST_MAX_FREQ 100000000 + + struct aspeed_spi_regs { + u32 conf; /* 0x00 CE Type Setting */ +@@ -593,6 +596,7 @@ static int aspeed_spi_write_reg(struct aspeed_spi_priv *priv, + aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len); + aspeed_spi_stop_user(priv, flash); + ++ debug("=== write opcode [%x] ==== \n", opcode); + switch(opcode) { + case SPINOR_OP_EN4B: + writel(readl(&priv->regs->ctrl) | BIT(flash->cs), &priv->regs->ctrl); +@@ -615,6 +619,8 @@ static void aspeed_spi_send_cmd_addr(struct aspeed_spi_priv *priv, + /* First, send the opcode */ + aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[0], 1); + ++ if(flash->iomode == CE_CTRL_IO_QUAD_ADDR_DATA) ++ writel(flash->ce_ctrl_user | flash->iomode, &priv->regs->ce_ctrl[flash->cs]); + /* + * The controller is configured for 4BYTE address mode. Fix + * the address width and send an extra byte if the SPI Flash +@@ -664,9 +670,6 @@ static ssize_t aspeed_spi_write_user(struct aspeed_spi_priv *priv, + { + aspeed_spi_start_user(priv, flash); + +- if(flash->iomode == CE_CTRL_IO_QPI_DATA) +- writel(flash->ce_ctrl_user | flash->iomode, &priv->regs->ce_ctrl[flash->cs]); +- + /* cmd buffer = cmd + addr : normally cmd is use signle mode*/ + aspeed_spi_send_cmd_addr(priv, flash, cmdbuf, cmdlen); + +@@ -872,15 +875,19 @@ static int aspeed_spi_flash_init(struct aspeed_spi_priv *priv, + else + read_hclk = aspeed_spi_hclk_divisor(priv, slave->speed); + +- if (slave->mode & (SPI_RX_DUAL | SPI_TX_DUAL)) { +- debug("CS%u: setting dual data mode\n", flash->cs); +- flash->iomode = CE_CTRL_IO_DUAL_DATA; +- flash->spi->read_opcode = SPINOR_OP_READ_1_1_2; +- } else if (slave->mode & (SPI_RX_QUAD | SPI_TX_QUAD)) { +- flash->iomode = CE_CTRL_IO_QUAD_DATA; +- flash->spi->read_opcode = SPINOR_OP_READ_1_4_4; +- } else { +- debug("normal read \n"); ++ switch(flash->spi->read_opcode) { ++ case SPINOR_OP_READ_1_1_2: ++ case SPINOR_OP_READ_1_1_2_4B: ++ flash->iomode = CE_CTRL_IO_DUAL_DATA; ++ break; ++ case SPINOR_OP_READ_1_1_4: ++ case SPINOR_OP_READ_1_1_4_4B: ++ flash->iomode = CE_CTRL_IO_QUAD_DATA; ++ break; ++ case SPINOR_OP_READ_1_4_4: ++ case SPINOR_OP_READ_1_4_4_4B: ++ flash->iomode = CE_CTRL_IO_QUAD_ADDR_DATA; ++ break; + } + + if(priv->new_ver) { +@@ -986,6 +993,19 @@ static int aspeed_spi_bind(struct udevice *bus) + return 0; + } + ++static int aspeed_get_max_freq(void) ++{ ++ u32 rev_id = readl(ASPEED_REVISION_ID); ++ ++ /*Limit max spi frequency less than 50MHz on AST2600-A0 due ++ * to FWSPICLK signal quality issue. ++ */ ++ if(rev_id == AST2600A0) ++ return AST2600A0_MAX_FREQ; ++ else ++ return AST_MAX_FREQ; ++} ++ + static int aspeed_spi_probe(struct udevice *bus) + { + struct resource res_regs, res_ahb; +@@ -1016,7 +1036,7 @@ static int aspeed_spi_probe(struct udevice *bus) + clk_free(&hclk); + + priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency", +- 100000000); ++ aspeed_get_max_freq()); + + priv->num_cs = dev_read_u32_default(bus, "num-cs", ASPEED_SPI_MAX_CS); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch new file mode 100644 index 000000000..40336d3dd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch @@ -0,0 +1,347 @@ +From dff3a123b0318f83ecd753eea8945ebdc15fd2f9 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Wed, 14 Nov 2018 10:21:40 -0800 +Subject: [PATCH 1/1] 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> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + arch/arm/include/asm/arch-aspeed/regs-scu.h | 2 + + board/aspeed/ast-g5/Makefile | 2 + + board/aspeed/ast-g5/ast-g5-espi.c | 248 ++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 16 ++ + board/aspeed/ast-g5/ast-g5.c | 3 + + 5 files changed, 271 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 c9b91795d1..019c00036a 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -554,6 +554,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 df4e63966e..58e0c648f4 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -1,2 +1,4 @@ + obj-y += ast-g5.o ++obj-y += ast-g5-intel.o ++obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o +diff --git a/board/aspeed/ast-g5/ast-g5-espi.c b/board/aspeed/ast-g5/ast-g5-espi.c +new file mode 100644 +index 0000000000..5a3ffe7bef +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-espi.c +@@ -0,0 +1,248 @@ ++/* ++ * 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) ++#define ASPEED_ESPI_CTRL_SW_RESET GENMASK(31, 24) ++ ++/* ESPI00C bits (Interrupt Enable) */ ++#define AST_ESPI_IEN_SYS_EV (1 << 8) ++#define AST_ESPI_IEN_GPIO_EV (1 << 9) ++#define AST_ESPI_IEN_HW_RST (1 << 31) ++ ++/* 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 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); ++ } ++} ++ ++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_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 ++ } ++ ++ 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); ++ ++ if (!(sys_event & 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); ++ } ++ ++ 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_IEN_HW_RST) { ++ uint32_t v = readl(AST_ESPI_BASE + ESPI000); ++ writel(v & ~ASPEED_ESPI_CTRL_SW_RESET, AST_ESPI_BASE + ESPI000); ++ writel(v | ASPEED_ESPI_CTRL_SW_RESET, AST_ESPI_BASE + ESPI000); ++ espi_handshake_ack(); ++ } ++ ++ writel(irq_status, AST_ESPI_BASE + ESPI008); // clear irq_status ++ return 0; ++} ++ ++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; ++ 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_IEN_HW_RST ++ | AST_ESPI_VW_SYS_EV1, ++ AST_ESPI_BASE + ESPI00C); // Enable events ++ ++ espi_handshake_ack(); ++ ++ request_irq(IRQ_SRC_ESPI, espi_irq_handler); ++ } else { ++ DBG_ESPI("No espi strap\n"); ++ } ++} +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +new file mode 100644 +index 0000000000..e79235c8d0 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -0,0 +1,16 @@ ++/* ++ * Copyright 2018 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <common.h> ++ ++extern void espi_init(void); ++void ast_g5_intel(void) ++{ ++ espi_init(); ++} +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index ca25348178..cab5fabcef 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -21,6 +21,8 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++extern void ast_g5_intel(void); ++ + int board_early_init_f(void) + { + /* make sure uart5 is using 24MHz clock */ +@@ -84,6 +86,7 @@ int board_init(void) + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + gd->flags = 0; + ++ ast_g5_intel(); + return 0; + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch new file mode 100644 index 000000000..94a658610 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-ast2600-Override-OTP-strap-settings.patch @@ -0,0 +1,46 @@ +From 3f53513c2b16ce2f9a24975cb23b2b58e70ba0f2 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 29 Jan 2020 14:55:44 -0800 +Subject: [PATCH] Override OTP strap settings + +This commit adds settings to override OTP strap. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/mach-aspeed/ast2600/platform.S | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm/mach-aspeed/ast2600/platform.S b/arch/arm/mach-aspeed/ast2600/platform.S +index 80ba06802acd..e7ae9041093c 100644 +--- a/arch/arm/mach-aspeed/ast2600/platform.S ++++ b/arch/arm/mach-aspeed/ast2600/platform.S +@@ -147,6 +147,26 @@ do_primary_core_setup: + /* unlock system control unit */ + scu_unlock + ++ /* disable CA7 CPU boot */ ++ ldr r0, =AST_SCU_HW_STRAP1_CLR ++ movw r1, #0x0001 @; Disable ARM CA7 CPU boot ++ movt r1, #0x0000 ++ str r1, [r0] ++ ++ /* enable eSPI, debug interface and disable UART5 boot*/ ++ ldr r0, =AST_SCU_HW_STRAP2_CLR ++ movw r1, #0x0040 @; Select eSPI ++ movt r1, #0x0000 ++ orr r1, #0x0010 @; Enable debug interface ++ orr r1, #0x0100 @; Disable UART5 boot ++ str r1, [r0] ++ ++ /* enable ACPI */ ++ ldr r0, =AST_SCU_HW_STRAP2 ++ ldr r1, [r0] ++ orr r1, #0x20 @; Enable ACPI ++ str r1, [r0] ++ + /* identify AST2600 A0/A1 */ + ldr r0, =AST_SCU_REV_ID + ldr r0, [r0] +-- +2.7.4 + 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..e11f15870 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch @@ -0,0 +1,427 @@ +From 15d04184a94aca6db889d77c2cc5a800b280da4b 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 01/30] 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> + +%% original patch: 0009-Add-basic-GPIO-support.patch +--- + board/aspeed/ast-g5/Makefile | 1 + + board/aspeed/ast-g5/ast-g5-gpio.c | 202 +++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-gpio.h | 103 +++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 45 +++++++ + board/aspeed/ast-g5/ast-g5.h | 1 + + 5 files changed, 352 insertions(+) + create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.c + create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.h + +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index 58e0c648f4..2970ae5741 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -2,3 +2,4 @@ obj-y += ast-g5.o + obj-y += ast-g5-intel.o + obj-y += ast-g5-espi.o + obj-y += ast-g5-irq.o ++obj-y += ast-g5-gpio.o +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.c b/board/aspeed/ast-g5/ast-g5-gpio.c +new file mode 100644 +index 0000000000..dc6962f4ba +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-gpio.c +@@ -0,0 +1,202 @@ ++/* ++ * 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_ASSERT(gpio_table[n].u8PinCFG); ++ 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_ASSERT(gpio_table[n].u8PinCFG); ++ 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; ++ // the output here is the logical output, which is ++ // NOT (value XOR assert) ++ // This just gets there without a conditional ++ 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; ++ uint8_t assert; ++ uint8_t init_val; ++ ++ 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); ++ assert = GPIO_ASSERT(gpio_table[i].u8PinCFG); ++ init_val = gpio_table[i].u8Value; ++ if ((assert && init_val) || !(assert || init_val)) ++ 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, 0); ++ 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, 0); ++ gpio_set_value(n, value); ++ return 0; ++ } ++ ++ return 1; ++} ++U_BOOT_CMD(gpio, 4, 0, do_gpio, ++ "do stuff with gpios <set|get> [n] [value]", ++ ""); +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h +new file mode 100644 +index 0000000000..54b7388a22 +--- /dev/null ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -0,0 +1,103 @@ ++#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 GPIO_ASSERT(N) (((N) >> 4) & 0x01) ++ ++#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 c2a8b33aec..1868c230eb 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -14,6 +14,50 @@ + #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_LOW_INPUT (GPCFG_LEVEL_TRIG) ++// Active Low, Level, Output Disabled ++ ++#define GPIO_CFG_FP_LED (GPCFG_OUTPUT_EN) ++// Active High, Pull-up, Level, Output Enabled ++ ++// 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_LOW_INPUT, 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 +151,7 @@ static void sgpio_init(void) + extern void espi_init(void); + void ast_g5_intel(void) + { ++ gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); + } +diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h +index 9fd10eccb3..908db1477b 100644 +--- a/board/aspeed/ast-g5/ast-g5.h ++++ b/board/aspeed/ast-g5/ast-g5.h +@@ -3,5 +3,6 @@ + + #include <common.h> + #include "ast-g5-irq.h" ++#include "ast-g5-gpio.h" + + #endif /* _AST_G5_H_ */ +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch new file mode 100644 index 000000000..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..e376001b3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch @@ -0,0 +1,149 @@ +From 2db86017f1cd48da9f6c102665d5ae3d1efe48cc 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> +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Change-Id: Ic9595621b21000ef465ff57ed2047855296e2714 +--- + board/aspeed/ast-g5/ast-g5-intel.c | 113 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 113 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 6e45cb4..e749992 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -146,6 +146,112 @@ 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[] = { ++ /* BMC Executing bootloader (Default) :- ++ * ChassisID: Blinking Blue 3Hz, StatusLED: Blinking Green 1Hz */ ++ [GPIO_ID_LED] = {GPIO_ID_LED, EIDLED_Blink_3HZ, 1, 0}, ++ [GPIO_GREEN_LED] = {GPIO_GREEN_LED, EIDLED_Blink_1HZ, 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 +263,11 @@ 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()) { ++ /* FFUJ mode:- ChassisID: Solid Blue, StatusLED: Solid Amber */ ++ id_led_control(GPIO_ID_LED, EIDLED_On); ++ id_led_control(GPIO_GREEN_LED, EIDLED_Off); ++ id_led_control(GPIO_AMBER_LED, EIDLED_On); ++ } + } +-- +2.7.4 + 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..4714dd6cc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch @@ -0,0 +1,141 @@ +From 039b9a278a4d075e455a38ec93171dc812aec8b2 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 16 Nov 2018 15:57:57 -0800 +Subject: [PATCH 1/1] aspeed: add Pwm Driver + +Change-Id: Ia8b80212f7c70aafcc6a71782936ec95cf9b7f38 +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + board/aspeed/ast-g5/ast-g5-intel.c | 113 +++++++++++++++++++++++++++++ + 1 file changed, 113 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index e74999223b..74e218dfd0 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -257,9 +257,122 @@ 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 DEFAULT_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 set_pwm_duty_cycle(int duty) ++{ ++ uint32_t chan; ++ uint32_t val; ++ ++ /* 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)duty) << 8) << ch_duty_shift; ++ writel(val, base + PWM_DUTY_CYCLE + ch_pair * 4); ++ } ++ ++} ++ ++static void pwm_init(void) ++{ ++ uint32_t val; ++ ++ /* 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); ++ ++ set_pwm_duty_cycle(DEFAULT_PWM_DUTY_VALUE); ++ ++ /* set up clock type M: period = 127 units at 24MHz/8 (resulting ~23kHz period) */ ++ writel(0x7f30, PWM_BASE_ADDR + PWM_CLOCK_SELECTION); ++ ++ /* enable pwm-tacho */ ++ ++ val = readl(PWM_BASE_ADDR + PWM_CONTROL); ++ val |= PWM_CLK_ENABLE; ++ writel(val, PWM_BASE_ADDR + PWM_CONTROL); ++} ++ + extern void espi_init(void); + void ast_g5_intel(void) + { ++ pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); + sgpio_init(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch new file mode 100644 index 000000000..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-AST2600-Enable-host-searial-port-clock-configuration.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-AST2600-Enable-host-searial-port-clock-configuration.patch new file mode 100644 index 000000000..5522d5f6c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-AST2600-Enable-host-searial-port-clock-configuration.patch @@ -0,0 +1,72 @@ +From ccfc20ceb2931e84ffb02b01099ccb7610b44d9c Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 10 Dec 2019 14:58:10 +0800 +Subject: [PATCH] AST2600: Enable host searial port clock configuration in + u-boot + +In u-boot could read env variable "hostsearialcfg" and set the corresponding +clock for host searail port. + +Tested: +setenv hostsearialcfg 1, speed is set to 192Mhz (baud rate 921600) +other value, speed is set to 24Mhz(baud rate 115200) +by default is 24Mhz. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + board/aspeed/ast2600_intel/intel.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index 100eb1e..eb6fbaf 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -35,9 +35,45 @@ int gpio_abort(void) + return value <= 0 ? 0 : 1; + } + ++#define SCU_BASE 0x1E6E2000 ++#define SCU_338 0x338 //Generate UART 24 MHz Reference from UXCLK ++#define SCU_33C 0x33c //Generate UART 24 MHz Reference from HUXCLK ++#define SCU_338_R_VALUE_192MHZ 0x8e ++#define SCU_338_N_VALUE_192MHZ 0x3c3 ++#define SCU_338_R_VALUE_24MHZ 0x06 ++#define SCU_338_N_VALUE_24MHZ 0x145 ++#define HOST_SERIAL_HIGH_SPEED_192MHZ 1 ++#define R_VALUE_BITS 8 ++#define V_VALUE_BITS 10 ++#define R_V_VALUE_MASK (1 << (R_VALUE_BITS + V_VALUE_BITS)) ++ + int misc_init_r(void) + { + /* This is called near the end of the _r init sequence */ ++ /* By default host serail is set 24Mhz */ ++ 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 = env_get("hostserialcfg"); ++ ++ if (host_serial_cfg_txt != NULL) ++ host_serial_cfg = simple_strtoul(host_serial_cfg_txt, NULL, 16); ++ ++ if (host_serial_cfg > HOST_SERIAL_HIGH_SPEED_192MHZ || host_serial_cfg < 0) { ++ printf("Invalid hostserialcfg %x, 24Mhz is set by default!\n", host_serial_cfg); ++ host_serial_cfg = 0; ++ } ++ ++ if (host_serial_cfg & HOST_SERIAL_HIGH_SPEED_192MHZ) { ++ writel((readl(SCU_BASE | SCU_338) & R_V_VALUE_MASK) | ++ (SCU_338_N_VALUE_192MHZ << R_VALUE_BITS) | SCU_338_R_VALUE_192MHZ, ++ SCU_BASE | SCU_338); ++ } else { ++ writel((readl(SCU_BASE | SCU_338) & R_V_VALUE_MASK) | ++ (SCU_338_N_VALUE_24MHZ << R_VALUE_BITS) | SCU_338_R_VALUE_24MHZ, ++ SCU_BASE | SCU_338); ++ } + + return 0; + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch new file mode 100755 index 000000000..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..2b6382967 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch @@ -0,0 +1,613 @@ +From 6d8db23becf9665193023e350adcad00b75195b0 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 1/1] 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> +Signed-off-by: James Feist <james.feist@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 90224333c4..05972b9d17 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 032f716722..c149426947 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -256,6 +256,7 @@ int intel_force_firmware_jumper_enabled(void) + } + + extern void espi_init(void); ++extern void kcs_init(void); + void ast_g5_intel(void) + { + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); +@@ -264,5 +265,7 @@ 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. */ + } + } +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 0000000000..7bff26f9db +--- /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 0000000000..bb697c455d +--- /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]; ++}; +-- +2.17.1 + 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..065f890bc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0025-Manufacturing-mode-physical-presence-detection.patch @@ -0,0 +1,114 @@ +From b6f898ef15eede75700e9e13a8e0b69d88b12fd4 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 15/30] 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> + +%% original patch: 0025-Manufacturing-mode-physical-presence-detection.patch +--- + 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 54b7388a22..8ccf437346 100644 +--- a/board/aspeed/ast-g5/ast-g5-gpio.h ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -73,7 +73,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 45ecd83fd3..efc3315caf 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) +@@ -58,6 +59,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_LOW_INPUT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ + }; + + #define LPC_SNOOP_ADDR 0x80 +@@ -403,6 +408,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]; +@@ -450,6 +479,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.17.1 + 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..ac458dd6c --- /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,302 @@ +From 0083904a79527cef9ca99e516ed015b56a6b95c7 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> + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@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 a1731be701..c8ac0af55c 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 0000000000..1b225d20dc +--- /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 0x70 ++ ++#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.17.1 + 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..3c21a7c0a --- /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,1273 @@ +From 0f64b0e0c0a122ce23b5ccc518f514ec296bc7f5 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 | 13 + + configs/ast_g5_phy_defconfig | 1 + + 10 files changed, 1093 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..3647d5f 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -349,6 +349,19 @@ 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()) { ++ printf("#### Force firmware update mode is enabled, " ++ "Serial console is disabled. ####\n"); ++ 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 +-- +2.7.4 + 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..392acb9ad --- /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,530 @@ +From bd0d8af493387ab1602a0a40b4a548981c1e4d00 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> +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@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 0b2d936c23..9021d7fc08 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 dde5adbc70..6ef3ca9f73 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 { +@@ -634,6 +635,10 @@ void ast_g5_intel(void) + ast_scu_write(ast_scu_read(AST_SCU_MISC1_CTRL) | + SCU_MISC_UART_DEBUG_DIS, AST_SCU_MISC1_CTRL); + ++ /* 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)); +@@ -649,6 +654,11 @@ void ast_g5_intel(void) + kcs_init(); + if (intel_get_platform_id() == COOPER_CITY_BOARD_ID) + set_pwm_duty_cycle(ELEVATED_PWM_DUTY_VALUE); ++ /* 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. */ + } + } +diff --git a/board/aspeed/ast-g5/fw-update.c b/board/aspeed/ast-g5/fw-update.c +index 99239938b5..89fe5fd4fd 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 ed033adfed..45e46ba596 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 3eba056e7f..6afc8d66b7 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 e490f6b527..7409d2e2f9 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 0000000000..77131688e7 +--- /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 0000000000..5c5b98bbe0 +--- /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 0x70 ++ ++/* 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.17.1 + 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/files/0034-Disable-uart-debug-interface.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0034-Disable-uart-debug-interface.patch new file mode 100644 index 000000000..941dc7d0d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0034-Disable-uart-debug-interface.patch @@ -0,0 +1,54 @@ +From 961561c437c8a3f3de1753c502a20c334966354e Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Tue, 20 Aug 2019 16:10:03 +0800 +Subject: [PATCH 1/2] Disable uart debug interface + +AST2500 SOC integrates a UART debug interface which can +input commands to AST2500 by using simple terminal +program without the assistance of CPU. + +For security requirements, we need to disable this feature, +set SCU2C[]10 = 1 to disable it. + +Tested: +Flash the u-boot.bin and dump SCU2C as below: +md 0x1e6e202c +1e6e202c: 00200400 + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + arch/arm/include/asm/arch-aspeed/regs-scu.h | 1 + + board/aspeed/ast-g5/ast-g5-intel.c | 4 ++++ + 2 files changed, 5 insertions(+) + +diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h +index 8a596ceafc..8333ba1c59 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -467,6 +467,7 @@ + #define SCU_MISC_VUART_TO_CTRL (0x1 << 13) + #define SCU_MISC_DIV13_EN (0x1 << 12) + #define SCU_MISC_Y_CLK_INVERT (0x1 << 11) ++#define SCU_MISC_UART_DEBUG_DIS (0x1 << 10) + #define SCU_MISC_OUT_DELAY (0x1 << 9) + #define SCU_MISC_PCI_TO_AHB_DIS (0x1 << 8) + #define SCU_MISC_2D_CRT_EN (0x1 << 7) +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index 324387a4bc..c58fd3591b 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -578,6 +578,10 @@ extern void espi_init(void); + extern void kcs_init(void); + void ast_g5_intel(void) + { ++ /* Disable uart port debug function */ ++ ast_scu_write(ast_scu_read(AST_SCU_MISC1_CTRL) | ++ SCU_MISC_UART_DEBUG_DIS, AST_SCU_MISC1_CTRL); ++ + uart_init(); + pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0035-PFR-platform-EXTRST-reset-mask-selection.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0035-PFR-platform-EXTRST-reset-mask-selection.patch new file mode 100644 index 000000000..85cf0cc5e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0035-PFR-platform-EXTRST-reset-mask-selection.patch @@ -0,0 +1,124 @@ +From 3886bca377525ca9a70a6e04403606e456c535ad Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Thu, 5 Sep 2019 15:03:21 +0530 +Subject: [PATCH] PFR platform - EXTRST# reset mask selection + +This is a fix taken from Purely PFR. +This commit will enable specific reset mask for EXTRST# signal. +On PFR platforms, EXTRST# signal is used by PFR CPLD to put BMC +in reset during firmware authentications, recovery and firmware +update flow, during which certain modules of BMC should be chosen +to be reset so that Host functionality would be intact. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + .../include/asm/arch-aspeed/ast-g5-intel.h | 31 +++++++++++++++++++ + arch/arm/include/asm/arch-aspeed/regs-scu.h | 29 +++++++++++++++++ + board/aspeed/ast-g5/ast-g5-intel.c | 9 ++++++ + 3 files changed, 69 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 64f4ed17bf..b9386b2cf6 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h ++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +@@ -12,6 +12,37 @@ + + #define AST_G5_INTEL 1 + ++/* EXTRST# mask for PFR platform ++ * EXTRST# is used by PFR CPLD to keep BMC in ++ * reset during firmware authentication, updates and recovery ++ * this mask selects the modules to be reset along with BMC so that ++ * Host functions are intact. ++ * (this is fix from Purley PFR ) ++ */ ++#define AST_WDT_RESET_MASK ( \ ++ WDT_RESET_MASK_SPI | \ ++ WDT_RESET_MASK_XDMA | \ ++ WDT_RESET_MASK_MCTP | \ ++ WDT_RESET_MASK_ADC | \ ++ WDT_RESET_MASK_JTAG | \ ++ WDT_RESET_MASK_PECI | \ ++ WDT_RESET_MASK_CRT | \ ++ WDT_RESET_MASK_MIC | \ ++ WDT_RESET_MASK_SDIO | \ ++ WDT_RESET_MASK_HAC | \ ++ WDT_RESET_MASK_VIDEO | \ ++ WDT_RESET_MASK_HID11 | \ ++ WDT_RESET_MASK_USB11 | \ ++ WDT_RESET_MASK_USB20 | \ ++ WDT_RESET_MASK_GRAPHICS | \ ++ WDT_RESET_MASK_MAC2 | \ ++ WDT_RESET_MASK_MAC1 | \ ++ WDT_RESET_MASK_I2C | \ ++ WDT_RESET_MASK_AHB | \ ++ WDT_RESET_MASK_COPROC | \ ++ WDT_RESET_MASK_ARM | \ ++ 0) ++ + #ifndef __ASSEMBLY__ + int intel_force_firmware_jumper_enabled(void); + int intel_failed_boot(void); +diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h +index 1bdb1d8574..0a4fb6f773 100644 +--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h ++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h +@@ -144,6 +144,35 @@ + #define SCU_RESET_AHB (0x1 << 1) + #define SCU_RESET_SRAM_CTRL (0x1 << 0) + ++/* AST_WDT/EXTRST - 0x9C selection masks */ ++#define WDT_RESET_MASK_MISC (1 << 25) /* Misc. SOC controller (WDT, RTC, Timer, UART, SRAM.) */ ++#define WDT_RESET_MASK_SPI (1 << 24) /* SPI controller */ ++#define WDT_RESET_MASK_XDMA (1 << 23) /* X-DMA controller */ ++#define WDT_RESET_MASK_MCTP (1 << 22) /* MCTP controller */ ++#define WDT_RESET_MASK_GPIO (1 << 21) /* GPIO controller */ ++#define WDT_RESET_MASK_ADC (1 << 20) /* ADC controller */ ++#define WDT_RESET_MASK_JTAG (1 << 19) /* JTAG master controller */ ++#define WDT_RESET_MASK_PECI (1 << 18) /* PECI controller */ ++#define WDT_RESET_MASK_PWM (1 << 17) /* PWM controller */ ++#define WDT_RESET_MASK_CRT (1 << 16) /* CRT mode 2D engine */ ++#define WDT_RESET_MASK_MIC (1 << 15) /* MIC controller */ ++#define WDT_RESET_MASK_SDIO (1 << 14) /* SD/SDIO controller */ ++#define WDT_RESET_MASK_LPC (1 << 13) /* LPC controller */ ++#define WDT_RESET_MASK_HAC (1 << 12) /* HAC engine */ ++#define WDT_RESET_MASK_VIDEO (1 << 11) /* Video engine */ ++#define WDT_RESET_MASK_HID11 (1 << 10) /* USB1.1 HID/USB2.0 Host EHCI2 controller */ ++#define WDT_RESET_MASK_USB11 (1 << 9) /* USB1.1 Host controller */ ++#define WDT_RESET_MASK_USB20 (1 << 8) /* USB2.0 Host/Hub controller */ ++#define WDT_RESET_MASK_GRAPHICS (1 << 7) /* Graphics CRT controller */ ++#define WDT_RESET_MASK_MAC2 (1 << 6) /* MAC#2 controller */ ++#define WDT_RESET_MASK_MAC1 (1 << 5) /* MAC#1 controller */ ++#define WDT_RESET_MASK_I2C (1 << 4) /* I2C controller */ ++#define WDT_RESET_MASK_AHB (1 << 3) /* AHB bridges */ ++#define WDT_RESET_MASK_SDRAM (1 << 2) /* SDRAM controller */ ++#define WDT_RESET_MASK_COPROC (1 << 1) /* Coprocessor */ ++#define WDT_RESET_MASK_ARM (1 << 0) /* ARM */ ++#define WDT_RESET_MASK_ALL 0x03ffffff /* all the bits above: 0-25*/ ++ + /* AST_SCU_RESET2 0xD4 - Reset Control register set 2 */ + #define SCU_RESET_CRT3 (0x1 << 8) + #define SCU_RESET_CRT2 (0x1 << 7) +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index f8dbae8163..e697bd17e5 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -684,6 +684,15 @@ void ast_g5_intel(void) + { + int platform_id; + ++ /* EXTRST# mask for PFR platform ++ * EXTRST# is used by PFR CPLD to keep BMC in ++ * reset during firmware authentication, updates and recovery ++ * this mask selects the modules to be reset along with BMC so that ++ * Host functions are intact. ++ * (this is fix from Purley PFR ) ++ */ ++ ast_scu_write(AST_WDT_RESET_MASK, AST_SCU_WDT_RESET); ++ + /* Disable uart port debug function */ + ast_scu_write(ast_scu_read(AST_SCU_MISC1_CTRL) | + SCU_MISC_UART_DEBUG_DIS, AST_SCU_MISC1_CTRL); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0036-Re-Enable-KCS.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0036-Re-Enable-KCS.patch new file mode 100644 index 000000000..976277f9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0036-Re-Enable-KCS.patch @@ -0,0 +1,35 @@ +From 6bd4135cd2b8e3a95f5c29e7edaa678e0ca6eded Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Thu, 19 Sep 2019 10:15:19 -0700 +Subject: [PATCH 1/1] Re-Enable KCS + +Phosphor-isolation isolates too much and seems to +make KCS not work. This removes the lines from that +patch that seem to be of question. + +Tested: AC/Cycled, cmdtool.efi 20 18 1 works + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + board/aspeed/ast-g5/ast-g5.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c +index ead2e1bb63..00bd92ae5f 100644 +--- a/board/aspeed/ast-g5/ast-g5.c ++++ b/board/aspeed/ast-g5/ast-g5.c +@@ -41,11 +41,6 @@ int board_init(void) + bool sdmc_unlocked; + u32 val; + +- /* iLPC2AHB */ +- val = readl(AST_SCU_BASE + AST_SCU_HW_STRAP1); +- val |= SCU_HW_STRAP_LPC_DEC_SUPER_IO; +- writel(val, AST_SCU_BASE + AST_SCU_HW_STRAP1); +- + val = readl(AST_LPC_BASE + AST_LPC_HICRB); + val |= LPC_HICRB_ILPC2AHB; + writel(val, AST_LPC_BASE + AST_LPC_HICRB); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0037-aspeed-ast-scu.c-fix-MAC1LINK-and-MAC2LINK-pin-pads-.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0037-aspeed-ast-scu.c-fix-MAC1LINK-and-MAC2LINK-pin-pads-.patch new file mode 100644 index 000000000..9c176e998 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0037-aspeed-ast-scu.c-fix-MAC1LINK-and-MAC2LINK-pin-pads-.patch @@ -0,0 +1,80 @@ +From 4b96a19bdde82d7fed24cb70e0bcaef16d8711c3 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 4 Oct 2019 15:54:43 -0700 +Subject: [PATCH] aspeed/ast-scu.c: fix MAC1LINK and MAC2LINK pin pads setting + +Intel platforms don't use these pins as PHY link monitoring inputs +so this commit disables them in SCU pin control register so that +the pins can be used as GPIOs. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/mach-aspeed/ast-scu.c | 37 +++++++++---------------------------- + 1 file changed, 9 insertions(+), 28 deletions(-) + +diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c +index 537cd4b3e1c7..28c48c115406 100644 +--- a/arch/arm/mach-aspeed/ast-scu.c ++++ b/arch/arm/mach-aspeed/ast-scu.c +@@ -419,49 +419,30 @@ void ast_scu_multi_func_eth(u8 num) + { + switch (num) { + case 0: +- if (ast_scu_read(AST_SCU_HW_STRAP1) & SCU_HW_STRAP_MAC0_RGMII) { ++ if (ast_scu_read(AST_SCU_HW_STRAP1) & SCU_HW_STRAP_MAC0_RGMII) + printf("MAC0 : RGMII\n"); +- ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) | +- SCU_FUN_PIN_MAC0_PHY_LINK, +- AST_SCU_FUN_PIN_CTRL1); +- } else { ++ else + printf("MAC0 : RMII/NCSI\n"); +- ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & +- ~SCU_FUN_PIN_MAC0_PHY_LINK, +- AST_SCU_FUN_PIN_CTRL1); +- } +- +-#ifdef AST_SOC_G5 +- ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) | +- SCU_FUN_PIN_MAC0_PHY_LINK, AST_SCU_FUN_PIN_CTRL1); + +-#endif ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & ++ ~SCU_FUN_PIN_MAC0_PHY_LINK, ++ AST_SCU_FUN_PIN_CTRL1); + ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL3) | + SCU_FUN_PIN_MAC0_MDIO | SCU_FUN_PIN_MAC0_MDC, + AST_SCU_FUN_PIN_CTRL3); +- + break; + case 1: +- if (ast_scu_read(AST_SCU_HW_STRAP1) & SCU_HW_STRAP_MAC1_RGMII) { ++ if (ast_scu_read(AST_SCU_HW_STRAP1) & SCU_HW_STRAP_MAC1_RGMII) + printf("MAC1 : RGMII\n"); +- ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) | +- SCU_FUN_PIN_MAC1_PHY_LINK, +- AST_SCU_FUN_PIN_CTRL1); +- } else { ++ else + printf("MAC1 : RMII/NCSI\n"); +- ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & +- ~SCU_FUN_PIN_MAC1_PHY_LINK, +- AST_SCU_FUN_PIN_CTRL1); +- } + +- ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) | +- SCU_FUN_PIN_MAC1_PHY_LINK, ++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & ++ ~SCU_FUN_PIN_MAC1_PHY_LINK, + AST_SCU_FUN_PIN_CTRL1); +- + ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL5) | + SCU_FUC_PIN_MAC1_MDIO, + AST_SCU_FUN_PIN_CTRL5); +- + break; + } + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0038-Increase-default-fan-speed-for-cooper-city.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0038-Increase-default-fan-speed-for-cooper-city.patch new file mode 100644 index 000000000..53cdd763e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0038-Increase-default-fan-speed-for-cooper-city.patch @@ -0,0 +1,131 @@ +From e465945672408b632d5e3c2cf7f08ade1268419e Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Thu, 24 Oct 2019 14:39:22 -0700 +Subject: [PATCH 1/1] Increase default fan speed for cooper city + +This increases the uboot fan speed for cooper city +as it has high core count CPUS. + +Tested: In uboot fans appeared to run faster + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + board/aspeed/ast-g5/ast-g5-gpio.h | 6 ++++ + board/aspeed/ast-g5/ast-g5-intel.c | 46 ++++++++++++++++++++++++++++++ + 2 files changed, 52 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h +index ed2499f5cc..9088cdd3e3 100644 +--- a/board/aspeed/ast-g5/ast-g5-gpio.h ++++ b/board/aspeed/ast-g5/ast-g5-gpio.h +@@ -70,9 +70,15 @@ + #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 PLATFORM_ID0_PORT_PIN PORT_PIN(GPIO_PORT_B, GPIO_PIN_0) ++#define PLATFORM_ID1_PORT_PIN PORT_PIN(GPIO_PORT_B, GPIO_PIN_1) ++#define PLATFORM_ID2_PORT_PIN PORT_PIN(GPIO_PORT_B, GPIO_PIN_2) ++#define PLATFORM_ID3_PORT_PIN PORT_PIN(GPIO_PORT_B, GPIO_PIN_3) ++#define PLATFORM_ID4_PORT_PIN PORT_PIN(GPIO_PORT_B, GPIO_PIN_4) + #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) ++#define PLATFORM_ID5_PORT_PIN PORT_PIN(GPIO_PORT_G, GPIO_PIN_5) + + // 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 c58fd3591b..9d5db68b7e 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -25,6 +25,12 @@ enum gpio_names { + GPIO_FF_UPD_JUMPER, + GPIO_ENABLE_TPM_PULSE, + GPIO_FP_PWR_BTN, ++ GPIO_PLATFORM_ID_0, ++ GPIO_PLATFORM_ID_1, ++ GPIO_PLATFORM_ID_2, ++ GPIO_PLATFORM_ID_3, ++ GPIO_PLATFORM_ID_4, ++ GPIO_PLATFORM_ID_5, + }; + + #define GPIO_CFG_DEFAULT (GPCFG_ACTIVE_HIGH | GPCFG_LEVEL_TRIG) +@@ -60,6 +66,21 @@ static const GPIOValue gpio_table[] = { + [GPIO_FP_PWR_BTN] = {FP_PWR_BTN_PORT_PIN, GPIO_CFG_DEFAULT, 0, + GPIO_DEBOUNCE_8MS}, + ++ /* Platform ID Pins */ ++ [GPIO_PLATFORM_ID_0] = {PLATFORM_ID0_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ [GPIO_PLATFORM_ID_1] = {PLATFORM_ID1_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ [GPIO_PLATFORM_ID_2] = {PLATFORM_ID2_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ [GPIO_PLATFORM_ID_3] = {PLATFORM_ID3_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ [GPIO_PLATFORM_ID_4] = {PLATFORM_ID4_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ [GPIO_PLATFORM_ID_5] = {PLATFORM_ID5_PORT_PIN, GPIO_CFG_DEFAULT, 0, ++ GPIO_DEBOUNCE_8MS}, ++ ++ + }; + + #define LPC_SNOOP_ADDR 0x80 +@@ -114,6 +135,8 @@ static const GPIOValue gpio_table[] = { + #define WATCHDOG_RESET_BIT 0x8 + #define BOOT_FAILURE_LIMIT 0x3 + ++#define COOPER_CITY_BOARD_ID 40 ++ + static int get_boot_failures(void) + { + return getenv_ulong("bootfailures", 10, 0); +@@ -295,6 +318,26 @@ int intel_failed_boot(void) + return get_boot_failures() >= BOOT_FAILURE_LIMIT; + } + ++int intel_get_platform_id(void) ++{ ++ int id = 0; ++ int temp = 0; ++ int gpios[] = {GPIO_PLATFORM_ID_0, ++ GPIO_PLATFORM_ID_1, ++ GPIO_PLATFORM_ID_2, ++ GPIO_PLATFORM_ID_3, ++ GPIO_PLATFORM_ID_4, ++ GPIO_PLATFORM_ID_5}; ++ int ii; ++ for (ii = 0; ii < ARRAY_SIZE(gpios); ii++){ ++ temp = gpio_get_value(gpios[ii]); ++ if(temp < 0) ++ return temp; ++ id |= temp << ii; ++ } ++ return id; ++} ++ + void arch_preboot_os(void) + { + // last second before booting... set the LEDs +@@ -322,6 +365,7 @@ void arch_preboot_os(void) + #define PWM_CLK_ENABLE BIT(0) + #define PWM_DUTY(PCT) (((PCT) * 128) / 100) + #define DEFAULT_PWM_DUTY_VALUE PWM_DUTY(57) ++#define ELEVATED_PWM_DUTY_VALUE PWM_DUTY(80) + + + static inline uint32_t ast_scu_read(uint32_t reg) +@@ -595,6 +639,8 @@ void ast_g5_intel(void) + id_led_control(GPIO_GREEN_LED, EIDLED_Off); + id_led_control(GPIO_AMBER_LED, EIDLED_On); + kcs_init(); ++ if (intel_get_platform_id() == COOPER_CITY_BOARD_ID) ++ set_pwm_duty_cycle(ELEVATED_PWM_DUTY_VALUE); + /* TODO: need to stop the booting here. */ + } + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0040-Initialize-the-BMC-host-mailbox-at-reset-time.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0040-Initialize-the-BMC-host-mailbox-at-reset-time.patch new file mode 100644 index 000000000..b36627d17 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0040-Initialize-the-BMC-host-mailbox-at-reset-time.patch @@ -0,0 +1,65 @@ +From 933d80ac82dbe1f74c653b0ac505fde406e2553c Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Mon, 27 Jan 2020 15:13:10 -0800 +Subject: [PATCH] Initialize the BMC/host mailbox at reset time + +When the BMC comes out of reset, the mailbox registers need to be set so +the communications with the host can start properly. + +Tested: boot the BMC and take note that the mailbox registers are no + longer random garbage. + +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +--- + board/aspeed/ast-g5/ast-g5-intel.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c +index ce87a46cd1..1086742045 100644 +--- a/board/aspeed/ast-g5/ast-g5-intel.c ++++ b/board/aspeed/ast-g5/ast-g5-intel.c +@@ -575,6 +575,33 @@ static void pwm_init(void) + writel(val, PWM_BASE_ADDR + PWM_CONTROL); + } + ++#define AST_MBX_COUNT 16 ++#define MB_HINIT_BP_REG1 (0) ++#define MB_HINIT_BP_REG2 (1) // reserved for future bit definition. ++#define MB_FW_MJ_VER_REG (2) ++#define MB_FW_MN_VER_REG (3) ++#define MB_HINIT_ERR_REG (4) ++#define MB_BOOTL_BP_REG1 (5) ++#define MB_BOOTL_BP_REG2 (6) // tracks which image selected ++#define MB_BOOTL_ERR_REG (7) ++#define MB_RUNTM_BP_REG1 (8) ++#define MB_RUNTM_BP_REG2 (9) // reserved for future bit definition. ++#define MB_RUNTM_ERR_REG (10) ++static void mailbox_init(void) ++{ ++ /* clear out default mbox values */ ++ int i; ++ for (i = 0; i < AST_MBX_COUNT; i++) ++ { ++ writel(0, AST_MBX_BASE + 4 * i); ++ } ++ /* by the time this is called, all the hardware init is done ++ * so we can mark that as complete */ ++ writel(0xff, AST_MBX_BASE + 4 * MB_HINIT_BP_REG1); ++ /* mark progress up through booting linux */ ++ writel(0x1f, AST_MBX_BASE + 4 * MB_BOOTL_BP_REG1); ++} ++ + extern void espi_init(void); + extern void kcs_init(void); + void ast_g5_intel(void) +@@ -597,6 +624,7 @@ void ast_g5_intel(void) + set_cpld_reg(PFR_CPLD_BOOT_CHECKPOINT_REG, PFR_CPLD_CHKPOINT_START); + + uart_init(); ++ mailbox_init(); + pwm_init(); + gpio_init(gpio_table, ARRAY_SIZE(gpio_table)); + espi_init(); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0041-Disabling-boot-delay.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0041-Disabling-boot-delay.patch new file mode 100644 index 000000000..69ec33a17 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0041-Disabling-boot-delay.patch @@ -0,0 +1,27 @@ +From e21ee4b456addc93a9afed0cb52ac2a53d3b785a Mon Sep 17 00:00:00 2001 +From: arun-pm <arun.p.m@linux.intel.com> +Date: Thu, 30 Jan 2020 10:32:13 +0530 +Subject: [PATCH] Disabling boot delay + +Boot delay is changed to -2 so that BMC will not stop in u-boot by pressing +ESC key. +--- + include/configs/ast-common.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/configs/ast-common.h b/include/configs/ast-common.h +index 0bc7f2d75f..dce6bbf5aa 100644 +--- a/include/configs/ast-common.h ++++ b/include/configs/ast-common.h +@@ -70,7 +70,7 @@ + /* + * Environment Config + */ +-#define CONFIG_BOOTDELAY 2 ++#define CONFIG_BOOTDELAY -2 + + /* + * Miscellaneous configurable options +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config new file mode 100644 index 000000000..19ace4b88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config @@ -0,0 +1,25 @@ +# Configuration file for fw_(printenv/setenv) utility. +# Up to two entries are valid, in this case the redundant +# environment sector is assumed present. +# Notice, that the "Number of sectors" is ignored on NOR and SPI-dataflash. +# Furthermore, if the Flash sector size is omitted, this value is assumed to +# be the same as the Environment size, which is valid for NOR and SPI-dataflash + +# NOR example +# MTD device name Device offset Env. size Flash sector size Number of sectors +#/dev/mtd1 0x0000 0x20000 0x20000 +#/dev/mtd2 0x0000 0x4000 0x4000 + +# MTD SPI-dataflash example +# MTD device name Device offset Env. size Flash sector size Number of sectors +#/dev/mtd2 0x00000 0x20000 +/dev/mtd/u-boot-env 0x00000 0x10000 +/dev/mtd/u-boot-env 0x10000 0x10000 +#/dev/mtd5 0x4200 0x4200 +#/dev/mtd6 0x4200 0x4200 + +# NAND example +#/dev/mtd0 0x4000 0x4000 0x20000 2 + +# Block device example +#/dev/mmcblk0 0xc0000 0x20000 diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/intel.cfg b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/intel.cfg new file mode 100644 index 000000000..8e247744a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/intel.cfg @@ -0,0 +1,11 @@ +CONFIG_MISC_INIT_R=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_CMD_LED=y +CONFIG_TARGET_AST2600_INTEL=y +CONFIG_BOARD_EARLY_INIT_F=y +CONFIG_BOARD_EARLY_INIT_R=y +CONFIG_DEFAULT_DEVICE_TREE="ast2600-intel" +CONFIG_SYS_ARCH_TIMER=y +CONFIG_CMD_IRQ=y diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend new file mode 100644 index 000000000..04496acf7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed-sdk_%.bbappend @@ -0,0 +1,20 @@ +FILESEXTRAPATHS_append_intel-ast2600:= "${THISDIR}/files:" + +# the meta-phosphor layer adds this patch, which conflicts +# with the intel layout for environment + +SRC_URI_append_intel-ast2600 = " \ + file://fw_env.config \ + file://intel.cfg \ + file://0000-AST2600-Add-the-latest-chip-initialization-code.patch \ + file://0001-Add-ast2600-intel-as-a-new-board.patch \ + file://0021-AST2600-Enable-host-searial-port-clock-configuration.patch \ + file://0003-ast2600-intel-layout-environment-addr.patch \ + file://0004-Disable-crashdump-trigger-gpio.patch \ + file://0005-Ast2600-Enable-interrupt-in-u-boot.patch \ + file://0006-SPI-Quad-IO-Mode.patch \ + file://0007-ast2600-Override-OTP-strap-settings.patch \ + " +do_install_append () { + install -m 0644 ${WORKDIR}/fw_env.config ${S}/tools/env/fw_env.config +} 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..170e84846 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend @@ -0,0 +1,71 @@ +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://fw_env.config \ + 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 \ + file://0034-Disable-uart-debug-interface.patch \ + file://0036-Re-Enable-KCS.patch \ + file://0037-aspeed-ast-scu.c-fix-MAC1LINK-and-MAC2LINK-pin-pads-.patch \ + file://0038-Increase-default-fan-speed-for-cooper-city.patch \ + file://0040-Initialize-the-BMC-host-mailbox-at-reset-time.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 \ + file://0035-PFR-platform-EXTRST-reset-mask-selection.patch \ + " +AUTOBOOT_SRC_URI = " \ + file://0041-Disabling-boot-delay.patch \ + " +SRC_URI_append_intel-ast2500 += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', PFR_SRC_URI, '', d)}" +SRC_URI_append_intel-ast2500 += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', AUTOBOOT_SRC_URI, d)}" +do_install_append () { + install -m 0644 ${WORKDIR}/fw_env.config ${S}/tools/env/fw_env.config +} + +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-sdk_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed-sdk_%.bbappend new file mode 100644 index 000000000..b271f3b38 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed-sdk_%.bbappend @@ -0,0 +1,14 @@ +FILESEXTRAPATHS_append_intel-ast2600:= "${THISDIR}/files:" + +SRC_URI_append_intel-ast2600 = " \ + file://fw_env.config \ + file://intel.cfg \ + file://0001-Add-ast2600-intel-as-a-new-board.patch \ + file://0003-ast2600-intel-layout-environment-addr.patch \ + " + +do_install_append () { + install -m 0644 ${WORKDIR}/fw_env.config ${D}${sysconfdir}/fw_env.config + install -m 0644 ${WORKDIR}/fw_env.config ${S}/tools/env/fw_env.config +} +RDEPENDS_${PN} = "udev-aspeed-mtd-partitions" 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 120000 index 000000000..742334ade --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-fw-utils-aspeed_%.bbappend @@ -0,0 +1 @@ +u-boot-aspeed_%.bbappend
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service new file mode 100644 index 000000000..e8b563850 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service @@ -0,0 +1,10 @@ +[Unit] +Description=Check for AC boot +After=xyz.openbmc_project.Settings.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/ac-boot-check.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh new file mode 100644 index 000000000..38728b512 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [[ `cat /proc/cmdline` =~ "resetreason=0x11" ]] +then + busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/control/host0/ac_boot xyz.openbmc_project.Common.ACBoot ACBoot s "True" +else + busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/control/host0/ac_boot xyz.openbmc_project.Common.ACBoot ACBoot s "False" +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb new file mode 100644 index 000000000..2a30696dc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb @@ -0,0 +1,24 @@ +SUMMARY = "AC Boot Check" +DESCRIPTION = "Script to check the resetreason for AC boot" + +S = "${WORKDIR}" +SRC_URI = "file://ac-boot-check.sh \ + file://ac-boot-check.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/ac-boot-check.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/ac-boot-check.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/ac-boot-check.sh ${D}/${bindir}/ac-boot-check.sh +} + +SYSTEMD_SERVICE_${PN} += " ac-boot-check.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb new file mode 100644 index 000000000..1f7fbe73b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb @@ -0,0 +1,33 @@ +inherit obmc-phosphor-systemd + +SUMMARY = "At Scale Debug Service" +DESCRIPTION = "At Scale Debug Service exposes remote JTAG target debug capabilities" + +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://LICENSE;md5=0d1c657b2ba1e8877940a8d1614ec560" + + +inherit cmake +DEPENDS = "sdbusplus openssl libpam libgpiod" + +do_configure[depends] += "virtual/kernel:do_shared_workdir" + +SRC_URI = "git://github.com/Intel-BMC/asd;protocol=git" +SRCREV = "1.4.2" + +inherit useradd + +USERADD_PACKAGES = "${PN}" + +# add a special user asdbg +USERADD_PARAM_${PN} = "-u 999 asdbg" + +S = "${WORKDIR}/git" + +SYSTEMD_SERVICE_${PN} += "com.intel.AtScaleDebug.service" + +# Specify any options you want to pass to cmake using EXTRA_OECMAKE: +EXTRA_OECMAKE = "-DBUILD_UT=OFF" + +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/" diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service new file mode 100644 index 000000000..4411de11c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service @@ -0,0 +1,12 @@ +[Unit] +Description=Intel BMC At Scale Debug +Requires=network-online.target + +[Service] +Restart=always +RestartSec=30 +ExecStart={bindir}/asd +Type=simple +SyslogIdentifier=asd + + diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service new file mode 100644 index 000000000..281d1a993 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service @@ -0,0 +1,12 @@ +[Unit] +Description=Intel BMC At Scale Debug JTAG test to check if remote debug setting is enabled + +[Service] +Type=oneshot +ExecStartPre=/bin/sleep 10 +ExecStart={bindir}/jtag_test +SyslogIdentifier=jtag_test +RemainAfterExit=true + +[Install] +WantedBy=obmc-host-start@0.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab new file mode 100644 index 000000000..0b53093ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab @@ -0,0 +1,10 @@ +/dev/root / auto defaults 1 1 +proc /proc proc defaults 0 0 +devpts /dev/pts devpts mode=0620,gid=5 0 0 +tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 +tmpfs /var/lib/systemd/coredump tmpfs rw,nosuid,nodev,size=67108864 0 0 +tmpfs /media tmpfs rw 0 0 + +# uncomment this if your device has a SD/MMC/Transflash slot +#/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend new file mode 100644 index 000000000..79e529179 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend @@ -0,0 +1,2 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI_append = " file://fstab" diff --git a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb new file mode 100644 index 000000000..6d2bfa88e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb @@ -0,0 +1,28 @@ +inherit obmc-phosphor-dbus-service +inherit obmc-phosphor-systemd + +SUMMARY = "CPU Crashdump" +DESCRIPTION = "CPU utilities for dumping CPU Crashdump and registers over PECI" + +DEPENDS = "boost cjson sdbusplus safec gtest libpeci" +inherit cmake + +EXTRA_OECMAKE = "-DCRASHDUMP_BUILD_UT=ON" + +LICENSE = "Proprietary" +LIC_FILES_CHKSUM = "file://LICENSE;md5=26bb6d0733830e7bab774914a8f8f20a" + +SRC_URI = "git://github.com/Intel-BMC/crashdump;protocol=git" +SRCREV = "0.5" + +S = "${WORKDIR}/git" + +SYSTEMD_SERVICE_${PN} += "com.intel.crashdump.service" +DBUS_SERVICE_${PN} += "com.intel.crashdump.service" + +# linux-libc-headers guides this way to include custom uapi headers +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" +do_configure[depends] += "virtual/kernel:do_shared_workdir" diff --git a/meta-openbmc-mods/meta-common/recipes-core/crashdump/files/com.intel.crashdump.service b/meta-openbmc-mods/meta-common/recipes-core/crashdump/files/com.intel.crashdump.service new file mode 100644 index 000000000..6f79573f0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/files/com.intel.crashdump.service @@ -0,0 +1,10 @@ +[Unit] +Description=Intel BMC CPU Crashdump + +[Service] +Restart=always +ExecStart={bindir}/crashdump +Type=simple + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend new file mode 100644 index 000000000..cfa1d0711 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend @@ -0,0 +1,22 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://enable-ssh.sh" + +add_manual_ssh_enable() { + install -d ${D}/usr/share/misc + install -m 0755 ${D}/${systemd_unitdir}/system/dropbear@.service ${D}/usr/share/misc/dropbear@.service + install -m 0755 ${D}/${systemd_unitdir}/system/dropbear.socket ${D}/usr/share/misc/dropbear.socket + install -m 0755 ${WORKDIR}/enable-ssh.sh ${D}${bindir}/enable-ssh.sh + # Remove dropbear service and socket by default, if debug-tweaks is disabled + rm ${D}/${systemd_unitdir}/system/dropbear@.service + rm ${D}/${systemd_unitdir}/system/dropbear.socket +} + +do_install_append() { + # Add manual ssh enable script if debug-tweaks is disabled + ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'add_manual_ssh_enable', d)} +} + +FILES_${PN} += "/usr/share/misc" +SYSTEMD_SERVICE_${PN} += "dropbearkey.service" +SYSTEMD_SERVICE_${PN}_remove += " ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'dropbear.socket', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh b/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh new file mode 100755 index 000000000..e97995cc1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ -e /etc/systemd/system/dropbear@.service ] && \ + [ -e /etc/systemd/system/sockets.target.wants/dropbear.socket ] +then + echo "SSH is already enabled" +else + cp /usr/share/misc/dropbear@.service /etc/systemd/system/dropbear@.service + cp /usr/share/misc/dropbear.socket /etc/systemd/system/dropbear.socket + ln -s /etc/systemd/system/dropbear.socket /etc/systemd/system/sockets.target.wants/dropbear.socket + groupmems -g priv-admin -a root + systemctl daemon-reload + systemctl restart dropbear.socket + echo "Enabled SSH service for root user successful" +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh new file mode 100644 index 000000000..17923b84d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh @@ -0,0 +1,355 @@ +#!/bin/sh + +log() { + echo "$@" +} + +FWTYPE="" +FWVER="" +redfish_log_fw_evt() { + local evt=$1 + local sev="" + local msg="" + [ -z "$FWTYPE" ] && return + [ -z "$FWVER" ] && return + case "$evt" in + start) + evt=OpenBMC.0.1.FirmwareUpdateStarted + msg="${FWTYPE} firmware update to version ${FWVER} started." + sev=OK + ;; + success) + evt=OpenBMC.0.1.FirmwareUpdateCompleted + msg="${FWTYPE} firmware update to version ${FWVER} completed successfully." + sev=OK + ;; + abort) + evt=OpenBMC.0.1.FirmwareUpdateFailed + msg="${FWTYPE} firmware update to version ${FWVER} failed." + sev=Warning + ;; + *) return ;; + esac + logger-systemd --journald <<-EOF + MESSAGE=$msg + PRIORITY=2 + SEVERITY=${sev} + REDFISH_MESSAGE_ID=${evt} + REDFISH_MESSAGE_ARGS=${FWTYPE},${FWVER} + EOF +} + +wait_for_log_sync() +{ + sync + sleep 5 +} + +PFR_BUS=4 +PFR_ADDR=0x38 +PFR_ID_REG=0x00 +PFR_STATE_REG=0x03 +PFR_PROV_REG=0x0a +PFR_INTENT_REG=0x13 +pfr_read() { + [ $# -ne 1 ] && return 1 + local reg=$1 + i2cget -y $PFR_BUS $PFR_ADDR $reg 2>/dev/null +} + +pfr_write() { + [ $# -ne 2 ] && return 1 + local reg=$1 + local val=$2 + i2cset -y $PFR_BUS $PFR_ADDR $reg $val >&/dev/null +} + +pfr_active_update() { + local factory_reset="" + systemctl stop nv-sync.service || \ + log "BMC NV sync failed to stop" + # transition from non-PFR to PFR image requires factory reset + [ ! -e /usr/share/pfr ] && factory_reset="-r" + mtd-util $factory_reset pfr write $LOCAL_PATH + redfish_log_fw_evt success + # only wait for logging if not transitioning from non-PFR to PFR + if [ -e /usr/share/pfr ]; then + # exit bmc no nv mode + systemctl start nv-sync.service || log "failed to start nv-sync" + wait_for_log_sync + fi + reboot +} + +pfr_staging_update() { + log "Updating $(basename $TGT)" + flash_erase $TGT $erase_offset $blk_cnt + log "Writing $(stat -c "%s" "$LOCAL_PATH") bytes" + # cat "$LOCAL_PATH" > "$TGT" + dd bs=4k seek=$(($erase_offset / 0x1000)) if=$LOCAL_PATH of=$TGT 2>/dev/null + + # remove the updated image from /tmp + rm -f $LOCAL_PATH + redfish_log_fw_evt success + log "Setting update intent in PFR CPLD" + wait_for_log_sync + + # write to PFRCPLD about BMC update intent. + pfr_write 0x13 $upd_intent_val +} + +pfr_active_mode() { + # check for 0xde in register file 0 + local id=$(pfr_read $PFR_ID_REG) || return 1 + [ "$id" == "0xde" ] || return 1 + local state=$(pfr_read $PFR_STATE_REG) || return 1 + local prov=$(pfr_read $PFR_PROV_REG) || return 1 + prov=$((prov & 0x20)) + [ "$prov" == "32" ] && return 0 + return 1 +} + +blk0blk1_update() { + # PFR-style image update section + # read the image type from the uploaded image + # Byte at location 0x8 gives image type + TGT="/dev/mtd/image-stg" + img_type=$(hexdump -s 8 -n 1 -e '/1 "%02x\n"' $LOCAL_PATH) + log "image-type=$img_type" + + if [ $local_file -eq 0 ]; then + img_type_str=$(busctl get-property xyz.openbmc_project.Software.BMC.Updater /xyz/openbmc_project/software/$img_obj xyz.openbmc_project.Software.Version Purpose | cut -d " " -f 2 | cut -d "." -f 6 | sed 's/.\{1\}$//') + img_target=$(busctl get-property xyz.openbmc_project.Software.BMC.Updater /xyz/openbmc_project/software/$img_obj xyz.openbmc_project.Software.Activation RequestedActivation | cut -d " " -f 2| cut -d "." -f 6 | sed 's/.\{1\}$//') + else + img_type_str='BMC' + img_target='Active' + fi + + apply_time=$(busctl get-property xyz.openbmc_project.Settings /xyz/openbmc_project/software/apply_time xyz.openbmc_project.Software.ApplyTime RequestedApplyTime | cut -d " " -f 2 | cut -d "." -f 6 | sed 's/.\{1\}$//') + log "image-name=$img_type_str" + log "image-target=$img_target" + log "apply_time=$apply_time" + + case "$img_type" in + 04) + if [ "$img_type_str" == 'BMC' ]; then + # BMC image - max size 32MB + log "BMC firmware image" + img_size=33554432 + if [ "$img_target" == 'StandbySpare' ]; then + upd_intent_val=0x10 + else + upd_intent_val=0x08 + fi + erase_offset=0 + FWTYPE="BMC" + FWVER="${RANDOM}-fixme" + else + # log error the image selected for update is not same as downloaded. + log "Mismatch: image selected for update and image parsed are different" + redfish_log_fw_evt abort + return 1 + fi + ;; + 00) + if [ "$img_type_str" == 'Other' ]; then + log "CPLD firmware image" + # CPLD image- max size 1MB + img_size=1048576 + if [ "$img_target" == 'StandbySpare' ]; then + upd_intent_val=0x20 + else + upd_intent_val=0x04 + fi + erase_offset=0x3000000 + FWTYPE="CPLD" + FWVER="${RANDOM}-fixme" + else + # log error the image selected for update is not same as downloaded. + log "Mismatch: image selected for update and image parsed are different" + redfish_log_fw_evt abort + return 1 + fi + ;; + 02) + if [ "$img_type_str" = 'Host' ]; then + # BIOS image- max size 16MB + log "BIOS firmware image" + img_size=16777216 + if [ "$img_target" == 'StandbySpare' ]; then + upd_intent_val=0x02 + else + upd_intent_val=0x41 + fi + erase_offset=0x2000000 + # TODO: parse out the fwtype and fwver once that is specified + FWTYPE="BIOS" + FWVER="${RANDOM}-fixme" + else + # log error the image selected for update is not same as downloaded. + log "Mismatch: image selected for update and image parsed are different" + redfish_log_fw_evt abort + return 1 + fi + ;; + *) + log "Unknown image type ${img_type}" + return 1 + ;; + esac + + # For deferred updates + if [ "$apply_time" == 'OnReset' ]; then + upd_intent_val=$(( "$upd_intent_val"|0x80 )) + fi + + # do a quick sanity check on the image + if [ $(stat -c "%s" "$LOCAL_PATH") -gt $img_size ]; then + log "Update file "$LOCAL_PATH" is bigger than the supported image size" + redfish_log_fw_evt abort + return 1 + fi + blk_cnt=$((img_size / 0x10000)) + + if pfr_active_mode; then + # pfr enforcing mode; any b0b1 image type + pfr_staging_update + elif [ "$img_type" == '04' ]; then + # legacy mode; pfr is not present but we got a pfr image + log "Updating BMC active firmware- PFR unprovisioned mode" + pfr_active_update + else + # error; pfr is not present but we got a pfr image, + # an invalid image, or nonBMC image + log "PFR inactive or invalid image type:${img_type}, cowardly refusing to process image" + redfish_log_fw_evt abort + return 1 + fi +} + +ping_pong_update() { + # do a quick sanity check on the image + if [ $(stat -c "%s" "$LOCAL_PATH") -lt 10000000 ]; then + log "Update file "$LOCAL_PATH" seems to be too small" + redfish_log_fw_evt abort + return 1 + fi + dtc -I dtb -O dtb "$LOCAL_PATH" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log "Update file $LOCAL_PATH doesn't seem to be in the proper format" + redfish_log_fw_evt abort + return 1 + fi + + # guess based on fw_env which partition we booted from + local BOOTADDR=$(fw_printenv bootcmd | awk '{print $2}') + local TGT="/dev/mtd/image-a" + case "$BOOTADDR" in + 20080000) TGT="/dev/mtd/image-b"; BOOTADDR="22480000" ;; + 22480000) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;; + *) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;; + esac + log "Updating $(basename $TGT) (use bootm $BOOTADDR)" + flash_erase $TGT 0 0 + log "Writing $(stat -c "%s" "$LOCAL_PATH") bytes" + cat "$LOCAL_PATH" > "$TGT" + fw_setenv "bootcmd" "bootm ${BOOTADDR}" + redfish_log_fw_evt success + wait_for_log_sync + # reboot + reboot +} + +fetch_fw() { + PROTO=$(echo "$URI" | sed 's,\([a-z]*\)://.*$,\1,') + REMOTE=$(echo "$URI" | sed 's,.*://\(.*\)$,\1,') + REMOTE_HOST=$(echo "$REMOTE" | sed 's,\([^/]*\)/.*$,\1,') + if [ "$PROTO" = 'scp' ]; then + REMOTE_PATH=$(echo "$REMOTE" | cut -d':' -f2) + else + REMOTE_PATH=$(echo "$REMOTE" | sed 's,[^/]*/\(.*\)$,\1,') + fi + LOCAL_PATH="/tmp/$(basename $REMOTE_PATH)" + log "PROTO=$PROTO" + log "REMOTE=$REMOTE" + log "REMOTE_HOST=$REMOTE_HOST" + log "REMOTE_PATH=$REMOTE_PATH" + if [ ! -e $LOCAL_PATH ] || [ $(stat -c %s $LOCAL_PATH) -eq 0 ]; then + log "Download '$REMOTE_PATH' from $PROTO $REMOTE_HOST $REMOTE_PATH" + case "$PROTO" in + scp) + mkdir -p $HOME/.ssh + if [ -e "$SSH_ID" ]; then + ARG_ID="-i $SSH_ID" + fi + scp $ARG_ID $REMOTE_HOST$REMOTE_PATH $LOCAL_PATH + if [ $? -ne 0 ]; then + log "scp $REMOTE $LOCAL_PATH failed!" + return 1 + fi + ;; + tftp) + cd /tmp + tftp -g -r "$REMOTE_PATH" "$REMOTE_HOST" + if [ $? -ne 0 ]; then + log "tftp -g -r \"$REMOTE_PATH\" \"$REMOTE_HOST\" failed!" + return 1 + fi + ;; + http|https|ftp) + wget --no-check-certificate "$URI" -O "$LOCAL_PATH" + if [ $? -ne 0 ]; then + log "wget $URI failed!" + return 1 + fi + ;; + file) + LOCAL_PATH=$(echo $URI | sed 's,^file://,,') + ;; + *) + log "Invalid URI $URI" + return 1 + ;; + esac + fi +} + +update_fw() { + redfish_log_fw_evt start + # determine firmware file type + local magic=$(hexdump -n 4 -v -e '/1 "%02x"' "$LOCAL_PATH") + case "$magic" in + d00dfeed) ping_pong_update ;; + 19fdeab6) blk0blk1_update ;; + *) log "Uknown file type ${magic}" + esac +} + +# if this script was sourced, just return without executing anything +[ "$_" != "$0" ] && return 0 >&/dev/null + +usage() { + echo "usage: $(basename $0) uri" + echo " uri is something like: file:///path/to/fw" + echo " tftp://tftp.server.ip.addr/path/to/fw" + echo " scp://[user@]scp.server.ip.addr:/path/to/fw" + echo " http[s]://web.server.ip.addr/path/to/fw" + echo " ftp://[user@]ftp.server.ip.addr/path/to/fw" + exit 1 +} + +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage; fi +if [ $# -eq 0 ]; then + # set DEFURI in $HOME/.fwupd.defaults + URI="$DEFURI" +else + if [[ "$1" == *"/"* ]]; then + URI=$1 # local file + local_file=1 ; + else + URI="file:////tmp/images/$1/image-runtime" + img_obj=$1 + local_file=0 ; + fi +fi +fetch_fw && update_fw diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl new file mode 100644 index 000000000..ae9f54263 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl @@ -0,0 +1,136 @@ +#!/bin/sh + +setup_image() +{ + set -x + local storage="$1" + local sz_mb="$2" + # create the backing store + dd if=/dev/zero of=$storage bs=1M seek=$sz_mb count=0 2>/dev/null + # this shows up as 23FC-F676 in /dev/disk/by-uuid + local diskid=0x23FCF676 + mkdosfs -n 'OPENBMC-FW' -i $diskid -I $storage >/dev/null 2>&1 +} + +mount_image() +{ + set -x + local storage="$1" + local stormnt="$2" + mkdir -p $stormnt || exit 1 + mount -o loop -t vfat $storage $stormnt +} + +cleanup_image() +{ + set -x + local storage="$1" + local stormnt="$2" + umount -f "$stormnt" + rm -f "$storage" + rmdir "$stormnt" +} + +GADGET_BASE=/sys/kernel/config/usb_gadget + +which_dev() +{ + local in_use=$(cat $GADGET_BASE/*/UDC) + cd /sys/class/udc + for D in *; do + case "$in_use" in + *"$D"*) ;; + *) echo "$D"; return 0;; + esac + done + return 1 +} + +usb_ms_insert() +{ + local name="$1" + local storage="$2" + + if [ -d $GADGET_BASE/$name ]; then + echo "device $name already exists" >&2 + return 1 + fi + mkdir $GADGET_BASE/$name + cd $GADGET_BASE/$name + + echo 0x1d6b > idVendor # Linux Foundation + echo 0x0105 > idProduct # FunctionFS Gadget + mkdir strings/0x409 + local machineid=$(cat /etc/machine-id) + local data="OpenBMC USB mass storage gadget device serial number" + local serial=$( echo -n "${machineid}${data}${machineid}" | \ + sha256sum | cut -b 0-12 ) + echo $serial > strings/0x409/serialnumber + echo OpenBMC > strings/0x409/manufacturer + echo "OpenBMC Mass Storage" > strings/0x409/product + + mkdir configs/c.1 + mkdir functions/mass_storage.$name + echo $storage > functions/mass_storage.$name/lun.0/file + echo 0 > functions/mass_storage.$name/lun.0/removable + mkdir configs/c.1/strings/0x409 + + echo "Conf 1" > configs/c.1/strings/0x409/configuration + echo 120 > configs/c.1/MaxPower + ln -s functions/mass_storage.$name configs/c.1 + local dev=$(which_dev) + echo $dev > UDC +} + +usb_ms_eject() +{ + local name="$1" + + echo '' > $GADGET_BASE/$name/UDC + + rm -f $GADGET_BASE/$name/configs/c.1/mass_storage.$name + rmdir $GADGET_BASE/$name/configs/c.1/strings/0x409 + rmdir $GADGET_BASE/$name/configs/c.1 + rmdir $GADGET_BASE/$name/functions/mass_storage.$name + rmdir $GADGET_BASE/$name/strings/0x409 + rmdir $GADGET_BASE/$name +} + +usage() +{ + echo "Usage: $0 <action> ..." + echo " $0 setup <file> <sizeMB>" + echo " $0 insert <name> <file>" + echo " $0 eject <name>" + echo " $0 mount <file> <mnt>" + echo " $0 cleanup <file> <mnt>" + exit 1 +} + +echo "$#: $0 $@" +case "$1" in + insert) + shift + usb_ms_insert "$@" + ;; + eject) + shift + usb_ms_eject "$@" + ;; + setup) + shift + setup_image "$@" + ;; + mount) + shift + mount_image "$@" + ;; + cleanup) + shift + cleanup_image "$@" + ;; + *) + usage + ;; +esac +exit $? diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb new file mode 100644 index 000000000..007a4aece --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb @@ -0,0 +1,30 @@ +SUMMARY = "Temporary intel-fw-update script" +DESCRIPTION = "At runtime, perform a firmware update and reboot" +PR = "r1" + +# flash_eraseall +RDEPENDS_intel-fw-update += "mtd-utils" +# wget tftp scp +RDEPENDS_intel-fw-update += "busybox dropbear" +# mkfs.vfat, parted +RDEPENDS_intel-fw-update += "dosfstools dtc" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +PFR_EN = "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'pfr', '', d)}" + +SRC_URI += "file://fwupd.sh" +SRC_URI += "file://usb-ctrl" + +FILES_${PN} += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '${datadir}/pfr', '', d)}" + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/fwupd.sh ${D}${bindir} + install -m 0755 ${WORKDIR}/usb-ctrl ${D}${bindir} + + if [ "${PFR_EN}" = "pfr" ]; then + install -d ${D}${datadir} + touch ${D}${datadir}/pfr + fi +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_git.bb b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_git.bb new file mode 100644 index 000000000..f70e81fd2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_git.bb @@ -0,0 +1,22 @@ +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +inherit cmake systemd + +SRC_URI = "git://github.com/Intel-BMC/host-error-monitor.git;protocol=ssh" + +DEPENDS = "boost sdbusplus libgpiod libpeci" + +PV = "0.1+git${SRCPV}" +SRCREV = "4b56eb0cd42ac87ae8bfd0b725fc274ee3cbbc36" + +S = "${WORKDIR}/git" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.HostErrorMonitor.service" +SECURITY_CFLAGS_pn-host-error-monitor = "${SECURITY_NOPIE_CFLAGS}" + +# 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/interfaces/libmctp/.clang-format b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format new file mode 100644 index 000000000..86a2a9d63 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format @@ -0,0 +1,21 @@ +--- +BasedOnStyle: LLVM +Language: Cpp +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Linux +AlwaysBreakBeforeMultilineStrings: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +IndentCaseLabels: false +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AlignAfterOpenBracket: true +SpaceAfterCStyleCast: false +MaxEmptyLinesToKeep: 2 +BreakBeforeBinaryOperators: NonAssignment +BreakStringLiterals: false +SortIncludes: true +ContinuationIndentWidth: 8 diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch new file mode 100644 index 000000000..7bba22ede --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch @@ -0,0 +1,141 @@ +From ab1634441f4dd218486f6bb3b94e90e2110ccc2a Mon Sep 17 00:00:00 2001 +From: Nikhil Potade <nikhil.potade@linux.intel.com> +Date: Tue, 19 Feb 2019 14:16:20 +0800 +Subject: [PATCH 1/1] Smbus changes for libmctp + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + CMakeLists.txt | 5 +++-- + core.c | 2 ++ + libmctp.h | 40 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 45 insertions(+), 2 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f3f05bd..7991b11 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -5,7 +5,7 @@ add_definitions (-DMCTP_HAVE_FILEIO) + add_definitions (-DMCTP_HAVE_STDIO) + add_definitions (-DMCTP_DEFAULT_ALLOC) + +-add_library (libmctp STATIC alloc.c core.c log.c libmctp.h serial.c) ++add_library (libmctp STATIC alloc.c core.c log.c libmctp.h serial.c smbus.c crc32c.c) + + target_include_directories (libmctp PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> +@@ -20,5 +20,6 @@ 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 crc32c.h DESTINATION ++ include) + +diff --git a/core.c b/core.c +index f8abbb1..79a681c 100644 +--- a/core.c ++++ b/core.c +@@ -17,6 +17,7 @@ + + /* Internal data structures */ + ++/* clang-format off */ + struct mctp_bus { + mctp_eid_t eid; + struct mctp_binding *binding; +@@ -56,6 +57,7 @@ struct mctp { + ROUTE_BRIDGE, + } route_policy; + }; ++/* clang-format on */ + + #ifndef BUILD_ASSERT + #define BUILD_ASSERT(x) \ +diff --git a/libmctp.h b/libmctp.h +index 69ec46a..b7212be 100644 +--- a/libmctp.h ++++ b/libmctp.h +@@ -15,6 +15,7 @@ extern "C" { + typedef uint8_t mctp_eid_t; + + /* MCTP packet definitions */ ++/* clang-format off */ + struct mctp_hdr { + uint8_t ver; + uint8_t dest; +@@ -30,19 +31,56 @@ struct mctp_hdr { + #define MCTP_HDR_SEQ_MASK (0x3) + #define MCTP_HDR_TAG_SHIFT (0) + #define MCTP_HDR_TAG_MASK (0x7) ++/* clang-format on */ + + /* Baseline Transmission Unit and packet size */ + #define MCTP_BTU 64 + #define MCTP_PACKET_SIZE(unit) ((unit) + sizeof(struct mctp_hdr)) + ++#define MCTP_CONTROL_MESSAGE_TYPE 0x00 ++ ++enum MCTP_COMMAND_CODE { ++ MCTP_COMMAND_CODE_SET_EID = 0x01, ++ MCTP_COMMAND_CODE_GET_EID = 0x02, ++ MCTP_COMMAND_CODE_GET_ENDPOINT_UUID = 0x03, ++ MCTP_COMMAND_CODE_GET_MCTP_VERSION_SUPPORT = 0x04, ++ MCTP_COMMAND_CODE_GET_MESSAGE_TYPE_SUPPORT = 0x05, ++ MCTP_COMMAND_CODE_GET_VENDOR_DEFINED_MSG_SUPPORT= 0x06, ++ MCTP_COMMAND_CODE_RESOLVE_ENDPOINT_ID = 0x07, ++ MCTP_COMMAND_CODE_ALLOCATE_ENDPOINT_IDS = 0x08, ++ MCTP_COMMAND_CODE_ROUTING_INFORMATION_UPDATE = 0x09, ++ MCTP_COMMAND_CODE_GET_ROUTING_TABLE_ENTRIES = 0x0A, ++ MCTP_COMMAND_CODE_PREPARE_FOR_ENDPOINT_DISCOVERY= 0x0B, ++ MCTP_COMMAND_CODE_ENDPOINT_DISCOVERY = 0x0C, ++ MCTP_COMMAND_CODE_DISCOVERY_NOTIFY = 0x0D, ++ MCTP_COMMAND_CODE_GET_NETWORK_ID = 0x0E, ++ MCTP_COMMAND_CODE_QUERY_HOP = 0x0F, ++ MCTP_COMMAND_CODE_RESOLVE_UUID = 0x10, ++ MCTP_COMMAND_CODE_QUERY_RATE_LIMIT = 0x11, ++ MCTP_COMMAND_CODE_REQUEST_TX_RATE_LIMIT = 0x12, ++ MCTP_COMMAND_CODE_UPDATE_RATE_LIMIT = 0x13, ++ MCTP_COMMAND_CODE_QUERY_SUPPORTED_INTERFACES = 0x14 ++}; ++ ++enum MCTP_CONTROL_MSG_COMPLETION_CODE { ++ MCTP_CONTROL_MSG_STATUS_SUCCESS = 0x00, ++ MCTP_CONTROL_MSG_STATUS_ERROR = 0x01, ++ MCTP_CONTROL_MSG_STATUS_ERROR_INVALID_DATA = 0x02, ++ MCTP_CONTROL_MSG_STATUS_ERROR_INVALID_LENGTH = 0x03, ++ MCTP_CONTROL_MSG_STATUS_ERROR_NOT_READY = 0x04, ++ MCTP_CONTROL_MSG_STATUS_ERROR_UNSUPPORTED_CMD = 0x05 ++}; ++ + /* packet buffers */ + ++/* clang-format off */ + struct mctp_pktbuf { + size_t start, end, size; + size_t mctp_hdr_off; + struct mctp_pktbuf *next; + unsigned char data[]; + }; ++/* clang-format on */ + + struct mctp_binding; + +@@ -90,6 +128,7 @@ int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, + void *msg, size_t msg_len); + + /* hardware bindings */ ++/* clang-format off */ + struct mctp_binding { + const char *name; + uint8_t version; +@@ -101,6 +140,7 @@ struct mctp_binding { + int (*tx)(struct mctp_binding *binding, + struct mctp_pktbuf *pkt); + }; ++/* clang-format on */ + + void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable); + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c new file mode 100644 index 000000000..0d5090e2c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c @@ -0,0 +1,93 @@ +#include "crc32c.h" +/*****************************************************************/ +/* */ +/* CRC LOOKUP TABLE */ +/* ================ */ +/* The following CRC lookup table was generated automagically */ +/* by the Rocksoft^tm Model CRC Algorithm Table Generation */ +/* Program V1.0 using the following model parameters: */ +/* */ +/* Width : 4 bytes. */ +/* Poly : 0x1EDC6F41L */ +/* Reverse : TRUE. */ +/* */ +/* For more information on the Rocksoft^tm Model CRC Algorithm, */ +/* see the document titled "A Painless Guide to CRC Error */ +/* Detection Algorithms" by Ross Williams */ +/* (ross@guest.adelaide.edu.au.). This document is likely to be */ +/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/*****************************************************************/ + +unsigned long crctable[256] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, + 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, + 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, + 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, + 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, + 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, + 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, + 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, + 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, + 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, + 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, + 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, + 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, + 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, + 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, + 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, + 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, + 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, + 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, + 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, + 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, + 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, + 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, + 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, + 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, + 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, + 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, + 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, + 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, + 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, + 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, + 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, + 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, + 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, + 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, + 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, + 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, + 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, + 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, + 0xAD7D5351L}; + +/*****************************************************************/ +/* End of CRC Lookup Table */ +/*****************************************************************/ + +uint32_t crc32c(uint8_t *data, int length) +{ + const uint32_t CRC_INIT = 0xffffffffL; + const uint32_t XO_ROT = 0xffffffffL; + + uint32_t crc = CRC_INIT; + + while (length--) { + crc = crctable[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); + } + crc = crc ^ XO_ROT; + + return crc; +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h new file mode 100644 index 000000000..4586547e6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h @@ -0,0 +1,16 @@ +#ifndef CRC32C_H +#define CRC32C_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdlib.h> + +uint32_t crc32c(uint8_t *buf, int len); + +#ifdef __cplusplus +} +#endif +#endif /* CRC32C_H */ diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h new file mode 100644 index 000000000..67690bcb3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef _LIBMCTP_SMBUS_H +#define _LIBMCTP_SMBUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libmctp.h" + +struct mctp_binding_smbus; + +struct mctp_binding_smbus *mctp_smbus_init(void); +int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus); +int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus); +void mctp_smbus_register_bus(struct mctp_binding_smbus *smbus, + struct mctp *mctp, mctp_eid_t eid); +int mctp_smbus_read(struct mctp_binding_smbus *smbus); +int mctp_smbus_open_bus(struct mctp_binding_smbus *smbus, int out_bus_num, + int root_bus_num); +void mctp_smbus_free(struct mctp_binding_smbus *smbus); +int mctp_smbus_open_in_bus(struct mctp_binding_smbus *smbus, int in_bus); +int mctp_smbus_open_out_bus(struct mctp_binding_smbus *smbus, int out_bus); +int mctp_smbus_set_in_fd(struct mctp_binding_smbus *smbus, int fd); +int mctp_smbus_set_out_fd(struct mctp_binding_smbus *smbus, int fd); + +#ifdef __cplusplus +} +#endif +#endif /* _LIBMCTP_SMBUS_H */ diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c new file mode 100644 index 000000000..2f099a7e5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c @@ -0,0 +1,467 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef MCTP_HAVE_FILEIO +#include <fcntl.h> +#endif + +#define pr_fmt(x) "smbus: " x + +#include <i2c/smbus.h> +#include <linux/i2c-dev.h> +#include <linux/i2c.h> +#include <sys/ioctl.h> + +#include "libmctp-alloc.h" +#include "libmctp-log.h" +#include "libmctp-smbus.h" +#include "libmctp.h" + +struct mctp_binding_smbus { + struct mctp_binding binding; + int out_fd; + int in_fd; + + unsigned long bus_id; + + /* receive buffer */ + uint8_t rxbuf[1024]; + struct mctp_pktbuf *rx_pkt; + + /* temporary transmit buffer */ + uint8_t txbuf[256]; +}; + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char *)(ptr) - (char *)&((type *)0)->member) +#endif + +#define binding_to_smbus(b) container_of(b, struct mctp_binding_smbus, binding) + +#define MCTP_COMMAND_CODE 0x0F +#define MCTP_SLAVE_ADDRESS 0x1d +#define MCTP_SOURCE_SLAVE_ADDRESS 0x21 + +#define SMBUS_PEC_BYTE_SIZE 1 +#define SMBUS_COMMAND_CODE_SIZE 1 +#define SMBUS_LENGTH_FIELD_SIZE 1 +#define SMBUS_ADDR_OFFSET_SLAVE 0x1000 + +struct mctp_smbus_header_tx { + uint8_t source_slave_address; +}; + +struct mctp_smbus_header_rx { + uint8_t destination_slave_address; + uint8_t command_code; + uint8_t byte_count; + uint8_t source_slave_address; +}; + +#define POLYCHECK (0x1070U << 3) +static uint8_t crc8_calculate(uint16_t d) +{ + int i; + + for (i = 0; i < 8; i++) { + if (d & 0x8000) { + d = d ^ POLYCHECK; + } + d = d << 1; + } + + return (uint8_t)(d >> 8); +} + +/* Incremental CRC8 over count bytes in the array pointed to by p */ +static uint8_t pec_calculate(uint8_t crc, uint8_t *p, size_t count) +{ + int i; + + for (i = 0; i < count; i++) { + crc = crc8_calculate((crc ^ p[i]) << 8); + } + + return crc; +} + +static uint8_t calculate_pec_byte(uint8_t *buf, size_t len, uint8_t address, + uint16_t flags) +{ + uint8_t addr = (address << 1) | (flags & I2C_M_RD ? 1 : 0); + uint8_t pec = pec_calculate(0, &addr, 1); + pec = pec_calculate(pec, buf, len); + + return pec; +} + +static int mctp_smbus_tx(struct mctp_binding_smbus *smbus, uint8_t len) +{ + +#ifdef I2C_M_HOLD + /* Hold message */ + static uint16_t holdtimeout = 1000; // timeout in ms. + struct i2c_msg msg[2] = +#else // !I2C_M_HOLD + struct i2c_msg msg[1] = +#endif // I2C_M_HOLD + {{.addr = MCTP_SLAVE_ADDRESS, + .flags = 0, + .len = len, + .buf = (__uint8_t *)smbus->txbuf} +#ifdef I2C_M_HOLD + , + {.addr = 0, + .flags = I2C_M_HOLD, + .len = sizeof(holdtimeout), + .buf = (__uint8_t *)&holdtimeout} +#endif // I2C_M_HOLD + }; + +#ifdef I2C_M_HOLD + struct i2c_rdwr_ioctl_data msgrdwr = {&msg, 2}; +#else // !I2C_M_HOLD + struct i2c_rdwr_ioctl_data msgrdwr = {&msg, 1}; +#endif // I2C_M_HOLD + + return ioctl(smbus->out_fd, I2C_RDWR, &msgrdwr); +} + +#ifdef I2C_M_HOLD +static int mctp_smbus_unhold_bus(struct mctp_binding_smbus *smbus) +{ + /* Unhold message */ + static uint16_t holdtimeout = 0; // unhold + struct i2c_msg holdmsg = {0, I2C_M_HOLD, sizeof(holdtimeout), + (__uint8_t *)&holdtimeout}; + + struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg, 1}; + + return ioctl(smbus->out_fd, I2C_RDWR, &msgrdwr); +} +#endif // I2C_M_HOLD + +static int mctp_binding_smbus_tx(struct mctp_binding *b, + struct mctp_pktbuf *pkt) +{ + struct mctp_binding_smbus *smbus = binding_to_smbus(b); + struct mctp_smbus_header_tx *hdr; + size_t pkt_length; + + uint8_t i2c_message_buf[256]; + uint8_t *buf_ptr; + uint8_t i2c_message_len; + + uint16_t timeout = 1000; + + /* the length field in the header excludes smbus framing + * and escape sequences */ + pkt_length = mctp_pktbuf_size(pkt); + + buf_ptr = (void *)smbus->txbuf; + *buf_ptr = MCTP_COMMAND_CODE; + buf_ptr++; + *buf_ptr = pkt_length + sizeof(*hdr); + buf_ptr++; + + hdr = (void *)buf_ptr; + hdr->source_slave_address = MCTP_SOURCE_SLAVE_ADDRESS; + buf_ptr = (buf_ptr + sizeof(*hdr)); + memcpy(buf_ptr, &pkt->data[pkt->start], pkt_length); + buf_ptr = buf_ptr + pkt_length; + + uint8_t pec_byte = calculate_pec_byte( + smbus->txbuf, + SMBUS_COMMAND_CODE_SIZE + SMBUS_LENGTH_FIELD_SIZE + sizeof(*hdr) + + pkt_length, + MCTP_SLAVE_ADDRESS, 0); + + *buf_ptr = pec_byte; + + i2c_message_len = SMBUS_COMMAND_CODE_SIZE + SMBUS_LENGTH_FIELD_SIZE + + sizeof(*hdr) + pkt_length + + SMBUS_PEC_BYTE_SIZE; // command code, length, + // header, data, pec byte + + if (mctp_smbus_tx(smbus, i2c_message_len)) { + mctp_prerr("Can't hold mux"); + return -1; + } + + return 0; +} + +#ifdef MCTP_HAVE_FILEIO +int mctp_smbus_read(struct mctp_binding_smbus *smbus) +{ + ssize_t len = 0; + struct mctp_smbus_header_rx *hdr; + int ret = 0; + + do { + ret = lseek(smbus->in_fd, 0, SEEK_SET); + if (ret < 0) { + mctp_prerr("Failed to seek"); + ret = -1; + } + + len = read(smbus->in_fd, smbus->rxbuf, sizeof(smbus->rxbuf)); + if (len < sizeof(*hdr)) { + // This condition hits from from time to time, even with + // a properly written poll loop, although it's not clear + // why. Return an error so that the upper layer can + // retry. + ret = 0; + break; + } + + hdr = (void *)smbus->rxbuf; + if (hdr->destination_slave_address + != (MCTP_SOURCE_SLAVE_ADDRESS & ~1)) { + mctp_prerr("Got bad slave address %d", + hdr->destination_slave_address); + ret = 0; + break; + } + if (hdr->command_code != MCTP_COMMAND_CODE) { + mctp_prerr("Got bad command code %d", + hdr->command_code); + // Not a payload intended for us + ret = 0; + break; + } + + if (hdr->byte_count != (len - sizeof(*hdr))) { + // Got an incorrectly sized payload + mctp_prerr("Got smbus payload sized %d, expecting %d", + hdr->byte_count, len - sizeof(*hdr)); + ret = 0; + break; + } + + if (len < 0) { + mctp_prerr("can't read from smbus device: %m"); + ret = -1; + break; + } + + smbus->rx_pkt = mctp_pktbuf_alloc(&(smbus->binding), 0); + assert(smbus->rx_pkt); + + if (mctp_pktbuf_push(smbus->rx_pkt, &smbus->rxbuf[sizeof(*hdr)], + len - sizeof(*hdr) - SMBUS_PEC_BYTE_SIZE) + != 0) { + mctp_prerr("Can't push tok pktbuf: %m"); + ret = -1; + break; + } + + mctp_bus_rx(&(smbus->binding), smbus->rx_pkt); + + smbus->rx_pkt = NULL; + + } while (0); + +#ifdef I2C_M_HOLD + if (mctp_smbus_unhold_bus(smbus)) { + mctp_prerr("Can't hold mux"); + ret = -1; + } +#endif // I2C_M_HOLD + + return ret; +} + +int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus) +{ + return smbus->in_fd; +} + + +int mctp_smbus_set_in_fd(struct mctp_binding_smbus *smbus, int fd) +{ + smbus->in_fd = fd; +} + +int mctp_smbus_set_out_fd(struct mctp_binding_smbus *smbus, int fd) +{ + smbus->out_fd = fd; +} + +int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus) +{ + return smbus->out_fd; +} + +int mctp_smbus_open_in_bus(struct mctp_binding_smbus *smbus, int in_bus) +{ + char filename[60]; + size_t filename_size = 0; + char slave_mqueue[20]; + size_t mqueue_size = 0; + int fd = 0; + size_t size = sizeof(filename); + int address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1; + int ret = -1; + + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", in_bus, + in_bus, SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + ret = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (ret >= 0) { + return ret; + } + + // Device doesn't exist. Create it. + filename_size = sizeof(filename); + snprintf(filename, filename_size, + "/sys/bus/i2c/devices/i2c-%d/new_device", in_bus); + filename[filename_size - 1] = '\0'; + + fd = open(filename, O_WRONLY); + if (fd < 0) { + mctp_prerr("can't open root device %s: %m", filename); + return -1; + } + + mqueue_size = sizeof(slave_mqueue); + snprintf(slave_mqueue, mqueue_size, "slave-mqueue %#04x", + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + size = write(fd, slave_mqueue, mqueue_size); + close(fd); + if (size != mqueue_size) { + mctp_prerr("can't create mqueue device on %s: %m", filename); + return -1; + } + + size = sizeof(filename); + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", in_bus, + in_bus, SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + return open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); +} + +int mctp_smbus_open_out_bus(struct mctp_binding_smbus *smbus, int out_bus) +{ + char filename[60]; + size_t size = sizeof(filename); + snprintf(filename, size, "/dev/i2c-%d", out_bus); + filename[size - 1] = '\0'; + + return open(filename, O_RDWR | O_NONBLOCK); +} + +/* +int mctp_smbus_open_bus(struct mctp_binding_smbus *smbus, int out_bus_num, + int root_bus_num) +{ + char filename[60]; + size_t filename_size = 0; + char slave_mqueue[20]; + size_t mqueue_size = 0; + int fd = 0; + size_t size = sizeof(filename); + int address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1; + + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", + root_bus_num, root_bus_num, + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + smbus->in_fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (smbus->in_fd < 0) { + // Device doesn't exist. Create it. + filename_size = sizeof(filename); + snprintf(filename, filename_size, + "/sys/bus/i2c/devices/i2c-%d/new_device", + root_bus_num); + filename[filename_size - 1] = '\0'; + + fd = open(filename, O_WRONLY); + if (fd < 0) { + mctp_prerr("can't open root device %s: %m", filename); + return -1; + } + + mqueue_size = sizeof(slave_mqueue); + snprintf(slave_mqueue, mqueue_size, "slave-mqueue %#04x", + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + size = write(fd, slave_mqueue, mqueue_size); + close(fd); + if (size != mqueue_size) { + mctp_prerr("can't create mqueue device on %s: %m", + filename); + return -1; + } + + size = sizeof(filename); + snprintf(filename, size, + "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", + root_bus_num, root_bus_num, + SMBUS_ADDR_OFFSET_SLAVE | address_7_bit); + + smbus->in_fd = + open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (smbus->in_fd < 0) { + mctp_prerr("can't open mqueue device on %s: %m", + filename); + return -2; + } + } + + size = sizeof(filename); + snprintf(filename, size, "/dev/i2c-%d", out_bus_num); + filename[size - 1] = '\0'; + + smbus->out_fd = open(filename, O_RDWR | O_NONBLOCK); + if (smbus->out_fd < 0) { + close(smbus->in_fd); + mctp_prerr("can't open device %s: %m", filename); + } + + return 0; +} +*/ +#endif + +void mctp_smbus_register_bus(struct mctp_binding_smbus *smbus, + struct mctp *mctp, mctp_eid_t eid) +{ + smbus->bus_id = mctp_register_bus(mctp, &smbus->binding, eid); + mctp_binding_set_tx_enabled(&smbus->binding, true); +} + +struct mctp_binding_smbus *mctp_smbus_init(void) +{ + struct mctp_binding_smbus *smbus; + + smbus = __mctp_alloc(sizeof(*smbus)); + memset(&(smbus->binding), 0, sizeof(smbus->binding)); + + smbus->in_fd = -1; + smbus->out_fd = -1; + + smbus->rx_pkt = NULL; + smbus->binding.name = "smbus"; + smbus->binding.version = 1; + smbus->binding.pkt_size = sizeof(smbus->rxbuf); + + smbus->binding.tx = mctp_binding_smbus_tx; + return smbus; +} + +void mctp_smbus_free(struct mctp_binding_smbus *smbus) +{ + __mctp_free(smbus); +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb new file mode 100644 index 000000000..97ce1179f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb @@ -0,0 +1,40 @@ +SUMMARY = "libmctp" +DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" + +SRC_URI = "git://github.com/openbmc/libmctp.git" +SRCREV = "b6516a083c622a76e3e485f56b743b2a63171881" + +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0 | GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=0d30807bb7a4f16d36e96b78f9ed8fae" + +inherit cmake + +S = "${WORKDIR}/git" + +DEPENDS += "i2c-tools" + +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Smbus-changes-for-libmctp.patch \ + file://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} +} + +# linux-libc-headers guides this way to include custom uapi headers +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" + +do_configure[depends] += "virtual/kernel:do_shared_workdir" diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend new file mode 100644 index 000000000..c20a59045 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend @@ -0,0 +1,5 @@ +EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DINTEL_PFR_ENABLED=ON', '', d)}" +EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" +EXTRA_OECMAKE += "-DUSING_ENTITY_MANAGER_DECORATORS=OFF" +SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git" +SRCREV = "4b1552d890fd091566fa7cf2d559f066a58eaae1" diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb new file mode 100644 index 000000000..955ed1921 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb @@ -0,0 +1,26 @@ +SUMMARY = "Kernel panic Check" +DESCRIPTION = "script tool to check if the reboot is caused by kernel panic \ + log the kernel panic to systemd journal, and also log to redfish \ + " + +S = "${WORKDIR}" +SRC_URI = "file://kernel-panic-check.sh \ + file://kernel-panic-check.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash logger-systemd" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/kernel-panic-check.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/kernel-panic-check.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/kernel-panic-check.sh ${D}/${bindir}/kernel-panic-check.sh +} + +SYSTEMD_SERVICE_${PN} += " kernel-panic-check.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service new file mode 100644 index 000000000..afe017baf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service @@ -0,0 +1,9 @@ +[Unit] +Description=Check for kernel panic + +[Service] +Type=oneshot +ExecStart=/usr/bin/kernel-panic-check.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh new file mode 100755 index 000000000..815f50b71 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh @@ -0,0 +1,16 @@ +#!/bin/sh +panicFile="/sys/fs/pstore/dmesg-ramoops-0" +if [ -f $panicFile ] +then + # log the detailed last kernel panic messages + logger -t kernel-panic-check "Reboot from kernel panic! Log as following:" + cat $panicFile | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.BMCKernelPanic +PRIORITY=4 +MESSAGE=BMC rebooted due to kernel panic +EOF + + rm -rf $panicFile +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_git.bb b/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_git.bb new file mode 100644 index 000000000..5a49156da --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_git.bb @@ -0,0 +1,17 @@ +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +inherit cmake + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" + +PV = "0.1+git${SRCPV}" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +S = "${WORKDIR}/git/libpeci" + +# 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/libxcrypt/libxcrypt_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend new file mode 100644 index 000000000..ee414efb8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend @@ -0,0 +1,5 @@ +# libxcrypt fails to compile under gcc with the -Os flag. Because we want to +# be able to compile the rest of the system with -Os, override the global +# setting here to fall back to -O3 +CFLAGS_append = "--param max-inline-insns-single=1000" +FULL_OPTIMIZATION = "-O3 -pipe ${DEBUG_FLAGS}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc new file mode 100644 index 000000000..abad9d12d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc @@ -0,0 +1,43 @@ +SUMMARY = "logger tool in util-linux with systemd support" +HOMEPAGE = "http://userweb.kernel.org/~kzak/util-linux/" +DESCRIPTION = "logger tool with systemd support, used to add log to systemd journald." + +SECTION = "base" + +LICENSE = "GPLv2+ & LGPLv2.1+ & BSD-3-Clause & BSD-4-Clause" + +LIC_FILES_CHKSUM = "file://README.licensing;md5=972a134f1e14b2b060e365df2fab0099 \ + file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \ + file://Documentation/licenses/COPYING.GPL-2.0-or-later;md5=b234ee4d69f5fce4486a80fdaf4a4263 \ + file://Documentation/licenses/COPYING.LGPL-2.1-or-later;md5=4fbd65380cdd255951079008b364516c \ + file://Documentation/licenses/COPYING.BSD-3-Clause;md5=58dcd8452651fc8b07d1f65ce07ca8af \ + file://Documentation/licenses/COPYING.BSD-4-Clause-UC;md5=263860f8968d8bafa5392cab74285262 \ + file://libuuid/COPYING;md5=6d2cafc999feb2c2de84d4d24b23290c \ + file://libmount/COPYING;md5=7c7e39fb7d70ffe5d693a643e29987c2 \ + file://libblkid/COPYING;md5=693bcbbe16d3a4a4b37bc906bc01cc04" + +inherit autotools gettext pkgconfig +DEPENDS = "libcap-ng ncurses virtual/crypt zlib systemd " +#DEPENDS_intel-ast2500 += " systemd " +#RDEPENDS_${PN} += " libsystemd" + +MAJOR_VERSION = "${@'.'.join(d.getVar('PV').split('.')[0:2])}" +SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-linux-${MAJOR_VERSION}.tar.xz \ + " + +S = "${WORKDIR}/util-linux-${MAJOR_VERSION}" + +EXTRA_OECONF = " --disable-nls --disable-all-programs \ + --disable-libuuid --disable-libblkid --disable-libmount \ + --disable-libsmartcols --disable-libfdisk --disable-pylibmount \ + --with-systemd \ + --enable-logger \ + " + +do_install_append () { + mv ${D}${bindir}/logger ${D}${bindir}/logger-systemd + rm -rf ${D}${sbindir} + rm -rf ${D}${base_libdir} + rm -rf ${D}${libdir} + rm -rf ${D}${datadir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch new file mode 100644 index 000000000..748b6ef09 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch @@ -0,0 +1,20 @@ +Ptest needs buildtest-TESTS and runtest-TESTS targets. +serial-tests is required to generate those targets. +Revert run.sh script accordingly to serialize running tests + +Signed-off-by: Tudor Florea <tudor.florea@enea.com> +Upstream-Status: Inappropriate + +Index: util-linux-2.32/configure.ac +=================================================================== +--- util-linux-2.32.orig/configure.ac ++++ util-linux-2.32/configure.ac +@@ -11,7 +11,7 @@ AC_CONFIG_MACRO_DIR([m4]) + dnl AC_USE_SYSTEM_EXTENSIONS must be called before any macros that run + dnl the compiler (like AC_PROG_LIBTOOL) to avoid autoconf errors. + AC_USE_SYSTEM_EXTENSIONS +-AM_INIT_AUTOMAKE([-Wall foreign 1.10 tar-pax no-dist-gzip dist-xz subdir-objects]) ++AM_INIT_AUTOMAKE([-Wall foreign 1.10 tar-pax no-dist-gzip dist-xz subdir-objects serial-tests]) + + m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], + [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])]) diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch new file mode 100644 index 000000000..e475289f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch @@ -0,0 +1,23 @@ +util-linux: take ${sbindir} from the environment if it is set there +fix the test, the [ ] syntax was getting eaten by autoconf + +Signed-off-by: Phil Blundell <pb@pbcl.net> +Signed-off-by: Saul Wold <sgw@linux.intel.com +Upstream-Status: Inappropriate [configuration] + +Index: util-linux-2.31/configure.ac +=================================================================== +--- util-linux-2.31.orig/configure.ac ++++ util-linux-2.31/configure.ac +@@ -89,7 +89,10 @@ AC_SUBST([runstatedir]) + usrbin_execdir='${exec_prefix}/bin' + AC_SUBST([usrbin_execdir]) + +-usrsbin_execdir='${exec_prefix}/sbin' ++if test -z "$usrsbin_execdir" ; ++then ++ usrsbin_execdir='${exec_prefix}/sbin' ++fi + AC_SUBST([usrsbin_execdir]) + + AS_CASE([$libdir], diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch new file mode 100644 index 000000000..417ca1d98 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch @@ -0,0 +1,25 @@ +Display testname for subtest + +Signed-off-by: Tudor Florea <tudor.florea@enea.com> +Upstream-Status: Pending + +--- + tests/functions.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/functions.sh b/tests/functions.sh +index 5246605..b24dc15 100644 +--- a/tests/functions.sh ++++ b/tests/functions.sh +@@ -320,7 +320,7 @@ function ts_init_subtest { + + if [ "$TS_PARSABLE" != "yes" ]; then + [ $TS_NSUBTESTS -eq 1 ] && echo +- printf "%16s: %-27s ..." "" "$TS_SUBNAME" ++ printf "%13s: %-30s ..." "$TS_COMPONENT" "$TS_SUBNAME" + fi + } + +-- +2.8.3 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch new file mode 100644 index 000000000..0537f7d85 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch @@ -0,0 +1,23 @@ +Define TESTS variable + +Signed-off-by: Tudor Florea <tudor.florea@enea.com> +Upstream-Status: Pending +--- + Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Makefile.am b/Makefile.am +index bbaccb1..7d5a6bb 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -48,6 +48,7 @@ systemdsystemunit_DATA = + dist_bashcompletion_DATA = + check_PROGRAMS = + dist_check_SCRIPTS = ++TESTS = $(check_PROGRAMS) + + PATHFILES = + +-- +2.8.3 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest new file mode 100644 index 000000000..e135ee583 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest @@ -0,0 +1,43 @@ +#!/bin/sh + + +# When udevd (from eudev) is running most eject/mount tests will fail because +# of automount. We need to stop udevd before executing util-linux's tests. +# The systemd-udevd daemon doesn't change the outcome of util-linux's tests. +UDEV_PID="`pidof "@base_sbindir@/udevd"`" +if [ "x$UDEV_PID" != "x" ]; then + /etc/init.d/udev stop +fi + +current_path=$(readlink -f $0) +export bindir=$(dirname $current_path) +export PATH=$bindir/bin:$PATH + +cd tests || exit 1 + +comps=$(find ts/ -type f -perm -111 -regex ".*/[^\.~]*" | sort) + + +echo +echo "-------------------- util-linux regression tests --------------------" +echo +echo " For development purpose only. " +echo " Don't execute on production system! " +echo + +res=0 +count=0 +for ts in $comps; +do + $ts | sed -u '{ + s/^\(.*\):\(.*\) \.\.\. OK$/PASS: \1:\2/ + s/^\(.*\):\(.*\) \.\.\. FAILED \(.*\)$/FAIL: \1:\2 \3/ + s/^\(.*\):\(.*\) \.\.\. SKIPPED \(.*\)$/SKIP: \1:\2 \3/ + }' +done + + +if [ "x$UDEV_PID" != "x" ]; then + /etc/init.d/udev start +fi + diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd new file mode 100644 index 000000000..4b368ccf5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd @@ -0,0 +1,3 @@ +auth include runuser +session optional pam_keyinit.so force revoke +session include runuser diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd new file mode 100644 index 000000000..48d133b9e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd @@ -0,0 +1,4 @@ +auth sufficient pam_rootok.so +session optional pam_keyinit.so revoke +session required pam_limits.so +session required pam_unix.so diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb new file mode 100644 index 000000000..b58628667 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb @@ -0,0 +1,12 @@ +require logger-systemd.inc + +SRC_URI += "file://configure-sbindir.patch \ + file://runuser.pamd \ + file://runuser-l.pamd \ + file://ptest.patch \ + file://run-ptest \ + file://display_testname_for_subtest.patch \ + file://avoid_parallel_tests.patch \ +" +SRC_URI[md5sum] = "a78cbeaed9c39094b96a48ba8f891d50" +SRC_URI[sha256sum] = "743f9d0c7252b6db246b659c1e1ce0bd45d8d4508b4dfa427bbb4a3e9b9f62b5"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb new file mode 100644 index 000000000..f8e5505ef --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb @@ -0,0 +1,24 @@ +# Add GSL: Guideline Support Library for c++ +# https://github.com/Microsoft/GSL + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://LICENSE;md5=363055e71e77071107ba2bb9a54bd9a7" + +SRC_URI = "git://github.com/Microsoft/GSL.git;protocol=https;nobranch=1" + +# Modify these as desired +PV = "1.0+git${SRCPV}" +#SRCREV = "${AUTOREV}" +SRCREV = "be43c79742dc36ee55b21c5d531a5ff301d0ef8d" + +S = "${WORKDIR}/git" + +do_install () { + install -d ${D}/usr/include + install -d ${D}/usr/include/gsl + for F in ${S}/include/gsl/*; do + install -m 0644 ${F} ${D}/usr/include/gsl + done +} + +ALLOW_EMPTY_${PN} = "1" diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service new file mode 100644 index 000000000..f5210dd5b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service @@ -0,0 +1,11 @@ +[Unit] +Description=Overlay sync to NV storage + +[Service] +# Run rsync periodically to sync the overlay to NV storage +ExecStart=bash -c 'while true; do rsync -a --delete /tmp/.overlay/ /tmp/.rwfs/.overlay; sync /tmp/.rwfs/.overlay; sleep 10; done' +# On shutdown, archive the bash history so we don't lose it and run one last sync +ExecStop=bash -c 'history -a; rsync -a --delete /tmp/.overlay/ /tmp/.rwfs/.overlay; sync /tmp/.rwfs/.overlay; sleep 5' + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb new file mode 100644 index 000000000..0ee70e880 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb @@ -0,0 +1,20 @@ +SUMMARY = "NV Overlay Sync" +DESCRIPTION = "Script to periodically sync the overlay to NV storage" + +S = "${WORKDIR}" +SRC_URI = "file://nv-sync.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/nv-sync.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/nv-sync.service ${D}${systemd_system_unitdir} +} + +SYSTEMD_SERVICE_${PN} += " nv-sync.service" diff --git a/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend new file mode 100644 index 000000000..a47d923f8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend @@ -0,0 +1,34 @@ +# WARNING! +# +# These modifications to os-release disable the bitbake parse +# cache (for the os-release recipe only). Before copying +# and pasting into another recipe ensure it is understood +# what that means! + +require version-vars.inc + +OS_RELEASE_FIELDS_append = " OPENBMC_VERSION IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16" + +python do_compile_append () { + import glob + with open(d.expand('${B}/os-release'), 'a') as f: + corebase = d.getVar('COREBASE', True) + f.write('\n# Build Configuration Details\n') + repo_status(d, f, corebase, '') + repo_status(d, f, os.path.join(corebase, 'meta-openbmc-mods'), '--tags') + appends_dir = os.path.join(d.getVar('TOPDIR', True), 'workspace', 'appends') + + for fn in glob.glob(os.path.join(appends_dir, '*.bbappend')): + with open(fn, 'r') as bb_f: + for line in bb_f: + if line.startswith('# srctreebase: '): + srctreebase = line.split(':', 1)[1].strip() + repo_status(d, f, srctreebase, '--tags') +} + + +# Ensure the git commands run every time bitbake is invoked. +BB_DONT_CACHE = "1" + +# Make os-release available to other recipes. +SYSROOT_DIRS_append = " ${sysconfdir}" diff --git a/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc b/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc new file mode 100644 index 000000000..0c8f3be56 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc @@ -0,0 +1,78 @@ +def irun_git(d, oeroot, git_cmd, **kwargs): + err = None + try: + cmd = 'git --work-tree {} --git-dir {}/.git {}'.format(oeroot, oeroot, git_cmd) + ret, err = bb.process.run(cmd, **kwargs) + if err is not None: + ret += err + except bb.process.ExecutionError as e: + ret = '' + if e.stdout is not None: + ret += e.stdout + if e.stderr is not None: + ret += e.stderr + except Exception as e: + ret = str(e) + return ret.strip('\n') + +def repo_status(d, f, repo, tagargs): + import subprocess + + cmd_list = [['HEAD', 'rev-parse HEAD'], + ['TAG', 'describe {} --dirty --long'.format(tagargs)], + ['STATUS', 'status -sb']] + + f.write(('\n# REPOSITORY: {} '.format(os.path.basename(repo))).ljust(80, '+') + '\n') + for item in cmd_list: + f.write('# {}: '.format(item[0])) + sb = irun_git(d, repo, item[1]) + if sb: + sb_lines = sb.split('\n') + if len(sb_lines) == 1: + f.write(sb_lines[0]) + else: + f.write('\n# ' + '\n# '.join(sb_lines)) + f.write('\n') + +python() { + import re + + gen = d.getVar('PRODUCT_GENERATION', True) + if gen is None: + gen = 'unknown' + + corebase = d.getVar('COREBASE', True) + mibase = os.path.join(corebase, 'meta-openbmc-mods') + obmc_vers = irun_git(d, corebase, 'describe --dirty --long') + if obmc_vers is None: + raise bb.build.FuncFailed("Missing version tag for openbmc-openbmc") + d.setVar('OPENBMC_VERSION', obmc_vers) + + obmc_hash = irun_git(d, corebase, 'rev-parse HEAD') + meta_vers = irun_git(d, mibase, + 'describe --long --abbrev=6 ' + + '--match \'{}-[0-9]*\.[0-9]*\''.format(gen)) + + # Until tags in meta-openbmc-mods, interim measure keep builds working. + if meta_vers.startswith('fatal:'): + meta_vers = '{}-0.0-0'.format(gen) + + meta_hash = irun_git(d, mibase, 'rev-parse HEAD') + version_id = '{}-{}'.format(meta_vers, obmc_hash[0:7]) + if version_id: + d.setVar('VERSION_ID', version_id) + versionList = version_id.split('-') + versionList = re.split('-|\.', version_id) + version = '{}.{}-{}'.format(versionList[0], versionList[1], versionList[2]) + d.setVar('VERSION', version) + d.setVar('IPMI_MAJOR', versionList[1]) + d.setVar('IPMI_MINOR', versionList[2]) + d.setVar('IPMI_AUX13', hex(min(int(versionList[3]), 0xff))) + d.setVar('IPMI_AUX14', '0x{}'.format(meta_hash[0:2])) + d.setVar('IPMI_AUX15', '0x{}'.format(meta_hash[2:4])) + d.setVar('IPMI_AUX16', '0x{}'.format(meta_hash[4:6])) + + build_id = irun_git(d, mibase, 'describe --abbrev=0') + if build_id: + d.setVar('BUILD_ID', build_id) +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend b/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend new file mode 100644 index 000000000..87a4c8503 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend @@ -0,0 +1 @@ +RRECOMMENDS_${PN}_append = " vim cmake sdbusplus" diff --git a/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb b/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb new file mode 100644 index 000000000..4bf1c9548 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb @@ -0,0 +1,24 @@ +# NOTE: LICENSE is being set to "CLOSED" for now. The PCIe reads over PECI expose +# more information than is accessible from the BIOS or OS, so we need to keep this +# internal to Intel until it's resolved. +LICENSE = "CLOSED" +LIC_FILES_CHKSUM = "" +inherit cmake systemd + +SRC_URI = "git://github.com/Intel-BMC/at-scale-debug;protocol=ssh" + +DEPENDS = "boost sdbusplus libpeci" + +PV = "0.1+git${SRCPV}" +SRCREV = "98c33cdb7d704a387edee4ac8f0ef98ea771b222" + +S = "${WORKDIR}/git/peci_pcie" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.PCIe.service" + +# linux-libc-headers guides this way to include custom uapi headers +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include" +do_configure[depends] += "virtual/kernel:do_shared_workdir" diff --git a/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc b/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc new file mode 100644 index 000000000..7b84c9916 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc @@ -0,0 +1,61 @@ +# /etc/inputrc - global inputrc for libreadline +# See readline(3readline) and `info rluserman' for more information. + +# Be 8 bit clean. +set input-meta on +set output-meta on + +# To allow the use of 8bit-characters like the german umlauts, comment out +# the line below. However this makes the meta key not work as a meta key, +# which is annoying to those which don't need to type in 8-bit characters. + +# set convert-meta off + +# try to enable the application keypad when it is called. Some systems +# need this to enable the arrow keys. +# set enable-keypad on + +# see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys + +# do not bell on tab-completion +# set bell-style none + +# some defaults / modifications for the emacs mode +$if mode=emacs + +# allow the use of the Home/End keys + "\e[1~": beginning-of-line + "\e[4~": end-of-line + +# allow the use of the Delete/Insert keys + "\e[3~": delete-char +# "\e[2~": quoted-insert + +# mappings for "page up" and "page down" to step to the beginning/end +# of the history +# "\e[5~": beginning-of-history +# "\e[6~": end-of-history + +# alternate mappings for "page up" and "page down" to search the history +# "\e[5~": history-search-backward +# "\e[6~": history-search-forward + +# # mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving +# "\e[5C": forward-word +# "\e[5D": backward-word +# "\e\e[C": forward-word +# "\e\e[D": backward-word + +# $if term=rxvt +# "\e[8~": end-of-line +# $endif + +# for non RH/Debian xterm, can't hurt for RH/DEbian xterm +# "\eOH": beginning-of-line +# "\eOF": end-of-line + +# for freebsd console +# "\e[H": beginning-of-line +# "\e[F": end-of-line + +$endif diff --git a/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend new file mode 100644 index 000000000..c63a45dd4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend @@ -0,0 +1,2 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI_append = " file://inputrc" diff --git a/meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb b/meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb new file mode 100644 index 000000000..429d5b4b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb @@ -0,0 +1,23 @@ +SUMMARY = "Phosphor OpenBMC REST framework" +DESCRIPTION = "Phosphor OpenBMC REST to DBUS daemon." +HOMEPAGE = "http://github.com/openbmc/rest-dbus" +PR = "r1" + +inherit allarch +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRC_URI += "git://github.com/openbmc/rest-dbus.git" + +SRCREV = "9273a302e8f2b3c3e939dff77758e90f163bf6a1" + +S = "${WORKDIR}/git" + +FILES_${PN} += "${datadir}/www/rest-dbus/*" + +do_install () { + install -d ${D}${datadir}/www/rest-dbus/res + install -m 644 ${S}/resources/** ${D}${datadir}/www/rest-dbus/res + install -m 644 ${S}/resources/index.html ${D}${datadir}/www/rest-dbus/index.html +} + diff --git a/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend new file mode 100644 index 000000000..4ce29534d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend @@ -0,0 +1,11 @@ +RDEPENDS_${PN} = "" +do_install_append() { + F=$(find ${D} -name check_for_unsafe_apis) + if [ -n "${F}" ]; then + # remove the unused perl script + rm -f "${F}" + # remove the script's destination directory, only if it is empty + rmdir "$(dirname ${F})" 2>/dev/null || : + fi +} + diff --git a/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb new file mode 100644 index 000000000..449dcf04d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb @@ -0,0 +1,15 @@ +SUMMARY = "Safe C Library" + +LICENSE = "safec" +LIC_FILES_CHKSUM = "file://COPYING;md5=6d0eb7dfc57806a006fcbc4e389cf164" +SECTION = "lib" + +inherit autotools pkgconfig + +S = "${WORKDIR}/git" +SRCREV = "a7da29dadadde04feec174f595b59d67a64f3956" +SRC_URI = "git://github.com/rurban/safeclib.git" + +COMPATIBLE_HOST = '(x86_64|i.86|powerpc|powerpc64|arm|aarch64).*-linux' + +RDEPENDS_${PN} = "perl" diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb new file mode 100644 index 000000000..29f8e4986 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb @@ -0,0 +1,26 @@ +SUMMARY = "Security registers check" +DESCRIPTION = "script tool to check if registers value are security \ + log the security event to systemd journal, and also log to redfish \ + " + +S = "${WORKDIR}" +SRC_URI = "file://security-registers-check.sh \ + file://security-registers-check.service \ +" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash logger-systemd" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/security-registers-check.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0777 ${WORKDIR}/security-registers-check.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0777 ${S}/security-registers-check.sh ${D}/${bindir}/security-registers-check.sh +} + +SYSTEMD_SERVICE_${PN} += " security-registers-check.service"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service new file mode 100644 index 000000000..b824dbe3e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service @@ -0,0 +1,10 @@ +[Unit] +Description=Check for security registers + +[Service] +Type=oneshot +ExecStart=/usr/bin/security-registers-check.sh +Nice=5 + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh new file mode 100644 index 000000000..211120c78 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh @@ -0,0 +1,42 @@ +#!/bin/sh +value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/uart_port_debug` +if [ $value == 0 ] + then + # log the detailed last security registers check messages + logger -t security-registers-check "Uart port debug is enabled! Log as following:" + echo "Uart port debug is enabled." | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityUartPortDebugEnabled +PRIORITY=4 +MESSAGE=BMC Uart port debug is enabled +EOF +fi + +value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/p2a-bridge` +if [ $value == 1 ] + then + # log the detailed last security registers check messages + logger -t security-registers-check "P2A(PCIe to AHB) bridge is enabled! Log as following:" + echo "P2A(PCIe to AHB) bridge is enabled." | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityP2aBridgeEnabled +PRIORITY=4 +MESSAGE=BMC P2A(PCIe to AHB) bridge is enabled +EOF +fi + +value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/boot-2nd-flash` +if [ $value == 1 ] + then + # log the detailed last security registers check messages + logger -t security-registers-check "BMC 2nd boot flash is enabled! Log as following:" + echo "BMC 2nd boot flash is enabled." | logger + # Also log it to redfish + cat <<EOF | logger-systemd --journald +REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityBoot2ndFlashEnabled +PRIORITY=4 +MESSAGE=BMC 2nd boot flash is enabled +EOF +fi diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend new file mode 100644 index 000000000..3d4e594a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend @@ -0,0 +1,10 @@ +# Remove these files since they are provided by obmc-intel-targets +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-start@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-stop@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-shutdown@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-reboot@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-host-startmin@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweron@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweroff@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-hard-poweroff@.target" +SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-powerreset@.target" diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf new file mode 100644 index 000000000..48c60d36b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf @@ -0,0 +1,42 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# Entries in this file show the compile time defaults. +# You can change settings by editing this file. +# Defaults can be restored by simply deleting this file. +# +# See journald.conf(5) for details. + +[Journal] +Storage=volatile +#Compress=yes +#Seal=yes +#SplitMode=uid +#SyncIntervalSec=5m +#RateLimitIntervalSec=30s +#RateLimitBurst=10000 +#SystemMaxUse=6M +#SystemKeepFree= +#SystemMaxFileSize=512K +#SystemMaxFiles=32 +RuntimeMaxUse=32M +#RuntimeKeepFree= +#RuntimeMaxFileSize= +#RuntimeMaxFiles=4 +#MaxRetentionSec= +#MaxFileSec=1month +#ForwardToSyslog=no +#ForwardToKMsg=no +#ForwardToConsole=no +#ForwardToWall=yes +#TTYPath=/dev/console +#MaxLevelStore=notice +#MaxLevelSyslog=debug +#MaxLevelKMsg=notice +#MaxLevelConsole=info +#MaxLevelWall=emerg +#LineMax=48K diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf new file mode 100644 index 000000000..aa455cbcb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf @@ -0,0 +1,2 @@ +[Service] +ExecStop=touch /var/lib/systemd/timesync/clock
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend new file mode 100644 index 000000000..b3c318e15 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://journald.conf \ + file://systemd-timesyncd-save-time.conf \ + " + +FILES_${PN} += " ${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf" + +do_install_append() { + install -m 644 -D ${WORKDIR}/systemd-timesyncd-save-time.conf ${D}${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf +} diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch new file mode 100644 index 000000000..5b9f17006 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch @@ -0,0 +1,28 @@ +From e02932693f92d6230b5520f431e127f7b6e2183e Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Tue, 6 Mar 2018 16:06:33 -0800 +Subject: [PATCH 1/1] Modfiy system.conf DefaultTimeoutStopSec + +Current time is 5 minutes, change it to 10 seconds. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + src/core/system.conf.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 8112125468..f7a35a56bb 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -39,7 +39,7 @@ + #DefaultStandardOutput=journal + #DefaultStandardError=inherit + #DefaultTimeoutStartSec=90s +-#DefaultTimeoutStopSec=90s ++DefaultTimeoutStopSec=10s + #DefaultTimeoutAbortSec= + #DefaultRestartSec=100ms + #DefaultStartLimitIntervalSec=10s +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service new file mode 100644 index 000000000..f71aea39d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: LGPL-2.1+ +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Wait Until Kernel Time Synchronized +Documentation=man:systemd-time-wait-sync.service(8) + +# Note that this tool doesn't need CAP_SYS_TIME itself, but it's primary +# usecase is to run in conjunction with a local NTP service such as +# systemd-timesyncd.service, which is conditioned this way. There might be +# niche usecases where running this service independently is desired, but let's +# make this all "just work" for the general case, and leave it to local +# modifications to make it work in the remaining cases. + +ConditionCapability=CAP_SYS_TIME +ConditionVirtualization=!container + +DefaultDependencies=no +Before=time-sync.target shutdown.target +Wants=time-sync.target +Conflicts=shutdown.target + +[Service] +Type=oneshot +ExecStart=/lib/systemd/systemd-time-wait-sync +TimeoutStartSec=10 +RemainAfterExit=yes + +[Install] +WantedBy=sysinit.target diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend new file mode 100644 index 000000000..d80714589 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend @@ -0,0 +1,15 @@ +# add some configuration overrides for systemd default /usr/lib/tmpfiles.d/ + +LICENSE = "GPL-2.0" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch \ + file://systemd-time-wait-sync.service \ + " + +USERADD_PACKAGES_remove = "${PN}-journal-gateway ${PN}-journal-upload ${PN}-journal-remote" + +do_install_append(){ + cp -f ${WORKDIR}/systemd-time-wait-sync.service ${D}/lib/systemd/system/ +} diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb new file mode 100644 index 000000000..2a00f6375 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb @@ -0,0 +1,21 @@ +DESCRIPTION = "OpenBMC mtd-util" + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://COPYING;md5=b77c43ae4eaf67bd73fb6452b2f113a3" + +SRC_URI = "git://github.com/Intel-BMC/mtd-util;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "679c6bddaa1fc4fdd473eb84d4e9f97f78ab0f12" + + +S = "${WORKDIR}/git" + +DEPENDS += "dbus openssl zlib boost microsoft-gsl" + +inherit cmake pkgconfig + +# Specify any options you want to pass to cmake using EXTRA_OECMAKE: +EXTRA_OECMAKE = "" + +EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '-DDEVELOPER_OPTIONS=ON', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend b/meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend new file mode 100644 index 000000000..00815c173 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend @@ -0,0 +1,7 @@ +# This commit pulls in the python world, and adds a very large chunk to our +# image size. I suspect we can make most of our things rely on python-core +# instead of full python, but this is a temporary fix. +# https://git.yoctoproject.org/cgit/cgit.cgi/poky/commit/?id=f384e39ad1ca1514fb7b5d7fa0d63e0c863761ca + +RPROVIDES_${PN}-core = "${PN}" +RPROVIDES_${PN}-modules = "" diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb b/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb new file mode 100644 index 000000000..50476715e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb @@ -0,0 +1,18 @@ +SUMMARY = "HelloWorld app with phosphor-logging usage example." +DESCRIPTION = "NOTE: Phosphor-logging has dependencies on systemd and sdbusplus." + +SRC_URI = "git://github.com/Intel-BMC/template-recipe;protocol=ssh" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +# Modify these as desired +PV = "1.0+git${SRCPV}" +SRCREV = "2d5d731254319de8b42d6438b0ce3908dd5b0dec" + +S = "${WORKDIR}/git" + +inherit cmake + +DEPENDS = "systemd sdbusplus phosphor-logging" +RDEPENDS_${PN} = "libsystemd sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend new file mode 100644 index 000000000..55fb00a77 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend @@ -0,0 +1,4 @@ +do_install_append () { +# Remove ipmi_pass from image, if debug-tweaks is not enabled + ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'rm ${D}/${sysconfdir}/ipmi_pass', d)} +} 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..6d0732265 --- /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 = "67c79b0ca6e013c8621dd2cff95e367dbb75bb2a" + diff --git a/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login new file mode 100644 index 000000000..51dd3a83b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login @@ -0,0 +1,90 @@ +# +# The PAM configuration file for the Shadow `login' service +# + +# Enforce a minimal delay in case of failure (in microseconds). +# (Replaces the `FAIL_DELAY' setting from login.defs) +# Note that other modules may require another minimal delay. (for example, +# to disable any delay, you should add the nodelay option to pam_unix) +auth optional pam_faildelay.so delay=3000000 + +# Outputs an issue file prior to each login prompt (Replaces the +# ISSUE_FILE option from login.defs). Uncomment for use +# auth required pam_issue.so issue=/etc/issue + +# Disallows root logins except on tty's listed in /etc/securetty +# (Replaces the `CONSOLE' setting from login.defs) +# Note that it is included as a "requisite" module. No password prompts will +# be displayed if this module fails to avoid having the root password +# transmitted on unsecure ttys. +# You can change it to a "required" module if you think it permits to +# guess valid user names of your system (invalid user names are considered +# as possibly being root). +auth [success=ok ignore=ignore user_unknown=ignore default=die] pam_securetty.so + +# Disallows other than root logins when /etc/nologin exists +# (Replaces the `NOLOGINS_FILE' option from login.defs) +auth requisite pam_nologin.so + +# This module parses environment configuration file(s) +# and also allows you to use an extended config +# file /etc/security/pam_env.conf. +# +# parsing /etc/environment needs "readenv=1" +session required pam_env.so readenv=1 + +# Allow only uid 0 for login prompt authentication +auth required pam_succeed_if.so uid eq 0 + +# Do regular pam unix based authentication. Allow null password. +auth [success=2 default=ignore] pam_unix.so quiet nullok_secure +# here's the fallback if no module succeeds +auth requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +auth required pam_permit.so + +# This allows certain extra groups to be granted to a user +# based on things like time of day, tty, service, and user. +# Please edit /etc/security/group.conf to fit your needs +# (Replaces the `CONSOLE_GROUPS' option in login.defs) +auth optional pam_group.so + +# Uncomment and edit /etc/security/time.conf if you need to set +# time restrainst on logins. +# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs +# as well as /etc/porttime) +# account requisite pam_time.so + +# Uncomment and edit /etc/security/access.conf if you need to +# set access limits. +# (Replaces /etc/login.access file) +# account required pam_access.so + +# Sets up user limits according to /etc/security/limits.conf +# (Replaces the use of /etc/limits in old login) +session required pam_limits.so + +# Prints the last login info upon succesful login +# (Replaces the `LASTLOG_ENAB' option from login.defs) +session optional pam_lastlog.so + +# Prints the motd upon succesful login +# (Replaces the `MOTD_FILE' option in login.defs) +session optional pam_motd.so + +# Prints the status of the user's mailbox upon succesful login +# (Replaces the `MAIL_CHECK_ENAB' option from login.defs). +# +# This also defines the MAIL environment variable +# However, userdel also needs MAIL_DIR and MAIL_FILE variables +# in /etc/login.defs to make sure that removing a user +# also removes the user's mail spool file. +# See comments in /etc/login.defs +session optional pam_mail.so standard + +# Standard Un*x account and session +account include common-account +password include common-password +session include common-session diff --git a/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend new file mode 100644 index 000000000..283d787e5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PAM_SRC_URI += "file://pam.d/login \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend new file mode 100644 index 000000000..7394e3e59 --- /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 = "49880e33ee430d50804f46c307bcadce5b3e3be2" diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch new file mode 100644 index 000000000..43600ac8a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch @@ -0,0 +1,162 @@ +From 0c0b7b5da551c99161bda98820a529ba29cbaac1 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +Date: Wed, 21 Aug 2019 16:52:30 -0700 +Subject: [PATCH] Fix keyboard and mouse input events dropping issue + +Restarting of HID input devices causes input events dropping issue +which is critical for BMC KVM uses. For an example, user can't enter +to BIOS by doing keep pressing 'F2' or 'Del' key because of this issue. + +To fix the issue, this commit removes the input device restarting +logic and refines error log journaling logic using errno checking. + +Tested: + 1. Open BMCweb -> Server control -> KVM. + 2. Make a host reset and keep pressing 'F2' key. + 3. Was able to enter to BIOS using the key press. + +Change-Id: Iec1bfad1d9e5825858844cab658bbfa3e6bc24f6 +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +--- + ikvm_input.cpp | 58 +++++++--------------------------------------------------- + ikvm_input.hpp | 4 ---- + ikvm_video.cpp | 3 +-- + 3 files changed, 8 insertions(+), 57 deletions(-) + +diff --git a/ikvm_input.cpp b/ikvm_input.cpp +index d95e6313f62c..df12f2715585 100644 +--- a/ikvm_input.cpp ++++ b/ikvm_input.cpp +@@ -23,9 +23,9 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::File::Error; + + Input::Input(const std::string& kbdPath, const std::string& ptrPath) : +- pointerError(false), sendKeyboard(false), sendPointer(false), +- keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0}, +- keyboardPath(kbdPath), pointerPath(ptrPath) ++ sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1), ++ keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath), ++ pointerPath(ptrPath) + { + if (!keyboardPath.empty()) + { +@@ -156,36 +156,6 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl) + rfbDefaultPtrAddEvent(buttonMask, x, y, cl); + } + +-void Input::restart() +-{ +- if (!keyboardPath.empty() && keyboardFd < 0) +- { +- keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC); +- if (keyboardFd < 0) +- { +- log<level::ERR>("Failed to open input device", +- entry("PATH=%s", keyboardPath.c_str()), +- entry("ERROR=%s", strerror(errno))); +- } +- +- sendKeyboard = false; +- } +- +- if (!pointerPath.empty() && pointerFd < 0) +- { +- pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK); +- if (pointerFd < 0) +- { +- log<level::ERR>("Failed to open input device", +- entry("PATH=%s", pointerPath.c_str()), +- entry("ERROR=%s", strerror(errno))); +- } +- +- pointerError = false; +- sendPointer = false; +- } +-} +- + void Input::sendWakeupPacket() + { + uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0}; +@@ -459,13 +429,10 @@ bool Input::writeKeyboard(const uint8_t *report) + { + if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH) + { +- log<level::ERR>("Failed to write keyboard report", +- entry("ERROR=%s", strerror(errno))); +- +- if (errno == ESHUTDOWN) ++ if (errno != ESHUTDOWN && errno != EAGAIN) + { +- close(keyboardFd); +- keyboardFd = -1; ++ log<level::ERR>("Failed to write keyboard report", ++ entry("ERROR=%s", strerror(errno))); + } + + return false; +@@ -478,23 +445,12 @@ void Input::writePointer(const uint8_t *report) + { + if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH) + { +- if (!pointerError) ++ if (errno != ESHUTDOWN && errno != EAGAIN) + { + log<level::ERR>("Failed to write pointer report", + entry("ERROR=%s", strerror(errno))); +- pointerError = true; +- } +- +- if (errno == ESHUTDOWN) +- { +- close(pointerFd); +- pointerFd = -1; + } + } +- else +- { +- pointerError = false; +- } + } + + } // namespace ikvm +diff --git a/ikvm_input.hpp b/ikvm_input.hpp +index 953333263e2d..2adc7c106755 100644 +--- a/ikvm_input.hpp ++++ b/ikvm_input.hpp +@@ -48,8 +48,6 @@ class Input + */ + static void pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl); + +- /* @brief Re-opens USB device in case the endpoint shutdown */ +- void restart(); + /* @brief Sends a wakeup data packet to the USB input device */ + void sendWakeupPacket(); + /* @brief Sends an HID report to the USB input device */ +@@ -90,8 +88,6 @@ class Input + bool writeKeyboard(const uint8_t *report); + void writePointer(const uint8_t *report); + +- /* @brief Indicates whether or not a pointer report error has occurred */ +- bool pointerError; + /* @brief Indicates whether or not to send a keyboard report */ + bool sendKeyboard; + /* @brief Indicates whether or not to send a pointer report */ +diff --git a/ikvm_video.cpp b/ikvm_video.cpp +index 6a5aa6c10927..7bd4b4eb6c98 100644 +--- a/ikvm_video.cpp ++++ b/ikvm_video.cpp +@@ -163,10 +163,9 @@ bool Video::needsResize() + restart(); + return false; + } +- else if (timingsError) ++ else + { + timingsError = false; +- input.restart(); + } + + if (timings.bt.width != width || timings.bt.height != height) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend new file mode 100644 index 000000000..8de421d18 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +#SRC_URI = "git://github.com/openbmc/obmc-ikvm" +SRCREV = "861337e8ec92767c4c88237ec5db494a2a67fa8d" + +SRC_URI += " \ + file://0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb new file mode 100644 index 000000000..b6fa1c9ea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb @@ -0,0 +1,21 @@ +SUMMARY = "HSBP Manager" +DESCRIPTION = "HSBP Manager monitors HSBPs through SMBUS" + +SRC_URI = "git://github.com/openbmc/s2600wf-misc.git" +SRCREV = "da0c35fce8b53c1fba05b253c2e24effbbd97197" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +SYSTEMD_SERVICE_${PN} = "hsbp-manager.service" + +DEPENDS = "boost \ + i2c-tools \ + sdbusplus" + +S = "${WORKDIR}/git/hsbp-manager" +inherit cmake systemd + +EXTRA_OECMAKE = "-DYOCTO=1" + diff --git a/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb new file mode 100644 index 000000000..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..c2c18247d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py @@ -0,0 +1,376 @@ +#!/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 = 32 # 32 bytes of PFM header +PFM_SPI_SIZE_DEF = 16 # 16 bytes of SPI PFM +PFM_SPI_SIZE_HASH = 32 # 32 bytes of SPI region HASH +PFM_I2C_SIZE = 40 # 40 bytes of i2c rules region in PFM + +PAGE_SIZE = 0x1000 # 4KB size of page + +def load_manifest(fname): + manifest = {} + with open(fname, 'r') as fd: + manifest = json.load(fd) + return manifest + +class pfm_spi(object): + + def __init__(self, prot_mask, start_addr, end_addr, hash, hash_pres): + self.spi_pfm = PFM_SPI + self.spi_prot_mask = prot_mask + self.spi_hash_pres = hash_pres + if hash_pres == 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'])) + + 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'])) + + # 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 = bytearray(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: + self.add_i2c_rules(i) + + def hash_and_map(self): + + # have copy of the update file for appending with PFR meta and compression + copyfile(self.firmware_file, self.pfr_rom_file) + with open("bmc_compressed.bin", "wb+") as upd: + for p in self.image_parts: + #filename, index, offset, size, protection. + print(p[0], p[1], p[2], p[3], p[4]) + self.hash_compress_regions(p, upd) + + def pbc_hdr(self): + ''' + typedef struct { + uint8_t tag[4]; /* PBC tag */ + uint32_t version; /* PBC Version- 0x0000_0002 */ + uint32_t page_size; /* NOR Flash page size = 0x0000_1000 */ + uint32_t pattern_size; /* 0xFF as pattern 1byte = 0x0000_0001 */ + uint32_t pattern; /* 0xFF pattern = 0x0000_00FF */ + uint32_t bitmap_size; /* 32768 pages for 128MB- 0x0000_8000 */ + uint32_t payload_length /* payload */ + uint8_t reserved[100]; /* Reserved 100bytes */ + uint8_t erase_bitmap[4096]; /* erase bit map for 32768 pages */ + uint8_t comp_bitmap[4096]; /* compression bit map for 32768 pages */ + uint8_t comp_payload; /* compressed payload */ + ''' + names = [ + 'tag', 'pbc_ver', 'page_sz', 'pattern_sz', 'pattern', 'bitmap_sz', + 'payload_size', 'resvd0', 'erase_bitmap', 'comp_bitmap', + ] + parts = { + 'tag': b'CBP_', + 'pbc_ver': struct.pack('<i',0x00000002), + 'page_sz': struct.pack('<i',0x00001000), + 'pattern_sz': struct.pack('<i',0x00000001), + 'pattern': struct.pack('<i',0x000000FF), + 'bitmap_sz': struct.pack('<i',0x00008000), + 'payload_size': struct.pack('<i',self.pbc_comp_payload), + 'resvd0' : b'\x00'*100, + 'erase_bitmap': bytes(self.pbc_erase_bitmap), + 'comp_bitmap': bytes(self.pbc_comp_bitmap), + } + + with open("pbc.bin", "wb+") as pbf: + pbf.write(b''.join([parts[n] for n in names])) + pbf.seek(0) # rewind to beginning of PBC file + self.act_dgst.update(pbf.read()) # add up PBC data for hashing + + def build_pfm(self): + ''' + typedef struct { + uint32_t tag; /* PFM_HDR_TAG above, no terminating null */ + uint8_t SVN; /* SVN- security revision of associated image data */ + uint8_t bkc; /* bkc */ + uint8_t pfm_ver_major; /* PFM revision */ + uint8_t pfm_ver_minor; + uint8_t reserved0[4]; + uint8_t build_num; + uint8_t build_hash[3]; + uint8_t reserved1[12]; /* reserved */ + uint32_t pfm_length; /* PFM size in bytes */ + pfm_spi pfm_spi[2]; /* PFM SPI regions - u-boot & fit-image */ + pfm_smbus pfm_smbus[4]; /* defined smbus rules for PSUs and HSBP */ + } __attribute__((packed)) pfm_hdr; + ''' + names = [ + 'tag', 'sec_rev', 'bkc', 'pfm_ver_major', 'pfm_ver_minor', 'resvd0', 'build_num', 'build_hash1', 'build_hash2', 'build_hash3', 'resvd1', 'pfm_len', + ] + parts = { + 'tag': struct.pack("<I", 0x02b3ce1d), + 'sec_rev': struct.pack('<B', self.sec_rev), + 'bkc': struct.pack('<B', 0x01), + 'pfm_ver_major': struct.pack('<B', ((int(self.build_version) >> 8) & 0xff)), + 'pfm_ver_minor': struct.pack('<B', (int(self.build_version) & 0x00ff)), + 'resvd0': b'\xff'* 4, + 'build_num': struct.pack('<B', int(self.build_number,16)), + 'build_hash1': struct.pack('<B', (int(self.build_hash) & 0xff)), + 'build_hash2': struct.pack('<B', ((int(self.build_hash) >> 8) & 0xff)), + 'build_hash3': struct.pack('<B', ((int(self.build_hash) >> 16) & 0xff)), + 'resvd1': b'\xff'* 12, + 'pfm_len': '' + } + + # PFM should be 128bytes aligned, find the padding bytes + padding_bytes = 0 + if (self.pfm_bytes % 128) != 0: + padding_bytes = 128 - (self.pfm_bytes % 128) + + print("padding={}".format(padding_bytes)) + print("PFM size1={}".format(self.pfm_bytes)) + self.pfm_bytes += padding_bytes + parts['pfm_len'] = struct.pack('<I', self.pfm_bytes) + print("PFM size2={}".format(self.pfm_bytes)) + + with open("pfm.bin", "wb+") as f: + f.write(b''.join([parts[n] for n in names])) + for i in self.pfm_spi_regions: + f.write(struct.pack('<B', int(i.spi_pfm))) + f.write(struct.pack('<B', int(i.spi_prot_mask))) + f.write(struct.pack('<h', int(i.spi_hash_pres))) + f.write(struct.pack('<I', int(i.spi_pfm_rsvd))) + f.write(struct.pack('<I', int(i.spi_start_addr))) + f.write(struct.pack('<I', int(i.spi_end_addr))) + + if i.spi_hash_pres == 1: + f.write(bytearray.fromhex(i.spi_hash)) + + for r in self.pfm_i2c_rules: + f.write(struct.pack('<B', int(r.i2c_pfm))) + f.write(struct.pack('<I', int(r.i2c_pfm_rsvd))) + f.write(struct.pack('<B', int(r.i2c_bus_id))) + f.write(struct.pack('<B', int(r.i2c_rule_id))) + f.write(struct.pack('<B', int(r.i2c_address, 16))) + f.write(r.i2c_cmd_whitelist) + + # write the padding bytes at the end + f.write(b'\xff' * padding_bytes) + +def main(): + if len(sys.argv) != 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..b567faa02 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_manifest.json @@ -0,0 +1,130 @@ +{ + "image-parts": [{ + "name": "u-boot", + "index": 0, + "offset": "0", + "size": "0x80000", + "prot_mask": 29, + "pfm": 1, + "hash": 1, + "compress": 1 + }, + { + "name": "pfm", + "index": 1, + "offset": "0x80000", + "size": "0x20000", + "prot_mask": 0, + "pfm": 1, + "hash": 0, + "compress": 0 + }, + { + "name": "u-boot-env", + "index": 2, + "offset": "0xa0000", + "size": "0x20000", + "prot_mask": 31, + "pfm": 1, + "hash": 0, + "compress": 1 + }, + { + "name": "sofs", + "index": 3, + "offset": "0xc0000", + "size": "0x200000", + "prot_mask": 31, + "pfm": 1, + "hash": 0, + "compress": 1 + }, + { + "name": "rwfs", + "index": 4, + "offset": "0x2c0000", + "size": "0x840000", + "prot_mask": 31, + "pfm": 1, + "hash": 0, + "compress": 1 + }, + { + "name": "fit-image-a", + "index": 5, + "offset": "0xb00000", + "size": "0x1f00000", + "prot_mask": 29, + "pfm": 1, + "hash": 1, + "compress": 1 + }, + { + "name": "rc-image", + "index": 6, + "offset": "0x2a00000", + "size": "0x2000000", + "prot_mask": 0, + "pfm": 1, + "hash": 0, + "compress": 0 + }, + { + "name": "image-stg", + "index": 7, + "offset": "0x4a00000", + "size": "0x3500000", + "prot_mask": 3, + "pfm": 1, + "hash": 0, + "compress": 0 + }, + { + "name": "cpld-rc", + "index": 8, + "offset": "0x7f00000", + "size": "0x100000", + "prot_mask": 0, + "pfm": 1, + "hash": 0, + "compress": 0 + } + ], + "i2c-rules": [{ + "bus-id": 3, + "rule-id": 3, + "address": "0xD0", + "cmd-whitelist": ["0x00", "0x01", "0x02", "0x03", "0x04", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F", + "0x10", "0x13", "0x17", "0x1B", "0x1C", "0x1D", "0x02", "0x021", "0x22", "0x23", "0x25", "0x30", + "0x31", "0x32", "0x33", "0x035", "0x36", "0x37", "0x38", "0x39", "0x3A", "0x3B", "0x3C", "0x3D"] + }, + { + "bus-id": 3, + "rule-id": 4, + "address": "0xD8", + "cmd-whitelist": ["0x00", "0x01", "0x02", "0x03", "0x04", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F", + "0x10", "0x13", "0x17", "0x1B", "0x1C", "0x1D", "0x02", "0x021", "0x22", "0x23", "0x25", "0x30", + "0x31", "0x32", "0x33", "0x035", "0x36", "0x37", "0x38", "0x39", "0x3A", "0x3B", "0x3C", "0x3D"] + }, + { + "bus-id": 1, + "rule-id": 6, + "address": "0xB0", + "cmd-whitelist": ["0x00", "0x03", "0x05", "0x06", "0x19", "0x1A", "0x30", "0x3A", "0x3B", "0x3C", "0x3D", "0x3E", "0x3F", + "0x79", "0x7A", "0x7B", "0x7C", "0x7D", "0x7E", "0x7F", "0x81", "0x82", "0x86", "0x87", "0x88", + "0x89", "0x8C", "0x8D", "0x8E", "0x8F", "0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96", + "0x97", "0x98", "0x9A", "0xA6", "0xA7", "0xD0", "0xD3", "0xD4", "0xD5", "0xD6", "0xD7", "0xD8", + "0xD9", "0xDC", "0xDD", "0xDE", "0xDE"] + }, + { + "bus-id": 1, + "rule-id": 4, + "address": "0xB2", + "cmd-whitelist": ["0x00", "0x03", "0x05", "0x06", "0x19", "0x1A", "0x30", "0x3A", "0x3B", "0x3C", "0x3D", "0x3E", "0x3F", + "0x79", "0x7A", "0x7B", "0x7C", "0x7D", "0x7E", "0x7F", "0x81", "0x82", "0x86", "0x87", "0x88", + "0x89", "0x8C", "0x8D", "0x8E", "0x8F", "0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96", + "0x97", "0x98", "0x9A", "0xA6", "0xA7", "0xD0", "0xD3", "0xD4", "0xD5", "0xD6", "0xD7", "0xD8", + "0xD9", "0xDC", "0xDD", "0xDE", "0xDE"] + } + ] +} 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..9965ab11c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb @@ -0,0 +1,20 @@ +SUMMARY = "Intel Blocksign tool for PFR image" +DESCRIPTION = "Image signing tool for BMC PFR image" + +inherit native cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +DEPENDS = "openssl-native libxml2-native " + +SRC_URI = "git://github.com/Intel-BMC/blocksign;protocol=ssh" + +SRCREV = "60d76db038a0d85851098b13451246abb0d876ed" + +S = "${WORKDIR}/git/" + +do_install_append() { + install -d ${D}/${bindir} + install -m 775 ${B}/blocksign ${D}/${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb new file mode 100644 index 000000000..d48ffb1a5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb @@ -0,0 +1,22 @@ +SUMMARY = "Intel PFR Manager Service" +DESCRIPTION = "Daemon to handle all PFR functionalities" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/intel-pfr-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.PFR.Manager.service" + +DEPENDS += " \ + sdbusplus \ + phosphor-logging \ + boost \ + i2c-tools \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb new file mode 100644 index 000000000..910e61142 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb @@ -0,0 +1,36 @@ +SUMMARY = "Intel PFR image manifest and image signing keys" +DESCRIPTION = "This copies PFR image generation scripts and image signing keys to staging area" + +PR = "r1" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +inherit native + +DEPENDS += " intel-blocksign-native" + +SRC_URI = " \ + file://pfr_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 intel pfr image generation scripts and image signing keys" + + install -d ${D}/${bindir} + install -d ${D}/${datadir}/pfrconfig + install -m 775 ${WORKDIR}/pfr_image.py ${D}${bindir} + install -m 400 ${WORKDIR}/pfr_manifest.json ${D}/${datadir}/pfrconfig + install -m 400 ${WORKDIR}/pfm_config.xml ${D}/${datadir}/pfrconfig + install -m 400 ${WORKDIR}/bmc_config.xml ${D}/${datadir}/pfrconfig + install -m 400 ${WORKDIR}/csk_prv.pem ${D}/${datadir}/pfrconfig + install -m 400 ${WORKDIR}/csk_pub.pem ${D}/${datadir}/pfrconfig + install -m 400 ${WORKDIR}/rk_pub.pem ${D}/${datadir}/pfrconfig + install -m 400 ${WORKDIR}/rk_prv.pem ${D}/${datadir}/pfrconfig +} diff --git a/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb new file mode 100644 index 000000000..4d91ac673 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb @@ -0,0 +1,38 @@ +SUMMARY = "OpenBMC for Intel - Applications" +PR = "r1" + +inherit packagegroup + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES = "${PACKAGES}" +PACKAGES = " \ + ${PN}-chassis \ + ${PN}-fans \ + ${PN}-flash \ + ${PN}-system \ + " + +PROVIDES += "virtual/obmc-chassis-mgmt" +PROVIDES += "virtual/obmc-fan-mgmt" +PROVIDES += "virtual/obmc-flash-mgmt" +PROVIDES += "virtual/obmc-system-mgmt" + +RPROVIDES_${PN}-chassis += "virtual-obmc-chassis-mgmt" +RPROVIDES_${PN}-fans += "virtual-obmc-fan-mgmt" +RPROVIDES_${PN}-flash += "virtual-obmc-flash-mgmt" +RPROVIDES_${PN}-system += "virtual-obmc-system-mgmt" + +SUMMARY_${PN}-chassis = "Intel Chassis" +RDEPENDS_${PN}-chassis = " \ + x86-power-control \ + " + +SUMMARY_${PN}-fans = "Intel Fans" +RDEPENDS_${PN}-fans = " \ + phosphor-pid-control \ + " + +SUMMARY_${PN}-flash = "Intel Flash" +RDEPENDS_${PN}-flash = "" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend new file mode 100644 index 000000000..c3443107d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend @@ -0,0 +1,2 @@ +RDEPENDS_${PN}-extrasdevtools = "libgpiod-tools" +RDEPENDS_${PN}-chassis-state-mgmt_remove = "obmc-phosphor-power" diff --git a/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb b/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb new file mode 100644 index 000000000..daeced419 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb @@ -0,0 +1,26 @@ +SUMMARY = "Power supply manager for Intel based platform" +DESCRIPTION = "Power supply manager which include PSU Cold Redundancy service" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +S = "${WORKDIR}/git/psu-manager/" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake +inherit systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.coldredundancy.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + boost \ + i2c-tools \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb new file mode 100644 index 000000000..97866ba4e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb @@ -0,0 +1,33 @@ +SUMMARY = "SMBIOS MDR version 1 service for Intel based platform" +DESCRIPTION = "SMBIOS MDR version 1 service for Intel based platfrom" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh;nobranch=1" +SRCREV = "6aab8bcc8fd0550753c87265036b1b7c4c8a9f71" + +S = "${WORKDIR}/git/services/smbios/" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +inherit cmake pkgconfig pythonnative +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "smbios-mdrv1.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service new file mode 100644 index 000000000..edfd3bf70 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service @@ -0,0 +1,13 @@ +[Unit] +Description=Intel BMC SMBIOS MDR V1 + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStartPre=/bin/mkdir -p /etc/smbios +ExecStart=/usr/bin/env smbiosapp +SyslogIdentifier=smbiosapp + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb new file mode 100644 index 000000000..306ef13f5 --- /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://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +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-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch new file mode 100644 index 000000000..31061624c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch @@ -0,0 +1,492 @@ +From da2fecd5d5b3f69bcc4d07fd1265415bd350e5a6 Mon Sep 17 00:00:00 2001 +From: Yuan Li <yuan.li@linux.intel.com> +Date: Tue, 19 Sep 2017 15:55:39 +0800 +Subject: [PATCH] arm: dts: add DTS for Intel ast2500 platforms + +Add the DTS file for Intel ast2500-based systems. + +Signed-off-by: Yuan Li <yuan.li@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +Signed-off-by: Zhu, Yunge <yunge.zhu@linux.intel.com> +Signed-off-by: Qiang XU <qiang.xu@linux.intel.com> +Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com> +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 460 +++++++++++++++++++++++++ + 1 file changed, 460 insertions(+) + create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +new file mode 100644 +index 0000000..1fe6240 +--- /dev/null ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +@@ -0,0 +1,460 @@ ++/dts-v1/; ++ ++#include "aspeed-g5.dtsi" ++#include <dt-bindings/gpio/aspeed-gpio.h> ++#include <dt-bindings/i2c/i2c.h> ++ ++/ { ++ model = "Intel AST2500 BMC"; ++ compatible = "intel,ast2500-bmc", "aspeed,ast2500"; ++ ++ aliases { ++ serial4 = &uart5; ++ }; ++ ++ chosen { ++ stdout-path = &uart5; ++ bootargs = "console=ttyS4,115200 earlyprintk"; ++ }; ++ ++ memory@80000000 { ++ reg = <0x80000000 0x20000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ vga_memory: framebuffer@7f000000 { ++ no-map; ++ reg = <0x7f000000 0x01000000>; ++ }; ++ ++ gfx_memory: framebuffer { ++ size = <0x01000000>; ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ video_engine_memory: jpegbuffer { ++ size = <0x02000000>; /* 32M */ ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ ramoops@9eff0000{ ++ compatible = "ramoops"; ++ reg = <0x9eff0000 0x10000>; ++ record-size = <0x2000>; ++ console-size = <0x2000>; ++ }; ++ }; ++ ++ vga-shared-memory { ++ compatible = "aspeed,ast2500-vga-sharedmem"; ++ reg = <0x9ff00000 0x100000>; ++ }; ++ ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, ++ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, ++ <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>, ++ <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ identify { ++ default-state = "on"; ++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_amber { ++ default-state = "off"; ++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_green { ++ default-state = "keep"; ++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ beeper { ++ compatible = "pwm-beeper"; ++ pwms = <&timer 6 1000000 0>; ++ }; ++}; ++ ++&fmc { ++ status = "okay"; ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++#include "openbmc-flash-layout-intel-64MB.dtsi" ++ }; ++}; ++ ++&espi { ++ status = "okay"; ++}; ++ ++&jtag { ++ status = "okay"; ++}; ++ ++&peci0 { ++ status = "okay"; ++ gpios = <&gpio ASPEED_GPIO(F, 6) 0>; ++}; ++ ++&syscon { ++ uart-clock-high-speed; ++ status = "okay"; ++ ++ misc_control { ++ compatible = "aspeed,bmc-misc"; ++ uart_port_debug { ++ offset = <0x2c>; ++ bit-mask = <0x1>; ++ bit-shift = <10>; ++ read-only; ++ }; ++ p2a-bridge { ++ offset = <0x180>; ++ bit-mask = <0x1>; ++ bit-shift = <1>; ++ read-only; ++ }; ++ boot-2nd-flash { ++ offset = <0x70>; ++ bit-mask = <0x1>; ++ bit-shift = <17>; ++ read-only; ++ }; ++ }; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&gpio { ++ status = "okay"; ++ gpio-line-names = ++ /*A0-A7*/ "","","","","","","","", ++ /*B0-B7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","","","", ++ /*C0-C7*/ "","","","","","","","", ++ /*D0-D7*/ "","","","","","","","", ++ /*E0-E7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","","DEBUG_EN_N","","", ++ /*F0-F7*/ "NMI_OUT","","","","CPU_ERR0","CPU_ERR1","PLTRST_N","PRDY_N", ++ /*G0-G7*/ "CPU_ERR2","CPU_CATERR","PCH_BMC_THERMTRIP","LCP_ENTER_BUTTON","LCP_LEFT_BUTTON","FM_BMC_BOARD_SKU_ID5_N","","", ++ /*H0-H7*/ "","","","FM_NODE_ID_1","FM_NODE_ID_2","FM_NODE_ID_3","FM_NODE_ID_4","FM_240VA_STATUS", ++ /*I0-I7*/ "FM_SYS_FAN0_PRSNT_D_N","FM_SYS_FAN1_PRSNT_D_N","FM_SYS_FAN2_PRSNT_D_N","FM_SYS_FAN3_PRSNT_D_N","FM_SYS_FAN4_PRSNT_D_N","FM_SYS_FAN5_PRSNT_D_N","","", ++ /*J0-J7*/ "","","","","","","","", ++ /*K0-K7*/ "","","","","","","","", ++ /*L0-L7*/ "","","","","","","","", ++ /*M0-M7*/ "","","","","","","","", ++ /*N0-N7*/ "","","","","","","","", ++ /*O0-O7*/ "","","","","","","","", ++ /*P0-P7*/ "","","","","","","","", ++ /*Q0-Q7*/ "","","","","","","","PWR_DEBUG_N", ++ /*R0-R7*/ "","XDP_PRST_N","","","","","","CHASSIS_INTRUSION", ++ /*S0-S7*/ "REMOTE_DEBUG_ENABLE","SYSPWROK","RSMRST_N","","","","","", ++ /*T0-T7*/ "","","","","","","","", ++ /*U0-U7*/ "","","","","","","","", ++ /*V0-V7*/ "","","","","","","","", ++ /*W0-W7*/ "","","","","","","","", ++ /*X0-X7*/ "","","","","","","","", ++ /*Y0-Y7*/ "SIO_S3","SIO_S5","","SIO_ONCONTROL","","","","", ++ /*Z0-Z7*/ "","SIO_POWER_GOOD","","","","","","", ++ /*AA0-AA7*/ "P3VBAT_BRIDGE_EN","","","","PREQ_N","TCK_MUX_SEL","SMI","POST_COMPLETE", ++ /*AB0-AB7*/ "","NMI_BUTTON","ID_BUTTON","PS_PWROK","","","","", ++ /*AC0-AC7*/ "","","","","","","",""; ++}; ++ ++&sgpio { ++ status = "okay"; ++ gpio-line-names = ++ /* SGPIO output lines */ ++ /*OA0-OA7*/ "","","","","","","","", ++ /*OB0-OB7*/ "LED_CPU1_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU1_CH2_DIMM1_FAULT","LED_CPU1_CH2_DIMM2_FAULT","LED_CPU1_CH3_DIMM1_FAULT","LED_CPU1_CH3_DIMM2_FAULT","LED_CPU1_CH4_DIMM1_FAULT","LED_CPU1_CH4_DIMM2_FAULT", ++ /*OC0-OC7*/ "LED_CPU1_CH5_DIMM1_FAULT","LED_CPU1_CH5_DIMM2_FAULT","LED_CPU1_CH6_DIMM1_FAULT","LED_CPU1_CH6_DIMM2_FAULT","LED_FAN1_FAULT","LED_FAN2_FAULT","LED_FAN3_FAULT","LED_FAN4_FAULT", ++ /*OD0-OD7*/ "LED_FAN5_FAULT","LED_FAN6_FAULT","LED_FAN7_FAULT","LED_FAN8_FAULT","LED_CPU2_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU2_CH2_DIMM1_FAULT","LED_CPU2_CH2_DIMM2_FAULT", ++ /*OE0-OE7*/ "LED_CPU2_CH3_DIMM1_FAULT","LED_CPU2_CH3_DIMM2_FAULT","LED_CPU2_CH4_DIMM1_FAULT","LED_CPU2_CH4_DIMM2_FAULT","LED_CPU2_CH5_DIMM1_FAULT","LED_CPU2_CH5_DIMM2_FAULT","LED_CPU2_CH6_DIMM1_FAULT","LED_CPU2_CH6_DIMM2_FAULT", ++ /*OF0-OF7*/ "LED_CPU3_CH1_DIMM1_FAULT","LED_CPU3_CH1_DIMM2_FAULT","LED_CPU3_CH2_DIMM1_FAULT","LED_CPU3_CH2_DIMM2_FAULT","LED_CPU3_CH3_DIMM1_FAULT","LED_CPU3_CH3_DIMM2_FAULT","LED_CPU3_CH4_DIMM1_FAULT","LED_CPU3_CH4_DIMM2_FAULT", ++ /*OG0-OG7*/ "LED_CPU3_CH5_DIMM1_FAULT","LED_CPU3_CH5_DIMM2_FAULT","LED_CPU3_CH6_DIMM1_FAULT","LED_CPU3_CH6_DIMM2_FAULT","LED_CPU4_CH1_DIMM1_FAULT","LED_CPU4_CH1_DIMM2_FAULT","LED_CPU4_CH2_DIMM1_FAULT","LED_CPU4_CH2_DIMM2_FAULT", ++ /*OH0-OH7*/ "LED_CPU4_CH3_DIMM1_FAULT","LED_CPU4_CH3_DIMM2_FAULT","LED_CPU4_CH4_DIMM1_FAULT","LED_CPU4_CH4_DIMM2_FAULT","LED_CPU4_CH5_DIMM1_FAULT","LED_CPU4_CH5_DIMM2_FAULT","LED_CPU4_CH6_DIMM1_FAULT","LED_CPU4_CH6_DIMM2_FAULT", ++ /*OI0-OI7*/ "","","","","","","","", ++ /*OJ0-OJ7*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ ++ /* SGPIO input lines */ ++ /*IA0-IA7*/ "CPU1_PRESENCE","CPU1_THERMTRIP","CPU1_VRHOT","CPU1_FIVR_FAULT","CPU1_MEM_ABCD_VRHOT","CPU1_MEM_EFGH_VRHOT","","", ++ /*IB0-IB7*/ "CPU1_MISMATCH","CPU1_MEM_THERM_EVENT","CPU2_PRESENCE","CPU2_THERMTRIP","CPU2_VRHOT","CPU2_FIVR_FAULT","CPU2_MEM_ABCD_VRHOT","CPU2_MEM_EFGH_VRHOT", ++ /*IC0-IC7*/ "","","CPU2_MISMATCH","CPU2_MEM_THERM_EVENT","","","","", ++ /*ID0-ID7*/ "","","","","","","","", ++ /*IE0-IE7*/ "","","","","","","","", ++ /*IF0-IF7*/ "","","","","","","","", ++ /*IG0-IG7*/ "","","","","","","","", ++ /*IH0-IH7*/ "","","","","","","","", ++ /*II0-II7*/ "","","","","","","","", ++ /*IJ0-IJ7*/ "","","","","","","",""; ++}; ++ ++&kcs3 { ++ kcs_addr = <0xCA2>; ++ status = "okay"; ++}; ++ ++&kcs4 { ++ kcs_addr = <0xCA4>; ++ status = "okay"; ++}; ++ ++&lpc_sio { ++ status = "okay"; ++}; ++ ++&lpc_snoop { ++ snoop-ports = <0x80>; ++ status = "okay"; ++}; ++ ++&mbox { ++ status = "okay"; ++}; ++ ++&uart_routing { ++ status = "okay"; ++}; ++ ++/** ++ * SAFS through SPI1 is available only on Wilson Point. ++ * These pins are used as fan presence checking gpios in WFP ++ * so commenting it out for now. ++ * &spi1 { ++ * status = "okay"; ++ * ++ * flash@0 { ++ * m25p,fast-read; ++ * status = "okay"; ++ * }; ++ *}; ++ */ ++ ++&uart1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_txd1_default ++ &pinctrl_rxd1_default ++ &pinctrl_nrts1_default ++ &pinctrl_ndtr1_default ++ &pinctrl_ndsr1_default ++ &pinctrl_ncts1_default ++ &pinctrl_ndcd1_default ++ &pinctrl_nri1_default>; ++}; ++ ++&uart2 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_txd2_default ++ &pinctrl_rxd2_default ++ &pinctrl_nrts2_default ++ &pinctrl_ndtr2_default ++ &pinctrl_ndsr2_default ++ &pinctrl_ncts2_default ++ &pinctrl_ndcd2_default ++ &pinctrl_nri2_default>; ++}; ++ ++&uart3 { ++ status = "okay"; ++}; ++ ++&uart4 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <>; ++}; ++ ++&uart5 { ++ status = "okay"; ++}; ++ ++&mac1 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; ++}; ++ ++&mac0 { ++ status = "okay"; ++ use-ncsi; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rmii1_default>; ++}; ++ ++&i2c0 { ++ multi-master; ++ general-call; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c3 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c4 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c5 { ++ bus-frequency = <1000000>; ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c6 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c7 { ++ multi-master; ++ #retries = <3>; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c9 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c11 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c13 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&gfx { ++ status = "okay"; ++ memory-region = <&gfx_memory>; ++}; ++ ++&vuart { ++ status = "okay"; ++}; ++ ++&pwm_tacho { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default ++ &pinctrl_pwm2_default &pinctrl_pwm3_default ++ &pinctrl_pwm4_default &pinctrl_pwm5_default ++ &pinctrl_pwm6_default &pinctrl_pwm7_default>; ++ ++ fan@0 { ++ reg = <0x00>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x00 0x01>; ++ }; ++ fan@1 { ++ reg = <0x01>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x02 0x03>; ++ }; ++ fan@2 { ++ reg = <0x02>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x04 0x05>; ++ }; ++ fan@3 { ++ reg = <0x03>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x06 0x07>; ++ }; ++ fan@4 { ++ reg = <0x04>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x08 0x09>; ++ }; ++ fan@5 { ++ reg = <0x05>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0A 0x0B>; ++ }; ++ fan@6 { ++ reg = <0x06>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0C 0x0D>; ++ }; ++ fan@7 { ++ reg = <0x07>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0E 0x0F>; ++ }; ++ ++}; ++ ++&timer { ++/* ++ * Available settings: ++ * fttmr010,pwm-outputs = <5>, <6>, <7>, <8>; ++ * pinctrl-0 = <&pinctrl_timer5_default &pinctrl_timer6_default ++ * &pinctrl_timer7_default &pinctrl_timer8_default>; ++ */ ++ fttmr010,pwm-outputs = <6>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_timer6_default>; ++ #pwm-cells = <3>; ++ status = "okay"; ++}; ++ ++&video { ++ status = "okay"; ++ memory-region = <&video_engine_memory>; ++}; ++ ++&vhub { ++ status = "okay"; ++}; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch new file mode 100644 index 000000000..dcc4b887e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch @@ -0,0 +1,530 @@ +From a25d8478847866e823aed2ecd1e360d5685410bf Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Tue, 19 Sep 2017 15:55:39 +0800 +Subject: [PATCH] arm: dts: add DTS for Intel ast2600 platforms + +Add the DTS file for Intel ast2600-based systems. + +Change-Id: Ib0b5358570a967c255a370bf2503cc2f448039bb +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com> +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +Signed-off-by: arun-pm <arun.p.m@linux.intel.com> +Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com> +--- + .../arm/boot/dts/aspeed-bmc-intel-ast2600.dts | 502 ++++++++++++++++++ + 1 file changed, 502 insertions(+) + create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts +new file mode 100644 +index 000000000000..d32b0390cd87 +--- /dev/null ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts +@@ -0,0 +1,502 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/dts-v1/; ++ ++#include "aspeed-g6.dtsi" ++#include <dt-bindings/gpio/aspeed-gpio.h> ++#include <dt-bindings/i2c/i2c.h> ++ ++/ { ++ model = "AST2600 EVB"; ++ compatible = "aspeed,ast2600"; ++ ++ chosen { ++ stdout-path = &uart5; ++ bootargs = "console=tty0 console=ttyS4,115200n8 root=/dev/ram rw init=/linuxrc"; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ gfx_memory: framebuffer { ++ size = <0x01000000>; ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ video_engine_memory: jpegbuffer { ++ size = <0x02000000>; /* 32M */ ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ video_memory: video { ++ size = <0x04000000>; ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ no-map; ++ }; ++ }; ++ ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>, ++ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>, ++ <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>, ++ <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ identify { ++ default-state = "off"; ++ gpios = <&gpio1 ASPEED_GPIO(B, 7) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_amber { ++ default-state = "off"; ++ gpios = <&gpio1 ASPEED_GPIO(G, 3) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_green { ++ default-state = "keep"; ++ gpios = <&gpio1 ASPEED_GPIO(G, 2) GPIO_ACTIVE_LOW>; ++ }; ++ }; ++/* ++ beeper { ++ compatible = "pwm-beeper"; ++ pwms = <&timer 7 1000000 0>; ++ }; */ ++}; ++ ++&fmc { ++ status = "okay"; ++ flash: m25p80@0 { ++ compatible = "m25p80", "jedec,spi-nor"; ++ reg = <0x0>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <40000000>; ++ spi-tx-bus-width = <4>; ++ m25p,fast-read; ++#include "openbmc-flash-layout-intel-64MB.dtsi" ++ }; ++}; ++ ++&espi { ++ status = "okay"; ++}; ++ ++&peci0 { ++ status = "okay"; ++ gpios = <&gpio0 ASPEED_GPIO(F, 6) 0>; ++}; ++ ++&syscon { ++ uart-clock-high-speed; ++ status = "okay"; ++}; ++ ++#if 0 ++ GPIO Alias: (runtime alias -> schematic name) ++ ID_BUTTON -> FP_ID_BTN_N ++ CPU_CATERR -> FM_PLT_BMC_THERMTRIP_N ++ PCH_BMC_THERMTRIP -> FM_PLT_BMC_THERMTRIP_N ++ RESET_BUTTON -> FP_BMC_RST_BTN_N ++ RESET_OUT -> RST_BMC_RSTBTN_OUT_R_N ++ POWER_BUTTON -> FP_BMC_PWR_BTN_R_N ++ POWER_OUT -> FM_BMC_PWR_BTN_N ++ PREQ_N -> DBP_ASD_BMC_PREQ_R_N ++ POST_COMPLETE -> FM_BIOS_POST_CMPLT_BMC_N ++ CPU_ERR0 -> FM_CPU_ERR0_LVT3_N ++ CPU_ERR1 -> FM_CPU_ERR1_LVT3_N ++ CPU_ERR2 -> FM_CPU_ERR2_LVT3_N ++ DEBUG_EN_N -> FM_JTAG_TCK_MUX_SEL_R ++ NMI_OUT -> IRQ_BMC_CPU_NMI_R ++ PLTRST_N -> RST_PLTRST_BMC_N ++ PRDY_N -> DBP_ASD_BMC_PRDY_R_N ++ PWR_DEBUG_N -> ++ XDP_PRST_N -> ++ SYSPWROK -> ++ RSMRST_N -> ++ SIO_S3 -> FM_SLPS3_R_N ++ SIO_S5 -> FM_SLPS4_R_N ++ SIO_ONCONTROL -> FM_BMC_ONCTL_R_N ++ SIO_POWER_GOOD -> PWRGD_CPU0_LVC3_R ++ PS_PWROK -> PWRGD_BMC_PS_PWROK_R ++ P3VBAT_BRIDGE_EN -> ++ TCK_MUX_SEL -> ++ SMI -> IRQ_SMI_ACTIVE_BMC_N ++ NMI_BUTTON -> FP_NMI_BTN_N ++#endif ++&gpio0 { ++ status = "okay"; ++ /* Enable GPIOP0 and GPIOP2 pass-through by default */ ++ /* pinctrl-names = "pass-through"; ++ pinctrl-0 = <&pinctrl_thru0_default ++ &pinctrl_thru1_default>; */ ++ gpio-line-names = ++ /*A0-A7*/ "","","","","SMB_CPU_PIROM_SCL","SMB_CPU_PIROM_SDA","SMB_IPMB_STBY_LVC3_R_SCL","SMB_IPMB_STBY_LVC3_R_SDA", ++ /*B0-B7*/ "FM_1200VA_OC","NMI_OUT","IRQ_SMB3_M2_ALERT_N","","RGMII_BMC_RMM4_LVC3_R_MDC","RGMII_BMC_RMM4_LVC3_R_MDIO","FM_BMC_BMCINIT_R","FP_ID_LED_N", ++ /*C0-C7*/ "FM_FORCE_BMC_UPDATE_N","RST_RGMII_PHYRST_N","FM_TPM_EN_PULSE","FM_BMC_CRASHLOG_TRIG_N","IRQ_BMC_PCH_NMI_R","FM_CPU1_DISABLE_COD_N","FM_4S_8S_N_MODE","FM_STANDALONE_MODE_N", ++ /*D0-D7*/ "CPU_ERR0","CPU_ERR1","CPU_ERR2","PRDY_N","FM_SPD_SWITCH_CTRL_N","","","", ++ /*E0-E7*/ "FM_SKT1_FAULT_LED","FM_SKT0_FAULT_LED","CLK_50M_CKMNG_BMCB","FM_BMC_BOARD_REV_ID2_N","","","","", ++ /*F0-F7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","FM_BMC_BOARD_SKU_ID5_N","ID_BUTTON","PS_PWROK", ++ /*G0-G7*/ "FM_SMB_BMC_NVME_LVC3_ALERT_N","RST_BMC_I2C_M2_R_N","FP_LED_STATUS_GREEN_N","FP_LED_STATUS_AMBER_N","FM_BMC_BOARD_REV_ID0_N","FM_BMC_BOARD_REV_ID1_N","FM_BMC_CPU_FBRK_OUT_R_N","DBP_PRESENT_IN_R2_N", ++ /*H0-H7*/ "SGPIO_BMC_CLK_R","SGPIO_BMC_LD_R","SGPIO_BMC_DOUT_R","SGPIO_BMC_DIN","PLTRST_N","CPU_CATERR","PCH_BMC_THERMTRIP","", ++ /*I0-I7*/ "JTAG_ASD_NTRST_R_N","JTAG_ASD_TDI_R","JTAG_ASD_TCK_R","JTAG_ASD_TMS_R","JTAG_ASD_TDO","FM_BMC_PWRBTN_OUT_R_N","FM_BMC_PWR_BTN_N","", ++ /*J0-J7*/ "SMB_CHASSENSOR_STBY_LVC3_SCL","SMB_CHASSENSOR_STBY_LVC3_SDA","FM_NODE_ID0","FM_NODE_ID1","","","","", ++ /*K0-K7*/ "SMB_HSBP_STBY_LVC3_R_SCL","SMB_HSBP_STBY_LVC3_R_SDA","SMB_SMLINK0_STBY_LVC3_R2_SCL","SMB_SMLINK0_STBY_LVC3_R2_SDA","SMB_TEMPSENSOR_STBY_LVC3_R_SCL","SMB_TEMPSENSOR_STBY_LVC3_R_SDA","SMB_PMBUS_SML1_STBY_LVC3_R_SCL","SMB_PMBUS_SML1_STBY_LVC3_R_SDA", ++ /*L0-L7*/ "SMB_PCIE_STBY_LVC3_R_SCL","SMB_PCIE_STBY_LVC3_R_SDA","SMB_HOST_STBY_BMC_LVC3_R_SCL","SMB_HOST_STBY_BMC_LVC3_R_SDA","PREQ_N","DEBUG_EN_N","V_BMC_GFX_HSYNC_R","V_BMC_GFX_VSYNC_R", ++ /*M0-M7*/ "SPA_CTS_N","SPA_DCD_N","SPA_DSR_N","PU_SPA_RI_N","SPA_DTR_N","SPA_RTS_N","SPA_SOUT","SPA_SIN", ++ /*N0-N7*/ "SPB_CTS_N","SPB_DCD_N","SPB_DSR_N","PU_SPB_RI_N","SPB_DTR_N","SPB_RTS_N","SPB_SOUT","SPB_SIN", ++ /*O0-O7*/ "FAN_BMC_PWM0","FAN_BMC_PWM1","FAN_BMC_PWM2","FAN_BMC_PWM3","FAN_BMC_PWM4","FAN_BMC_PWM5","NMI_BUTTON","SPEAKER_BMC_R", ++ /*P0-P7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","FAN_BMC_PWM6","FAN_BMC_PWM7","FAN_BMC_PWM8","FAN_BMC_PWM9", ++ /*Q0-Q7*/ "FAN_BMC_TACH0","FAN_BMC_TACH1","FAN_BMC_TACH2","FAN_BMC_TACH3","FAN_BMC_TACH4","FAN_BMC_TACH5","FAN_BMC_TACH6","FAN_BMC_TACH7", ++ /*R0-R7*/ "FAN_BMC_TACH8","FAN_BMC_TACH9","","","","","","", ++ /*S0-S7*/ "RST_BMC_PCIE_MUX_N","FM_BMC_EUP_LOT6_N","","","","A_P3V_BAT_SCALED_EN","REMOTE_DEBUG_ENABLE","FM_PCHHOT_N", ++ /*T0-T7*/ "A_P12V_PSU_SCALED","A_P12V_AUX_SCALED","A_P3V3_SCALED","A_P5V_SCALED","A_PVNN_PCH_AUX_SENSOR","A_P1V05_PCH_AUX_SENSOR","A_P1V8_AUX_SENSOR","A_P3V_BAT_SCALED", ++ /*U0-U7*/ "A_PVCCIN_CPU0_SENSOR","A_PVCCIN_CPU1_SENSOR","A_PVCCINFAON_CPU0_SENSOR","A_PVCCINFAON_CPU1_SENSOR","A_PVCCFA_EHV_FIVRA_CPU0_SENSOR","A_PVCCFA_EHV_FIVRA_CPU1_SENSOR","A_PVCCD_HV_CPU0_SENSOR","A_PVCCD_HV_CPU1_SENSOR", ++ /*V0-V7*/ "SIO_S3","SIO_S5","TP_BMC_SIO_PWREQ_N","SIO_ONCONTROL","SIO_POWER_GOOD","LED_BMC_HB_LED_N","FM_BMC_SUSACK_N","", ++ /*W0-W7*/ "LPC_LAD0_ESPI_R_IO0","LPC_LAD1_ESPI_R_IO1","LPC_LAD2_ESPI_R_IO2","LPC_LAD3_ESPI_R_IO3","CLK_24M_66M_LPC0_ESPI_BMC","LPC_LFRAME_N_ESPI_CS0_BMC_N","IRQ_LPC_SERIRQ_ESPI_ALERT_N","RST_LPC_LRST_ESPI_RST_BMC_R_N", ++ /*X0-X7*/ "","SMI","POST_COMPLETE","","","","","", ++ /*Y0-Y7*/ "","IRQ_SML0_ALERT_BMC_R2_N","","IRQ_SML1_PMBUS_BMC_ALERT_N","SPI_BMC_BOOT_R_IO2","SPI_BMC_BOOT_R_IO3","PU_SPI_BMC_BOOT_ABR","PU_SPI_BMC_BOOT_WP_N", ++ /*Z0-Z7*/ "PWRGD_P3V3_RISER1","PWRGD_P3V3_RISER2","","HW_STRAP_5","HW_STRAP_6","HW_STRAP_7","HW_STRAP_2","HW_STRAP_3"; ++}; ++ ++&gpio1 { ++ status = "disabled"; ++ gpio-line-names = /* GPIO18 A-E */ ++ /*A0-A7*/ "","","RST_EMMC_BMC_R_N","FM_SYS_FAN6_PRSNT_D_N","FM_SYS_FAN0_PRSNT_D_N","FM_SYS_FAN1_PRSNT_D_N","FM_SYS_FAN2_PRSNT_D_N","FM_SYS_FAN3_PRSNT_D_N", ++ /*B0-B7*/ "FM_SYS_FAN4_PRSNT_D_N","FM_SYS_FAN5_PRSNT_D_N","","FM_SYS_FAN7_PRSNT_D_N","RGMII_BMC_RMM4_TX_R_CLK","RGMII_BMC_RMM4_TX_R_CTRL","RGMII_BMC_RMM4_R_TXD0","RGMII_BMC_RMM4_R_TXD1", ++ /*C0-C7*/ "RGMII_BMC_RMM4_R_TXD2","RGMII_BMC_RMM4_R_TXD3","RGMII_BMC_RMM4_RX_CLK","RGMII_BMC_RMM4_RX_CTRL","RGMII_BMC_RMM4_RXD0","RGMII_BMC_RMM4_RXD1","RGMII_BMC_RMM4_RXD2","RGMII_BMC_RMM4_RXD3", ++ /*D0-D7*/ "EMMC_BMC_R_CLK","EMMC_BMC_R_CMD","EMMC_BMC_R_DATA0","EMMC_BMC_R_DATA1","EMMC_BMC_R_DATA2","EMMC_BMC_R_DATA3","EMMC_BMC_CD_N","EMMC_BMC_WP_N", ++ /*E0-E3*/ "EMMC_BMC_R_DATA4","EMMC_BMC_R_DATA5","EMMC_BMC_R_DATA6","EMMC_BMC_R_DATA7"; ++}; ++ ++&sgpio { ++ status = "okay"; ++ gpio-line-names = ++ /* SGPIO output lines */ ++ /*OA0-OA7*/ "","","","","","","","", ++ /*OB0-OB7*/ "LED_CPU1_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU1_CH2_DIMM1_FAULT","LED_CPU1_CH2_DIMM2_FAULT","LED_CPU1_CH3_DIMM1_FAULT","LED_CPU1_CH3_DIMM2_FAULT","LED_CPU1_CH4_DIMM1_FAULT","LED_CPU1_CH4_DIMM2_FAULT", ++ /*OC0-OC7*/ "LED_CPU1_CH5_DIMM1_FAULT","LED_CPU1_CH5_DIMM2_FAULT","LED_CPU1_CH6_DIMM1_FAULT","LED_CPU1_CH6_DIMM2_FAULT","LED_FAN1_FAULT","LED_FAN2_FAULT","LED_FAN3_FAULT","LED_FAN4_FAULT", ++ /*OD0-OD7*/ "LED_FAN5_FAULT","LED_FAN6_FAULT","LED_FAN7_FAULT","LED_FAN8_FAULT","LED_CPU2_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU2_CH2_DIMM1_FAULT","LED_CPU2_CH2_DIMM2_FAULT", ++ /*OE0-OE7*/ "LED_CPU2_CH3_DIMM1_FAULT","LED_CPU2_CH3_DIMM2_FAULT","LED_CPU2_CH4_DIMM1_FAULT","LED_CPU2_CH4_DIMM2_FAULT","LED_CPU2_CH5_DIMM1_FAULT","LED_CPU2_CH5_DIMM2_FAULT","LED_CPU2_CH6_DIMM1_FAULT","LED_CPU2_CH6_DIMM2_FAULT", ++ /*OF0-OF7*/ "LED_CPU3_CH1_DIMM1_FAULT","LED_CPU3_CH1_DIMM2_FAULT","LED_CPU3_CH2_DIMM1_FAULT","LED_CPU3_CH2_DIMM2_FAULT","LED_CPU3_CH3_DIMM1_FAULT","LED_CPU3_CH3_DIMM2_FAULT","LED_CPU3_CH4_DIMM1_FAULT","LED_CPU3_CH4_DIMM2_FAULT", ++ /*OG0-OG7*/ "LED_CPU3_CH5_DIMM1_FAULT","LED_CPU3_CH5_DIMM2_FAULT","LED_CPU3_CH6_DIMM1_FAULT","LED_CPU3_CH6_DIMM2_FAULT","LED_CPU4_CH1_DIMM1_FAULT","LED_CPU4_CH1_DIMM2_FAULT","LED_CPU4_CH2_DIMM1_FAULT","LED_CPU4_CH2_DIMM2_FAULT", ++ /*OH0-OH7*/ "LED_CPU4_CH3_DIMM1_FAULT","LED_CPU4_CH3_DIMM2_FAULT","LED_CPU4_CH4_DIMM1_FAULT","LED_CPU4_CH4_DIMM2_FAULT","LED_CPU4_CH5_DIMM1_FAULT","LED_CPU4_CH5_DIMM2_FAULT","LED_CPU4_CH6_DIMM1_FAULT","LED_CPU4_CH6_DIMM2_FAULT", ++ /*OI0-OI7*/ "","","","","","","","", ++ /*OJ0-OJ7*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ ++ /* SGPIO input lines */ ++ /* Some lines have been renamed from the net names: ++ CPU1_PRESENCE -> FM_CPU0_SKTOCC_LVT3_N ++ CPU1_THERMTRIP -> H_CPU0_THERMTRIP_LVC1_N ++ CPU1_VRHOT -> IRQ_CPU0_VRHOT_N ++ CPU1_FIVR_FAULT -> H_CPU0_MON_FAIL_PLD_LVC1_N ++ CPU1_MEM_ABCD_VRHOT -> ?? ++ CPU1_MEM_EFGH_VRHOT -> ?? ++ CPU2_PRESENCE -> FM_CPU1_SKTOCC_LVT3_N ++ CPU2_THERMTRIP -> H_CPU1_THERMTRIP_LVC1_N ++ CPU2_VRHOT -> IRQ_CPU1_VRHOT_N ++ CPU2_FIVR_FAULT -> H_CPU1_MON_FAIL_PLD_LVC1_N ++ CPU2_MEM_ABCD_VRHOT -> ?? ++ CPU2_MEM_EFGH_VRHOT -> ?? ++ ++ /*IA0-IA7*/ "CPU1_PRESENCE","CPU1_THERMTRIP","CPU1_VRHOT","CPU1_FIVR_FAULT","IRQ_CPU0_MEM_VRHOT_N","H_CPU0_MEMHOT_OUT_LVC1_N","FM_CPU0_PROC_ID0","FM_CPU0_PROC_ID1", ++ /*IB0-IB7*/ "WCPU_MISMATCH","IRQ_PSYS_CRIT_N","CPU2_PRESENCE","CPU2_THERMTRIP","CPU2_VRHOT","CPU2_FIVR_FAULT","IRQ_CPU1_MEM_VRHOT_N","H_CPU1_MEMHOT_OUT_LVC1_N", ++ /*IC0-IC7*/ "FM_CPU1_PROC_ID0","FM_CPU1_PROC_ID1","","","","","","", ++ /*ID0-ID7*/ "","","","","","","","", ++ /*IE0-IE7*/ "","","","","","","","", ++ /*IF0-IF7*/ "FPGA_REV_TEST_0","FPGA_REV_TEST_1","FPGA_REV_TEST_2","FPGA_REV_TEST_3","FPGA_REV_TEST_4","FPGA_REV_TEST_5","FPGA_REV_TEST_6","FPGA_REV_TEST_7", ++ /*IG0-IG7*/ "FPGA_REV_0","FPGA_REV_1","FPGA_REV_2","FPGA_REV_3","FPGA_REV_4","FPGA_REV_5","FPGA_REV_6","FPGA_REV_7", ++ /*IH0-IH7*/ "","WMEMX_PWR_FLT","WCPUX_MEM_PWR_FLT","PWRGD_P3V3_FF","WPSU_PWR_FLT","","","WPCH_PWR_FLT", ++ /*II0-II7*/ "FM_CPU0_PKGID0","FM_CPU0_PKGID1","FM_CPU0_PKGID2","H_CPU0_MEMTRIP_LVC1_N","FM_CPU1_PKGID0","FM_CPU1_PKGID1","FM_CPU1_PKGID2","H_CPU1_MEMTRIP_LVC1_N", ++ /*IJ0-IJ7*/ "","","","","","","",""; ++}; ++ ++&kcs3 { ++ kcs_addr = <0xCA2>; ++ status = "okay"; ++}; ++ ++&kcs4 { ++ kcs_addr = <0xCA4>; ++ status = "okay"; ++}; ++ ++&lpc_sio { ++ status = "okay"; ++}; ++ ++&lpc_snoop { ++ snoop-ports = <0x80>; ++ status = "okay"; ++}; ++ ++&mbox { ++ status = "okay"; ++}; ++ ++&mdio1 { ++ status = "okay"; ++ ++ ethphy1: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; ++ ++&mac1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii2_default>; ++ clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>, ++ <&syscon ASPEED_CLK_MAC2RCLK>; ++ clock-names = "MACCLK", "RCLK"; ++ phy-mode = "rgmii"; ++ phy-handle = <ðphy1>; ++}; ++ ++&mdio2 { ++ status = "okay"; ++ ++ ethphy2: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ }; ++}; ++ ++&adc0 { ++ status = "okay"; ++}; ++ ++&adc1 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++ // Workaround for A0 ++ compatible = "snps,dw-apb-uart"; ++ 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"; ++ // Workaround for A0 ++ compatible = "snps,dw-apb-uart"; ++ 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"; ++ // Workaround for A0 ++ compatible = "snps,dw-apb-uart"; ++ pinctrl-0 = <>; ++}; ++ ++&uart4 { ++ status = "okay"; ++ // Workaround for A0 ++ compatible = "snps,dw-apb-uart"; ++ pinctrl-0 = <>; ++}; ++ ++&uart5 { ++ status = "okay"; ++ // Workaround for A0 ++ compatible = "snps,dw-apb-uart"; ++}; ++ ++&uart_routing { ++ status = "okay"; ++}; ++ ++&emmc_controller{ ++ status = "okay"; ++}; ++ ++&emmc { ++ non-removable; ++ bus-width = <4>; ++ max-frequency = <52000000>; ++}; ++ ++&i2c0 { ++ /* SMB_CHASSENSOR_STBY_LVC3 */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c4 { ++ /* SMB_HSBP_STBY_LVC3_R */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c5 { ++ /* SMB_SMLINK0_STBY_LVC3_R2 */ ++ bus-frequency = <1000000>; ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c6 { ++ /* SMB_TEMPSENSOR_STBY_LVC3_R */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c7 { ++ /* SMB_PMBUS_SML1_STBY_LVC3_R */ ++ multi-master; ++ #retries = <3>; ++ status = "okay"; ++}; ++ ++&i2c8 { ++ /* SMB_PCIE_STBY_LVC3_R */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c9 { ++ /* SMB_HOST_STBY_BMC_LVC3_R */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c12 { ++ /* SMB_CPU_PIROM */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i2c13 { ++ /* SMB_IPMB_STBY_LVC3_R */ ++ multi-master; ++ status = "okay"; ++}; ++ ++&i3c0 { ++ /* I3C_SPD_DDRABCD_CPU0_BMC ; FIXME: i3c driver hangs kernel on probe...*/ ++ status = "disabled"; ++}; ++ ++&i3c1 { ++ /* I3C_SPD_DDREFGH_CPU0_BMC */ ++ status = "disabled"; ++}; ++ ++&i3c2 { ++ /* I3C_SPD_DDRABCD_CPU1_BMC */ ++ status = "disabled"; ++}; ++ ++&i3c3 { ++ /* I3C_SPD_DDREFGH_CPU1_BMC */ ++ status = "disabled"; ++}; ++ ++&gfx { ++ status = "okay"; ++ memory-region = <&gfx_memory>; ++}; ++ ++&pwm_tacho { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_tach0_default ++ &pinctrl_pwm1_default &pinctrl_tach1_default ++ &pinctrl_pwm2_default &pinctrl_tach2_default ++ &pinctrl_pwm3_default &pinctrl_tach3_default ++ &pinctrl_pwm4_default &pinctrl_tach4_default ++ &pinctrl_pwm5_default &pinctrl_tach5_default ++ &pinctrl_pwm12g1_default &pinctrl_tach6_default ++ &pinctrl_pwm13g1_default &pinctrl_tach7_default ++ &pinctrl_pwm14g1_default &pinctrl_tach8_default ++ &pinctrl_pwm15g1_default &pinctrl_tach9_default>; /*pwm 6-11 used for some other functionality*/ ++ ++ fan@0 { ++ reg = <0x00>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x00>; ++ }; ++ fan@1 { ++ reg = <0x01>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x01>; ++ }; ++ fan@2 { ++ reg = <0x02>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x02>; ++ }; ++ fan@3 { ++ reg = <0x03>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x03>; ++ }; ++ fan@4 { ++ reg = <0x04>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x04>; ++ }; ++ fan@5 { ++ reg = <0x05>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x05>; ++ }; ++ fan@6 { ++ reg = <0x06>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x06>; ++ }; ++ fan@7 { ++ reg = <0x07>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x07>; ++ }; ++ fan@8 { ++ reg = <0x08>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x08>; ++ }; ++ fan@9 { ++ reg = <0x09>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x09>; ++ }; ++}; ++ ++&video { ++ status = "okay"; ++ memory-region = <&video_engine_memory>; ++}; ++ ++&vhub { ++ status = "okay"; ++}; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch new file mode 100644 index 000000000..d75229a15 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch @@ -0,0 +1,212 @@ +From 5e5758fe5929766a9b4677b86f9343a777526fe8 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Thu, 12 Sep 2019 15:55:39 +0800 +Subject: [PATCH] arm: dts: base aspeed g6 dtsi fixups + +Additions to the base g6 dtsi file for Aspeed ast2600 systems. +This mostly includes entries for the drivers that are not upstream. + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + arch/arm/boot/dts/aspeed-g6.dtsi | 129 +++++++++++++++++++++++++++++- + include/dt-bindings/clock/ast2600-clock.h | 8 ++ + 2 files changed, 135 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 2af9efa1faa1..54add29d8217 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -28,6 +28,12 @@ + i2c13 = &i2c13; + i2c14 = &i2c14; + i2c15 = &i2c15; ++ i3c0 = &i3c0; ++ i3c1 = &i3c1; ++ i3c2 = &i3c2; ++ i3c3 = &i3c3; ++ i3c4 = &i3c4; ++ i3c5 = &i3c5; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; +@@ -297,11 +303,21 @@ + quality = <100>; + }; + ++ adc: adc@1e6e9000 { ++ compatible = "aspeed,ast2500-adc"; ++ reg = <0x1e6e9000 0x100>; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; ++ resets = <&syscon ASPEED_RESET_ADC>; ++ #io-channel-cells = <1>; ++ status = "disabled"; ++ }; ++ + gpio0: gpio@1e780000 { + #gpio-cells = <2>; + gpio-controller; + compatible = "aspeed,ast2600-gpio"; +- reg = <0x1e780000 0x800>; ++ reg = <0x1e780000 0x200>; + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; + gpio-ranges = <&pinctrl 0 0 208>; + ngpios = <208>; +@@ -314,7 +330,7 @@ + #gpio-cells = <2>; + gpio-controller; + compatible = "aspeed,ast2600-gpio"; +- reg = <0x1e780800 0x800>; ++ reg = <0x1e780800 0x200>; + interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + gpio-ranges = <&pinctrl 0 208 36>; + ngpios = <36>; +@@ -398,6 +414,13 @@ + ranges = <0x0 0x1e78b000 0x100>; + }; + ++ i3c: bus@1e7a0000 { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x1e7a0000 0x8000>; ++ }; ++ + lpc: lpc@1e789000 { + compatible = "aspeed,ast2600-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; +@@ -486,6 +509,20 @@ + sio_regs: regs { + compatible = "aspeed,bmc-misc"; + }; ++ ++ lpc_sio: lpc-sio@100 { ++ compatible = "aspeed,ast2500-lpc-sio"; ++ reg = <0x100 0x20>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; ++ ++ mbox: mbox@180 { ++ compatible = "aspeed,ast2600-mbox"; ++ reg = <0x180 0x5c>; ++ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>; ++ #mbox-cells = <1>; ++ }; + }; + }; + +@@ -871,3 +908,91 @@ + status = "disabled"; + }; + }; ++ ++&i3c { ++ i3c0: i3c0@2000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x2000 0x1000>; ++ compatible = "snps,dw-i3c-master-1.00a"; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_I3C0>; ++ bus-frequency = <100000>; ++ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ i3c1: i3c1@3000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x3000 0x1000>; ++ compatible = "snps,dw-i3c-master-1.00a"; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_I3C1>; ++ bus-frequency = <100000>; ++ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ i3c2: i3c2@4000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x4000 0x1000>; ++ compatible = "snps,dw-i3c-master-1.00a"; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_I3C2>; ++ bus-frequency = <100000>; ++ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i3c3_default>; ++ status = "disabled"; ++ }; ++ ++ i3c3: i3c3@5000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x5000 0x1000>; ++ compatible = "snps,dw-i3c-master-1.00a"; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_I3C3>; ++ bus-frequency = <100000>; ++ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i3c4_default>; ++ status = "disabled"; ++ }; ++ ++ i3c4: i3c4@6000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x6000 0x1000>; ++ compatible = "snps,dw-i3c-master-1.00a"; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_I3C4>; ++ bus-frequency = <100000>; ++ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i3c5_default>; ++ status = "disabled"; ++ }; ++ ++ i3c5: i3c5@7000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x7000 0x1000>; ++ compatible = "snps,dw-i3c-master-1.00a"; ++ clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_I3C5>; ++ bus-frequency = <100000>; ++ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i3c6_default>; ++ status = "disabled"; ++ }; ++}; +diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h +index 62b9520a00fd..3d90582a813f 100644 +--- a/include/dt-bindings/clock/ast2600-clock.h ++++ b/include/dt-bindings/clock/ast2600-clock.h +@@ -91,6 +91,14 @@ + /* Only list resets here that are not part of a gate */ + #define ASPEED_RESET_ADC 55 + #define ASPEED_RESET_JTAG_MASTER2 54 ++#define ASPEED_RESET_I3C7 47 ++#define ASPEED_RESET_I3C6 46 ++#define ASPEED_RESET_I3C5 45 ++#define ASPEED_RESET_I3C4 44 ++#define ASPEED_RESET_I3C3 43 ++#define ASPEED_RESET_I3C2 42 ++#define ASPEED_RESET_I3C1 41 ++#define ASPEED_RESET_I3C0 40 + #define ASPEED_RESET_I3C_DMA 39 + #define ASPEED_RESET_PWM 37 + #define ASPEED_RESET_PECI 36 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch new file mode 100644 index 000000000..08e350c15 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch @@ -0,0 +1,645 @@ +From 1365492683b47f63d470d0666fee258a5c7ca3c3 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Thu, 12 Sep 2019 15:26:08 -0700 +Subject: [PATCH 04/52] Add Aspeed fmc-spi driver + +Add the Aspeed fmc-spi driver from the Apeed SDK v5.02 + +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + arch/arm/boot/dts/aspeed-g6.dtsi | 43 ++- + drivers/spi/Kconfig | 6 + + drivers/spi/Makefile | 1 + + drivers/spi/fmc_spi.c | 530 +++++++++++++++++++++++++++++++ + 4 files changed, 579 insertions(+), 1 deletion(-) + create mode 100644 drivers/spi/fmc_spi.c + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 42f644ac8111..1aab48fbf49e 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -90,7 +90,7 @@ + <0x40464000 0x2000>, + <0x40466000 0x2000>; + }; +- ++#if 1 + fmc: spi@1e620000 { + reg = < 0x1e620000 0xc4 + 0x20000000 0x10000000 >; +@@ -169,6 +169,47 @@ + status = "disabled"; + }; + }; ++#else ++ spi0: spi@1e620000 { ++ /* reg : cs0 : cs1 : cs2 */ ++ reg = <0x1e620000 0x100 ++ 0x20000000 0x40 ++ 0x28000000 0x40>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "aspeed,fmc-spi"; ++ clocks = <&syscon ASPEED_CLK_AHB>; ++ status = "disable"; ++ number_of_chip_select = /bits/ 16 <2>; ++ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ spi1: spi1@1e630000 { ++ /* reg : cs0 : cs1 */ ++ reg = <0x1e630000 0x100 ++ 0x30000000 0x20 ++ 0x32000000 0x20>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "aspeed,fmc-spi"; ++ clocks = <&syscon ASPEED_CLK_AHB>; ++ status = "disable"; ++ number_of_chip_select = /bits/ 16 <2>; ++ }; ++ ++ spi2: spi2@1e631000 { ++ /* reg : cs0 : cs1 */ ++ reg = <0x1e631000 0x100 ++ 0x38000000 0x20 ++ 0x3A000000 0x20>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "aspeed,fmc-spi"; ++ clocks = <&syscon ASPEED_CLK_AHB>; ++ status = "disable"; ++ number_of_chip_select = /bits/ 16 <2>; ++ }; ++#endif + + mdio0: mdio@1e650000 { + compatible = "aspeed,ast2600-mdio"; +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index 6ee514fd0920..9f32c31ffa3c 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -57,6 +57,12 @@ config SPI_MEM + + comment "SPI Master Controller Drivers" + ++config SPI_FMC ++ tristate "Aspeed FMC SPI Controller" ++ depends on ARCH_ASPEED ++ help ++ This selects a driver for the AST FMC SPI Controller ++ + config SPI_ALTERA + tristate "Altera SPI Controller" + help +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index adbebee93a75..224b9b71e29c 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_SPI_SPIDEV) += spidev.o + obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o + + # SPI master controller drivers (bus) ++obj-$(CONFIG_SPI_FMC) += fmc_spi.o + obj-$(CONFIG_SPI_ALTERA) += spi-altera.o + obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o + obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o +diff --git a/drivers/spi/fmc_spi.c b/drivers/spi/fmc_spi.c +new file mode 100644 +index 000000000000..f21f7a00496e +--- /dev/null ++++ b/drivers/spi/fmc_spi.c +@@ -0,0 +1,530 @@ ++/* ++ * fmc_spi.c - FMC SPI driver for the Aspeed SoC ++ * ++ * Copyright (C) ASPEED Technology Inc. ++ * Ryan Chen <ryan_chen@aspeedtech.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/clk.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/platform_device.h> ++#include <linux/err.h> ++#include <linux/errno.h> ++#include <linux/wait.h> ++#include <linux/delay.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++ ++#include <linux/of_address.h> ++#include <linux/of_irq.h> ++#include <linux/of_platform.h> ++ ++/******************************************************************************/ ++/* AST_SPI_CONFIG 0x00 : SPI00 CE Type Setting Register */ ++#define AST_G5_SPI_CONF_CE1_WEN (0x1 << 17) ++#define AST_G5_SPI_CONF_CE0_WEN (0x1 << 16) ++ ++#define SPI_CONF_CE0_WEN (0x1) ++ ++/* Register offsets */ ++#define FMC_SPI_CONFIG 0x00 ++#define FMC_SPI_CTRL 0x04 ++#define FMC_SPI_DMA_STS 0x08 ++ ++#define FMC_SPI_CE0_CTRL 0x10 ++#define FMC_SPI_CE1_CTRL 0x14 ++ ++#define AST_SPI_DMA_CTRL 0x80 ++#define AST_SPI_DMA_FLASH_BASE 0x84 ++#define AST_SPI_DMA_DRAM_BASE 0x88 ++#define AST_SPI_DMA_LENGTH 0x8c ++ ++/* AST_FMC_CONFIG 0x00 : FMC00 CE Type Setting Register */ ++#define FMC_CONF_LAGACY_DIS (0x1 << 31) ++#define FMC_CONF_CE1_WEN (0x1 << 17) ++#define FMC_CONF_CE0_WEN (0x1 << 16) ++#define FMC_CONF_CE1_SPI (0x2 << 2) ++#define FMC_CONF_CE0_SPI (0x2) ++ ++/* FMC_SPI_CTRL : 0x04 : FMC04 CE Control Register */ ++#define FMC_CTRL_CE1_4BYTE_MODE (0x1 << 1) ++#define FMC_CTRL_CE0_4BYTE_MODE (0x1) ++ ++/* FMC_SPI_DMA_STS : 0x08 : FMC08 Interrupt Control and Status Register */ ++#define FMC_STS_DMA_READY 0x0800 ++#define FMC_STS_DMA_CLEAR 0x0800 ++ ++/* FMC_CE0_CTRL for SPI 0x10, 0x14, 0x18, 0x1c, 0x20 */ ++#define SPI_IO_MODE_MASK (3 << 28) ++#define SPI_SINGLE_BIT (0 << 28) ++#define SPI_DUAL_MODE (0x2 << 28) ++#define SPI_DUAL_IO_MODE (0x3 << 28) ++#define SPI_QUAD_MODE (0x4 << 28) ++#define SPI_QUAD_IO_MODE (0x5 << 28) ++ ++#define SPI_CE_WIDTH(x) (x << 24) ++#define SPI_CMD_DATA_MASK (0xff << 16) ++#define SPI_CMD_DATA(x) (x << 16) ++#define SPI_DUMMY_CMD (1 << 15) ++#define SPI_DUMMY_HIGH (1 << 14) ++//#define SPI_CLK_DIV (1 << 13) ?? TODO ask.... ++//#define SPI_ADDR_CYCLE (1 << 13) ?? TODO ask.... ++#define SPI_CMD_MERGE_DIS (1 << 12) ++#define SPI_CLK_DIV(x) (x << 8) ++#define SPI_CLK_DIV_MASK (0xf << 8) ++ ++#define SPI_DUMMY_LOW_MASK (0x3 << 6) ++#define SPI_DUMMY_LOW(x) ((x) << 6) ++#define SPI_LSB_FIRST_CTRL (1 << 5) ++#define SPI_CPOL_1 (1 << 4) ++#define SPI_DUAL_DATA (1 << 3) ++#define SPI_CE_INACTIVE (1 << 2) ++#define SPI_CMD_MODE_MASK (0x3) ++#define SPI_CMD_NORMAL_READ_MODE 0 ++#define SPI_CMD_READ_CMD_MODE 1 ++#define SPI_CMD_WRITE_CMD_MODE 2 ++#define SPI_CMD_USER_MODE 3 ++ ++/* AST_SPI_DMA_CTRL 0x80 */ ++#define FMC_DMA_ENABLE (0x1) ++ ++/******************************************************************************/ ++struct fmc_spi_host { ++ void __iomem *base; ++ void __iomem *ctrl_reg; ++ u32 buff[5]; ++ struct spi_master *master; ++ struct spi_device *spi_dev; ++ struct device *dev; ++ u32 ahb_clk; ++ spinlock_t lock; ++}; ++ ++static u32 ast_spi_calculate_divisor(struct fmc_spi_host *host, ++ u32 max_speed_hz) ++{ ++ // [0] ->15 : HCLK , HCLK/16 ++ u8 SPI_DIV[16] = { ++ 16, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0 ++ }; ++ u32 i, spi_cdvr = 0; ++ ++ for (i = 1; i < 17; i++) { ++ if (max_speed_hz >= (host->ahb_clk / i)) { ++ spi_cdvr = SPI_DIV[i - 1]; ++ break; ++ } ++ } ++ ++ // printk("hclk is %d, divisor is %d, target :%d , cal speed %d\n", host->ahb_clk, spi_cdvr, spi->max_speed_hz, hclk/i); ++ return spi_cdvr; ++} ++ ++/* the spi->mode bits understood by this driver: */ ++#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) ++ ++static int fmc_spi_setup(struct spi_device *spi) ++{ ++ struct fmc_spi_host *host = ++ (struct fmc_spi_host *)spi_master_get_devdata(spi->master); ++ unsigned int bits = spi->bits_per_word; ++ u32 fmc_config = 0; ++ u32 spi_ctrl = 0; ++ u32 divisor; ++ ++ // dev_dbg(host->dev, "fmc_spi_setup() cs: %d, spi->mode %d \n", spi->chip_select, spi->mode); ++ // printk("fmc_spi_setup() cs: %d, spi->mode %d spi->max_speed_hz %d , spi->bits_per_word %d \n", spi->chip_select, spi->mode, spi->max_speed_hz, spi->bits_per_word); ++ ++ switch (spi->chip_select) { ++ case 0: ++ fmc_config |= FMC_CONF_CE0_WEN | FMC_CONF_CE0_SPI; ++ host->ctrl_reg = host->base + FMC_SPI_CE0_CTRL; ++ break; ++ case 1: ++ fmc_config |= FMC_CONF_CE1_WEN | FMC_CONF_CE1_SPI; ++ host->ctrl_reg = host->base + FMC_SPI_CE0_CTRL; ++ break; ++ default: ++ dev_dbg(&spi->dev, ++ "setup: invalid chipselect %u (%u defined)\n", ++ spi->chip_select, spi->master->num_chipselect); ++ return -EINVAL; ++ break; ++ } ++ writel(fmc_config, host->base); ++ ++ if (bits == 0) ++ bits = 8; ++ ++ if (bits < 8 || bits > 16) { ++ dev_dbg(&spi->dev, ++ "setup: invalid bits_per_word %u (8 to 16)\n", bits); ++ return -EINVAL; ++ } ++ ++ if (spi->mode & ~MODEBITS) { ++ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", ++ spi->mode & ~MODEBITS); ++ return -EINVAL; ++ } ++ ++ /* see notes above re chipselect */ ++ if ((spi->chip_select == 0) && (spi->mode & SPI_CS_HIGH)) { ++ dev_dbg(&spi->dev, "setup: can't be active-high\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Pre-new_1 chips start out at half the peripheral ++ * bus speed. ++ */ ++ ++ if (spi->max_speed_hz) { ++ /* Set the SPI slaves select and characteristic control register */ ++ divisor = ast_spi_calculate_divisor(host, spi->max_speed_hz); ++ } else { ++ /* speed zero means "as slow as possible" */ ++ divisor = 15; ++ } ++ ++ spi_ctrl &= ~SPI_CLK_DIV_MASK; ++ // printk("set div %x \n",divisor); ++ //TODO MASK first ++ spi_ctrl |= SPI_CLK_DIV(divisor); ++ ++ /* only support mode 0 (CPOL=0, CPHA=0) and cannot support mode 1 ~ mode 3 */ ++ ++#if 0 ++ if (SPI_CPHA & spi->mode) ++ cpha = SPI_CPHA_1; ++ else ++ cpha = SPI_CPHA_0; ++#endif ++ ++ // if (SPI_CPOL & spi->mode) ++ // spi_ctrl |= SPI_CPOL_1; ++ // else ++ // spi_ctrl &= ~SPI_CPOL_1; ++ ++ //ISSUE : ast spi ctrl couldn't use mode 3, so fix mode 0 ++ spi_ctrl &= ~SPI_CPOL_1; ++ ++ if (SPI_LSB_FIRST & spi->mode) ++ spi_ctrl |= SPI_LSB_FIRST_CTRL; ++ else ++ spi_ctrl &= ~SPI_LSB_FIRST_CTRL; ++ ++ /* Configure SPI controller */ ++ writel(spi_ctrl, host->ctrl_reg); ++ ++ // printk("ctrl %x, ", spi_ctrl); ++ return 0; ++} ++ ++static int fmc_spi_transfer(struct spi_device *spi, struct spi_message *msg) ++{ ++ struct fmc_spi_host *host = ++ (struct fmc_spi_host *)spi_master_get_devdata(spi->master); ++ struct spi_transfer *xfer; ++ const u8 *tx_buf; ++ u8 *rx_buf; ++ unsigned long flags; ++ ++ int i = 0, j = 0; ++ ++ // dev_dbg(host->dev, "xfer %s \n", dev_name(&spi->dev)); ++ // printk("xfer spi->chip_select %d \n", spi->chip_select); ++ ++ host->spi_dev = spi; ++ spin_lock_irqsave(&host->lock, flags); ++ ++ writel(readl(host->ctrl_reg) | SPI_CMD_USER_MODE, host->ctrl_reg); ++ msg->actual_length = 0; ++ msg->status = 0; ++ ++ list_for_each_entry (xfer, &msg->transfers, transfer_list) { ++ dev_dbg(host->dev, ++ "xfer[%d] %p: width %d, len %u, tx %p/%08x, rx %p/%08x\n", ++ j, xfer, xfer->bits_per_word, xfer->len, xfer->tx_buf, ++ xfer->tx_dma, xfer->rx_buf, xfer->rx_dma); ++ ++ tx_buf = xfer->tx_buf; ++ rx_buf = xfer->rx_buf; ++ ++ if (tx_buf != 0) { ++#if 0 ++ printk("tx : "); ++ if(xfer->len > 10) { ++ for(i=0;i<10;i++) ++ printk("%x ",tx_buf[i]); ++ } else { ++ for(i=0;i<xfer->len;i++) ++ printk("%x ",tx_buf[i]); ++ } ++ printk("\n"); ++#endif ++ for (i = 0; i < xfer->len; i++) { ++ writeb(tx_buf[i], ++ (void *)host->buff ++ [host->spi_dev->chip_select]); ++ } ++ } ++ //Issue need clarify ++ udelay(1); ++ if (rx_buf != 0) { ++ for (i = 0; i < xfer->len; i++) { ++ rx_buf[i] = readb( ++ (void *)host->buff ++ [host->spi_dev->chip_select]); ++ } ++#if 0 ++ printk("rx : "); ++ if(xfer->len > 10) { ++ for(i=0;i<10;i++) ++ printk(" %x",rx_buf[i]); ++ } else { ++ for(i=0;i<xfer->len;i++) ++ printk(" %x",rx_buf[i]); ++ } ++ printk("\n"); ++#endif ++ } ++ dev_dbg(host->dev, "old msg->actual_length %d , +len %d \n", ++ msg->actual_length, xfer->len); ++ msg->actual_length += xfer->len; ++ dev_dbg(host->dev, "new msg->actual_length %d \n", ++ msg->actual_length); ++ // j++; ++ } ++ ++ // writel( SPI_CE_INACTIVE | readl(host->spi_data->ctrl_reg),host->spi_data->ctrl_reg); ++ writel(readl(host->ctrl_reg) & ~SPI_CMD_USER_MODE, host->ctrl_reg); ++ msg->status = 0; ++ ++ msg->complete(msg->context); ++ ++ // spin_unlock(&host->lock); ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ return 0; ++} ++ ++static void fmc_spi_cleanup(struct spi_device *spi) ++{ ++ struct fmc_spi_host *host = spi_master_get_devdata(spi->master); ++ unsigned long flags; ++ dev_dbg(host->dev, "fmc_spi_cleanup() \n"); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ // if (host->stay == spi) { ++ // host->stay = NULL; ++ // cs_deactivate(host, spi); ++ // } ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++#if 0 ++static int fmc_spi_flash_read(struct spi_device *spi, ++ struct spi_flash_read_message *msg) ++{ ++// struct fmc_spi_host *host = spi_master_get_devdata(spi->master); ++ int ret = 0; ++ ++// printk("read msg->from %x, msg->len %x , msg->buf %x , msg->addr_width %d , msg->dummy_bytes %x , msg->read_opcode %x \n", msg->from, msg->len, msg->buf, msg->addr_width, msg->dummy_bytes, msg->read_opcode); ++ ++// memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len); ++ msg->retlen = msg->len; ++ ++ return ret; ++} ++#endif ++ ++static int fmc_spi_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ struct fmc_spi_host *host; ++ struct spi_master *master; ++ struct clk *clk; ++ int cs_num = 0; ++ int err = 0; ++ ++ dev_dbg(&pdev->dev, "fmc_spi_probe() \n"); ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct fmc_spi_host)); ++ if (NULL == master) { ++ dev_err(&pdev->dev, "No memory for spi_master\n"); ++ err = -ENOMEM; ++ goto err_nomem; ++ } ++ ++ /* the spi->mode bits understood by this driver: */ ++ master->mode_bits = ++ SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_RX_DUAL | SPI_TX_DUAL; ++ master->bits_per_word_mask = SPI_BPW_MASK(8); ++ ++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_RX_DUAL; ++ // master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); ++ master->dev.of_node = pdev->dev.of_node; ++ master->bus_num = pdev->id; ++ // master->num_chipselect = master->dev.of_node ? 0 : 4; ++ platform_set_drvdata(pdev, master); ++ ++ host = spi_master_get_devdata(master); ++ memset(host, 0, sizeof(struct fmc_spi_host)); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM 0\n"); ++ err = -ENXIO; ++ goto err_no_io_res; ++ } ++ ++ host->base = devm_ioremap_resource(&pdev->dev, res); ++ if (!host->base) { ++ dev_err(&pdev->dev, "cannot remap register\n"); ++ err = -EIO; ++ goto err_no_io_res; ++ } ++ ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "no clock defined\n"); ++ return -ENODEV; ++ } ++ host->ahb_clk = clk_get_rate(clk); ++ ++ dev_dbg(&pdev->dev, "remap phy %x, virt %x \n", (u32)res->start, ++ (u32)host->base); ++ ++ host->master = spi_master_get(master); ++ ++ if (of_property_read_u16(pdev->dev.of_node, "number_of_chip_select", ++ &host->master->num_chipselect)) ++ goto err_register; ++ ++ for (cs_num = 0; cs_num < host->master->num_chipselect; cs_num++) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, cs_num + 1); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_IO 0\n"); ++ return -ENXIO; ++ } ++ ++ host->buff[cs_num] = ++ (u32)devm_ioremap_resource(&pdev->dev, res); ++ if (!host->buff[cs_num]) { ++ dev_err(&pdev->dev, "cannot remap buffer \n"); ++ err = -EIO; ++ goto err_no_io_res; ++ } ++ ++ dev_dbg(&pdev->dev, "remap io phy %x, virt %x \n", ++ (u32)res->start, (u32)host->buff[cs_num]); ++ } ++ ++ host->master->bus_num = pdev->id; ++ host->dev = &pdev->dev; ++ ++ /* Setup the state for bitbang driver */ ++ host->master->setup = fmc_spi_setup; ++ host->master->transfer = fmc_spi_transfer; ++ host->master->cleanup = fmc_spi_cleanup; ++ // host->master->spi_flash_read = fmc_spi_flash_read; ++ ++ platform_set_drvdata(pdev, host); ++ ++ /* Register our spi controller */ ++ err = devm_spi_register_master(&pdev->dev, host->master); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register SPI master\n"); ++ goto err_register; ++ } ++ ++ dev_dbg(&pdev->dev, "fmc_spi : driver load \n"); ++ ++ return 0; ++ ++err_register: ++ spi_master_put(host->master); ++ iounmap(host->base); ++ for (cs_num = 0; cs_num < host->master->num_chipselect; cs_num++) { ++ iounmap((void *)host->buff[cs_num]); ++ } ++ ++err_no_io_res: ++ kfree(master); ++ kfree(host); ++ ++err_nomem: ++ return err; ++} ++ ++static int fmc_spi_remove(struct platform_device *pdev) ++{ ++ struct resource *res0; ++ struct fmc_spi_host *host = platform_get_drvdata(pdev); ++ ++ dev_dbg(host->dev, "fmc_spi_remove()\n"); ++ ++ if (!host) ++ return -1; ++ ++ res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(res0->start, res0->end - res0->start + 1); ++ iounmap(host->base); ++ iounmap(host->buff); ++ ++ platform_set_drvdata(pdev, NULL); ++ spi_unregister_master(host->master); ++ spi_master_put(host->master); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int fmc_spi_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ return 0; ++} ++ ++static int fmc_spi_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++#else ++#define fmc_spi_suspend NULL ++#define fmc_spi_resume NULL ++#endif ++ ++static const struct of_device_id fmc_spi_of_match[] = { ++ { .compatible = "aspeed,fmc-spi" }, ++ {}, ++}; ++ ++static struct platform_driver fmc_spi_driver = { ++ .probe = fmc_spi_probe, ++ .remove = fmc_spi_remove, ++#ifdef CONFIG_PM ++ .suspend = fmc_spi_suspend, ++ .resume = fmc_spi_resume, ++#endif ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = fmc_spi_of_match, ++ }, ++}; ++ ++module_platform_driver(fmc_spi_driver); ++ ++MODULE_DESCRIPTION("FMC SPI Driver"); ++MODULE_AUTHOR("Ryan Chen"); ++MODULE_LICENSE("GPL"); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch new file mode 100644 index 000000000..6123b8701 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch @@ -0,0 +1,173 @@ +From 12ef9a4189cd44212a5a5bd2e1c6fce0756ace9f Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Fri, 3 May 2019 16:12:39 -0700 +Subject: [PATCH] Enable pass-through on GPIOE1 and GPIOE3 free + +This change adds a gpio_disable_free() implementation that checks +if the GPIO being freed is GPIOE1 (33) or GPIOE3 (35) and will +re-enable the pass-through mux. + +Tested: +Requested GPIOs 33 and 35 and used devmem to check that pass-through +was disabled. Then freed them and checked that pass-through was +enabled again. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 17 ++++++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c | 17 ++++++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed.c | 53 ++++++++++++++++++++++++++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed.h | 3 ++ + 4 files changed, 90 insertions(+) + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index 0cab4c2576e2..c5406e2da320 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -2780,6 +2780,22 @@ static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx, + return 0; + } + ++#define GPIOE1 33 ++#define GPIOE3 35 ++static void aspeed_g5_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset) ++{ ++ /* ++ * If we're freeing GPIOE1 (33) or GPIOE3 (35) then re-enable the ++ * pass-through mux setting; otherwise, do nothing. ++ */ ++ if (offset != GPIOE1 && offset != GPIOE3) ++ return; ++ ++ aspeed_gpio_disable_free(pctldev, range, offset); ++} ++ + static const struct aspeed_pin_config_map aspeed_g5_pin_config_map[] = { + { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)}, + { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)}, +@@ -2815,6 +2831,7 @@ static const struct pinmux_ops aspeed_g5_pinmux_ops = { + .get_function_groups = aspeed_pinmux_get_fn_groups, + .set_mux = aspeed_pinmux_set_mux, + .gpio_request_enable = aspeed_gpio_request_enable, ++ .gpio_disable_free = aspeed_g5_gpio_disable_free, + .strict = true, + }; + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +index fb96e8d2e6c8..bcd8c5656265 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +@@ -2655,6 +2655,22 @@ static int aspeed_g6_sig_expr_set(struct aspeed_pinmux_data *ctx, + return 0; + } + ++#define GPIOP1 121 ++#define GPIOP3 123 ++static void aspeed_g6_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset) ++{ ++ /* ++ * If we're freeing GPIOP1 (121) or GPIOP3 (123) then re-enable the ++ * pass-through mux setting; otherwise, do nothing. ++ */ ++ if (offset != GPIOP1 && offset != GPIOP3) ++ return; ++ ++ aspeed_gpio_disable_free(pctldev, range, offset); ++} ++ + static const struct aspeed_pin_config_map aspeed_g6_pin_config_map[] = { + { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)}, + { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)}, +@@ -2695,6 +2711,7 @@ static const struct pinmux_ops aspeed_g6_pinmux_ops = { + .get_function_groups = aspeed_pinmux_get_fn_groups, + .set_mux = aspeed_pinmux_set_mux, + .gpio_request_enable = aspeed_gpio_request_enable, ++ .gpio_disable_free = aspeed_g6_gpio_disable_free, + .strict = true, + }; + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +index 53f3f8aec695..ca53f3743d16 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +@@ -375,6 +375,59 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, + return 0; + } + ++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset) ++{ ++ struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); ++ const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; ++ const struct aspeed_sig_expr ***prios, **funcs, *expr; ++ int ret; ++ ++ if (!pdesc) ++ return; ++ ++ dev_dbg(pctldev->dev, ++ "Freeing pass-through pin %s (%d). Re-enabling pass-through.\n", ++ pdesc->name, offset); ++ ++ prios = pdesc->prios; ++ ++ if (!prios) ++ return; ++ ++ /* Disable any functions of higher priority than GPIO just in case */ ++ while ((funcs = *prios)) { ++ if (aspeed_gpio_in_exprs(funcs)) ++ break; ++ ++ ret = aspeed_disable_sig(&pdata->pinmux, funcs); ++ if (ret) ++ return; ++ ++ prios++; ++ } ++ ++ if (!funcs) { ++ char *signals = get_defined_signals(pdesc); ++ ++ pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n", ++ pdesc->name, offset, signals); ++ kfree(signals); ++ ++ return; ++ } ++ ++ /* ++ * Pass-through should be one priority higher than the GPIO function, ++ * so decrement our prios and enable that function ++ */ ++ prios--; ++ funcs = *prios; ++ expr = *funcs; ++ aspeed_sig_expr_enable(&pdata->pinmux, expr); ++} ++ + int aspeed_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *pdesc, + struct aspeed_pinctrl_data *pdata) +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h +index 4dcde3bc29c8..bd497c20a15f 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h +@@ -101,6 +101,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, + int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset); ++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset); + int aspeed_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *pdesc, + struct aspeed_pinctrl_data *pdata); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch new file mode 100644 index 000000000..1ee1c68de --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch @@ -0,0 +1,70 @@ +From b34fdedc21c98db698150d5014e12927a017b07f Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 6 May 2019 14:18:27 -0700 +Subject: [PATCH] Enable GPIOE0 and GPIOE2 pass-through by default + +This change sets the gpio DT pinctrl default configuration to +enable GPIOE0 and GPIOE2 pass-through. Since this causes +pinctrl_get_select_default() to be called automatically for +the gpio driver to claim the GPIO pins in those groups, we +also need to call pinctrl_put() to release claim on the +pass-through GPIOs so they can be requested at runtime. + +Tested: +Disabled pass-through in uboot and confirmed that after booting +Linux, pass-through is enabled and 'cat /sys/kernel/debug/pinctrl/ +1e6e2000.syscon\:pinctrl-aspeed-g5-pinctrl/pinmux-pins' shows that +the pass-through GPIOs are UNCLAIMED. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 4 ++++ + drivers/gpio/gpio-aspeed.c | 10 ++++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +index 72bb1b3..ea1d9cd3 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +@@ -134,6 +134,10 @@ + + &gpio { + status = "okay"; ++ /* Enable GPIOE0 and GPIOE2 pass-through by default */ ++ pinctrl-names = "pass-through"; ++ pinctrl-0 = <&pinctrl_gpie0_default ++ &pinctrl_gpie2_default>; + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","","","", +diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c +index 09e53c5..6165b44 100644 +--- a/drivers/gpio/gpio-aspeed.c ++++ b/drivers/gpio/gpio-aspeed.c +@@ -1140,6 +1140,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) + { + const struct of_device_id *gpio_id; + struct aspeed_gpio *gpio; ++ struct pinctrl *pinctrl; + int rc, i, banks, err; + u32 ngpio; + +@@ -1190,6 +1191,15 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) + return -ENOMEM; + + /* ++ * Select the pass-through pinctrl config to enable the pass-through ++ * mux for GPIOs marked as pass-through. Then call pinctrl_put() to ++ * release claim of the GPIO pins, so they can be requested at runtime. ++ */ ++ pinctrl = pinctrl_get_select(&pdev->dev, "pass-through"); ++ if (!IS_ERR(pinctrl)) ++ pinctrl_put(pinctrl); ++ ++ /* + * Populate it with initial values read from the HW and switch + * all command sources to the ARM by default + */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch new file mode 100644 index 000000000..ca54df9ee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch @@ -0,0 +1,30 @@ +From 9a71adc7aecbfdf066ba54c763c2ecd8fb09d3cd Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Wed, 6 Feb 2019 15:59:34 +0530 +Subject: [PATCH] Selecting 128MB for PFR + +PFR platforms requires 128MB flash mapping. +This will override the existing 64MB flash map +and loads 128MB flash map. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +index 4815104459f1..df02bb1aaf36 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +@@ -89,7 +89,7 @@ + flash@0 { + status = "okay"; + m25p,fast-read; +-#include "openbmc-flash-layout-intel-64MB.dtsi" ++#include "openbmc-flash-layout-intel-128MB.dtsi" + }; + }; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch new file mode 100644 index 000000000..b9c14c1ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch @@ -0,0 +1,123 @@ +From 5f984831a3f451e299ecaf42d65dee36ff0ffeee Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Fri, 24 May 2019 12:42:59 -0700 +Subject: [PATCH] Allow monitoring of power control input GPIOs + +The pass-through input GPIOs cannot be monitored because when +requested, pass-through is disabled which causes a change on the +pass-through output. + +The SIO GPIOs cannot be monitored because when requested, the +request is rejected based on the value of the ACPI strap. + +This change removes the register check condition from the pass- +through and desired SIO GPIOs so they can be requsted and +monitored from power control. + +Tested: +For pass-through, I used gpioset to hold a request on the input +GPIOs and confirmed that pass-through remained enabled. + +For SIO, I used gpioget to confirm that I can successfully request +and read the GPIO value. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 10 +++++----- + drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c | 10 +++++----- + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index c5406e2da320..fde74c23ca7f 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -279,7 +279,7 @@ FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21); + + #define B20 32 + SIG_EXPR_LIST_DECL_SINGLE(B20, NCTS3, NCTS3, SIG_DESC_SET(SCU80, 16)); +-SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE0, GPIE0_DESC); ++SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE0); + SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE, GPIE_DESC); + SIG_EXPR_LIST_DECL_DUAL(B20, GPIE0IN, GPIE0, GPIE); + PIN_DECL_2(B20, GPIOE0, NCTS3, GPIE0IN); +@@ -299,7 +299,7 @@ FUNC_GROUP_DECL(GPIE0, B20, C20); + + #define F18 34 + SIG_EXPR_LIST_DECL_SINGLE(F18, NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18)); +-SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE2, GPIE2_DESC); ++SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE2); + SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE, GPIE_DESC); + SIG_EXPR_LIST_DECL_DUAL(F18, GPIE2IN, GPIE2, GPIE); + PIN_DECL_2(F18, GPIOE2, NDSR3, GPIE2IN); +@@ -1412,7 +1412,7 @@ FUNC_GROUP_DECL(ADC15, H4); + + #define R22 192 + SIG_EXPR_DECL_SINGLE(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8)); +-SIG_EXPR_DECL_SINGLE(SIOS3, ACPI, ACPI_DESC); ++SIG_EXPR_DECL_SINGLE(SIOS3, ACPI); + SIG_EXPR_LIST_DECL_DUAL(R22, SIOS3, SIOS3, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(R22, DASHR22, DASHR22, SIG_DESC_SET(SCU94, 10)); + PIN_DECL_2(R22, GPIOY0, SIOS3, DASHR22); +@@ -1420,7 +1420,7 @@ FUNC_GROUP_DECL(SIOS3, R22); + + #define R21 193 + SIG_EXPR_DECL_SINGLE(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9)); +-SIG_EXPR_DECL_SINGLE(SIOS5, ACPI, ACPI_DESC); ++SIG_EXPR_DECL_SINGLE(SIOS5, ACPI); + SIG_EXPR_LIST_DECL_DUAL(R21, SIOS5, SIOS5, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(R21, DASHR21, DASHR21, SIG_DESC_SET(SCU94, 10)); + PIN_DECL_2(R21, GPIOY1, SIOS5, DASHR21); +@@ -1436,7 +1436,7 @@ FUNC_GROUP_DECL(SIOPWREQ, P22); + + #define P21 195 + SIG_EXPR_DECL_SINGLE(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11)); +-SIG_EXPR_DECL_SINGLE(SIOONCTRL, ACPI, ACPI_DESC); ++SIG_EXPR_DECL_SINGLE(SIOONCTRL, ACPI); + SIG_EXPR_LIST_DECL_DUAL(P21, SIOONCTRL, SIOONCTRL, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(P21, DASHP21, DASHP21, SIG_DESC_SET(SCU94, 11)); + PIN_DECL_2(P21, GPIOY3, SIOONCTRL, DASHP21); +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +index bcd8c5656265..c18ceb52c289 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +@@ -762,7 +762,7 @@ SSSF_PIN_DECL(AC23, GPIOO7, PWM7, SIG_DESC_SET(SCU41C, 23)); + + #define AB22 120 + SIG_EXPR_LIST_DECL_SEMG(AB22, PWM8, PWM8G1, PWM8, SIG_DESC_SET(SCU41C, 24)); +-SIG_EXPR_LIST_DECL_SESG(AB22, THRUIN0, THRU0, SIG_DESC_SET(SCU4BC, 24)); ++SIG_EXPR_LIST_DECL_SESG(AB22, THRUIN0, THRU0); + PIN_DECL_2(AB22, GPIOP0, PWM8, THRUIN0); + GROUP_DECL(PWM8G1, AB22); + FUNC_DECL_2(PWM8, PWM8G0, PWM8G1); +@@ -779,7 +779,7 @@ FUNC_DECL_2(PWM9, PWM9G0, PWM9G1); + + #define AA23 122 + SIG_EXPR_LIST_DECL_SEMG(AA23, PWM10, PWM10G1, PWM10, SIG_DESC_SET(SCU41C, 26)); +-SIG_EXPR_LIST_DECL_SESG(AA23, THRUIN1, THRU1, SIG_DESC_SET(SCU4BC, 26)); ++SIG_EXPR_LIST_DECL_SESG(AA23, THRUIN1, THRU1); + PIN_DECL_2(AA23, GPIOP2, PWM10, THRUIN1); + GROUP_DECL(PWM10G1, AA23); + FUNC_DECL_2(PWM10, PWM10G0, PWM10G1); +@@ -1070,16 +1070,16 @@ FUNC_GROUP_DECL(GPIU7, AC17); + FUNC_GROUP_DECL(ADC15, AC17); + + #define AB15 168 +-SSSF_PIN_DECL(AB15, GPIOV0, SIOS3, SIG_DESC_SET(SCU434, 8)); ++SSSF_PIN_DECL(AB15, GPIOV0, SIOS3); + + #define AF14 169 +-SSSF_PIN_DECL(AF14, GPIOV1, SIOS5, SIG_DESC_SET(SCU434, 9)); ++SSSF_PIN_DECL(AF14, GPIOV1, SIOS5); + + #define AD14 170 + SSSF_PIN_DECL(AD14, GPIOV2, SIOPWREQ, SIG_DESC_SET(SCU434, 10)); + + #define AC15 171 +-SSSF_PIN_DECL(AC15, GPIOV3, SIOONCTRL, SIG_DESC_SET(SCU434, 11)); ++SSSF_PIN_DECL(AC15, GPIOV3, SIOONCTRL); + + #define AE15 172 + SSSF_PIN_DECL(AE15, GPIOV4, SIOPWRGD, SIG_DESC_SET(SCU434, 12)); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch new file mode 100644 index 000000000..476a07043 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch @@ -0,0 +1,28 @@ +From b7e8941cf3b1c1c42330207600c91fb23781a77b Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Tue, 2 Jul 2019 10:14:59 -0700 +Subject: [PATCH] aspeed-pwm-tacho: change default fan speed + +Change it from max to 58% + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + drivers/hwmon/aspeed-pwm-tacho.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c +index 40c489be62ea..ae5771f881b5 100644 +--- a/drivers/hwmon/aspeed-pwm-tacho.c ++++ b/drivers/hwmon/aspeed-pwm-tacho.c +@@ -160,7 +160,7 @@ + */ + #define M_TACH_MODE 0x02 /* 10b */ + #define M_TACH_UNIT 0x0210 +-#define INIT_FAN_CTRL 0xFF ++#define INIT_FAN_CTRL 150 /* 58% */ + + /* How long we sleep in us while waiting for an RPM result. */ + #define ASPEED_RPM_STATUS_SLEEP_USEC 500 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch new file mode 100644 index 000000000..993beb9ec --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch @@ -0,0 +1,31 @@ +From ea37c85db4d2a593d4f3392e21ec2cc108b111e5 Mon Sep 17 00:00:00 2001 +From: Juston Li <juston.li@intel.com> +Date: Mon, 27 Mar 2017 11:16:00 -0700 +Subject: [PATCH] arm: dts: aspeed-g5: add espi + +Signed-off-by: Juston Li <juston.li@intel.com> +--- + arch/arm/boot/dts/aspeed-g5.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 6580b232771e..452ec323534f 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -408,6 +408,13 @@ + status = "disabled"; + }; + ++ espi: espi@1e6ee000 { ++ compatible = "aspeed,ast2500-espi-slave"; ++ reg = <0x1e6ee000 0x100>; ++ interrupts = <23>; ++ status = "disabled"; ++ }; ++ + lpc: lpc@1e789000 { + compatible = "aspeed,ast2500-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch new file mode 100644 index 000000000..b9de9f5a9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch @@ -0,0 +1,117 @@ +From f57d473a30f208754457bdb63512c307f7499ac8 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Mon, 4 Jun 2018 13:45:42 -0700 +Subject: [PATCH] New flash map for intel + +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + .../boot/dts/openbmc-flash-layout-intel-128MB.dtsi | 50 ++++++++++++++++++++++ + .../boot/dts/openbmc-flash-layout-intel-64MB.dtsi | 38 ++++++++++++++++ + 2 files changed, 88 insertions(+) + create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi + create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi + +diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi +new file mode 100644 +index 000000000000..0d3794423aed +--- /dev/null ++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// 128MB flash layout: PFR (active + tmp1/tmp2 + extra) ++// image with common RW partition ++ ++partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ u-boot@0 { ++ reg = <0x0 0x80000>; ++ label = "u-boot"; ++ }; ++ ++ pfm@80000 { ++ reg = <0x80000 0x20000>; ++ label = "pfm"; ++ }; ++ ++ u-boot-env@a0000 { ++ reg = <0xa0000 0x20000>; ++ label = "u-boot-env"; ++ }; ++ ++ sofs@c0000 { ++ reg = <0xc0000 0x200000>; ++ label = "sofs"; ++ }; ++ ++ rwfs@2c0000 { ++ reg = <0x2c0000 0x840000>; ++ label = "rwfs"; ++ }; ++ ++ fit-image-a@b00000 { ++ reg = <0xb00000 0x1f00000>; ++ label = "image-a"; ++ }; ++ ++ rc-image@2a00000 { ++ reg = <0x2a00000 0x2000000>; ++ label = "rc-image"; ++ }; ++ ++ image-staging@4a00000 { ++ reg = <0x4a00000 0x3600000>; ++ label = "image-stg"; ++ }; ++ ++}; +diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi +new file mode 100644 +index 000000000000..092708f5021f +--- /dev/null ++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// 64MB flash layout: redundant image with common RW partition ++ ++partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ u-boot@0 { ++ reg = <0x0 0x80000>; ++ label = "u-boot"; ++ }; ++ ++ fit-image-a@80000 { ++ reg = <0x80000 0x1b80000>; ++ label = "image-a"; ++ }; ++ ++ sofs@1c00000 { ++ reg = <0x1c00000 0x200000>; ++ label = "sofs"; ++ }; ++ ++ rwfs@1e00000 { ++ reg = <0x1e00000 0x600000>; ++ label = "rwfs"; ++ }; ++ ++ u-boot-env@2400000 { ++ reg = <0x2400000 0x20000>; ++ label = "u-boot-env"; ++ }; ++ ++ fit-image-b@2480000 { ++ reg = <0x2480000 0x1b80000>; ++ label = "image-b"; ++ }; ++}; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch new file mode 100644 index 000000000..950272e1b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch @@ -0,0 +1,760 @@ +From a49e262cca260d15dc245fdd1870c89068042063 Mon Sep 17 00:00:00 2001 +From: "Feist, James" <james.feist@intel.com> +Date: Tue, 4 Jun 2019 14:00:39 -0700 +Subject: [PATCH] Add ASPEED SGPIO driver + +Add SGPIO driver support for Aspeed SoCs. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/gpio/Kconfig | 8 + + drivers/gpio/Makefile | 1 + + drivers/gpio/sgpio-aspeed.c | 704 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 713 insertions(+) + create mode 100644 drivers/gpio/sgpio-aspeed.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 7138290cdd36..0235b20a95f6 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -128,6 +128,14 @@ config GPIO_ASPEED_SGPIO + help + Say Y here to support Aspeed AST2500 SGPIO functionality. + ++config SGPIO_ASPEED ++ tristate "ASPEED SGPIO support" ++ depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO ++ select GPIO_GENERIC ++ select GPIOLIB_IRQCHIP ++ help ++ Say Y here to support ASPEED SGPIO functionality. ++ + config GPIO_ATH79 + tristate "Atheros AR71XX/AR724X/AR913X GPIO support" + default y if ATH79 +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index e4599f90f702..0e80c8cd5ae7 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o + obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o + obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o + obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o ++obj-$(CONFIG_SGPIO_ASPEED) += sgpio-aspeed.o + obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o + obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o + obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o +diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c +new file mode 100644 +index 000000000000..5028e9144a75 +--- /dev/null ++++ b/drivers/gpio/sgpio-aspeed.c +@@ -0,0 +1,704 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2019 Intel Corporation ++ ++#include <linux/bitfield.h> ++#include <linux/clk.h> ++#include <linux/gpio/driver.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++ ++#define ASPEED_SGPIO_CTRL 0x54 ++#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) ++#define ASPEED_SGPIO_CLK_DIV_MIN 1 ++#define ASPEED_SGPIO_CLK_DIV_MAX 65535 ++#define ASPEED_SGPIO_PINBYTES_MASK GENMASK(9, 6) ++#define ASPEED_SGPIO_PINBYTES_MIN 1 ++#define ASPEED_SGPIO_PINBYTES_MAX 10 ++#define ASPEED_SGPIO_ENABLE BIT(0) ++ ++#define ASPEED_SGPIO_BUS_FREQ_DEFAULT 1000000 ++ ++struct aspeed_bank_props { ++ unsigned int bank; ++ u32 input; ++ u32 output; ++}; ++ ++struct aspeed_sgpio_config { ++ unsigned int nr_pgpios; ++ unsigned int nr_gpios; ++ const struct aspeed_bank_props *props; ++}; ++ ++struct aspeed_sgpio { ++ struct gpio_chip chip; ++ struct irq_chip irqc; ++ spinlock_t lock; ++ void __iomem *base; ++ int irq; ++ const struct aspeed_sgpio_config *config; ++}; ++ ++struct aspeed_sgpio_bank { ++ uint16_t val_reg; ++ uint16_t rdata_reg; ++ uint16_t tolerance_reg; ++ uint16_t irq_regs; ++ bool support_irq; ++ const char names[4][3]; ++}; ++ ++/* ++ * Note: The "val" register returns the input value sampled on the line. ++ * Or, it can be used for writing a value on the line. ++ * ++ * The "rdata" register returns the content of the write latch and thus ++ * can be used to read back what was last written reliably. ++ */ ++ ++static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { ++ { ++ .val_reg = 0x0000, ++ .rdata_reg = 0x0070, ++ .tolerance_reg = 0x0018, ++ .irq_regs = 0x0004, ++ .support_irq = false, ++ .names = { "OA", "OB", "OC", "OD" }, ++ }, ++ { ++ .val_reg = 0x001C, ++ .rdata_reg = 0x0074, ++ .tolerance_reg = 0x0034, ++ .irq_regs = 0x0020, ++ .support_irq = false, ++ .names = { "OE", "OF", "OG", "OH" }, ++ }, ++ { ++ .val_reg = 0x0038, ++ .rdata_reg = 0x0078, ++ .tolerance_reg = 0x0050, ++ .irq_regs = 0x003C, ++ .support_irq = false, ++ .names = { "OI", "OJ" }, ++ }, ++ { ++ .val_reg = 0x0000, ++ .rdata_reg = 0x0070, ++ .tolerance_reg = 0x0018, ++ .irq_regs = 0x0004, ++ .support_irq = true, ++ .names = { "IA", "IB", "IC", "ID" }, ++ }, ++ { ++ .val_reg = 0x001C, ++ .rdata_reg = 0x0074, ++ .tolerance_reg = 0x0034, ++ .irq_regs = 0x0020, ++ .support_irq = true, ++ .names = { "IE", "IF", "IG", "IH" }, ++ }, ++ { ++ .val_reg = 0x0038, ++ .rdata_reg = 0x0078, ++ .tolerance_reg = 0x0050, ++ .irq_regs = 0x003C, ++ .support_irq = true, ++ .names = { "II", "IJ" }, ++ }, ++}; ++ ++enum aspeed_sgpio_reg { ++ reg_val, ++ reg_rdata, ++ reg_irq_enable, ++ reg_irq_type0, ++ reg_irq_type1, ++ reg_irq_type2, ++ reg_irq_status, ++ reg_tolerance, ++}; ++ ++#define GPIO_IRQ_ENABLE 0x00 ++#define GPIO_IRQ_TYPE0 0x04 ++#define GPIO_IRQ_TYPE1 0x08 ++#define GPIO_IRQ_TYPE2 0x0c ++#define GPIO_IRQ_STATUS 0x10 ++ ++/* This will be resolved at compile time */ ++static inline void __iomem *bank_reg(struct aspeed_sgpio *gpio, ++ const struct aspeed_sgpio_bank *bank, ++ const enum aspeed_sgpio_reg reg) ++{ ++ switch (reg) { ++ case reg_val: ++ return gpio->base + bank->val_reg; ++ case reg_rdata: ++ return gpio->base + bank->rdata_reg; ++ case reg_irq_enable: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; ++ case reg_irq_type0: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; ++ case reg_irq_type1: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; ++ case reg_irq_type2: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; ++ case reg_irq_status: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; ++ case reg_tolerance: ++ return gpio->base + bank->tolerance_reg; ++ default: ++ WARN_ON(1); ++ } ++ ++ return NULL; ++} ++ ++#define GPIO_BANK(x) ((x) >> 5) ++#define GPIO_OFFSET(x) ((x) & 0x1f) ++#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) ++ ++static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) ++{ ++ unsigned int bank = GPIO_BANK(offset); ++ ++ WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); ++ return &aspeed_sgpio_banks[bank]; ++} ++ ++static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props) ++{ ++ return !(props->input || props->output); ++} ++ ++static inline const struct aspeed_bank_props *find_bank_props( ++ struct aspeed_sgpio *gpio, unsigned int offset) ++{ ++ const struct aspeed_bank_props *props = gpio->config->props; ++ ++ while (!is_bank_props_sentinel(props)) { ++ if (props->bank == GPIO_BANK(offset)) ++ return props; ++ props++; ++ } ++ ++ return NULL; ++} ++ ++static inline bool have_input(struct aspeed_sgpio *gpio, unsigned int offset) ++{ ++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset); ++ ++ return !props || (props->input & GPIO_BIT(offset)); ++} ++ ++static inline bool have_output(struct aspeed_sgpio *gpio, unsigned int offset) ++{ ++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset); ++ ++ return !props || (props->output & GPIO_BIT(offset)); ++} ++ ++static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ enum aspeed_sgpio_reg reg; ++ ++ if (have_output(gpio, offset)) ++ reg = reg_rdata; ++ else ++ reg = reg_val; ++ ++ return !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); ++} ++ ++static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) ++{ ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ unsigned long flags; ++ u32 reg; ++ ++ if (!have_output(gpio, offset)) ++ return; ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ reg = ioread32(bank_reg(gpio, bank, reg_rdata)); ++ ++ if (val) ++ reg |= GPIO_BIT(offset); ++ else ++ reg &= ~GPIO_BIT(offset); ++ ++ iowrite32(reg, bank_reg(gpio, bank, reg_val)); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ ++ if (!have_input(gpio, offset)) ++ return -ENOTSUPP; ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, ++ int val) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ ++ if (!have_output(gpio, offset)) ++ return -ENOTSUPP; ++ ++ aspeed_sgpio_set(gc, offset, val); ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ ++ if (have_output(gpio, offset)) ++ return 0; ++ else if (have_input(gpio, offset)) ++ return 1; ++ ++ return -ENOTSUPP; ++} ++ ++static inline int ++irqd_to_aspeed_sgpio_data(struct irq_data *d, struct aspeed_sgpio **gpio, ++ const struct aspeed_sgpio_bank **bank, ++ u32 *bit, int *offset) ++{ ++ struct aspeed_sgpio *internal; ++ ++ *offset = irqd_to_hwirq(d); ++ ++ internal = irq_data_get_irq_chip_data(d); ++ ++ *gpio = internal; ++ *bank = to_bank(*offset); ++ *bit = GPIO_BIT(*offset); ++ ++ return 0; ++} ++ ++static void aspeed_sgpio_irq_ack(struct irq_data *d) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ struct aspeed_sgpio *gpio; ++ void __iomem *status_addr; ++ unsigned long flags; ++ int rc, offset; ++ u32 bit; ++ ++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ if (rc) ++ return; ++ ++ status_addr = bank_reg(gpio, bank, reg_irq_status); ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ iowrite32(bit, status_addr); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ struct aspeed_sgpio *gpio; ++ unsigned long flags; ++ u32 reg, bit; ++ void __iomem *addr; ++ int rc, offset; ++ ++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ if (rc) ++ return; ++ ++ if (!bank->support_irq) ++ return; ++ ++ addr = bank_reg(gpio, bank, reg_irq_enable); ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ reg = ioread32(addr); ++ if (set) ++ reg |= bit; ++ else ++ reg &= ~bit; ++ ++ iowrite32(reg, addr); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static void aspeed_sgpio_irq_mask(struct irq_data *d) ++{ ++ aspeed_sgpio_irq_set_mask(d, false); ++} ++ ++static void aspeed_sgpio_irq_unmask(struct irq_data *d) ++{ ++ aspeed_sgpio_irq_set_mask(d, true); ++} ++ ++static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) ++{ ++ u32 type0 = 0; ++ u32 type1 = 0; ++ u32 type2 = 0; ++ u32 bit, reg; ++ const struct aspeed_sgpio_bank *bank; ++ irq_flow_handler_t handler; ++ struct aspeed_sgpio *gpio; ++ unsigned long flags; ++ void __iomem *addr; ++ int rc, offset; ++ ++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ if (rc) ++ return -EINVAL; ++ ++ if (!bank->support_irq) ++ return -ENOTSUPP; ++ ++ switch (type & IRQ_TYPE_SENSE_MASK) { ++ case IRQ_TYPE_EDGE_BOTH: ++ type2 |= bit; ++ /* fall through */ ++ case IRQ_TYPE_EDGE_RISING: ++ type0 |= bit; ++ /* fall through */ ++ case IRQ_TYPE_EDGE_FALLING: ++ handler = handle_edge_irq; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ type0 |= bit; ++ /* fall through */ ++ case IRQ_TYPE_LEVEL_LOW: ++ type1 |= bit; ++ handler = handle_level_irq; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ addr = bank_reg(gpio, bank, reg_irq_type0); ++ reg = ioread32(addr); ++ reg = (reg & ~bit) | type0; ++ iowrite32(reg, addr); ++ ++ addr = bank_reg(gpio, bank, reg_irq_type1); ++ reg = ioread32(addr); ++ reg = (reg & ~bit) | type1; ++ iowrite32(reg, addr); ++ ++ addr = bank_reg(gpio, bank, reg_irq_type2); ++ reg = ioread32(addr); ++ reg = (reg & ~bit) | type2; ++ iowrite32(reg, addr); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ irq_set_handler_locked(d, handler); ++ ++ return 0; ++} ++ ++static void aspeed_sgpio_irq_handler(struct irq_desc *desc) ++{ ++ struct gpio_chip *gc = irq_desc_get_handler_data(desc); ++ struct aspeed_sgpio *data = gpiochip_get_data(gc); ++ struct irq_chip *ic = irq_desc_get_chip(desc); ++ unsigned int i, p, girq; ++ unsigned long reg; ++ ++ chained_irq_enter(ic, desc); ++ ++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { ++ const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; ++ ++ if (!bank->support_irq) ++ continue; ++ ++ reg = ioread32(bank_reg(data, bank, reg_irq_status)); ++ ++ for_each_set_bit(p, ®, 32) { ++ girq = irq_find_mapping(gc->irq.domain, i * 32 + p); ++ generic_handle_irq(girq); ++ } ++ } ++ ++ chained_irq_exit(ic, desc); ++} ++ ++static void aspeed_sgpio_init_irq_valid_mask(struct gpio_chip *gc, ++ unsigned long *valid_mask, ++ unsigned int ngpios) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ const struct aspeed_bank_props *props = gpio->config->props; ++ ++ while (!is_bank_props_sentinel(props)) { ++ unsigned int offset; ++ const unsigned long int input = props->input; ++ ++ /* Pretty crummy approach, but similar to GPIO core */ ++ for_each_clear_bit(offset, &input, 32) { ++ unsigned int i = props->bank * 32 + offset; ++ ++ if (i >= gpio->chip.ngpio) ++ break; ++ ++ clear_bit(i, valid_mask); ++ } ++ ++ props++; ++ } ++} ++ ++static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, ++ struct platform_device *pdev) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ struct gpio_irq_chip *girq; ++ int rc, i; ++ ++ /* Initialize IRQ and tolerant settings */ ++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { ++ bank = &aspeed_sgpio_banks[i]; ++ ++ /* Value will be reset by WDT reset */ ++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_tolerance)); ++ ++ if (!bank->support_irq) ++ continue; ++ ++ /* disable irq enable bits */ ++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); ++ /* clear status bits */ ++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); ++ /* set rising or level-high irq */ ++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type0)); ++ /* trigger type is level */ ++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type1)); ++ /* single trigger mode */ ++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); ++ } ++ ++ rc = platform_get_irq(pdev, 0); ++ if (rc < 0) ++ return rc; ++ ++ gpio->irq = rc; ++ girq = &gpio->chip.irq; ++ girq->chip = &gpio->irqc; ++ girq->chip->name = dev_name(&pdev->dev); ++ girq->chip->irq_ack = aspeed_sgpio_irq_ack; ++ girq->chip->irq_mask = aspeed_sgpio_irq_mask; ++ girq->chip->irq_unmask = aspeed_sgpio_irq_unmask; ++ girq->chip->irq_set_type = aspeed_sgpio_set_type; ++ girq->parent_handler = aspeed_sgpio_irq_handler; ++ girq->num_parents = 1; ++ girq->parents = devm_kcalloc(&pdev->dev, 1, ++ sizeof(*girq->parents), ++ GFP_KERNEL); ++ if (!girq->parents) ++ return -ENOMEM; ++ girq->parents[0] = gpio->irq; ++ girq->default_type = IRQ_TYPE_NONE; ++ girq->handler = handle_bad_irq; ++ girq->init_valid_mask = aspeed_sgpio_init_irq_valid_mask; ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, ++ unsigned int offset, bool enable) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(chip); ++ unsigned long flags; ++ void __iomem *treg; ++ u32 val; ++ ++ treg = bank_reg(gpio, to_bank(offset), reg_tolerance); ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ val = readl(treg); ++ ++ if (enable) ++ val |= GPIO_BIT(offset); ++ else ++ val &= ~GPIO_BIT(offset); ++ ++ writel(val, treg); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, ++ unsigned long config) ++{ ++ unsigned long param = pinconf_to_config_param(config); ++ u32 arg = pinconf_to_config_argument(config); ++ ++ if (param == PIN_CONFIG_PERSIST_STATE) ++ return aspeed_sgpio_reset_tolerance(chip, offset, arg); ++ ++ return -ENOTSUPP; ++} ++ ++/* ++ * Any banks not specified in a struct aspeed_bank_props array are assumed to ++ * have the properties: ++ * ++ * { .input = 0xffffffff, .output = 0xffffffff } ++ */ ++ ++static const struct aspeed_bank_props ast_sgpio_bank_props[] = { ++ /* input output */ ++ { 0, 0x00000000, 0xffffffff }, /* OA/OB/OC/OD */ ++ { 1, 0x00000000, 0xffffffff }, /* OE/OF/OG/OH */ ++ { 2, 0x00000000, 0x0000ffff }, /* OI/OJ */ ++ { 3, 0xffffffff, 0x00000000 }, /* IA/IB/IC/ID */ ++ { 4, 0xffffffff, 0x00000000 }, /* IE/IF/IG/IH */ ++ { 5, 0x0000ffff, 0x00000000 }, /* II/IJ */ ++ { } ++}; ++ ++/* ++ * This H/W has 80 bidirectional lines so this driver provides total 160 lines ++ * for 80 outputs and 80 inputs. To simplify bank register manipulation, it ++ * uses 96 lines per each input and output set so total 192 lines it has. ++ */ ++static const struct aspeed_sgpio_config ast2400_config = ++ { .nr_pgpios = 224, .nr_gpios = 192, .props = ast_sgpio_bank_props }; ++ ++static const struct aspeed_sgpio_config ast2500_config = ++ { .nr_pgpios = 232, .nr_gpios = 192, .props = ast_sgpio_bank_props }; ++ ++static const struct of_device_id aspeed_sgpio_of_table[] = { ++ { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_config }, ++ { .compatible = "aspeed,ast2500-sgpio", .data = &ast2500_config }, ++ { .compatible = "aspeed,ast2600-sgpio", .data = &ast2500_config }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); ++ ++static int __init aspeed_sgpio_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *gpio_id; ++ u32 sgpio_freq, clk_div, nb_gpios; ++ struct aspeed_sgpio *gpio; ++ unsigned long src_freq; ++ struct clk *clk; ++ int rc; ++ ++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); ++ if (!gpio) ++ return -ENOMEM; ++ ++ gpio->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(gpio->base)) ++ return PTR_ERR(gpio->base); ++ ++ spin_lock_init(&gpio->lock); ++ ++ gpio_id = of_match_node(aspeed_sgpio_of_table, pdev->dev.of_node); ++ if (!gpio_id) ++ return -EINVAL; ++ ++ gpio->config = gpio_id->data; ++ ++ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); ++ if (rc < 0) { ++ dev_warn(&pdev->dev, "Could not read bus-frequency property. Use default.\n"); ++ sgpio_freq = ASPEED_SGPIO_BUS_FREQ_DEFAULT; ++ } ++ ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) { ++ rc = PTR_ERR(clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to get clk source.\n"); ++ return rc; ++ } ++ ++ /* ++ * There is a limitation that SGPIO clock division has to be larger or ++ * equal to 1. And a read back value of clock division is 1-bit left ++ * shifted from the actual value. ++ * ++ * GPIO254[31:16] - Serial GPIO clock division: ++ * Serial GPIO clock period = period of PCLK * 2 * (GPIO254[31:16] + 1) ++ * ++ * SGPIO master controller updates every data input when SGPMLD is low. ++ * For an example, SGPIO clock is 1MHz and number of SGPIO is 80. Each ++ * SGPIO will be updated every 80us. ++ */ ++ src_freq = clk_get_rate(clk); ++ clk_div = src_freq / (2 * sgpio_freq) - 1; ++ if (clk_div < ASPEED_SGPIO_CLK_DIV_MIN) ++ clk_div = ASPEED_SGPIO_CLK_DIV_MIN; ++ else if (clk_div > ASPEED_SGPIO_CLK_DIV_MAX) ++ clk_div = ASPEED_SGPIO_CLK_DIV_MAX; ++ ++ nb_gpios = gpio->config->nr_gpios / 16; ++ if (nb_gpios < ASPEED_SGPIO_PINBYTES_MIN) ++ nb_gpios = ASPEED_SGPIO_PINBYTES_MIN; ++ else if (nb_gpios > ASPEED_SGPIO_PINBYTES_MAX) ++ nb_gpios = ASPEED_SGPIO_PINBYTES_MAX; ++ ++ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, clk_div) | ++ FIELD_PREP(ASPEED_SGPIO_PINBYTES_MASK, nb_gpios) | ++ ASPEED_SGPIO_ENABLE, ++ gpio->base + ASPEED_SGPIO_CTRL); ++ ++ gpio->chip.parent = &pdev->dev; ++ gpio->chip.ngpio = gpio->config->nr_gpios; ++ ++ gpio->chip.direction_input = aspeed_sgpio_dir_in; ++ gpio->chip.direction_output = aspeed_sgpio_dir_out; ++ gpio->chip.get_direction = aspeed_sgpio_get_direction; ++ gpio->chip.get = aspeed_sgpio_get; ++ gpio->chip.set = aspeed_sgpio_set; ++ gpio->chip.set_config = aspeed_sgpio_set_config; ++ gpio->chip.label = dev_name(&pdev->dev); ++ gpio->chip.base = -1; ++ ++ rc = aspeed_sgpio_setup_irqs(gpio, pdev); ++ if (rc < 0) ++ return rc; ++ ++ return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); ++} ++ ++static struct platform_driver aspeed_sgpio_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_sgpio_of_table, ++ }, ++}; ++ ++module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); ++ ++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); ++MODULE_DESCRIPTION("Aspeed SGPIO Master Driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch new file mode 100644 index 000000000..50c31f625 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch @@ -0,0 +1,227 @@ +From 89b5ebd26fc44b4bf820aa507bc88eec028ba218 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Wed, 16 May 2018 10:03:14 -0700 +Subject: [PATCH] SGPIO DT and pinctrl fixup + +This commit fixes DT and pinctrl for SGPIO use. + +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/boot/dts/aspeed-g4.dtsi | 56 +++++++++++------------------- + arch/arm/boot/dts/aspeed-g5.dtsi | 3 +- + arch/arm/boot/dts/aspeed-g6.dtsi | 15 ++++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 ++++++++++++------------- + 4 files changed, 60 insertions(+), 62 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index b875c0785833..e9fd66ab3099 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -254,6 +254,20 @@ + #interrupt-cells = <2>; + }; + ++ sgpio: sgpio@1e780200 { ++ #gpio-cells = <2>; ++ gpio-controller; ++ compatible = "aspeed,ast2400-sgpio"; ++ reg = <0x1e780200 0x0100>; ++ interrupts = <40>; ++ interrupt-controller; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ bus-frequency = <1000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sgpm_default>; ++ status = "disabled"; ++ }; ++ + timer: timer@1e782000 { + /* This timer is a Faraday FTTMR010 derivative */ + compatible = "aspeed,ast2400-timer"; +@@ -1227,44 +1241,14 @@ + groups = "SD2"; + }; + +- pinctrl_sgpmck_default: sgpmck_default { +- function = "SGPMCK"; +- groups = "SGPMCK"; +- }; +- +- pinctrl_sgpmi_default: sgpmi_default { +- function = "SGPMI"; +- groups = "SGPMI"; +- }; +- +- pinctrl_sgpmld_default: sgpmld_default { +- function = "SGPMLD"; +- groups = "SGPMLD"; +- }; +- +- pinctrl_sgpmo_default: sgpmo_default { +- function = "SGPMO"; +- groups = "SGPMO"; +- }; +- +- pinctrl_sgpsck_default: sgpsck_default { +- function = "SGPSCK"; +- groups = "SGPSCK"; +- }; +- +- pinctrl_sgpsi0_default: sgpsi0_default { +- function = "SGPSI0"; +- groups = "SGPSI0"; +- }; +- +- pinctrl_sgpsi1_default: sgpsi1_default { +- function = "SGPSI1"; +- groups = "SGPSI1"; ++ pinctrl_sgpm_default: sgpm_default { ++ function = "SGPM"; ++ groups = "SGPM"; + }; + +- pinctrl_sgpsld_default: sgpsld_default { +- function = "SGPSLD"; +- groups = "SGPSLD"; ++ pinctrl_sgps_default: sgps_default { ++ function = "SGPS"; ++ groups = "SGPS"; + }; + + pinctrl_sioonctrl_default: sioonctrl_default { +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 452ec323534f..20b2eb8052b7 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -326,8 +326,7 @@ + reg = <0x1e780200 0x0100>; + clocks = <&syscon ASPEED_CLK_APB>; + interrupt-controller; +- ngpios = <8>; +- bus-frequency = <12000000>; ++ bus-frequency = <1000000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sgpm_default>; + status = "disabled"; +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 54add29d8217..459070693aba 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -339,6 +339,21 @@ + #interrupt-cells = <2>; + }; + ++ sgpio: sgpio@1e780500 { ++ #gpio-cells = <2>; ++ gpio-controller; ++ compatible = "aspeed,ast2600-sgpio"; ++ reg = <0x1e780500 0x0100>; ++ #interrupt-cells = <2>; ++ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-controller; ++ bus-frequency = <1000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sgpm1_default>; ++ clocks = <&syscon ASPEED_CLK_APB1>; ++ status = "disabled"; ++ }; ++ + rtc: rtc@1e781000 { + compatible = "aspeed,ast2600-rtc"; + reg = <0x1e781000 0x18>; +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +index bfed0e274643..10dadfd0e6e1 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +@@ -430,16 +430,22 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30)); + SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31)); + + #define A14 48 +-SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0)); ++SIG_EXPR_LIST_DECL_SINGLE(A14, SGPSCK, SGPS, SIG_DESC_SET(SCU84, 0)); ++PIN_DECL_1(A14, GPIOG0, SGPSCK); + + #define E13 49 +-SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1)); ++SIG_EXPR_LIST_DECL_SINGLE(E13, SGPSLD, SGPS, SIG_DESC_SET(SCU84, 1)); ++PIN_DECL_1(E13, GPIOG1, SGPSLD); + + #define D13 50 +-SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2)); ++SIG_EXPR_LIST_DECL_SINGLE(D13, SGPSIO, SGPS, SIG_DESC_SET(SCU84, 2)); ++PIN_DECL_1(D13, GPIOG2, SGPSIO); + + #define C13 51 +-SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3)); ++SIG_EXPR_LIST_DECL_SINGLE(C13, SGPSI1, SGPS, SIG_DESC_SET(SCU84, 3)); ++PIN_DECL_1(C13, GPIOG3, SGPSI1); ++ ++FUNC_GROUP_DECL(SGPS, A14, E13, D13, C13); + + #define B13 52 + SIG_EXPR_LIST_DECL_SINGLE(B13, OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1)); +@@ -613,16 +619,22 @@ FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20); + FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20); + + #define J5 72 +-SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8)); ++SIG_EXPR_LIST_DECL_SINGLE(J5, SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8)); ++PIN_DECL_1(J5, GPIOJ0, SGPMCK); + + #define J4 73 +-SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9)); ++SIG_EXPR_LIST_DECL_SINGLE(J4, SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9)); ++PIN_DECL_1(J4, GPIOJ1, SGPMLD); + + #define K5 74 +-SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10)); ++SIG_EXPR_LIST_DECL_SINGLE(K5, SGPMO, SGPM, SIG_DESC_SET(SCU84, 10)); ++PIN_DECL_1(K5, GPIOJ2, SGPMO); + + #define J3 75 +-SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11)); ++SIG_EXPR_LIST_DECL_SINGLE(J3, SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); ++PIN_DECL_1(J3, GPIOJ3, SGPMI); ++ ++FUNC_GROUP_DECL(SGPM, J5, J4, K5, J3); + + #define T4 76 + SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, SIG_DESC_SET(SCU84, 12)); +@@ -2234,14 +2246,8 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { + ASPEED_PINCTRL_GROUP(SALT4), + ASPEED_PINCTRL_GROUP(SD1), + ASPEED_PINCTRL_GROUP(SD2), +- ASPEED_PINCTRL_GROUP(SGPMCK), +- ASPEED_PINCTRL_GROUP(SGPMI), +- ASPEED_PINCTRL_GROUP(SGPMLD), +- ASPEED_PINCTRL_GROUP(SGPMO), +- ASPEED_PINCTRL_GROUP(SGPSCK), +- ASPEED_PINCTRL_GROUP(SGPSI0), +- ASPEED_PINCTRL_GROUP(SGPSI1), +- ASPEED_PINCTRL_GROUP(SGPSLD), ++ ASPEED_PINCTRL_GROUP(SGPM), ++ ASPEED_PINCTRL_GROUP(SGPS), + ASPEED_PINCTRL_GROUP(SIOONCTRL), + ASPEED_PINCTRL_GROUP(SIOPBI), + ASPEED_PINCTRL_GROUP(SIOPBO), +@@ -2389,14 +2395,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { + ASPEED_PINCTRL_FUNC(SALT4), + ASPEED_PINCTRL_FUNC(SD1), + ASPEED_PINCTRL_FUNC(SD2), +- ASPEED_PINCTRL_FUNC(SGPMCK), +- ASPEED_PINCTRL_FUNC(SGPMI), +- ASPEED_PINCTRL_FUNC(SGPMLD), +- ASPEED_PINCTRL_FUNC(SGPMO), +- ASPEED_PINCTRL_FUNC(SGPSCK), +- ASPEED_PINCTRL_FUNC(SGPSI0), +- ASPEED_PINCTRL_FUNC(SGPSI1), +- ASPEED_PINCTRL_FUNC(SGPSLD), ++ ASPEED_PINCTRL_FUNC(SGPM), ++ ASPEED_PINCTRL_FUNC(SGPS), + ASPEED_PINCTRL_FUNC(SIOONCTRL), + ASPEED_PINCTRL_FUNC(SIOPBI), + ASPEED_PINCTRL_FUNC(SIOPBO), +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch new file mode 100644 index 000000000..128b11ecf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch @@ -0,0 +1,425 @@ +From f588865f8180a6370ac639bdfc186ffc5b926246 Mon Sep 17 00:00:00 2001 +From: Haiyue Wang <haiyue.wang@linux.intel.com> +Date: Tue, 13 Feb 2018 14:28:12 +0800 +Subject: [PATCH] Add I2C IPMB support + +Some protocols over I2C are designed for bi-directional transferring +messages by using I2C Master Write protocol. Like the MCTP (Management +Component Transport Protocol) and IPMB (Intelligent Platform Management +Bus), they both require that the userspace can receive messages from +I2C dirvers under slave mode. + +This new slave mqueue backend is used to receive and queue messages, it +will exposes these messages to userspace by sysfs bin file. + +Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com> +--- + Documentation/i2c/slave-mqueue-backend.rst | 124 +++++++++++++++++ + drivers/i2c/Kconfig | 23 +++ + drivers/i2c/Makefile | 1 + + drivers/i2c/i2c-slave-mqueue.c | 217 +++++++++++++++++++++++++++++ + 4 files changed, 365 insertions(+) + create mode 100644 Documentation/i2c/slave-mqueue-backend.rst + create mode 100644 drivers/i2c/i2c-slave-mqueue.c + +diff --git a/Documentation/i2c/slave-mqueue-backend.rst b/Documentation/i2c/slave-mqueue-backend.rst +new file mode 100644 +index 000000000000..2d0d06d8df9d +--- /dev/null ++++ b/Documentation/i2c/slave-mqueue-backend.rst +@@ -0,0 +1,124 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++===================================== ++Linux I2C slave message queue backend ++===================================== ++ ++:Author: Haiyue Wang <haiyue.wang@linux.intel.com> ++ ++Some protocols over I2C/SMBus are designed for bi-directional transferring ++messages by using I2C Master Write protocol. This requires that both sides ++of the communication have slave addresses. ++ ++Like MCTP (Management Component Transport Protocol) and IPMB (Intelligent ++Platform Management Bus), they both require that the userspace can receive ++messages from i2c dirvers under slave mode. ++ ++This I2C slave mqueue (message queue) backend is used to receive and queue ++messages from the remote i2c intelligent device; and it will add the target ++slave address (with R/W# bit is always 0) into the message at the first byte, ++so that userspace can use this byte to dispatch the messages into different ++handling modules. Also, like IPMB, the address byte is in its message format, ++it needs it to do checksum. ++ ++For messages are time related, so this backend will flush the oldest message ++to queue the newest one. ++ ++Link ++---- ++`Intelligent Platform Management Bus ++Communications Protocol Specification ++<https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmp-spec-v1.0.pdf>`_ ++ ++`Management Component Transport Protocol (MCTP) ++SMBus/I2C Transport Binding Specification ++<https://www.dmtf.org/sites/default/files/standards/documents/DSP0237_1.1.0.pdf>`_ ++ ++How to use ++---------- ++For example, the I2C5 bus has slave address 0x10, the below command will create ++the related message queue interface: ++ ++ echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-5/new_device ++ ++Then you can dump the messages like this: ++ ++ hexdump -C /sys/bus/i2c/devices/5-1010/slave-mqueue ++ ++Code Example ++------------ ++*Note: call 'lseek' before 'read', this is a requirement from kernfs' design.* ++ ++:: ++ ++ #include <sys/types.h> ++ #include <sys/stat.h> ++ #include <unistd.h> ++ #include <poll.h> ++ #include <time.h> ++ #include <fcntl.h> ++ #include <stdio.h> ++ ++ int main(int argc, char *argv[]) ++ { ++ int i, r; ++ struct pollfd pfd; ++ struct timespec ts; ++ unsigned char data[256]; ++ ++ pfd.fd = open(argv[1], O_RDONLY | O_NONBLOCK); ++ if (pfd.fd < 0) ++ return -1; ++ ++ pfd.events = POLLPRI; ++ ++ while (1) { ++ r = poll(&pfd, 1, 5000); ++ ++ if (r < 0) ++ break; ++ ++ if (r == 0 || !(pfd.revents & POLLPRI)) ++ continue; ++ ++ lseek(pfd.fd, 0, SEEK_SET); ++ r = read(pfd.fd, data, sizeof(data)); ++ if (r <= 0) ++ continue; ++ ++ clock_gettime(CLOCK_MONOTONIC, &ts); ++ printf("[%ld.%.9ld] :", ts.tv_sec, ts.tv_nsec); ++ for (i = 0; i < r; i++) ++ printf(" %02x", data[i]); ++ printf("\n"); ++ } ++ ++ close(pfd.fd); ++ ++ return 0; ++ } ++ ++Result ++------ ++*./a.out "/sys/bus/i2c/devices/5-1010/slave-mqueue"* ++ ++:: ++ ++ [10183.232500449] : 20 18 c8 2c 78 01 5b ++ [10183.479358348] : 20 18 c8 2c 78 01 5b ++ [10183.726556812] : 20 18 c8 2c 78 01 5b ++ [10183.972605863] : 20 18 c8 2c 78 01 5b ++ [10184.220124772] : 20 18 c8 2c 78 01 5b ++ [10184.467764166] : 20 18 c8 2c 78 01 5b ++ [10193.233421784] : 20 18 c8 2c 7c 01 57 ++ [10193.480273460] : 20 18 c8 2c 7c 01 57 ++ [10193.726788733] : 20 18 c8 2c 7c 01 57 ++ [10193.972781945] : 20 18 c8 2c 7c 01 57 ++ [10194.220487360] : 20 18 c8 2c 7c 01 57 ++ [10194.468089259] : 20 18 c8 2c 7c 01 57 ++ [10203.233433099] : 20 18 c8 2c 80 01 53 ++ [10203.481058715] : 20 18 c8 2c 80 01 53 ++ [10203.727610472] : 20 18 c8 2c 80 01 53 ++ [10203.974044856] : 20 18 c8 2c 80 01 53 ++ [10204.220734634] : 20 18 c8 2c 80 01 53 ++ [10204.468461664] : 20 18 c8 2c 80 01 53 +diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig +index abedd55a1264..49a2379876c6 100644 +--- a/drivers/i2c/Kconfig ++++ b/drivers/i2c/Kconfig +@@ -119,6 +119,29 @@ if I2C_SLAVE + config I2C_SLAVE_EEPROM + tristate "I2C eeprom slave driver" + ++config I2C_SLAVE_MQUEUE_MESSAGE_SIZE ++ int "The message size of I2C mqueue slave" ++ default 120 ++ ++config I2C_SLAVE_MQUEUE_QUEUE_SIZE ++ int "The queue size of I2C mqueue slave" ++ default 32 ++ help ++ This number MUST be power of 2. ++ ++config I2C_SLAVE_MQUEUE ++ tristate "I2C mqueue (message queue) slave driver" ++ help ++ Some protocols over I2C are designed for bi-directional transferring ++ messages by using I2C Master Write protocol. This driver is used to ++ receive and queue messages from the remote I2C device. ++ ++ Userspace can get the messages by reading sysfs file that this driver ++ exposes. ++ ++ This support is also available as a module. If so, the module will be ++ called i2c-slave-mqueue. ++ + endif + + config I2C_DEBUG_CORE +diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile +index bed6ba63c983..9a31bc75a446 100644 +--- a/drivers/i2c/Makefile ++++ b/drivers/i2c/Makefile +@@ -16,5 +16,6 @@ obj-$(CONFIG_I2C_MUX) += i2c-mux.o + obj-y += algos/ busses/ muxes/ + obj-$(CONFIG_I2C_STUB) += i2c-stub.o + obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o ++obj-$(CONFIG_I2C_SLAVE_MQUEUE) += i2c-slave-mqueue.o + + ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG +diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c +new file mode 100644 +index 000000000000..6014bca0ff2a +--- /dev/null ++++ b/drivers/i2c/i2c-slave-mqueue.c +@@ -0,0 +1,217 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2017 - 2018, Intel Corporation. ++ ++#include <linux/i2c.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/sysfs.h> ++ ++#define MQ_MSGBUF_SIZE CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE ++#define MQ_QUEUE_SIZE CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE ++#define MQ_QUEUE_NEXT(x) (((x) + 1) & (MQ_QUEUE_SIZE - 1)) ++ ++struct mq_msg { ++ int len; ++ u8 *buf; ++}; ++ ++struct mq_queue { ++ struct bin_attribute bin; ++ struct kernfs_node *kn; ++ ++ spinlock_t lock; /* spinlock for queue index handling */ ++ int in; ++ int out; ++ ++ struct mq_msg *curr; ++ int truncated; /* drop current if truncated */ ++ struct mq_msg *queue; ++}; ++ ++static int i2c_slave_mqueue_callback(struct i2c_client *client, ++ enum i2c_slave_event event, u8 *val) ++{ ++ struct mq_queue *mq = i2c_get_clientdata(client); ++ struct mq_msg *msg = mq->curr; ++ int ret = 0; ++ ++ switch (event) { ++ case I2C_SLAVE_WRITE_REQUESTED: ++ mq->truncated = 0; ++ ++ msg->len = 1; ++ msg->buf[0] = client->addr << 1; ++ break; ++ ++ case I2C_SLAVE_WRITE_RECEIVED: ++ if (msg->len < MQ_MSGBUF_SIZE) { ++ msg->buf[msg->len++] = *val; ++ } else { ++ dev_err(&client->dev, "message is truncated!\n"); ++ mq->truncated = 1; ++ ret = -EINVAL; ++ } ++ break; ++ ++ case I2C_SLAVE_STOP: ++ if (unlikely(mq->truncated || msg->len < 2)) ++ break; ++ ++ spin_lock(&mq->lock); ++ mq->in = MQ_QUEUE_NEXT(mq->in); ++ mq->curr = &mq->queue[mq->in]; ++ mq->curr->len = 0; ++ ++ /* Flush the oldest message */ ++ if (mq->out == mq->in) ++ mq->out = MQ_QUEUE_NEXT(mq->out); ++ spin_unlock(&mq->lock); ++ ++ kernfs_notify(mq->kn); ++ break; ++ ++ default: ++ *val = 0xFF; ++ break; ++ } ++ ++ return ret; ++} ++ ++static ssize_t i2c_slave_mqueue_bin_read(struct file *filp, ++ struct kobject *kobj, ++ struct bin_attribute *attr, ++ char *buf, loff_t pos, size_t count) ++{ ++ struct mq_queue *mq; ++ struct mq_msg *msg; ++ unsigned long flags; ++ bool more = false; ++ ssize_t ret = 0; ++ ++ mq = dev_get_drvdata(container_of(kobj, struct device, kobj)); ++ ++ spin_lock_irqsave(&mq->lock, flags); ++ if (mq->out != mq->in) { ++ msg = &mq->queue[mq->out]; ++ ++ if (msg->len <= count) { ++ ret = msg->len; ++ memcpy(buf, msg->buf, ret); ++ } else { ++ ret = -EOVERFLOW; /* Drop this HUGE one. */ ++ } ++ ++ mq->out = MQ_QUEUE_NEXT(mq->out); ++ if (mq->out != mq->in) ++ more = true; ++ } ++ spin_unlock_irqrestore(&mq->lock, flags); ++ ++ if (more) ++ kernfs_notify(mq->kn); ++ ++ return ret; ++} ++ ++static int i2c_slave_mqueue_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct mq_queue *mq; ++ int ret, i; ++ void *buf; ++ ++ mq = devm_kzalloc(dev, sizeof(*mq), GFP_KERNEL); ++ if (!mq) ++ return -ENOMEM; ++ ++ BUILD_BUG_ON(!is_power_of_2(MQ_QUEUE_SIZE)); ++ ++ buf = devm_kmalloc_array(dev, MQ_QUEUE_SIZE, MQ_MSGBUF_SIZE, ++ GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ mq->queue = devm_kzalloc(dev, sizeof(*mq->queue) * MQ_QUEUE_SIZE, ++ GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ for (i = 0; i < MQ_QUEUE_SIZE; i++) ++ mq->queue[i].buf = buf + i * MQ_MSGBUF_SIZE; ++ ++ i2c_set_clientdata(client, mq); ++ ++ spin_lock_init(&mq->lock); ++ mq->curr = &mq->queue[0]; ++ ++ sysfs_bin_attr_init(&mq->bin); ++ mq->bin.attr.name = "slave-mqueue"; ++ mq->bin.attr.mode = 0400; ++ mq->bin.read = i2c_slave_mqueue_bin_read; ++ mq->bin.size = MQ_MSGBUF_SIZE * MQ_QUEUE_SIZE; ++ ++ ret = sysfs_create_bin_file(&dev->kobj, &mq->bin); ++ if (ret) ++ return ret; ++ ++ mq->kn = kernfs_find_and_get(dev->kobj.sd, mq->bin.attr.name); ++ if (!mq->kn) { ++ sysfs_remove_bin_file(&dev->kobj, &mq->bin); ++ return -EFAULT; ++ } ++ ++ ret = i2c_slave_register(client, i2c_slave_mqueue_callback); ++ if (ret) { ++ kernfs_put(mq->kn); ++ sysfs_remove_bin_file(&dev->kobj, &mq->bin); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int i2c_slave_mqueue_remove(struct i2c_client *client) ++{ ++ struct mq_queue *mq = i2c_get_clientdata(client); ++ ++ i2c_slave_unregister(client); ++ ++ kernfs_put(mq->kn); ++ sysfs_remove_bin_file(&client->dev.kobj, &mq->bin); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id i2c_slave_mqueue_id[] = { ++ { "slave-mqueue", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, i2c_slave_mqueue_id); ++ ++#if IS_ENABLED(CONFIG_OF) ++static const struct of_device_id i2c_slave_mqueue_of_match[] = { ++ { .compatible = "slave-mqueue", .data = (void *)0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, i2c_slave_mqueue_of_match); ++#endif ++ ++static struct i2c_driver i2c_slave_mqueue_driver = { ++ .driver = { ++ .name = "i2c-slave-mqueue", ++ .of_match_table = of_match_ptr(i2c_slave_mqueue_of_match), ++ }, ++ .probe = i2c_slave_mqueue_probe, ++ .remove = i2c_slave_mqueue_remove, ++ .id_table = i2c_slave_mqueue_id, ++}; ++module_i2c_driver(i2c_slave_mqueue_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>"); ++MODULE_DESCRIPTION("I2C slave mode for receiving and queuing messages"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch new file mode 100644 index 000000000..bd468e29d --- /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 5d411ed0d66d3d00232519ed7d4ab6fac45e7c6e 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 e9fd66ab3099..f3edda4ae477 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -393,6 +393,15 @@ + sio_regs: regs { + compatible = "aspeed,bmc-misc"; + }; ++ ++ mbox: mbox@180 { ++ compatible = "aspeed,ast2400-mbox"; ++ reg = <0x180 0x5c>; ++ interrupts = <46>; ++ #mbox-cells = <1>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 20b2eb8052b7..bd6d1461e4bd 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -502,6 +502,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..b4b1bcad8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch @@ -0,0 +1,580 @@ +From 39f76bd49fd481999cf51fbdfbea3e820efc7227 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@intel.com> +Date: Mon, 13 Nov 2017 16:29:44 +0800 +Subject: [PATCH] Aspeed LPC SIO driver + +Add lpc sio device driver for AST2500/2400 + +Signed-off-by: Yong Li <yong.b.li@intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../bindings/soc/aspeed/aspeed-lpc-sio.txt | 17 + + arch/arm/boot/dts/aspeed-g4.dtsi | 7 + + arch/arm/boot/dts/aspeed-g5.dtsi | 7 + + drivers/soc/aspeed/Kconfig | 7 + + drivers/soc/aspeed/Makefile | 1 + + drivers/soc/aspeed/aspeed-lpc-sio.c | 410 +++++++++++++++++++++ + include/uapi/linux/aspeed-lpc-sio.h | 45 +++ + 7 files changed, 494 insertions(+) + create mode 100644 Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt + create mode 100644 drivers/soc/aspeed/aspeed-lpc-sio.c + create mode 100644 include/uapi/linux/aspeed-lpc-sio.h + +diff --git a/Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt b/Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt +new file mode 100644 +index 000000000000..c74ea3a4e5ac +--- /dev/null ++++ b/Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt +@@ -0,0 +1,17 @@ ++* Aspeed LPC SIO driver. ++ ++Required properties: ++- compatible : Should be one of: ++ "aspeed,ast2400-lpc-sio" ++ "aspeed,ast2500-lpc-sio" ++- reg : Should contain lpc-sio registers location and length ++- clocks: contains a phandle to the syscon node describing the clocks. ++ There should then be one cell representing the clock to use. ++ ++Example: ++lpc_sio: lpc-sio@100 { ++ compatible = "aspeed,ast2500-lpc-sio"; ++ reg = <0x100 0x20>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++}; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index f3edda4ae477..a70bee24d058 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -394,6 +394,13 @@ + compatible = "aspeed,bmc-misc"; + }; + ++ lpc_sio: lpc-sio@100 { ++ compatible = "aspeed,ast2400-lpc-sio"; ++ reg = <0x100 0x20>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; ++ + mbox: mbox@180 { + compatible = "aspeed,ast2400-mbox"; + reg = <0x180 0x5c>; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index bd6d1461e4bd..c15be82c3a9d 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -503,6 +503,13 @@ + compatible = "aspeed,bmc-misc"; + }; + ++ lpc_sio: lpc-sio@100 { ++ compatible = "aspeed,ast2500-lpc-sio"; ++ reg = <0x100 0x20>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; ++ + mbox: mbox@180 { + compatible = "aspeed,ast2500-mbox"; + reg = <0x180 0x5c>; +diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig +index a4be8e566bc7..285c19042c65 100644 +--- a/drivers/soc/aspeed/Kconfig ++++ b/drivers/soc/aspeed/Kconfig +@@ -28,6 +28,13 @@ config ASPEED_LPC_MBOX + Expose the ASPEED LPC MBOX registers found on Aspeed SOCs (AST2400 + and AST2500) to userspace. + ++config ASPEED_LPC_SIO ++ tristate "Aspeed ast2400/2500 HOST LPC SIO support" ++ depends on SOC_ASPEED && REGMAP && MFD_SYSCON ++ help ++ Provides a driver to control the LPC SIO interface on ASPEED platform ++ through ioctl()s. ++ + config ASPEED_LPC_SNOOP + tristate "Aspeed ast2500 HOST LPC snoop support" + depends on SOC_ASPEED && REGMAP && MFD_SYSCON +diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile +index f3ff29b874ed..2e547cc47e62 100644 +--- a/drivers/soc/aspeed/Makefile ++++ b/drivers/soc/aspeed/Makefile +@@ -2,5 +2,6 @@ + obj-$(CONFIG_ASPEED_BMC_MISC) += aspeed-bmc-misc.o + obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o + obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o ++obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o + obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o + obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o +diff --git a/drivers/soc/aspeed/aspeed-lpc-sio.c b/drivers/soc/aspeed/aspeed-lpc-sio.c +new file mode 100644 +index 000000000000..d4a4da112ff4 +--- /dev/null ++++ b/drivers/soc/aspeed/aspeed-lpc-sio.c +@@ -0,0 +1,410 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) 2012-2017 ASPEED Technology Inc. ++// Copyright (c) 2017-2020 Intel Corporation ++ ++#include <linux/aspeed-lpc-sio.h> ++#include <linux/clk.h> ++#include <linux/mfd/syscon.h> ++#include <linux/miscdevice.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/poll.h> ++#include <linux/regmap.h> ++ ++#define SOC_NAME "aspeed" ++#define DEVICE_NAME "lpc-sio" ++ ++#define AST_LPC_SWCR0300 0x00 ++#define LPC_PWRGD_STS BIT(30) ++#define LPC_PWRGD_RISING_EVT_STS BIT(29) ++#define LPC_PWRGD_FALLING_EVT_STS BIT(28) ++#define LPC_PWRBTN_STS BIT(27) ++#define LPC_PWRBTN_RISING_EVT_STS BIT(26) ++#define LPC_PWRBTN_FALLING_EVT_STS BIT(25) ++#define LPC_S5N_STS BIT(21) ++#define LPC_S5N_RISING_EVT_STS BIT(20) ++#define LPC_S5N_FALLING_EVT_STS BIT(19) ++#define LPC_S3N_STS BIT(18) ++#define LPC_S3N_RISING_EVT_STS BIT(17) ++#define LPC_S3N_FALLING_EVT_STS BIT(16) ++#define LPC_PWBTO_RAW_STS BIT(15) ++#define LPC_LAST_ONCTL_STS BIT(14) ++#define LPC_WAS_PFAIL_STS BIT(13) ++#define LPC_POWER_UP_FAIL_STS BIT(12) /* Crowbar */ ++#define LPC_PWRBTN_OVERRIDE_STS BIT(11) ++#define LPC_BMC_TRIG_WAKEUP_EVT_STS BIT(8) ++ ++#define AST_LPC_SWCR0704 0x04 ++#define LPC_BMC_TRIG_WAKEUP_EVT_EN BIT(8) ++ ++#define AST_LPC_SWCR0B08 0x08 ++#define LPC_PWREQ_OUTPUT_LEVEL BIT(25) ++#define LPC_PWBTO_OUTPUT_LEVEL BIT(24) ++#define LPC_ONCTL_STS BIT(15) ++#define LPC_ONCTL_GPIO_LEVEL BIT(14) ++#define LPC_ONCTL_EN_GPIO_OUTPUT BIT(13) ++#define LPC_ONCTL_EN_GPIO_MODE BIT(12) ++#define LPC_BMC_TRIG_WAKEUP_EVT BIT(6) ++ ++#define AST_LPC_SWCR0F0C 0x0C ++#define AST_LPC_SWCR1310 0x10 ++#define AST_LPC_SWCR1714 0x14 ++#define AST_LPC_SWCR1B18 0x18 ++#define AST_LPC_SWCR1F1C 0x1C ++#define AST_LPC_ACPIE3E0 0x20 ++#define AST_LPC_ACPIC1C0 0x24 ++ ++#define AST_LPC_ACPIB3B0 0x28 ++#define LPC_BMC_TRIG_SCI_EVT_STS BIT(8) ++ ++#define AST_LPC_ACPIB7B4 0x2C ++#define LPC_BMC_TRIG_SCI_EVT_EN BIT(8) ++ ++struct aspeed_lpc_sio { ++ struct miscdevice miscdev; ++ struct regmap *regmap; ++ struct clk *clk; ++ struct semaphore lock; ++ unsigned int reg_base; ++}; ++ ++static struct aspeed_lpc_sio *file_aspeed_lpc_sio(struct file *file) ++{ ++ return container_of(file->private_data, struct aspeed_lpc_sio, ++ miscdev); ++} ++ ++static int aspeed_lpc_sio_open(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++#define LPC_SLP3N5N_EVENT_STATUS (\ ++ LPC_S5N_RISING_EVT_STS | \ ++ LPC_S5N_FALLING_EVT_STS | \ ++ LPC_S3N_RISING_EVT_STS | \ ++ LPC_S3N_FALLING_EVT_STS) ++ ++/* ++ * SLPS3n SLPS5n State ++ * --------------------------------- ++ * 1 1 S12 ++ * 0 1 S3I ++ * x 0 S45 ++ ************************************* ++ */ ++ ++static void sio_get_acpi_state(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg, val; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ regmap_read(lpc_sio->regmap, reg, &val); ++ ++ /* update the ACPI state event status */ ++ if (sio_data->param != 0) { ++ if (val & LPC_SLP3N5N_EVENT_STATUS) { ++ sio_data->param = 1; ++ regmap_write(lpc_sio->regmap, reg, ++ LPC_SLP3N5N_EVENT_STATUS); ++ } else { ++ sio_data->param = 0; ++ } ++ } ++ ++ if ((val & LPC_S3N_STS) && (val & LPC_S5N_STS)) ++ sio_data->data = ACPI_STATE_S12; ++ else if ((val & LPC_S3N_STS) == 0 && (val & LPC_S5N_STS)) ++ sio_data->data = ACPI_STATE_S3I; ++ else ++ sio_data->data = ACPI_STATE_S45; ++} ++ ++#define LPC_PWRGD_EVENT_STATUS ( \ ++ LPC_PWRGD_RISING_EVT_STS | \ ++ LPC_PWRGD_FALLING_EVT_STS) ++ ++static void sio_get_pwrgd_status(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg, val; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ regmap_read(lpc_sio->regmap, reg, &val); ++ ++ /* update the PWRGD event status */ ++ if (sio_data->param != 0) { ++ if (val & LPC_PWRGD_EVENT_STATUS) { ++ sio_data->param = 1; ++ regmap_write(lpc_sio->regmap, reg, ++ LPC_PWRGD_EVENT_STATUS); ++ } else { ++ sio_data->param = 0; ++ } ++ } ++ ++ sio_data->data = (val & LPC_PWRGD_STS) != 0 ? 1 : 0; ++} ++ ++static void sio_get_onctl_status(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg, val; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08; ++ regmap_read(lpc_sio->regmap, reg, &val); ++ ++ sio_data->data = (val & LPC_ONCTL_STS) != 0 ? 1 : 0; ++} ++ ++static void sio_set_onctl_gpio(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg, val; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08; ++ regmap_read(lpc_sio->regmap, reg, &val); ++ ++ /* Enable ONCTL GPIO mode */ ++ if (sio_data->param != 0) { ++ val |= LPC_ONCTL_EN_GPIO_MODE; ++ val |= LPC_ONCTL_EN_GPIO_OUTPUT; ++ ++ if (sio_data->data != 0) ++ val |= LPC_ONCTL_GPIO_LEVEL; ++ else ++ val &= ~LPC_ONCTL_GPIO_LEVEL; ++ ++ regmap_write(lpc_sio->regmap, reg, val); ++ } else { ++ val &= ~LPC_ONCTL_EN_GPIO_MODE; ++ regmap_write(lpc_sio->regmap, reg, val); ++ } ++} ++ ++static void sio_get_pwrbtn_override(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg, val; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ regmap_read(lpc_sio->regmap, reg, &val); ++ ++ /* clear the PWRBTN OVERRIDE status */ ++ if (sio_data->param != 0 && val & LPC_PWRBTN_OVERRIDE_STS) ++ regmap_write(lpc_sio->regmap, reg, LPC_PWRBTN_OVERRIDE_STS); ++ ++ sio_data->data = (val & LPC_PWRBTN_OVERRIDE_STS) != 0 ? 1 : 0; ++} ++ ++static void sio_get_pfail_status(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg, val; ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ regmap_read(lpc_sio->regmap, reg, &val); ++ ++ /* [ASPEED]: SWCR_03_00[13] (Was_pfail: default 1) is used to identify ++ * this current booting is from AC loss (not DC loss) if FW cleans this ++ * bit after booting successfully every time. ++ **********************************************************************/ ++ if (val & LPC_WAS_PFAIL_STS) { ++ regmap_write(lpc_sio->regmap, reg, 0); /* W0C */ ++ sio_data->data = 1; ++ } else { ++ sio_data->data = 0; ++ } ++} ++ ++static void sio_set_bmc_sci_event(struct aspeed_lpc_sio *lpc_sio, ++ struct sio_ioctl_data *sio_data) ++{ ++ u32 reg; ++ ++ if (sio_data->param) { ++ reg = lpc_sio->reg_base + AST_LPC_ACPIB7B4; ++ regmap_write_bits(lpc_sio->regmap, reg, ++ LPC_BMC_TRIG_SCI_EVT_EN, ++ LPC_BMC_TRIG_SCI_EVT_EN); ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0704; ++ regmap_write_bits(lpc_sio->regmap, reg, ++ LPC_BMC_TRIG_WAKEUP_EVT_EN, ++ LPC_BMC_TRIG_WAKEUP_EVT_EN); ++ ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08; ++ regmap_write_bits(lpc_sio->regmap, reg, ++ LPC_BMC_TRIG_WAKEUP_EVT, ++ LPC_BMC_TRIG_WAKEUP_EVT); ++ } else { ++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300; ++ regmap_write_bits(lpc_sio->regmap, reg, ++ LPC_BMC_TRIG_WAKEUP_EVT_STS, ++ LPC_BMC_TRIG_WAKEUP_EVT_STS); ++ ++ reg = lpc_sio->reg_base + AST_LPC_ACPIB3B0; ++ regmap_write_bits(lpc_sio->regmap, reg, ++ LPC_BMC_TRIG_SCI_EVT_STS, ++ LPC_BMC_TRIG_SCI_EVT_STS); ++ } ++ ++ sio_data->data = sio_data->param; ++} ++ ++typedef void (*sio_cmd_fn) (struct aspeed_lpc_sio *sio_dev, ++ struct sio_ioctl_data *sio_data); ++ ++static sio_cmd_fn sio_cmd_handle[SIO_MAX_CMD] = { ++ [SIO_GET_ACPI_STATE] = sio_get_acpi_state, ++ [SIO_GET_PWRGD_STATUS] = sio_get_pwrgd_status, ++ [SIO_GET_ONCTL_STATUS] = sio_get_onctl_status, ++ [SIO_SET_ONCTL_GPIO] = sio_set_onctl_gpio, ++ [SIO_GET_PWRBTN_OVERRIDE] = sio_get_pwrbtn_override, ++ [SIO_GET_PFAIL_STATUS] = sio_get_pfail_status, ++ [SIO_SET_BMC_SCI_EVENT] = sio_set_bmc_sci_event, ++}; ++ ++static long aspeed_lpc_sio_ioctl(struct file *file, unsigned int cmd, ++ unsigned long param) ++{ ++ struct aspeed_lpc_sio *lpc_sio = file_aspeed_lpc_sio(file); ++ struct sio_ioctl_data sio_data; ++ sio_cmd_fn cmd_fn; ++ long ret; ++ ++ if (copy_from_user(&sio_data, (void __user *)param, sizeof(sio_data))) ++ return -EFAULT; ++ ++ if (cmd != SIO_IOC_COMMAND || sio_data.sio_cmd >= SIO_MAX_CMD) ++ return -EINVAL; ++ ++ cmd_fn = sio_cmd_handle[sio_data.sio_cmd]; ++ if (!cmd_fn) ++ return -EINVAL; ++ ++ if (down_interruptible(&lpc_sio->lock) != 0) ++ return -ERESTARTSYS; ++ ++ cmd_fn(lpc_sio, &sio_data); ++ ret = copy_to_user((void __user *)param, &sio_data, sizeof(sio_data)); ++ ++ up(&lpc_sio->lock); ++ ++ return ret; ++} ++ ++static const struct file_operations aspeed_lpc_sio_fops = { ++ .owner = THIS_MODULE, ++ .open = aspeed_lpc_sio_open, ++ .unlocked_ioctl = aspeed_lpc_sio_ioctl, ++}; ++ ++static int aspeed_lpc_sio_probe(struct platform_device *pdev) ++{ ++ struct aspeed_lpc_sio *lpc_sio; ++ struct device *dev; ++ u32 val; ++ int ret; ++ ++ dev = &pdev->dev; ++ ++ lpc_sio = devm_kzalloc(dev, sizeof(*lpc_sio), GFP_KERNEL); ++ if (!lpc_sio) ++ return -ENOMEM; ++ ++ dev_set_drvdata(&pdev->dev, lpc_sio); ++ ++ ret = of_property_read_u32(dev->of_node, "reg", &lpc_sio->reg_base); ++ if (ret) { ++ dev_err(dev, "Couldn't read reg device-tree property\n"); ++ return ret; ++ } ++ ++ lpc_sio->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node); ++ if (IS_ERR(lpc_sio->regmap)) { ++ dev_err(dev, "Couldn't get regmap\n"); ++ return -ENODEV; ++ } ++ ++ /* ++ * We check that the regmap works on this very first access, ++ * but as this is an MMIO-backed regmap, subsequent regmap ++ * access is not going to fail and we skip error checks from ++ * this point. ++ */ ++ ret = regmap_read(lpc_sio->regmap, AST_LPC_SWCR0300, &val); ++ if (ret) { ++ dev_err(dev, "failed to read regmap\n"); ++ return ret; ++ } ++ ++ sema_init(&lpc_sio->lock, 1); ++ ++ lpc_sio->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(lpc_sio->clk)) { ++ ret = PTR_ERR(lpc_sio->clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return ret; ++ } ++ ret = clk_prepare_enable(lpc_sio->clk); ++ if (ret) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return ret; ++ } ++ ++ lpc_sio->miscdev.minor = MISC_DYNAMIC_MINOR; ++ lpc_sio->miscdev.name = DEVICE_NAME; ++ lpc_sio->miscdev.fops = &aspeed_lpc_sio_fops; ++ lpc_sio->miscdev.parent = dev; ++ ret = misc_register(&lpc_sio->miscdev); ++ if (ret) { ++ dev_err(dev, "Unable to register device\n"); ++ goto err; ++ } ++ ++ dev_info(dev, "Loaded at %pap (0x%08x)\n", &lpc_sio->regmap, ++ lpc_sio->reg_base); ++ ++ return 0; ++ ++err: ++ clk_disable_unprepare(lpc_sio->clk); ++ ++ return ret; ++} ++ ++static int aspeed_lpc_sio_remove(struct platform_device *pdev) ++{ ++ struct aspeed_lpc_sio *lpc_sio = dev_get_drvdata(&pdev->dev); ++ ++ misc_deregister(&lpc_sio->miscdev); ++ clk_disable_unprepare(lpc_sio->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id aspeed_lpc_sio_match[] = { ++ { .compatible = "aspeed,ast2500-lpc-sio" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, aspeed_lpc_sio_match); ++ ++static struct platform_driver aspeed_lpc_sio_driver = { ++ .driver = { ++ .name = SOC_NAME "-" DEVICE_NAME, ++ .of_match_table = of_match_ptr(aspeed_lpc_sio_match), ++ }, ++ .probe = aspeed_lpc_sio_probe, ++ .remove = aspeed_lpc_sio_remove, ++}; ++module_platform_driver(aspeed_lpc_sio_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); ++MODULE_AUTHOR("Yong Li <yong.blli@linux.intel.com>"); ++MODULE_DESCRIPTION("ASPEED AST LPC SIO device driver"); +diff --git a/include/uapi/linux/aspeed-lpc-sio.h b/include/uapi/linux/aspeed-lpc-sio.h +new file mode 100644 +index 000000000000..acf89a7d2b4a +--- /dev/null ++++ b/include/uapi/linux/aspeed-lpc-sio.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2012-2020 ASPEED Technology Inc. ++ * Copyright (c) 2017 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ */ ++ ++#ifndef _UAPI_LINUX_ASPEED_LPC_SIO_H ++#define _UAPI_LINUX_ASPEED_LPC_SIO_H ++ ++#include <linux/ioctl.h> ++ ++enum ACPI_SLP_STATE { ++ ACPI_STATE_S12 = 1, ++ ACPI_STATE_S3I, ++ ACPI_STATE_S45 ++}; ++ ++/* SWC & ACPI for SuperIO IOCTL */ ++enum SIO_CMD { ++ SIO_GET_ACPI_STATE = 0, ++ SIO_GET_PWRGD_STATUS, ++ SIO_GET_ONCTL_STATUS, ++ SIO_SET_ONCTL_GPIO, ++ SIO_GET_PWRBTN_OVERRIDE, ++ SIO_GET_PFAIL_STATUS, /* Start from AC Loss */ ++ SIO_SET_BMC_SCI_EVENT, ++ ++ SIO_MAX_CMD ++}; ++ ++struct sio_ioctl_data { ++ unsigned short sio_cmd; ++ unsigned short param; ++ unsigned int data; ++}; ++ ++#define SIO_IOC_BASE 'P' ++#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data) ++ ++#endif /* _UAPI_LINUX_ASPEED_LPC_SIO_H */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch new file mode 100644 index 000000000..64059b1da --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch @@ -0,0 +1,762 @@ +From 34308f4078361987adfb854bdc6876abdaf323cb Mon Sep 17 00:00:00 2001 +From: Haiyue Wang <haiyue.wang@linux.intel.com> +Date: Sat, 24 Feb 2018 11:12:32 +0800 +Subject: [PATCH] Add AST2500 eSPI driver + +When PCH works under eSPI mode, the PMC (Power Management Controller) in +PCH is waiting for SUS_ACK from BMC after it alerts SUS_WARN. It is in +dead loop if no SUS_ACK assert. This is the basic requirement for the BMC +works as eSPI slave. + +Also for the host power on / off actions, from BMC side, the following VW +(Virtual Wire) messages are done in firmware: +1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS +2. SUS_ACK +3. OOB_RESET_ACK +4. HOST_RESET_ACK + +Also, it provides monitoring interface of PLTRST_N signal through +/dev/espi-pltrstn + +Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +--- + .../devicetree/bindings/misc/aspeed,espi-slave.txt | 20 + + Documentation/misc-devices/espi-slave.rst | 118 ++++++ + arch/arm/boot/dts/aspeed-g5.dtsi | 4 + + arch/arm/boot/dts/aspeed-g6.dtsi | 14 + + drivers/misc/Kconfig | 8 + + drivers/misc/Makefile | 1 + + drivers/misc/aspeed-espi-slave.c | 468 +++++++++++++++++++++ + include/dt-bindings/clock/ast2600-clock.h | 1 + + 8 files changed, 634 insertions(+) + create mode 100644 Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt + create mode 100644 Documentation/misc-devices/espi-slave.rst + create mode 100644 drivers/misc/aspeed-espi-slave.c + +diff --git a/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt +new file mode 100644 +index 000000000000..f72d9ae32f3e +--- /dev/null ++++ b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt +@@ -0,0 +1,20 @@ ++ASPEED eSPI Slave Controller ++ ++Required properties: ++ - compatible: must be one of: ++ - "aspeed,ast2500-espi-slave" ++ - "aspeed,ast2600-espi-slave" ++ ++ - reg: physical base address of the controller and length of memory mapped ++ region ++ ++ - interrupts: interrupt generated by the controller ++ ++Example: ++ ++ espi: espi@1e6ee000 { ++ compatible = "aspeed,ast2500-espi-slave"; ++ reg = <0x1e6ee000 0x100>; ++ interrupts = <23>; ++ status = "disabled"; ++}; +diff --git a/Documentation/misc-devices/espi-slave.rst b/Documentation/misc-devices/espi-slave.rst +new file mode 100644 +index 000000000000..887a69a7130a +--- /dev/null ++++ b/Documentation/misc-devices/espi-slave.rst +@@ -0,0 +1,118 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++========== ++eSPI Slave ++========== ++ ++:Author: Haiyue Wang <haiyue.wang@linux.intel.com> ++ ++The PCH (**eSPI master**) provides the eSPI to support connection of a ++BMC (**eSPI slave**) to the platform. ++ ++The LPC and eSPI interfaces are mutually exclusive. Both use the same ++pins, but on power-up, a HW strap determines if the eSPI or the LPC bus ++is operational. Once selected, it’s not possible to change to the other ++interface. ++ ++``eSPI Channels and Supported Transactions`` ++ +------+---------------------+----------------------+--------------------+ ++ | CH # | Channel | Posted Cycles | Non-Posted Cycles | ++ +======+=====================+======================+====================+ ++ | 0 | Peripheral | Memory Write, | Memory Read, | ++ | | | Completions | I/O Read/Write | ++ +------+---------------------+----------------------+--------------------+ ++ | 1 | Virtual Wire | Virtual Wire GET/PUT | N/A | ++ +------+---------------------+----------------------+--------------------+ ++ | 2 | Out-of-Band Message | SMBus Packet GET/PUT | N/A | ++ +------+---------------------+----------------------+--------------------+ ++ | 3 | Flash Access | N/A | Flash Read, Write, | ++ | | | | Erase | ++ +------+---------------------+----------------------+--------------------+ ++ | N/A | General | Register Accesses | N/A | ++ +------+---------------------+----------------------+--------------------+ ++ ++Virtual Wire Channel (Channel 1) Overview ++----------------------------------------- ++ ++The Virtual Wire channel uses a standard message format to communicate ++several types of signals between the components on the platform:: ++ ++ - Sideband and GPIO Pins: System events and other dedicated signals ++ between the PCH and eSPI slave. These signals are tunneled between the ++ two components over eSPI. ++ ++ - Serial IRQ Interrupts: Interrupts are tunneled from the eSPI slave to ++ the PCH. Both edge and triggered interrupts are supported. ++ ++When PCH runs on eSPI mode, from BMC side, the following VW messages are ++done in firmware:: ++ ++ 1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS ++ 2. SUS_ACK ++ 3. OOB_RESET_ACK ++ 4. HOST_RESET_ACK ++ ++``eSPI Virtual Wires (VW)`` ++ +----------------------+---------+---------------------------------------+ ++ |Virtual Wire |PCH Pin |Comments | ++ | |Direction| | ++ +======================+=========+=======================================+ ++ |SUS_WARN# |Output |PCH pin is a GPIO when eSPI is enabled.| ++ | | |eSPI controller receives as VW message.| ++ +----------------------+---------+---------------------------------------+ ++ |SUS_ACK# |Input |PCH pin is a GPIO when eSPI is enabled.| ++ | | |eSPI controller receives as VW message.| ++ +----------------------+---------+---------------------------------------+ ++ |SLAVE_BOOT_LOAD_DONE |Input |Sent when the BMC has completed its | ++ | | |boot process as an indication to | ++ | | |eSPI-MC to continue with the G3 to S0 | ++ | | |exit. | ++ | | |The eSPI Master waits for the assertion| ++ | | |of this virtual wire before proceeding | ++ | | |with the SLP_S5# deassertion. | ++ | | |The intent is that it is never changed | ++ | | |except on a G3 exit - it is reset on a | ++ | | |G3 entry. | ++ +----------------------+---------+---------------------------------------+ ++ |SLAVE_BOOT_LOAD_STATUS|Input |Sent upon completion of the Slave Boot | ++ | | |Load from the attached flash. A stat of| ++ | | |1 indicates that the boot code load was| ++ | | |successful and that the integrity of | ++ | | |the image is intact. | ++ +----------------------+---------+---------------------------------------+ ++ |HOST_RESET_WARN |Output |Sent from the MC just before the Host | ++ | | |is about to enter reset. Upon receiving| ++ | | |, the BMC must flush and quiesce its | ++ | | |upstream Peripheral Channel request | ++ | | |queues and assert HOST_RESET_ACK VWire.| ++ | | |The MC subsequently completes any | ++ | | |outstanding posted transactions or | ++ | | |completions and then disables the | ++ | | |Peripheral Channel via a write to | ++ | | |the Slave's Configuration Register. | ++ +----------------------+---------+---------------------------------------+ ++ |HOST_RESET_ACK |Input |ACK for the HOST_RESET_WARN message | ++ +----------------------+---------+---------------------------------------+ ++ |OOB_RESET_WARN |Output |Sent from the MC just before the OOB | ++ | | |processor is about to enter reset. Upon| ++ | | |receiving, the BMC must flush and | ++ | | |quiesce its OOB Channel upstream | ++ | | |request queues and assert OOB_RESET_ACK| ++ | | |VWire. The-MC subsequently completes | ++ | | |any outstanding posted transactions or | ++ | | |completions and then disables the OOB | ++ | | |Channel via a write to the Slave's | ++ | | |Configuration Register. | ++ +----------------------+---------+---------------------------------------+ ++ |OOB_RESET_ACK |Input |ACK for OOB_RESET_WARN message | ++ +----------------------+---------+---------------------------------------+ ++ ++`Intel C620 Series Chipset Platform Controller Hub ++<https://www.intel.com/content/www/us/en/chipsets/c620-series-chipset-datasheet.html>`_ ++ ++ -- 17. Enhanced Serial Peripheral Interface ++ ++ ++`Enhanced Serial Peripheral Interface (eSPI) ++- Interface Base Specification (for Client and Server Platforms) ++<https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0.pdf>`_ +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index c15be82c3a9d..bd2037e52a94 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -316,6 +316,7 @@ + clocks = <&syscon ASPEED_CLK_APB>; + interrupt-controller; + #interrupt-cells = <2>; ++ status = "disabled"; + }; + + sgpio: sgpio@1e780200 { +@@ -412,6 +413,9 @@ + reg = <0x1e6ee000 0x100>; + interrupts = <23>; + status = "disabled"; ++ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_espi_default>; + }; + + lpc: lpc@1e789000 { +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 62d101dc6926..753770912f0a 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -3,6 +3,7 @@ + + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/ast2600-clock.h> ++#include <dt-bindings/gpio/aspeed-gpio.h> + + / { + model = "Aspeed BMC"; +@@ -674,6 +675,19 @@ + status = "disabled"; + }; + ++ espi: espi@1e6ee000 { ++ compatible = "aspeed,ast2600-espi-slave"; ++ reg = <0x1e6ee000 0x200>; ++ interrupts-extended = <&gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>, ++ <&gpio0 ASPEED_GPIO(W, 7) IRQ_TYPE_EDGE_FALLING>; ++ status = "disabled"; ++ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>; ++ resets = <&syscon ASPEED_RESET_ESPI>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_espi_default>, ++ <&pinctrl_espialt_default>; ++ }; ++ + i2c: bus@1e78a000 { + compatible = "simple-bus"; + #address-cells = <1>; +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 06a2b753cc7c..0f9b5a356c93 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -433,6 +433,14 @@ config VEXPRESS_SYSCFG + bus. System Configuration interface is one of the possible means + of generating transactions on this bus. + ++config ASPEED_ESPI_SLAVE ++ depends on ARCH_ASPEED || COMPILE_TEST ++ depends on REGMAP_MMIO ++ tristate "Aspeed ast2500 eSPI slave device driver" ++ ---help--- ++ Control Aspeed ast2500 eSPI slave controller to handle event ++ which needs the firmware's processing. ++ + config PCI_ENDPOINT_TEST + depends on PCI + select CRC32 +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index b9e6d4c3e906..53864687e8fd 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -51,6 +51,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ + obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o + obj-$(CONFIG_CXL_BASE) += cxl/ ++obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o + obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o + obj-$(CONFIG_OCXL) += ocxl/ + obj-y += cardreader/ +diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c +new file mode 100644 +index 000000000000..87bc81948694 +--- /dev/null ++++ b/drivers/misc/aspeed-espi-slave.c +@@ -0,0 +1,468 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2015-2019, Intel Corporation. ++ ++#include <linux/clk.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/reset.h> ++#include <linux/sched/signal.h> ++#include <linux/spinlock.h> ++#include <linux/uaccess.h> ++ ++#define ASPEED_ESPI_CTRL 0x00 ++#define ASPEED_ESPI_CTRL_SW_RESET GENMASK(31, 24) ++#define ASPEED_ESPI_CTRL_OOB_CHRDY BIT(4) ++#define ASPEED_ESPI_INT_STS 0x08 ++#define ASPEED_ESPI_HW_RESET BIT(31) ++#define ASPEED_ESPI_VW_SYSEVT1 BIT(22) ++#define ASPEED_ESPI_VW_SYSEVT BIT(8) ++#define ASPEED_ESPI_INT_EN 0x0C ++#define ASPEED_ESPI_DATA_PORT 0x28 ++#define ASPEED_ESPI_SYSEVT_INT_EN 0x94 ++#define ASPEED_ESPI_SYSEVT 0x98 ++#define ASPEED_ESPI_SYSEVT_HOST_RST_ACK BIT(27) ++#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23) ++#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20) ++#define ASPEED_ESPI_SYSEVT_OOB_RST_ACK BIT(16) ++#define ASPEED_ESPI_SYSEVT_INT_T0 0x110 ++#define ASPEED_ESPI_SYSEVT_INT_T1 0x114 ++#define ASPEED_ESPI_SYSEVT_INT_T2 0x118 ++#define ASPEED_ESPI_SYSEVT_INT_STS 0x11C ++#define ASPEED_ESPI_SYSEVT_HOST_RST_WARN BIT(8) ++#define ASPEED_ESPI_SYSEVT_OOB_RST_WARN BIT(6) ++#define ASPEED_ESPI_SYSEVT_PLTRSTN BIT(5) ++#define ASPEED_ESPI_SYSEVT1_INT_EN 0x100 ++#define ASPEED_ESPI_SYSEVT1 0x104 ++#define ASPEED_ESPI_SYSEVT1_SUS_ACK BIT(20) ++#define ASPEED_ESPI_SYSEVT1_INT_T0 0x120 ++#define ASPEED_ESPI_SYSEVT1_INT_T1 0x124 ++#define ASPEED_ESPI_SYSEVT1_INT_T2 0x128 ++#define ASPEED_ESPI_SYSEVT1_INT_STS 0x12C ++#define ASPEED_ESPI_SYSEVT1_SUS_WARN BIT(0) ++ ++#define ASPEED_ESPI_INT_MASK \ ++ (ASPEED_ESPI_HW_RESET | \ ++ ASPEED_ESPI_VW_SYSEVT1 | \ ++ ASPEED_ESPI_VW_SYSEVT) ++ ++/* ++ * Setup Interrupt Type / Enable of System Event from Master ++ * T2 T1 T0 ++ * 1) HOST_RST_WARN : Dual Edge 1 0 0 ++ * 2) OOB_RST_WARN : Dual Edge 1 0 0 ++ * 3) PLTRSTN : Dual Edge 1 0 0 ++ */ ++#define ASPEED_ESPI_SYSEVT_INT_T0_MASK 0 ++#define ASPEED_ESPI_SYSEVT_INT_T1_MASK 0 ++#define ASPEED_ESPI_SYSEVT_INT_T2_MASK \ ++ (ASPEED_ESPI_SYSEVT_HOST_RST_WARN | \ ++ ASPEED_ESPI_SYSEVT_OOB_RST_WARN | \ ++ ASPEED_ESPI_SYSEVT_PLTRSTN) ++#define ASPEED_ESPI_SYSEVT_INT_MASK \ ++ (ASPEED_ESPI_SYSEVT_INT_T0_MASK | \ ++ ASPEED_ESPI_SYSEVT_INT_T1_MASK | \ ++ ASPEED_ESPI_SYSEVT_INT_T2_MASK) ++ ++/* ++ * Setup Interrupt Type / Enable of System Event 1 from Master ++ * T2 T1 T0 ++ * 1) SUS_WARN : Rising Edge 0 0 1 ++ */ ++#define ASPEED_ESPI_SYSEVT1_INT_T0_MASK ASPEED_ESPI_SYSEVT1_SUS_WARN ++#define ASPEED_ESPI_SYSEVT1_INT_T1_MASK 0 ++#define ASPEED_ESPI_SYSEVT1_INT_T2_MASK 0 ++#define ASPEED_ESPI_SYSEVT1_INT_MASK \ ++ (ASPEED_ESPI_SYSEVT1_INT_T0_MASK | \ ++ ASPEED_ESPI_SYSEVT1_INT_T1_MASK | \ ++ ASPEED_ESPI_SYSEVT1_INT_T2_MASK) ++ ++struct aspeed_espi { ++ struct regmap *map; ++ struct clk *clk; ++ struct device *dev; ++ struct reset_control *reset; ++ int irq; ++ int rst_irq; ++ ++ /* for PLTRST_N signal monitoring interface */ ++ struct miscdevice pltrstn_miscdev; ++ spinlock_t pltrstn_lock; /* for PLTRST_N signal sampling */ ++ wait_queue_head_t pltrstn_waitq; ++ char pltrstn; ++}; ++ ++static void aspeed_espi_sys_event(struct aspeed_espi *priv) ++{ ++ u32 sts, evt; ++ ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, &sts); ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt); ++ ++ dev_dbg(priv->dev, "sys: sts = %08x, evt = %08x\n", sts, evt); ++ ++ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) { ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT, ++ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS | ++ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ dev_dbg(priv->dev, "Setting espi slave boot done\n"); ++ } ++ if (sts & ASPEED_ESPI_SYSEVT_HOST_RST_WARN && ++ evt & ASPEED_ESPI_SYSEVT_HOST_RST_WARN) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT, ++ ASPEED_ESPI_SYSEVT_HOST_RST_ACK, ++ ASPEED_ESPI_SYSEVT_HOST_RST_ACK); ++ dev_dbg(priv->dev, "SYSEVT_HOST_RST_WARN: acked\n"); ++ } ++ if (sts & ASPEED_ESPI_SYSEVT_OOB_RST_WARN && ++ evt & ASPEED_ESPI_SYSEVT_OOB_RST_WARN) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT, ++ ASPEED_ESPI_SYSEVT_OOB_RST_ACK, ++ ASPEED_ESPI_SYSEVT_OOB_RST_ACK); ++ dev_dbg(priv->dev, "SYSEVT_OOB_RST_WARN: acked\n"); ++ } ++ if (sts & ASPEED_ESPI_SYSEVT_PLTRSTN || priv->pltrstn == 'U') { ++ priv->pltrstn = (evt & ASPEED_ESPI_SYSEVT_PLTRSTN) ? '1' : '0'; ++ wake_up_interruptible(&priv->pltrstn_waitq); ++ dev_dbg(priv->dev, "SYSEVT_PLTRSTN: %c\n", priv->pltrstn); ++ } ++ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, sts); ++} ++ ++static void aspeed_espi_sys_event1(struct aspeed_espi *priv) ++{ ++ u32 sts, evt; ++ ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, &sts); ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt); ++ ++ dev_dbg(priv->dev, "sys event1: sts = %08x, evt = %08x\n", sts, evt); ++ ++ if (sts & ASPEED_ESPI_SYSEVT1_SUS_WARN && ++ evt & ASPEED_ESPI_SYSEVT1_SUS_WARN) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT1, ++ ASPEED_ESPI_SYSEVT1_SUS_ACK, ++ ASPEED_ESPI_SYSEVT1_SUS_ACK); ++ dev_dbg(priv->dev, "SYSEVT1_SUS_WARN: acked\n"); ++ } ++ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, sts); ++} ++ ++static void aspeed_espi_boot_ack(struct aspeed_espi *priv) ++{ ++ u32 evt; ++ ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt); ++ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) { ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT, ++ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS | ++ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ dev_dbg(priv->dev, "Setting espi slave boot done\n"); ++ } ++ ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt); ++ if (evt & ASPEED_ESPI_SYSEVT1_SUS_WARN && ++ !(evt & ASPEED_ESPI_SYSEVT1_SUS_ACK)) { ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1, ++ evt | ASPEED_ESPI_SYSEVT1_SUS_ACK); ++ dev_dbg(priv->dev, "Boot SYSEVT1_SUS_WARN: acked\n"); ++ } ++} ++ ++static irqreturn_t aspeed_espi_irq(int irq, void *arg) ++{ ++ struct aspeed_espi *priv = arg; ++ u32 sts, sts_handled = 0; ++ ++ regmap_read(priv->map, ASPEED_ESPI_INT_STS, &sts); ++ ++ dev_dbg(priv->dev, "INT_STS: 0x%08x\n", sts); ++ ++ if (sts & ASPEED_ESPI_VW_SYSEVT) { ++ aspeed_espi_sys_event(priv); ++ sts_handled |= ASPEED_ESPI_VW_SYSEVT; ++ } ++ ++ if (sts & ASPEED_ESPI_VW_SYSEVT1) { ++ aspeed_espi_sys_event1(priv); ++ sts_handled |= ASPEED_ESPI_VW_SYSEVT1; ++ } ++ ++ if (sts & ASPEED_ESPI_HW_RESET) { ++ if (priv->rst_irq < 0) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_SW_RESET, 0); ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_SW_RESET, ++ ASPEED_ESPI_CTRL_SW_RESET); ++ } ++ ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_OOB_CHRDY, ++ ASPEED_ESPI_CTRL_OOB_CHRDY); ++ aspeed_espi_boot_ack(priv); ++ sts_handled |= ASPEED_ESPI_HW_RESET; ++ } ++ ++ regmap_write(priv->map, ASPEED_ESPI_INT_STS, sts); ++ ++ return sts != sts_handled ? IRQ_NONE : IRQ_HANDLED; ++} ++ ++static void aspeed_espi_config_irq(struct aspeed_espi *priv) ++{ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T0, ++ ASPEED_ESPI_SYSEVT_INT_T0_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T1, ++ ASPEED_ESPI_SYSEVT_INT_T1_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T2, ++ ASPEED_ESPI_SYSEVT_INT_T2_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_EN, ++ ASPEED_ESPI_SYSEVT_INT_MASK); ++ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T0, ++ ASPEED_ESPI_SYSEVT1_INT_T0_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T1, ++ ASPEED_ESPI_SYSEVT1_INT_T1_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T2, ++ ASPEED_ESPI_SYSEVT1_INT_T2_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_EN, ++ ASPEED_ESPI_SYSEVT1_INT_MASK); ++ ++ regmap_write(priv->map, ASPEED_ESPI_INT_EN, ASPEED_ESPI_INT_MASK); ++} ++ ++static irqreturn_t aspeed_espi_reset_isr(int irq, void *arg) ++{ ++ struct aspeed_espi *priv = arg; ++ ++ reset_control_assert(priv->reset); ++ reset_control_deassert(priv->reset); ++ ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_SW_RESET, 0); ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_SW_RESET, ASPEED_ESPI_CTRL_SW_RESET); ++ ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_OOB_CHRDY, 0); ++ ++ aspeed_espi_config_irq(priv); ++ ++ return IRQ_HANDLED; ++} ++ ++static inline struct aspeed_espi *to_aspeed_espi(struct file *filp) ++{ ++ return container_of(filp->private_data, struct aspeed_espi, ++ pltrstn_miscdev); ++} ++ ++static int aspeed_espi_pltrstn_open(struct inode *inode, struct file *filp) ++{ ++ if ((filp->f_flags & O_ACCMODE) != O_RDONLY) ++ return -EACCES; ++ ++ return 0; ++} ++ ++static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct aspeed_espi *priv = to_aspeed_espi(filp); ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ char old_sample; ++ int ret = 0; ++ ++ spin_lock_irqsave(&priv->pltrstn_lock, flags); ++ ++ add_wait_queue(&priv->pltrstn_waitq, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ old_sample = priv->pltrstn; ++ ++ do { ++ char new_sample = priv->pltrstn; ++ ++ if (filp->f_flags & O_NONBLOCK || old_sample != new_sample) { ++ ret = put_user(new_sample, (unsigned long __user *)buf); ++ if (!ret) ++ ret = sizeof(new_sample); ++ } else if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ } ++ ++ if (!ret) { ++ spin_unlock_irqrestore(&priv->pltrstn_lock, flags); ++ schedule(); ++ spin_lock_irqsave(&priv->pltrstn_lock, flags); ++ } ++ } while (!ret); ++ ++ remove_wait_queue(&priv->pltrstn_waitq, &wait); ++ set_current_state(TASK_RUNNING); ++ ++ spin_unlock_irqrestore(&priv->pltrstn_lock, flags); ++ ++ return ret; ++} ++ ++static const struct file_operations aspeed_espi_pltrstn_fops = { ++ .owner = THIS_MODULE, ++ .open = aspeed_espi_pltrstn_open, ++ .read = aspeed_espi_pltrstn_read, ++}; ++ ++static const struct regmap_config aspeed_espi_regmap_cfg = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = ASPEED_ESPI_SYSEVT1_INT_STS, ++}; ++ ++static int aspeed_espi_probe(struct platform_device *pdev) ++{ ++ struct aspeed_espi *priv; ++ struct resource *res; ++ void __iomem *regs; ++ u32 ctrl; ++ int ret; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(&pdev->dev, priv); ++ priv->dev = &pdev->dev; ++ ++ priv->map = devm_regmap_init_mmio(&pdev->dev, regs, ++ &aspeed_espi_regmap_cfg); ++ if (IS_ERR(priv->map)) ++ return PTR_ERR(priv->map); ++ ++ spin_lock_init(&priv->pltrstn_lock); ++ init_waitqueue_head(&priv->pltrstn_waitq); ++ priv->pltrstn = 'U'; /* means it's not reported yet from master */ ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (priv->irq < 0) ++ return priv->irq; ++ ++ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_espi_irq, 0, ++ "aspeed-espi-irq", priv); ++ if (ret) ++ return ret; ++ ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2600-espi-slave")) { ++ priv->rst_irq = platform_get_irq(pdev, 1); ++ if (priv->rst_irq < 0) ++ return priv->rst_irq; ++ ++ ret = devm_request_irq(&pdev->dev, priv->rst_irq, ++ aspeed_espi_reset_isr, 0, ++ "aspeed-espi-rst-irq", priv); ++ if (ret) ++ return ret; ++ ++ priv->reset = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->reset)) ++ return PTR_ERR(priv->reset); ++ } else { ++ priv->rst_irq = -ENOTSUPP; ++ } ++ ++ priv->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ ret = PTR_ERR(priv->clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "couldn't get clock\n"); ++ return ret; ++ } ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "couldn't enable clock\n"); ++ return ret; ++ } ++ ++ /* ++ * We check that the regmap works on this very first access, but as this ++ * is an MMIO-backed regmap, subsequent regmap access is not going to ++ * fail and we skip error checks from this point. ++ */ ++ ret = regmap_read(priv->map, ASPEED_ESPI_CTRL, &ctrl); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to read ctrl register\n"); ++ goto err_clk_disable_out; ++ } ++ regmap_write(priv->map, ASPEED_ESPI_CTRL, ++ ctrl | ASPEED_ESPI_CTRL_OOB_CHRDY); ++ ++ priv->pltrstn_miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->pltrstn_miscdev.name = "espi-pltrstn"; ++ priv->pltrstn_miscdev.fops = &aspeed_espi_pltrstn_fops; ++ priv->pltrstn_miscdev.parent = &pdev->dev; ++ ++ ret = misc_register(&priv->pltrstn_miscdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to register device\n"); ++ goto err_clk_disable_out; ++ } ++ ++ aspeed_espi_config_irq(priv); ++ aspeed_espi_boot_ack(priv); ++ ++ dev_info(&pdev->dev, "eSPI registered, irq %d\n", priv->irq); ++ ++ return 0; ++ ++err_clk_disable_out: ++ clk_disable_unprepare(priv->clk); ++ ++ return ret; ++} ++ ++static int aspeed_espi_remove(struct platform_device *pdev) ++{ ++ struct aspeed_espi *priv = dev_get_drvdata(&pdev->dev); ++ ++ misc_deregister(&priv->pltrstn_miscdev); ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id of_espi_match_table[] = { ++ { .compatible = "aspeed,ast2500-espi-slave" }, ++ { .compatible = "aspeed,ast2600-espi-slave" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, of_espi_match_table); ++ ++static struct platform_driver aspeed_espi_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_match_ptr(of_espi_match_table), ++ }, ++ .probe = aspeed_espi_probe, ++ .remove = aspeed_espi_remove, ++}; ++module_platform_driver(aspeed_espi_driver); ++ ++MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>"); ++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); ++MODULE_DESCRIPTION("Aspeed eSPI driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h +index 3d90582a813f..1e18364de03d 100644 +--- a/include/dt-bindings/clock/ast2600-clock.h ++++ b/include/dt-bindings/clock/ast2600-clock.h +@@ -104,6 +104,7 @@ + #define ASPEED_RESET_PECI 36 + #define ASPEED_RESET_MII 35 + #define ASPEED_RESET_I2C 34 ++#define ASPEED_RESET_ESPI 32 + #define ASPEED_RESET_H2X 31 + #define ASPEED_RESET_GP_MCU 30 + #define ASPEED_RESET_DP_MCU 29 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch new file mode 100644 index 000000000..45dec5b20 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch @@ -0,0 +1,95 @@ +From a4413fe3ba94906243b632e0b9e0e9a91620dd22 Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Fri, 1 Mar 2019 11:46:09 -0700 +Subject: [PATCH] Add AST2500 JTAG driver + +Update AST2500 JTAG driver. Remove Legacy driver but keep headers. + +Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com> +--- + include/uapi/linux/jtag_drv.h | 73 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 73 insertions(+) + create mode 100644 include/uapi/linux/jtag_drv.h + +diff --git a/include/uapi/linux/jtag_drv.h b/include/uapi/linux/jtag_drv.h +new file mode 100644 +index 000000000000..4df638f8fa43 +--- /dev/null ++++ b/include/uapi/linux/jtag_drv.h +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (C) 2012-2017 ASPEED Technology Inc. */ ++/* Copyright (c) 2018 Intel Corporation */ ++ ++#ifndef __JTAG_DRV_H__ ++#define __JTAG_DRV_H__ ++ ++enum xfer_mode { ++ HW_MODE = 0, ++ SW_MODE ++} xfer_mode; ++ ++struct tck_bitbang { ++ __u8 tms; ++ __u8 tdi; ++ __u8 tdo; ++} __attribute__((__packed__)); ++ ++struct scan_xfer { ++ __u8 mode; ++ __u32 tap_state; ++ __u32 length; ++ __u8 *tdi; ++ __u32 tdi_bytes; ++ __u8 *tdo; ++ __u32 tdo_bytes; ++ __u32 end_tap_state; ++} __attribute__((__packed__)); ++ ++struct set_tck_param { ++ __u8 mode; ++ __u32 tck; ++} __attribute__((__packed__)); ++ ++struct get_tck_param { ++ __u8 mode; ++ __u32 tck; ++} __attribute__((__packed__)); ++ ++struct tap_state_param { ++ __u8 mode; ++ __u32 from_state; ++ __u32 to_state; ++} __attribute__((__packed__)); ++ ++enum jtag_states { ++ jtag_tlr, ++ jtag_rti, ++ jtag_sel_dr, ++ jtag_cap_dr, ++ jtag_shf_dr, ++ jtag_ex1_dr, ++ jtag_pau_dr, ++ jtag_ex2_dr, ++ jtag_upd_dr, ++ jtag_sel_ir, ++ jtag_cap_ir, ++ jtag_shf_ir, ++ jtag_ex1_ir, ++ jtag_pau_ir, ++ jtag_ex2_ir, ++ jtag_upd_ir ++} jtag_states; ++ ++#define JTAGIOC_BASE 'T' ++ ++#define AST_JTAG_SET_TCK _IOW(JTAGIOC_BASE, 3, struct set_tck_param) ++#define AST_JTAG_GET_TCK _IOR(JTAGIOC_BASE, 4, struct get_tck_param) ++#define AST_JTAG_BITBANG _IOWR(JTAGIOC_BASE, 5, struct tck_bitbang) ++#define AST_JTAG_SET_TAPSTATE _IOW(JTAGIOC_BASE, 6, struct tap_state_param) ++#define AST_JTAG_READWRITESCAN _IOWR(JTAGIOC_BASE, 7, struct scan_xfer) ++ ++#endif +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch new file mode 100644 index 000000000..c9844e1bd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch @@ -0,0 +1,145 @@ +From a57f401058e452f9abb6f3233e7f2776af1e6b8d Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 29 Jun 2018 11:00:02 -0700 +Subject: [PATCH] Add dump debug code into I2C drivers + +This commit enables dump debug of master and slave I2C drivers. +This is only for downstream debug purpose so it shouldn't go to +the upstream. + +Usage (in case of bus 5 for an example): +echo 5 > /sys/module/i2c_aspeed/parameters/dump_debug_bus_id +echo 1 > /sys/module/i2c_aspeed/parameters/dump_debug +echo 5 > /sys/module/i2c_slave_mqueue/parameters/dump_debug_bus_id +echo 1 > /sys/module/i2c_slave_mqueue/parameters/dump_debug + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 26 ++++++++++++++++++++++++++ + drivers/i2c/i2c-slave-mqueue.c | 24 ++++++++++++++++++++++++ + 2 files changed, 50 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index a7be6f24450b..c113ffa8d5df 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -169,6 +169,21 @@ struct aspeed_i2c_bus { + #endif /* CONFIG_I2C_SLAVE */ + }; + ++static bool dump_debug __read_mostly; ++static int dump_debug_bus_id __read_mostly; ++ ++#define I2C_HEX_DUMP(bus, addr, flags, buf, len) \ ++ do { \ ++ if (dump_debug && (bus)->adap.nr == dump_debug_bus_id) { \ ++ char dump_info[100] = {0,}; \ ++ snprintf(dump_info, sizeof(dump_info), \ ++ "bus_id:%d, addr:0x%02x, flags:0x%02x: ", \ ++ (bus)->adap.nr, addr, flags); \ ++ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, \ ++ 16, 1, buf, len, true); \ ++ } \ ++ } while (0) ++ + static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus); + + static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) +@@ -657,6 +672,7 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, + { + struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap); + unsigned long time_left, flags; ++ int i; + + spin_lock_irqsave(&bus->lock, flags); + bus->cmd_err = 0; +@@ -708,6 +724,11 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, + return -ETIMEDOUT; + } + ++ for (i = 0; i < num; i++) { ++ I2C_HEX_DUMP(bus, msgs[i].addr, msgs[i].flags, ++ msgs[i].buf, msgs[i].len); ++ } ++ + return bus->master_xfer_result; + } + +@@ -1079,6 +1100,11 @@ static struct platform_driver aspeed_i2c_bus_driver = { + }; + module_platform_driver(aspeed_i2c_bus_driver); + ++module_param_named(dump_debug, dump_debug, bool, 0644); ++MODULE_PARM_DESC(dump_debug, "debug flag for dump printing"); ++module_param_named(dump_debug_bus_id, dump_debug_bus_id, int, 0644); ++MODULE_PARM_DESC(dump_debug_bus_id, "bus id for dump debug printing"); ++ + MODULE_AUTHOR("Brendan Higgins <brendanhiggins@google.com>"); + MODULE_DESCRIPTION("Aspeed I2C Bus Driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c +index 6014bca0ff2a..2c7a6038409c 100644 +--- a/drivers/i2c/i2c-slave-mqueue.c ++++ b/drivers/i2c/i2c-slave-mqueue.c +@@ -21,6 +21,7 @@ struct mq_msg { + struct mq_queue { + struct bin_attribute bin; + struct kernfs_node *kn; ++ struct i2c_client *client; + + spinlock_t lock; /* spinlock for queue index handling */ + int in; +@@ -31,6 +32,21 @@ struct mq_queue { + struct mq_msg *queue; + }; + ++static bool dump_debug __read_mostly; ++static int dump_debug_bus_id __read_mostly; ++ ++#define I2C_HEX_DUMP(client, buf, len) \ ++ do { \ ++ if (dump_debug && \ ++ (client)->adapter->nr == dump_debug_bus_id) { \ ++ char dump_info[100] = {0,}; \ ++ snprintf(dump_info, sizeof(dump_info), \ ++ "bus_id:%d: ", (client)->adapter->nr); \ ++ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, \ ++ 16, 1, buf, len, true); \ ++ } \ ++ } while (0) ++ + static int i2c_slave_mqueue_callback(struct i2c_client *client, + enum i2c_slave_event event, u8 *val) + { +@@ -101,6 +117,7 @@ static ssize_t i2c_slave_mqueue_bin_read(struct file *filp, + if (msg->len <= count) { + ret = msg->len; + memcpy(buf, msg->buf, ret); ++ I2C_HEX_DUMP(mq->client, buf, ret); + } else { + ret = -EOVERFLOW; /* Drop this HUGE one. */ + } +@@ -131,6 +148,8 @@ static int i2c_slave_mqueue_probe(struct i2c_client *client, + + BUILD_BUG_ON(!is_power_of_2(MQ_QUEUE_SIZE)); + ++ mq->client = client; ++ + buf = devm_kmalloc_array(dev, MQ_QUEUE_SIZE, MQ_MSGBUF_SIZE, + GFP_KERNEL); + if (!buf) +@@ -212,6 +231,11 @@ static struct i2c_driver i2c_slave_mqueue_driver = { + }; + module_i2c_driver(i2c_slave_mqueue_driver); + ++module_param_named(dump_debug, dump_debug, bool, 0644); ++MODULE_PARM_DESC(dump_debug, "debug flag for dump printing"); ++module_param_named(dump_debug_bus_id, dump_debug_bus_id, int, 0644); ++MODULE_PARM_DESC(dump_debug_bus_id, "bus id for dump debug printing"); ++ + MODULE_LICENSE("GPL v2"); + MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>"); + MODULE_DESCRIPTION("I2C slave mode for receiving and queuing messages"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch new file mode 100644 index 000000000..5240a05f5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch @@ -0,0 +1,135 @@ +From 0bc792097e73c07bc324e2c9b0172fb27b51a087 Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Wed, 2 Jan 2019 15:06:43 +0800 +Subject: [PATCH] Add high speed baud rate support for UART + +In order to support high speed baud rate(921600 bps), +the default UART clock(24MHz) needs to be switched +to 192MHz(from USB2.0 port1 PHY). + +Create a new 192M Hz clock and assign it to uart, +based on uart clock source configuration in SCU4C. + +bootloader(u-boot) will set SCU4C based on the environment configuration + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + drivers/clk/clk-aspeed.c | 44 +++++++++++++++++++++++++++----- + include/dt-bindings/clock/aspeed-clock.h | 2 ++ + 2 files changed, 39 insertions(+), 7 deletions(-) + +diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c +index 411ff5fb2c07..5e1c87bc8a99 100644 +--- a/drivers/clk/clk-aspeed.c ++++ b/drivers/clk/clk-aspeed.c +@@ -14,7 +14,9 @@ + + #include "clk-aspeed.h" + +-#define ASPEED_NUM_CLKS 38 ++#define ASPEED_NUM_CLKS ASPEED_CLK_MAX ++#define UART_HIGH_SPEED_CLK 192000000 ++#define UART_LOW_SPEED_CLK 24000000 + + #define ASPEED_RESET2_OFFSET 32 + +@@ -29,6 +31,12 @@ + #define ASPEED_MISC_CTRL 0x2c + #define UART_DIV13_EN BIT(12) + #define ASPEED_MAC_CLK_DLY 0x48 ++#define ASPEED_MISC2_CTRL 0x4c ++#define UART1_HS_CLK_EN BIT(24) ++#define UART2_HS_CLK_EN BIT(25) ++#define UART3_HS_CLK_EN BIT(26) ++#define UART4_HS_CLK_EN BIT(27) ++#define UART5_HS_CLK_EN BIT(28) + #define ASPEED_STRAP 0x70 + #define CLKIN_25MHZ_EN BIT(23) + #define AST2400_CLK_SOURCE_SEL BIT(18) +@@ -386,7 +394,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) + struct aspeed_reset *ar; + struct regmap *map; + struct clk_hw *hw; +- u32 val, rate; ++ u32 val, rate, rate_hi; + int i, ret; + + map = syscon_node_to_regmap(dev->of_node); +@@ -420,16 +428,25 @@ static int aspeed_clk_probe(struct platform_device *pdev) + + /* UART clock div13 setting */ + regmap_read(map, ASPEED_MISC_CTRL, &val); +- if (val & UART_DIV13_EN) +- rate = 24000000 / 13; +- else +- rate = 24000000; ++ if (val & UART_DIV13_EN) { ++ rate = UART_LOW_SPEED_CLK / 13; ++ rate_hi = UART_HIGH_SPEED_CLK / 13; ++ } else { ++ rate = UART_LOW_SPEED_CLK; ++ rate_hi = UART_HIGH_SPEED_CLK; ++ } + /* TODO: Find the parent data for the uart clock */ + hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_UART] = hw; + ++ hw = clk_hw_register_fixed_rate(dev, "uart-hs", "usb-port1-gate", 0, ++ rate_hi); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ aspeed_clk_data->hws[ASPEED_CLK_UART_HS] = hw; ++ + /* + * Memory controller (M-PLL) PLL. This clock is configured by the + * bootloader, and is exposed to Linux as a read-only clock rate. +@@ -539,9 +556,22 @@ static int aspeed_clk_probe(struct platform_device *pdev) + * UART[1..5] clock source mux + */ + ++ /* Get the uart clock source configuration from SCU4C*/ ++ regmap_read(map, ASPEED_MISC2_CTRL, &val); + for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) { + const struct aspeed_gate_data *gd = &aspeed_gates[i]; + u32 gate_flags; ++ char *parent_name; ++ ++ /* For uart, needs to adjust the clock based on SCU4C value */ ++ if ((i == ASPEED_CLK_GATE_UART1CLK && (val & UART1_HS_CLK_EN)) || ++ (i == ASPEED_CLK_GATE_UART2CLK && (val & UART2_HS_CLK_EN)) || ++ (i == ASPEED_CLK_GATE_UART5CLK && (val & UART5_HS_CLK_EN)) || ++ (i == ASPEED_CLK_GATE_UART3CLK && (val & UART3_HS_CLK_EN)) || ++ (i == ASPEED_CLK_GATE_UART4CLK && (val & UART4_HS_CLK_EN))) ++ parent_name = "uart-hs"; ++ else ++ parent_name = gd->parent_name; + + /* Special case: the USB port 1 clock (bit 14) is always + * working the opposite way from the other ones. +@@ -549,7 +579,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) + gate_flags = (gd->clock_idx == 14) ? 0 : CLK_GATE_SET_TO_DISABLE; + hw = aspeed_clk_hw_register_gate(dev, + gd->name, +- gd->parent_name, ++ parent_name, + gd->flags, + map, + gd->clock_idx, +diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h +index 9ff4f6e4558c..41d531dd0b48 100644 +--- a/include/dt-bindings/clock/aspeed-clock.h ++++ b/include/dt-bindings/clock/aspeed-clock.h +@@ -41,6 +41,8 @@ + #define ASPEED_CLK_24M 35 + #define ASPEED_CLK_MAC1RCLK 36 + #define ASPEED_CLK_MAC2RCLK 37 ++#define ASPEED_CLK_UART_HS 38 ++#define ASPEED_CLK_MAX 39 + + #define ASPEED_RESET_XDMA 0 + #define ASPEED_RESET_MCTP 1 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch new file mode 100644 index 000000000..2ba9e5002 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch @@ -0,0 +1,559 @@ +From 09aa5d5af94823f100fb515d45b0a04fc8d7ee4f Mon Sep 17 00:00:00 2001 +From: Oskar Senft <osk@google.com> +Date: Wed, 8 Aug 2018 10:15:05 -0400 +Subject: [PATCH] misc: aspeed: Add Aspeed UART routing control driver. + +This driver adds sysfs files that allow the BMC userspace to configure +how UARTs and physical serial I/O ports are routed. + +Tested: Checked correct behavior (both read & write) on TYAN S7106 +board by manually changing routing settings and confirming that bits +flow as expected. Tested for UART1 and UART3 as this board doesn't have +the other UARTs wired up in a testable way. + +Signed-off-by: Oskar Senft <osk@google.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + .../ABI/stable/sysfs-driver-aspeed-uart-routing | 14 + + Documentation/misc-devices/aspeed-uart-routing.txt | 49 +++ + arch/arm/boot/dts/aspeed-g5.dtsi | 6 + + arch/arm/boot/dts/aspeed-g6.dtsi | 6 + + drivers/misc/Kconfig | 6 + + drivers/misc/Makefile | 1 + + drivers/misc/aspeed-uart-routing.c | 383 +++++++++++++++++++++ + 7 files changed, 465 insertions(+) + create mode 100644 Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing + create mode 100644 Documentation/misc-devices/aspeed-uart-routing.txt + create mode 100644 drivers/misc/aspeed-uart-routing.c + +diff --git a/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing +new file mode 100644 +index 000000000000..5068737d9c12 +--- /dev/null ++++ b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing +@@ -0,0 +1,14 @@ ++What: /sys/bus/platform/drivers/aspeed-uart-routing/*/io* ++Date: August 2018 ++Contact: Oskar Senft <osk@google.com> ++Description: Configures the input source for the specific physical ++ serial I/O port. ++Users: OpenBMC. Proposed changes should be mailed to ++ openbmc@lists.ozlabs.org ++ ++What: /sys/bus/platform/drivers/aspeed-uart-routing/*/uart* ++Date: August 2018 ++Contact: Oskar Senft <osk@google.com> ++Description: Configures the input source for the specific UART. ++Users: OpenBMC. Proposed changes should be mailed to ++ openbmc@lists.ozlabs.org +diff --git a/Documentation/misc-devices/aspeed-uart-routing.txt b/Documentation/misc-devices/aspeed-uart-routing.txt +new file mode 100644 +index 000000000000..cf1c2a466875 +--- /dev/null ++++ b/Documentation/misc-devices/aspeed-uart-routing.txt +@@ -0,0 +1,49 @@ ++Kernel driver aspeed-uart-routing ++================================= ++ ++Supported chips: ++ASPEED AST2500/AST2600 ++ ++Author: ++Google LLC ++ ++Description ++----------- ++ ++The Aspeed AST2500/AST2600 allows to dynamically route the inputs for the ++built-in UARTS and physical serial I/O ports. ++ ++This allows, for example, to connect the output of UART to another UART. ++This can be used to enable host<->BMC communication via UARTs, e.g. to allow ++access to the host's serial console. ++ ++This driver is for the BMC side. The sysfs files allow the BMC userspace ++which owns the system configuration policy, to configure how UARTs and ++physical serial I/O ports are routed. ++ ++The driver provides the following files in sysfs: ++uart1 Configure the input signal to UART1. ++uart2 Configure the input signal to UART2. ++uart3 Configure the input signal to UART3. ++uart4 Configure the input signal to UART4. ++uart5 Configure the input signal to UART5. ++io1 Configure the input signal to physical serial port 1. ++io2 Configure the input signal to physical serial port 2. ++io3 Configure the input signal to physical serial port 3. ++io4 Configure the input signal to physical serial port 4. ++io5 Configure the input signal to physical serial port 5. ++ ++When read, each file shows the list of available options with the currently ++selected option marked by square brackets "[]". The list of available options ++depends on the selected file. ++ ++Example: ++$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 ++[io1] io2 io3 io4 uart2 uart3 uart4 io6 ++ ++In this case, UART1 gets its input signal from IO1 (physical serial port 1). ++ ++$ echo -n "uart3" \ ++ >/sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 ++$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 ++io1 io2 io3 io4 uart2 [uart3] uart4 io6 +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index bd2037e52a94..797013debaa7 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -523,6 +523,12 @@ + status = "disabled"; + }; + }; ++ ++ uart_routing: uart_routing@9c { ++ compatible = "aspeed,ast2500-uart-routing"; ++ reg = <0x9c 0x4>; ++ status = "disabled"; ++ }; + }; + + peci: bus@1e78b000 { +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index e4c1ab3d274e..8cc978058f16 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -291,6 +291,12 @@ + compatible = "aspeed,ast2600-pinctrl"; + }; + ++ uart_routing: uart_routing@9c { ++ compatible = "aspeed,ast2500-uart-routing"; ++ reg = <0x9c 0x4>; ++ status = "disabled"; ++ }; ++ + smp-memram@180 { + compatible = "aspeed,ast2600-smpmem"; + reg = <0x180 0x40>; +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 0f9b5a356c93..8af817694648 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -441,6 +441,12 @@ config ASPEED_ESPI_SLAVE + Control Aspeed ast2500 eSPI slave controller to handle event + which needs the firmware's processing. + ++config ASPEED_UART_ROUTING ++ tristate "Aspeed ast2500 UART routing control" ++ help ++ If you want to configure UART routing on Aspeed BMC platforms, enable ++ this option. ++ + config PCI_ENDPOINT_TEST + depends on PCI + select CRC32 +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 53864687e8fd..a4372208f4de 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -52,6 +52,7 @@ obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o + obj-$(CONFIG_CXL_BASE) += cxl/ + obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o ++obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o + obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o + obj-$(CONFIG_OCXL) += ocxl/ + obj-y += cardreader/ +diff --git a/drivers/misc/aspeed-uart-routing.c b/drivers/misc/aspeed-uart-routing.c +new file mode 100644 +index 000000000000..21ef5d98c317 +--- /dev/null ++++ b/drivers/misc/aspeed-uart-routing.c +@@ -0,0 +1,383 @@ ++/* ++ * UART Routing driver for Aspeed AST2500 ++ * ++ * Copyright (c) 2018 Google LLC ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include <linux/device.h> ++#include <linux/module.h> ++#include <linux/of_address.h> ++#include <linux/of_platform.h> ++ ++/* The Aspeed AST2500 allows to dynamically route the inputs for the built-in ++ * UARTS and physical serial I/O ports. ++ * ++ * This allows, for example, to connect the output of UART to another UART. ++ * This can be used to enable host<->BMC communication via UARTs, e.g. to allow ++ * access to the host's serial console. ++ * ++ * This driver is for the BMC side. The sysfs files allow the BMC userspace ++ * which owns the system configuration policy, to configure how UARTs and ++ * physical serial I/O ports are routed. ++ */ ++ ++#define ASPEED_HICRA_IO1 "io1" ++#define ASPEED_HICRA_IO2 "io2" ++#define ASPEED_HICRA_IO3 "io3" ++#define ASPEED_HICRA_IO4 "io4" ++#define ASPEED_HICRA_IO5 "io5" ++#define ASPEED_HICRA_IO6 "io6" ++#define ASPEED_HICRA_UART1 "uart1" ++#define ASPEED_HICRA_UART2 "uart2" ++#define ASPEED_HICRA_UART3 "uart3" ++#define ASPEED_HICRA_UART4 "uart4" ++#define ASPEED_HICRA_UART5 "uart5" ++ ++struct aspeed_uart_routing { ++ struct device *dev; ++ void __iomem *regs; ++ spinlock_t lock; ++}; ++ ++struct aspeed_uart_routing_selector { ++ struct device_attribute dev_attr; ++ int shift; ++ int mask; ++ const char * const options[]; ++}; ++ ++#define to_routing_selector(_dev_attr) \ ++ container_of(_dev_attr, struct aspeed_uart_routing_selector, dev_attr) ++ ++ ++static ssize_t aspeed_uart_routing_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf); ++ ++static ssize_t aspeed_uart_routing_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count); ++ ++#define ROUTING_ATTR(_name) { \ ++ .attr = {.name = _name, \ ++ .mode = VERIFY_OCTAL_PERMISSIONS(S_IWUSR | S_IRUGO) }, \ ++ .show = aspeed_uart_routing_show, \ ++ .store = aspeed_uart_routing_store, \ ++} ++ ++static struct aspeed_uart_routing_selector uart5_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART5), ++ .shift = 28, ++ .mask = 0xf, ++ .options = { ++ ASPEED_HICRA_IO5, // 0 ++ ASPEED_HICRA_IO1, // 1 ++ ASPEED_HICRA_IO2, // 2 ++ ASPEED_HICRA_IO3, // 3 ++ ASPEED_HICRA_IO4, // 4 ++ ASPEED_HICRA_UART1, // 5 ++ ASPEED_HICRA_UART2, // 6 ++ ASPEED_HICRA_UART3, // 7 ++ ASPEED_HICRA_UART4, // 8 ++ ASPEED_HICRA_IO6, // 9 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector uart4_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART4), ++ .shift = 25, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_IO4, // 0 ++ ASPEED_HICRA_IO1, // 1 ++ ASPEED_HICRA_IO2, // 2 ++ ASPEED_HICRA_IO3, // 3 ++ ASPEED_HICRA_UART1, // 4 ++ ASPEED_HICRA_UART2, // 5 ++ ASPEED_HICRA_UART3, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector uart3_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART3), ++ .shift = 22, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_IO3, // 0 ++ ASPEED_HICRA_IO4, // 1 ++ ASPEED_HICRA_IO1, // 2 ++ ASPEED_HICRA_IO2, // 3 ++ ASPEED_HICRA_UART4, // 4 ++ ASPEED_HICRA_UART1, // 5 ++ ASPEED_HICRA_UART2, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector uart2_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART2), ++ .shift = 19, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_IO2, // 0 ++ ASPEED_HICRA_IO3, // 1 ++ ASPEED_HICRA_IO4, // 2 ++ ASPEED_HICRA_IO1, // 3 ++ ASPEED_HICRA_UART3, // 4 ++ ASPEED_HICRA_UART4, // 5 ++ ASPEED_HICRA_UART1, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector uart1_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART1), ++ .shift = 16, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_IO1, // 0 ++ ASPEED_HICRA_IO2, // 1 ++ ASPEED_HICRA_IO3, // 2 ++ ASPEED_HICRA_IO4, // 3 ++ ASPEED_HICRA_UART2, // 4 ++ ASPEED_HICRA_UART3, // 5 ++ ASPEED_HICRA_UART4, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector io5_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO5), ++ .shift = 12, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_UART5, // 0 ++ ASPEED_HICRA_UART1, // 1 ++ ASPEED_HICRA_UART2, // 2 ++ ASPEED_HICRA_UART3, // 3 ++ ASPEED_HICRA_UART4, // 4 ++ ASPEED_HICRA_IO1, // 5 ++ ASPEED_HICRA_IO3, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector io4_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO4), ++ .shift = 9, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_UART4, // 0 ++ ASPEED_HICRA_UART5, // 1 ++ ASPEED_HICRA_UART1, // 2 ++ ASPEED_HICRA_UART2, // 3 ++ ASPEED_HICRA_UART3, // 4 ++ ASPEED_HICRA_IO1, // 5 ++ ASPEED_HICRA_IO2, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector io3_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO3), ++ .shift = 6, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_UART3, // 0 ++ ASPEED_HICRA_UART4, // 1 ++ ASPEED_HICRA_UART5, // 2 ++ ASPEED_HICRA_UART1, // 3 ++ ASPEED_HICRA_UART2, // 4 ++ ASPEED_HICRA_IO1, // 5 ++ ASPEED_HICRA_IO2, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector io2_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO2), ++ .shift = 3, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_UART2, // 0 ++ ASPEED_HICRA_UART3, // 1 ++ ASPEED_HICRA_UART4, // 2 ++ ASPEED_HICRA_UART5, // 3 ++ ASPEED_HICRA_UART1, // 4 ++ ASPEED_HICRA_IO3, // 5 ++ ASPEED_HICRA_IO4, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++static struct aspeed_uart_routing_selector io1_sel = { ++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO1), ++ .shift = 0, ++ .mask = 0x7, ++ .options = { ++ ASPEED_HICRA_UART1, // 0 ++ ASPEED_HICRA_UART2, // 1 ++ ASPEED_HICRA_UART3, // 2 ++ ASPEED_HICRA_UART4, // 3 ++ ASPEED_HICRA_UART5, // 4 ++ ASPEED_HICRA_IO3, // 5 ++ ASPEED_HICRA_IO4, // 6 ++ ASPEED_HICRA_IO6, // 7 ++ NULL, // NULL termination ++ }, ++}; ++ ++ ++static struct attribute *aspeed_uart_routing_attrs[] = { ++ &uart1_sel.dev_attr.attr, ++ &uart2_sel.dev_attr.attr, ++ &uart3_sel.dev_attr.attr, ++ &uart4_sel.dev_attr.attr, ++ &uart5_sel.dev_attr.attr, ++ &io1_sel.dev_attr.attr, ++ &io2_sel.dev_attr.attr, ++ &io3_sel.dev_attr.attr, ++ &io4_sel.dev_attr.attr, ++ &io5_sel.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group aspeed_uart_routing_attr_group = { ++ .attrs = aspeed_uart_routing_attrs, ++}; ++ ++static ssize_t aspeed_uart_routing_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev); ++ struct aspeed_uart_routing_selector *sel = to_routing_selector(attr); ++ int val, pos, len; ++ ++ val = (readl(uart_routing->regs) >> sel->shift) & sel->mask; ++ ++ len = 0; ++ for (pos = 0; sel->options[pos] != NULL; ++pos) { ++ if (pos == val) { ++ len += snprintf(buf + len, PAGE_SIZE - 1 - len, ++ "[%s] ", sel->options[pos]); ++ } else { ++ len += snprintf(buf + len, PAGE_SIZE - 1 - len, ++ "%s ", sel->options[pos]); ++ } ++ } ++ ++ if (val >= pos) { ++ len += snprintf(buf + len, PAGE_SIZE - 1 - len, ++ "[unknown(%d)]", val); ++ } ++ ++ len += snprintf(buf + len, PAGE_SIZE - 1 - len, "\n"); ++ ++ return len; ++} ++ ++static ssize_t aspeed_uart_routing_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev); ++ struct aspeed_uart_routing_selector *sel = to_routing_selector(attr); ++ int val; ++ u32 reg; ++ ++ val = match_string(sel->options, -1, buf); ++ if (val < 0) { ++ dev_err(dev, "invalid value \"%s\"\n", buf); ++ return -EINVAL; ++ } ++ ++ spin_lock(&uart_routing->lock); ++ reg = readl(uart_routing->regs); ++ // Zero out existing value in specified bits. ++ reg &= ~(sel->mask << sel->shift); ++ // Set new value in specified bits. ++ reg |= (val & sel->mask) << sel->shift; ++ writel(reg, uart_routing->regs); ++ spin_unlock(&uart_routing->lock); ++ ++ return count; ++} ++ ++static int aspeed_uart_routing_probe(struct platform_device *pdev) ++{ ++ struct aspeed_uart_routing *uart_routing; ++ struct resource *res; ++ int rc; ++ ++ uart_routing = devm_kzalloc(&pdev->dev, ++ sizeof(*uart_routing), ++ GFP_KERNEL); ++ if (!uart_routing) ++ return -ENOMEM; ++ ++ spin_lock_init(&uart_routing->lock); ++ uart_routing->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ uart_routing->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(uart_routing->regs)) ++ return PTR_ERR(uart_routing->regs); ++ ++ rc = sysfs_create_group(&uart_routing->dev->kobj, ++ &aspeed_uart_routing_attr_group); ++ if (rc < 0) ++ return rc; ++ ++ platform_set_drvdata(pdev, uart_routing); ++ ++ return 0; ++} ++ ++static int aspeed_uart_routing_remove(struct platform_device *pdev) ++{ ++ struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev); ++ ++ sysfs_remove_group(&uart_routing->dev->kobj, ++ &aspeed_uart_routing_attr_group); ++ ++ return 0; ++} ++ ++static const struct of_device_id aspeed_uart_routing_table[] = { ++ { .compatible = "aspeed,ast2500-uart-routing" }, ++ { }, ++}; ++ ++static struct platform_driver aspeed_uart_routing_driver = { ++ .driver = { ++ .name = "aspeed-uart-routing", ++ .of_match_table = aspeed_uart_routing_table, ++ }, ++ .probe = aspeed_uart_routing_probe, ++ .remove = aspeed_uart_routing_remove, ++}; ++ ++module_platform_driver(aspeed_uart_routing_driver); ++ ++MODULE_AUTHOR("Oskar Senft <osk@google.com>"); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Driver to configure Aspeed UART routing"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch new file mode 100644 index 000000000..2f0fd3a31 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch @@ -0,0 +1,85 @@ +From 65c8090f2b418892aee9f239729fa417bd508a00 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 3 Oct 2018 10:17:58 -0700 +Subject: [PATCH] arm: dts: aspeed: Swap the mac nodes numbering + +This patch swaps the numbering of mac0 and mac1 to make a dedicated +nic get assigned the first ethernet device number. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/boot/dts/aspeed-g4.dtsi | 16 ++++++++-------- + arch/arm/boot/dts/aspeed-g5.dtsi | 16 ++++++++-------- + 2 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index a70bee24d058..054d97229626 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -120,14 +120,6 @@ + reg = <0x1e6c2000 0x80>; + }; + +- mac0: ethernet@1e660000 { +- compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; +- reg = <0x1e660000 0x180>; +- interrupts = <2>; +- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; +- status = "disabled"; +- }; +- + mac1: ethernet@1e680000 { + compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; + reg = <0x1e680000 0x180>; +@@ -136,6 +128,14 @@ + status = "disabled"; + }; + ++ mac0: ethernet@1e660000 { ++ compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; ++ reg = <0x1e660000 0x180>; ++ interrupts = <2>; ++ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; ++ status = "disabled"; ++ }; ++ + ehci0: usb@1e6a1000 { + compatible = "aspeed,ast2400-ehci", "generic-ehci"; + reg = <0x1e6a1000 0x100>; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 797013debaa7..27ed188296a1 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -148,14 +148,6 @@ + reg = <0x1e6c2000 0x80>; + }; + +- mac0: ethernet@1e660000 { +- compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; +- reg = <0x1e660000 0x180>; +- interrupts = <2>; +- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; +- status = "disabled"; +- }; +- + mac1: ethernet@1e680000 { + compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; + reg = <0x1e680000 0x180>; +@@ -164,6 +156,14 @@ + status = "disabled"; + }; + ++ mac0: ethernet@1e660000 { ++ compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; ++ reg = <0x1e660000 0x180>; ++ interrupts = <2>; ++ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; ++ status = "disabled"; ++ }; ++ + ehci0: usb@1e6a1000 { + compatible = "aspeed,ast2500-ehci", "generic-ehci"; + reg = <0x1e6a1000 0x100>; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch new file mode 100644 index 000000000..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..0fdd40d77 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch @@ -0,0 +1,514 @@ +From b20b1ce81f4451d9e906b84e7edcc22d4e70e7df Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 11 Feb 2019 17:02:35 -0800 +Subject: [PATCH] Add Aspeed PWM driver which uses FTTMR010 timer IP + +This commit adds Aspeed PWM driver which uses timer pulse output +feature in Aspeed SoCs. The timer IP is derived from Faraday +Technologies FTTMR010 IP but has some customized register +structure changes only for Aspeed SoCs. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/boot/dts/aspeed-g5.dtsi | 2 +- + drivers/pwm/Kconfig | 9 + + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-fttmr010.c | 441 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 452 insertions(+), 1 deletion(-) + create mode 100644 drivers/pwm/pwm-fttmr010.c + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 27ed188296a1..45202bc3d60c 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -341,7 +341,7 @@ + + timer: timer@1e782000 { + /* This timer is a Faraday FTTMR010 derivative */ +- compatible = "aspeed,ast2400-timer"; ++ compatible = "aspeed,ast2500-timer"; + reg = <0x1e782000 0x90>; + interrupts = <16 17 18 35 36 37 38 39>; + clocks = <&syscon ASPEED_CLK_APB>; +diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +index e3a2518503ed..21def8cd5af6 100644 +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -171,6 +171,15 @@ config PWM_FSL_FTM + To compile this driver as a module, choose M here: the module + will be called pwm-fsl-ftm. + ++config PWM_FTTMR010 ++ tristate "Faraday Technology FTTMR010 timer PWM support" ++ help ++ Generic PWM framework driver for Faraday Technology FTTMR010 Timer ++ PWM output ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-fttmr010 ++ + config PWM_HIBVT + tristate "HiSilicon BVT PWM support" + depends on ARCH_HISI || COMPILE_TEST +diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile +index 26326adf71d7..3a9e9840b5ae 100644 +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o + obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o + obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o + obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o ++obj-$(CONFIG_PWM_FTTMR010) += pwm-fttmr010.o + obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o + obj-$(CONFIG_PWM_IMG) += pwm-img.o + obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o +diff --git a/drivers/pwm/pwm-fttmr010.c b/drivers/pwm/pwm-fttmr010.c +new file mode 100644 +index 000000000000..283ded6906f1 +--- /dev/null ++++ b/drivers/pwm/pwm-fttmr010.c +@@ -0,0 +1,441 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2019 Intel Corporation ++ ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/pwm.h> ++ ++#define TIMER_CR 0x30 ++ ++#define TIMER5_ASPEED_COUNT 0x50 ++#define TIMER5_ASPEED_LOAD 0x54 ++#define TIMER5_ASPEED_MATCH1 0x58 ++#define TIMER5_ASPEED_MATCH2 0x5c ++#define TIMER6_ASPEED_COUNT 0x60 ++#define TIMER6_ASPEED_LOAD 0x64 ++#define TIMER6_ASPEED_MATCH1 0x68 ++#define TIMER6_ASPEED_MATCH2 0x6c ++#define TIMER7_ASPEED_COUNT 0x70 ++#define TIMER7_ASPEED_LOAD 0x74 ++#define TIMER7_ASPEED_MATCH1 0x78 ++#define TIMER7_ASPEED_MATCH2 0x7c ++#define TIMER8_ASPEED_COUNT 0x80 ++#define TIMER8_ASPEED_LOAD 0x84 ++#define TIMER8_ASPEED_MATCH1 0x88 ++#define TIMER8_ASPEED_MATCH2 0x8c ++ ++#define TIMER_5_CR_ASPEED_ENABLE BIT(16) ++#define TIMER_5_CR_ASPEED_CLOCK BIT(17) ++#define TIMER_5_CR_ASPEED_INT BIT(18) ++#define TIMER_5_CR_ASPEED_PULSE_OUT BIT(19) ++#define TIMER_6_CR_ASPEED_ENABLE BIT(20) ++#define TIMER_6_CR_ASPEED_CLOCK BIT(21) ++#define TIMER_6_CR_ASPEED_INT BIT(22) ++#define TIMER_6_CR_ASPEED_PULSE_OUT BIT(23) ++#define TIMER_7_CR_ASPEED_ENABLE BIT(24) ++#define TIMER_7_CR_ASPEED_CLOCK BIT(25) ++#define TIMER_7_CR_ASPEED_INT BIT(26) ++#define TIMER_7_CR_ASPEED_PULSE_OUT BIT(27) ++#define TIMER_8_CR_ASPEED_ENABLE BIT(28) ++#define TIMER_8_CR_ASPEED_CLOCK BIT(29) ++#define TIMER_8_CR_ASPEED_INT BIT(30) ++#define TIMER_8_CR_ASPEED_PULSE_OUT BIT(31) ++ ++/** ++ * struct pwm_fttmr010_variant - variant data depends on SoC ++ * @bits: timer counter resolution ++ * @chan_min: lowest timer channel which has pwm pulse output ++ * @chan_max: highest timer channel which has pwm pulse output ++ * @output_mask: pwm pulse output mask which is defined in device tree ++ */ ++struct pwm_fttmr010_variant { ++ u8 bits; ++ u8 chan_min; ++ u8 chan_max; ++ u8 output_mask; ++}; ++ ++/** ++ * struct pwm_fttmr010_chan - private data of FTTMR010 PWM channel ++ * @period_ns: current period in nanoseconds programmed to the hardware ++ * @duty_ns: current duty time in nanoseconds programmed to the hardware ++ */ ++struct pwm_fttmr010_chan { ++ u32 period_ns; ++ u32 duty_ns; ++}; ++ ++/** ++ * struct pwm_fttmr010 - private data of FTTMR010 PWM ++ * @chip: generic PWM chip ++ * @variant: local copy of hardware variant data ++ * @disabled_mask: disabled status for all channels - one bit per channel ++ * @base: base address of mapped PWM registers ++ * @clk: clock used to drive the timers ++ */ ++struct pwm_fttmr010 { ++ struct pwm_chip chip; ++ struct pwm_fttmr010_variant variant; ++ u8 disabled_mask; ++ void __iomem *base; ++ struct clk *clk; ++ u32 clk_tick_ns; ++}; ++ ++static inline ++struct pwm_fttmr010 *to_pwm_fttmr010(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct pwm_fttmr010, chip); ++} ++ ++static int pwm_fttmr010_request(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); ++ struct pwm_fttmr010_chan *chan; ++ ++ if (!(priv->variant.output_mask & BIT(pwm->hwpwm))) { ++ dev_warn(chip->dev, ++ "tried to request PWM channel %d without output\n", ++ pwm->hwpwm); ++ return -EINVAL; ++ } ++ ++ chan = devm_kzalloc(chip->dev, sizeof(*chan), GFP_KERNEL); ++ if (!chan) ++ return -ENOMEM; ++ ++ pwm_set_chip_data(pwm, chan); ++ ++ return 0; ++} ++ ++static void pwm_fttmr010_free(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ devm_kfree(chip->dev, pwm_get_chip_data(pwm)); ++ pwm_set_chip_data(pwm, NULL); ++} ++ ++static int pwm_fttmr010_enable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); ++ u32 cr; ++ ++ cr = readl(priv->base + TIMER_CR); ++ ++ switch (pwm->hwpwm) { ++ case 5: ++ cr |= (TIMER_5_CR_ASPEED_ENABLE | TIMER_5_CR_ASPEED_PULSE_OUT); ++ break; ++ case 6: ++ cr |= (TIMER_6_CR_ASPEED_ENABLE | TIMER_6_CR_ASPEED_PULSE_OUT); ++ break; ++ case 7: ++ cr |= (TIMER_7_CR_ASPEED_ENABLE | TIMER_7_CR_ASPEED_PULSE_OUT); ++ break; ++ case 8: ++ cr |= (TIMER_8_CR_ASPEED_ENABLE | TIMER_8_CR_ASPEED_PULSE_OUT); ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ writel(cr, priv->base + TIMER_CR); ++ priv->disabled_mask &= ~BIT(pwm->hwpwm); ++ ++ return 0; ++} ++ ++static void pwm_fttmr010_disable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); ++ u32 cr; ++ ++ cr = readl(priv->base + TIMER_CR); ++ ++ switch (pwm->hwpwm) { ++ case 5: ++ cr &= ~(TIMER_5_CR_ASPEED_ENABLE | TIMER_5_CR_ASPEED_PULSE_OUT); ++ break; ++ case 6: ++ cr &= ~(TIMER_6_CR_ASPEED_ENABLE | TIMER_6_CR_ASPEED_PULSE_OUT); ++ break; ++ case 7: ++ cr &= ~(TIMER_7_CR_ASPEED_ENABLE | TIMER_7_CR_ASPEED_PULSE_OUT); ++ break; ++ case 8: ++ cr &= ~(TIMER_8_CR_ASPEED_ENABLE | TIMER_8_CR_ASPEED_PULSE_OUT); ++ break; ++ default: ++ return; ++ } ++ ++ writel(cr, priv->base + TIMER_CR); ++ priv->disabled_mask |= BIT(pwm->hwpwm); ++} ++ ++static int pwm_fttmr010_config(struct pwm_chip *chip, struct pwm_device *pwm, ++ int duty_ns, int period_ns) ++{ ++ u32 tload, tmatch, creg_offset, lreg_offset, mreg_offset; ++ struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm); ++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); ++ ++ /* ++ * We currently avoid using 64bit arithmetic by using the ++ * fact that anything faster than 1Hz is easily representable ++ * by 32bits. ++ */ ++ if (period_ns > NSEC_PER_SEC) ++ return -ERANGE; ++ ++ /* No need to update */ ++ if (chan->period_ns == period_ns || chan->duty_ns == duty_ns) ++ return 0; ++ ++ tload = period_ns / priv->clk_tick_ns; ++ ++ /* Period is too short */ ++ if (tload <= 1) ++ return -ERANGE; ++ ++ tmatch = duty_ns / priv->clk_tick_ns; ++ ++ /* 0% duty is not available */ ++ if (!tmatch) ++ ++tmatch; ++ ++ tmatch = tload - tmatch; ++ ++ /* Decrement to get tick numbers, instead of tick counts */ ++ --tload; ++ --tmatch; ++ ++ if (tload == 0 || tmatch == 0) ++ return -ERANGE; ++ ++ dev_dbg(priv->chip.dev, "clk_tick_ns:%u, tload:%u, tmatch:%u\n", ++ priv->clk_tick_ns, tload, tmatch); ++ ++ switch (pwm->hwpwm) { ++ case 5: ++ creg_offset = TIMER5_ASPEED_COUNT; ++ lreg_offset = TIMER5_ASPEED_LOAD; ++ mreg_offset = TIMER5_ASPEED_MATCH1; ++ break; ++ case 6: ++ creg_offset = TIMER6_ASPEED_COUNT; ++ lreg_offset = TIMER6_ASPEED_LOAD; ++ mreg_offset = TIMER6_ASPEED_MATCH1; ++ break; ++ case 7: ++ creg_offset = TIMER7_ASPEED_COUNT; ++ lreg_offset = TIMER7_ASPEED_LOAD; ++ mreg_offset = TIMER7_ASPEED_MATCH1; ++ break; ++ case 8: ++ creg_offset = TIMER8_ASPEED_COUNT; ++ lreg_offset = TIMER8_ASPEED_LOAD; ++ mreg_offset = TIMER8_ASPEED_MATCH1; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ writel(tload, priv->base + creg_offset); ++ writel(tload, priv->base + lreg_offset); ++ writel(tmatch, priv->base + mreg_offset); ++ ++ chan->period_ns = period_ns; ++ chan->duty_ns = duty_ns; ++ ++ return 0; ++} ++ ++static const struct pwm_ops pwm_fttmr010_ops = { ++ .request = pwm_fttmr010_request, ++ .free = pwm_fttmr010_free, ++ .enable = pwm_fttmr010_enable, ++ .disable = pwm_fttmr010_disable, ++ .config = pwm_fttmr010_config, ++ .owner = THIS_MODULE, ++}; ++ ++#ifdef CONFIG_OF ++static const struct pwm_fttmr010_variant aspeed_variant = { ++ .bits = 32, ++ .chan_min = 5, ++ .chan_max = 8, ++}; ++ ++static const struct of_device_id pwm_fttmr010_matches[] = { ++ { .compatible = "aspeed,ast2400-timer", .data = &aspeed_variant }, ++ { .compatible = "aspeed,ast2500-timer", .data = &aspeed_variant }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, pwm_fttmr010_matches); ++ ++static int pwm_fttmr010_parse_dt(struct pwm_fttmr010 *priv) ++{ ++ struct device_node *np = priv->chip.dev->of_node; ++ const struct of_device_id *match; ++ struct property *prop; ++ const __be32 *cur; ++ u32 val; ++ ++ match = of_match_node(pwm_fttmr010_matches, np); ++ if (!match) ++ return -ENODEV; ++ ++ memcpy(&priv->variant, match->data, sizeof(priv->variant)); ++ ++ of_property_for_each_u32(np, "fttmr010,pwm-outputs", prop, cur, val) { ++ if (val < priv->variant.chan_min || ++ val > priv->variant.chan_max) { ++ dev_err(priv->chip.dev, ++ "invalid channel index in fttmr010,pwm-outputs property\n"); ++ continue; ++ } ++ priv->variant.output_mask |= BIT(val); ++ } ++ ++ return 0; ++} ++#else ++static int pwm_fttmr010_parse_dt(struct pwm_fttmr010 *priv) ++{ ++ return -ENODEV; ++} ++#endif ++ ++static int pwm_fttmr010_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct pwm_fttmr010 *priv; ++ struct resource *res; ++ ulong clk_rate; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->chip.dev = &pdev->dev; ++ priv->chip.ops = &pwm_fttmr010_ops; ++ priv->chip.base = -1; ++ ++ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { ++ ret = pwm_fttmr010_parse_dt(priv); ++ if (ret) ++ return ret; ++ ++ priv->chip.of_xlate = of_pwm_xlate_with_flags; ++ priv->chip.of_pwm_n_cells = 3; ++ } else { ++ if (!pdev->dev.platform_data) { ++ dev_err(&pdev->dev, "no platform data specified\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&priv->variant, pdev->dev.platform_data, ++ sizeof(priv->variant)); ++ } ++ ++ priv->chip.npwm = priv->variant.chan_max + 1; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ priv->clk = devm_clk_get(&pdev->dev, "PCLK"); ++ if (IS_ERR(priv->clk)) { ++ dev_err(dev, "failed to get timer base clk\n"); ++ return PTR_ERR(priv->clk); ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret < 0) { ++ dev_err(dev, "failed to enable base clock\n"); ++ return ret; ++ } ++ ++ clk_rate = clk_get_rate(priv->clk); ++ priv->clk_tick_ns = NSEC_PER_SEC / clk_rate; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ ret = pwmchip_add(&priv->chip); ++ if (ret < 0) { ++ dev_err(dev, "failed to register PWM chip\n"); ++ clk_disable_unprepare(priv->clk); ++ return ret; ++ } ++ ++ dev_dbg(dev, "clk at %lu\n", clk_rate); ++ ++ return 0; ++} ++ ++static int pwm_fttmr010_remove(struct platform_device *pdev) ++{ ++ struct pwm_fttmr010 *priv = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = pwmchip_remove(&priv->chip); ++ if (ret < 0) ++ return ret; ++ ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int pwm_fttmr010_resume(struct device *dev) ++{ ++ struct pwm_fttmr010 *priv = dev_get_drvdata(dev); ++ struct pwm_chip *chip = &priv->chip; ++ unsigned int i; ++ ++ for (i = priv->variant.chan_min; i < priv->variant.chan_max; i++) { ++ struct pwm_device *pwm = &chip->pwms[i]; ++ struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm); ++ ++ if (!chan) ++ continue; ++ ++ if (chan->period_ns) { ++ pwm_fttmr010_config(chip, pwm, chan->duty_ns, ++ chan->period_ns); ++ } ++ ++ if (priv->disabled_mask & BIT(i)) ++ pwm_fttmr010_disable(chip, pwm); ++ else ++ pwm_fttmr010_enable(chip, pwm); ++ } ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(pwm_fttmr010_pm_ops, NULL, pwm_fttmr010_resume); ++ ++static struct platform_driver pwm_fttmr010_driver = { ++ .driver = { ++ .name = "fttmr010-timer-pwm", ++ .pm = &pwm_fttmr010_pm_ops, ++ .of_match_table = of_match_ptr(pwm_fttmr010_matches), ++ }, ++ .probe = pwm_fttmr010_probe, ++ .remove = pwm_fttmr010_remove, ++}; ++module_platform_driver(pwm_fttmr010_driver); ++ ++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); ++MODULE_DESCRIPTION("FTTMR010 PWM Driver for timer pulse outputs"); ++MODULE_LICENSE("GPL v2"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch new file mode 100644 index 000000000..198beaa93 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch @@ -0,0 +1,488 @@ +From ee9cee93b96b791f52295d7763985fdb10903e2b Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 15 Feb 2019 16:05:09 -0800 +Subject: [PATCH] i2c: Add mux hold/unhold msg types + +This commit adds mux hold/unhold message types to support extended +mux control for IPMB and MCTP devices. A hold or an unhold message +can be added at the end of I2C message stream wrapped by +repeated-start, also can be used as a single message independantly. + +This mux hold/unhold message will be delivered throughout all mux +levels in the path. Means that if it goes to multi-level mux path, +all muxes will be held/unheld by this message. + +1. Hold message + struct i2c_msg msg; + uint16_t timeout = 5000; // timeout in ms. 5 secs in this example. + + msg.addr = 0x0; // any value can be used. addr will be ignored in this packet. + msg.flags = I2C_M_HOLD; // set this flag to indicate it's a hold message. + msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer. + msg.buf = (uint8_t *)&timeout; // set timeout value. + +2. Unhold message + struct i2c_msg msg; + uint16_t timeout = 0; // set 0 for an unhold message. + + msg.addr = 0x0; // any value can be used. addr will be ignored in this packet. + msg.flags = I2C_M_HOLD; // set this flag to indicate it's an unhold message. + msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer. + msg.buf = (uint8_t *)&timeout; // set timeout value. + + This unhold message can be delivered to a mux adapter even when + a bus is locked so that any holding state can be unheld + immediately by invoking this unhold message. + +This patch would not be welcomed from upstream so it should be kept +in downstream only. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/i2c-core-base.c | 70 +++++++++++++++++++++++++-- + drivers/i2c/i2c-core-smbus.c | 22 +++++++-- + drivers/i2c/i2c-mux.c | 109 +++++++++++++++++++++++++++++++++++++++---- + include/linux/i2c-mux.h | 3 ++ + include/linux/i2c.h | 25 ++++++++++ + include/uapi/linux/i2c.h | 1 + + 6 files changed, 214 insertions(+), 16 deletions(-) + +diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c +index 5f6a4985f2bc..d1cd7afe4068 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -1297,6 +1297,25 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr) + } + EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify); + ++static void i2c_adapter_hold(struct i2c_adapter *adapter, unsigned long timeout) ++{ ++ mutex_lock(&adapter->hold_lock); ++ mod_timer(&adapter->hold_timer, jiffies + timeout); ++} ++ ++static void i2c_adapter_unhold(struct i2c_adapter *adapter) ++{ ++ del_timer_sync(&adapter->hold_timer); ++ mutex_unlock(&adapter->hold_lock); ++} ++ ++static void i2c_adapter_hold_timer_callback(struct timer_list *t) ++{ ++ struct i2c_adapter *adapter = from_timer(adapter, t, hold_timer); ++ ++ i2c_adapter_unhold(adapter); ++} ++ + static int i2c_register_adapter(struct i2c_adapter *adap) + { + int res = -EINVAL; +@@ -1379,6 +1398,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap) + bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); + mutex_unlock(&core_lock); + ++ mutex_init(&adap->hold_lock); ++ timer_setup(&adap->hold_timer, i2c_adapter_hold_timer_callback, 0); ++ + return 0; + + out_reg: +@@ -1599,6 +1621,8 @@ void i2c_del_adapter(struct i2c_adapter *adap) + idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); + ++ i2c_adapter_unhold(adap); ++ + /* Clear the device structure in case this adapter is ever going to be + added again */ + memset(&adap->dev, 0, sizeof(adap->dev)); +@@ -1948,7 +1972,9 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, + */ + int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + { ++ enum i2c_hold_msg_type hold_msg = I2C_HOLD_MSG_NONE; + unsigned long orig_jiffies; ++ unsigned long timeout; + int ret, try; + + if (WARN_ON(!msgs || num < 1)) +@@ -1961,6 +1987,25 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) + return -EOPNOTSUPP; + ++ /* Do not deliver a mux hold msg to root bus adapter */ ++ if (!i2c_parent_is_i2c_adapter(adap)) { ++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags, ++ msgs[num - 1].len, ++ (u16 *)msgs[num - 1].buf); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf); ++ i2c_adapter_hold(adap, timeout); ++ ++ if (--num == 0) ++ return 0; ++ } else if (hold_msg == I2C_HOLD_MSG_RESET) { ++ i2c_adapter_unhold(adap); ++ return 0; ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&adap->hold_lock); ++ } ++ } ++ + /* + * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets + * enabled. This is an efficient way of keeping the for-loop from +@@ -1997,6 +2042,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + trace_i2c_result(adap, num, ret); + } + ++ if (!i2c_parent_is_i2c_adapter(adap) && hold_msg == I2C_HOLD_MSG_NONE) ++ mutex_unlock(&adap->hold_lock); ++ + return ret; + } + EXPORT_SYMBOL(__i2c_transfer); +@@ -2015,6 +2063,7 @@ EXPORT_SYMBOL(__i2c_transfer); + */ + int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + { ++ bool do_bus_lock = true; + int ret; + + if (!adap->algo->master_xfer) { +@@ -2038,12 +2087,25 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + * one (discarding status on the second message) or errno + * (discarding status on the first one). + */ +- ret = __i2c_lock_bus_helper(adap); +- if (ret) +- return ret; ++ /* ++ * Do not lock a bus for delivering an unhold msg to a mux ++ * adpater. This is just for a single length unhold msg case. ++ */ ++ if (num == 1 && i2c_parent_is_i2c_adapter(adap) && ++ i2c_check_hold_msg(msgs[0].flags, msgs[0].len, ++ (u16 *)msgs[0].buf) == ++ I2C_HOLD_MSG_RESET) ++ do_bus_lock = false; ++ ++ if (do_bus_lock) { ++ ret = __i2c_lock_bus_helper(adap); ++ if (ret) ++ return ret; ++ } + + ret = __i2c_transfer(adap, msgs, num); +- i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); ++ if (do_bus_lock) ++ i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); + + return ret; + } +diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c +index 3ac426a8ab5a..f7bf95101e34 100644 +--- a/drivers/i2c/i2c-core-smbus.c ++++ b/drivers/i2c/i2c-core-smbus.c +@@ -526,15 +526,29 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char read_write, + u8 command, int protocol, union i2c_smbus_data *data) + { ++ bool do_bus_lock = true; + s32 res; + +- res = __i2c_lock_bus_helper(adapter); +- if (res) +- return res; ++ /* ++ * Do not lock a bus for delivering an unhold msg to a mux adpater. ++ * This is just for a single length unhold msg case. ++ */ ++ if (i2c_parent_is_i2c_adapter(adapter) && ++ i2c_check_hold_msg(flags, ++ protocol == I2C_SMBUS_WORD_DATA ? 2 : 0, ++ &data->word) == I2C_HOLD_MSG_RESET) ++ do_bus_lock = false; ++ ++ if (do_bus_lock) { ++ res = __i2c_lock_bus_helper(adapter); ++ if (res) ++ return res; ++ } + + res = __i2c_smbus_xfer(adapter, addr, flags, read_write, + command, protocol, data); +- i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); ++ if (do_bus_lock) ++ i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); + + return res; + } +diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c +index 774507b54b57..c6e433238b22 100644 +--- a/drivers/i2c/i2c-mux.c ++++ b/drivers/i2c/i2c-mux.c +@@ -27,6 +27,7 @@ + #include <linux/of.h> + #include <linux/slab.h> + #include <linux/sysfs.h> ++#include <linux/timer.h> + + /* multiplexer per channel data */ + struct i2c_mux_priv { +@@ -36,21 +37,57 @@ struct i2c_mux_priv { + u32 chan_id; + }; + ++static void i2c_mux_hold(struct i2c_mux_core *muxc, unsigned long timeout) ++{ ++ mutex_lock(&muxc->hold_lock); ++ mod_timer(&muxc->hold_timer, jiffies + timeout); ++} ++ ++static void i2c_mux_unhold(struct i2c_mux_core *muxc) ++{ ++ del_timer_sync(&muxc->hold_timer); ++ mutex_unlock(&muxc->hold_lock); ++} ++ ++static void i2c_mux_hold_timer_callback(struct timer_list *t) ++{ ++ struct i2c_mux_core *muxc = from_timer(muxc, t, hold_timer); ++ ++ i2c_mux_unhold(muxc); ++} ++ + static int __i2c_mux_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) + { + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Switch to the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags, ++ msgs[num - 1].len, ++ (u16 *)msgs[num - 1].buf); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = __i2c_transfer(parent, msgs, num); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -61,15 +98,32 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap, + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Switch to the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags, ++ msgs[num - 1].len, ++ (u16 *)msgs[num - 1].buf); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = i2c_transfer(parent, msgs, num); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -82,16 +136,33 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Select the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(flags, ++ size == I2C_SMBUS_WORD_DATA ? 2 : 0, ++ &data->word); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(data->word); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = __i2c_smbus_xfer(parent, addr, flags, + read_write, command, size, data); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -104,16 +175,33 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap, + struct i2c_mux_priv *priv = adap->algo_data; + struct i2c_mux_core *muxc = priv->muxc; + struct i2c_adapter *parent = muxc->parent; ++ enum i2c_hold_msg_type hold_msg; ++ unsigned long timeout; + int ret; + + /* Select the right mux port and perform the transfer. */ + ++ hold_msg = i2c_check_hold_msg(flags, ++ size == I2C_SMBUS_WORD_DATA ? 2 : 0, ++ &data->word); ++ if (hold_msg == I2C_HOLD_MSG_SET) { ++ timeout = msecs_to_jiffies(data->word); ++ i2c_mux_hold(muxc, timeout); ++ } else if (hold_msg == I2C_HOLD_MSG_NONE) { ++ mutex_lock(&muxc->hold_lock); ++ } + ret = muxc->select(muxc, priv->chan_id); + if (ret >= 0) + ret = i2c_smbus_xfer(parent, addr, flags, + read_write, command, size, data); +- if (muxc->deselect) +- muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg != I2C_HOLD_MSG_SET) { ++ if (muxc->deselect) ++ muxc->deselect(muxc, priv->chan_id); ++ if (hold_msg == I2C_HOLD_MSG_RESET) ++ i2c_mux_unhold(muxc); ++ else ++ mutex_unlock(&muxc->hold_lock); ++ } + + return ret; + } +@@ -263,6 +351,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, + muxc->deselect = deselect; + muxc->max_adapters = max_adapters; + ++ mutex_init(&muxc->hold_lock); ++ timer_setup(&muxc->hold_timer, i2c_mux_hold_timer_callback, 0); ++ + return muxc; + } + EXPORT_SYMBOL_GPL(i2c_mux_alloc); +@@ -441,6 +532,8 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc) + { + char symlink_name[20]; + ++ i2c_mux_unhold(muxc); ++ + while (muxc->num_adapters) { + struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters]; + struct i2c_mux_priv *priv = adap->algo_data; +diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h +index c5a977320f82..47f8763d6ed2 100644 +--- a/include/linux/i2c-mux.h ++++ b/include/linux/i2c-mux.h +@@ -27,6 +27,9 @@ struct i2c_mux_core { + int (*select)(struct i2c_mux_core *, u32 chan_id); + int (*deselect)(struct i2c_mux_core *, u32 chan_id); + ++ struct mutex hold_lock; /* mutex for channel holding */ ++ struct timer_list hold_timer; ++ + int num_adapters; + int max_adapters; + struct i2c_adapter *adapter[0]; +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index 1361637c369d..b4055d133338 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -711,6 +711,13 @@ struct i2c_adapter { + const struct i2c_adapter_quirks *quirks; + + struct irq_domain *host_notify_domain; ++ ++ /* ++ * These will be used by root adpaters only. For muxes, each mux core ++ * has these individually. ++ */ ++ struct mutex hold_lock; /* mutex for bus holding */ ++ struct timer_list hold_timer; + }; + #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) + +@@ -1005,4 +1012,22 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha + } + #endif /* CONFIG_ACPI */ + ++enum i2c_hold_msg_type { ++ I2C_HOLD_MSG_NONE, ++ I2C_HOLD_MSG_SET, ++ I2C_HOLD_MSG_RESET ++}; ++ ++static inline enum i2c_hold_msg_type i2c_check_hold_msg(u16 flags, u16 len, u16 *buf) ++{ ++ if (flags & I2C_M_HOLD && len == sizeof(u16)) { ++ if (*buf) ++ return I2C_HOLD_MSG_SET; ++ ++ return I2C_HOLD_MSG_RESET; ++ } ++ ++ return I2C_HOLD_MSG_NONE; ++} ++ + #endif /* _LINUX_I2C_H */ +diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h +index f71a1751cacf..a1db9b17ed36 100644 +--- a/include/uapi/linux/i2c.h ++++ b/include/uapi/linux/i2c.h +@@ -72,6 +72,7 @@ struct i2c_msg { + #define I2C_M_RD 0x0001 /* read data, from slave to master */ + /* I2C_M_RD is guaranteed to be 0x0001! */ + #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ ++#define I2C_M_HOLD 0x0100 /* for holding a mux path */ + #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */ + /* makes only sense in kernelspace */ + /* userspace buffers are copied anyway */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch new file mode 100644 index 000000000..5b9d4ef8b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch @@ -0,0 +1,105 @@ +From 37e7896bf297edef4f2877998ca7a5c086015591 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 7 Mar 2019 15:17:40 -0800 +Subject: [PATCH] Add bus-timeout-ms and #retries device tree properties + +BMC uses I2C bus 7 as a PMBus channel to communicate with PSUs, +also ME uses this bus as SMLink to control PSUs so this bus is +managed by multi-masters. In this use case, some arbitration errors +are expected so we need to add retry logic. And PMBus subsystem +uses I2C bus in kernel internally so retry logic should be +supported in kernel level. + +To support the use case, this commit adds 'bus-timeout-ms' and +'#retries' device tree properties to set the bus specific +parameters at kernel boot time without using any additional ioctls +from user space. + +This patch would not be accepted by I2C maintainer in linux +upstream because he doesn't like adding these legacy properties +into device tree, so keep it only in downstream. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + Documentation/devicetree/bindings/i2c/i2c-aspeed.txt | 3 +++ + Documentation/devicetree/bindings/i2c/i2c.txt | 6 ++++++ + drivers/i2c/busses/i2c-aspeed.c | 1 - + drivers/i2c/i2c-core-base.c | 12 ++++++++++-- + 4 files changed, 19 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index 8fbd8633a387..7da7e813b2b0 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -16,6 +16,9 @@ Optional Properties: + - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not + specified + - multi-master : states that there is another master active on this bus. ++- bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not ++ specified. ++- #retries : Number of retries for master transfer. + + Example: + +diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt +index 44efafdfd7f5..e382931cf3d6 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c.txt +@@ -80,6 +80,12 @@ wants to support one of the below features, it should adapt the bindings below. + Names of map programmable addresses. + It can contain any map needing another address than default one. + ++- bus-timeout-ms ++ Bus timeout in milliseconds. ++ ++- #retries ++ Number of retries for master transfer. ++ + Binding may contain optional "interrupts" property, describing interrupts + used by the device. I2C core will assign "irq" interrupt (or the very first + interrupt if not using interrupt names) as primary interrupt for the slave. +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index c113ffa8d5df..7becfcd67142 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -1032,7 +1032,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + spin_lock_init(&bus->lock); + init_completion(&bus->cmd_complete); + bus->adap.owner = THIS_MODULE; +- bus->adap.retries = 0; + bus->adap.algo = &aspeed_i2c_algo; + bus->adap.dev.parent = &pdev->dev; + bus->adap.dev.of_node = pdev->dev.of_node; +diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c +index d1cd7afe4068..1db991220fae 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -1318,6 +1318,7 @@ static void i2c_adapter_hold_timer_callback(struct timer_list *t) + + static int i2c_register_adapter(struct i2c_adapter *adap) + { ++ u32 bus_timeout_ms = 0; + int res = -EINVAL; + + /* Can't register until after driver model init */ +@@ -1345,8 +1346,15 @@ static int i2c_register_adapter(struct i2c_adapter *adap) + INIT_LIST_HEAD(&adap->userspace_clients); + + /* Set default timeout to 1 second if not already set */ +- if (adap->timeout == 0) +- adap->timeout = HZ; ++ if (adap->timeout == 0) { ++ device_property_read_u32(&adap->dev, "bus-timeout-ms", ++ &bus_timeout_ms); ++ adap->timeout = bus_timeout_ms ? ++ msecs_to_jiffies(bus_timeout_ms) : HZ; ++ } ++ ++ /* Set retries count if it has the property setting */ ++ device_property_read_u32(&adap->dev, "#retries", &adap->retries); + + /* register soft irqs for Host Notify */ + res = i2c_setup_host_notify_irq_domain(adap); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch new file mode 100644 index 000000000..6cc7d1138 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch @@ -0,0 +1,154 @@ +From 301c1aaba9e59eb593406d878451e3ea4fe355bb Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:04:16 -0700 +Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC BT driver + +If LPC BT driver is registered ahead of lpc-ctrl module, LPC BT +block will be enabled without heart beating of LCLK until lpc-ctrl +enables the LCLK. This issue causes improper handling on host +interrupts when the host sends interrupt in that time frame. Then +kernel eventually forcibly disables the interrupt with dumping +stack and printing a 'nobody cared this irq' message out. + +To prevent this issue, all LPC sub-nodes should enable LCLK +individually so this patch adds clock control logic into the LPC +BT driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + .../bindings/ipmi/aspeed,ast2400-ibt-bmc.txt | 3 +++ + arch/arm/boot/dts/aspeed-g4.dtsi | 1 + + arch/arm/boot/dts/aspeed-g5.dtsi | 1 + + arch/arm/boot/dts/aspeed-g6.dtsi | 1 + + drivers/char/ipmi/bt-bmc.c | 24 +++++++++++++++++++++- + 5 files changed, 29 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt +index 028268fd99ee..d13887d60f19 100644 +--- a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt ++++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt +@@ -10,6 +10,8 @@ Required properties: + "aspeed,ast2400-ibt-bmc" + "aspeed,ast2500-ibt-bmc" + - reg: physical address and size of the registers ++- clocks: contains a phandle to the syscon node describing the clocks. ++ There should then be one cell representing the clock to use. + + Optional properties: + +@@ -22,4 +24,5 @@ Example: + compatible = "aspeed,ast2400-ibt-bmc"; + reg = <0x1e789140 0x18>; + interrupts = <8>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + }; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index 054d97229626..db962ab435af 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -386,6 +386,7 @@ + ibt: ibt@c0 { + compatible = "aspeed,ast2400-ibt-bmc"; + reg = <0xc0 0x18>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + interrupts = <8>; + status = "disabled"; + }; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 45202bc3d60c..c4724ec27041 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -499,6 +499,7 @@ + ibt: ibt@c0 { + compatible = "aspeed,ast2500-ibt-bmc"; + reg = <0xc0 0x18>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + interrupts = <8>; + status = "disabled"; + }; +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 8cc978058f16..a557a7e6fe8d 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -524,6 +524,7 @@ + ibt: ibt@c0 { + compatible = "aspeed,ast2600-ibt-bmc"; + reg = <0xc0 0x18>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; +diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c +index 0e600449931b..87bf3ff28542 100644 +--- a/drivers/char/ipmi/bt-bmc.c ++++ b/drivers/char/ipmi/bt-bmc.c +@@ -5,6 +5,7 @@ + + #include <linux/atomic.h> + #include <linux/bt-bmc.h> ++#include <linux/clk.h> + #include <linux/errno.h> + #include <linux/interrupt.h> + #include <linux/io.h> +@@ -60,6 +61,7 @@ struct bt_bmc { + struct device dev; + struct miscdevice miscdev; + struct regmap *map; ++ struct clk *clk; + int offset; + int irq; + wait_queue_head_t queue; +@@ -467,6 +469,19 @@ static int bt_bmc_probe(struct platform_device *pdev) + mutex_init(&bt_bmc->mutex); + init_waitqueue_head(&bt_bmc->queue); + ++ bt_bmc->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(bt_bmc->clk)) { ++ rc = PTR_ERR(bt_bmc->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; ++ } ++ rc = clk_prepare_enable(bt_bmc->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ + bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR, + bt_bmc->miscdev.name = DEVICE_NAME, + bt_bmc->miscdev.fops = &bt_bmc_fops, +@@ -474,7 +489,7 @@ static int bt_bmc_probe(struct platform_device *pdev) + rc = misc_register(&bt_bmc->miscdev); + if (rc) { + dev_err(dev, "Unable to register misc device\n"); +- return rc; ++ goto err; + } + + bt_bmc_config_irq(bt_bmc, pdev); +@@ -498,6 +513,11 @@ static int bt_bmc_probe(struct platform_device *pdev) + clr_b_busy(bt_bmc); + + return 0; ++ ++err: ++ clk_disable_unprepare(bt_bmc->clk); ++ ++ return rc; + } + + static int bt_bmc_remove(struct platform_device *pdev) +@@ -507,6 +527,8 @@ static int bt_bmc_remove(struct platform_device *pdev) + misc_deregister(&bt_bmc->miscdev); + if (!bt_bmc->irq) + del_timer_sync(&bt_bmc->poll_timer); ++ clk_disable_unprepare(bt_bmc->clk); ++ + return 0; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch new file mode 100644 index 000000000..b3ace73f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch @@ -0,0 +1,139 @@ +From 404f73827714e324a21250b1a855fdc10fcfaf51 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:27:48 -0700 +Subject: [PATCH] misc: Add clock control logic into Aspeed LPC SNOOP driver + +If LPC SNOOP driver is registered ahead of lpc-ctrl module, LPC +SNOOP block will be enabled without heart beating of LCLK until +lpc-ctrl enables the LCLK. This issue causes improper handling on +host interrupts when the host sends interrupt in that time frame. +Then kernel eventually forcibly disables the interrupt with +dumping stack and printing a 'nobody cared this irq' message out. + +To prevent this issue, all LPC sub-nodes should enable LCLK +individually so this patch adds clock control logic into the LPC +SNOOP driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + arch/arm/boot/dts/aspeed-g4.dtsi | 1 + + arch/arm/boot/dts/aspeed-g5.dtsi | 1 + + arch/arm/boot/dts/aspeed-g6.dtsi | 1 + + drivers/soc/aspeed/aspeed-lpc-snoop.c | 30 +++++++++++++++++++++++++++--- + 4 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index db962ab435af..24a20384b5e8 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -369,6 +369,7 @@ + compatible = "aspeed,ast2400-lpc-snoop"; + reg = <0x0 0x80>; + interrupts = <8>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index c4724ec27041..18d2a465c0ed 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -482,6 +482,7 @@ + compatible = "aspeed,ast2500-lpc-snoop"; + reg = <0x0 0x80>; + interrupts = <8>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index a557a7e6fe8d..4035d7bd647e 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -507,6 +507,7 @@ + compatible = "aspeed,ast2600-lpc-snoop"; + reg = <0x0 0x80>; + interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + +diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c +index c7b4ac066b40..ed272677fc82 100644 +--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c ++++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c +@@ -11,6 +11,7 @@ + */ + + #include <linux/bitops.h> ++#include <linux/clk.h> + #include <linux/interrupt.h> + #include <linux/fs.h> + #include <linux/kfifo.h> +@@ -67,6 +68,7 @@ struct aspeed_lpc_snoop_channel { + struct aspeed_lpc_snoop { + struct regmap *regmap; + int irq; ++ struct clk *clk; + struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; + }; + +@@ -282,22 +284,42 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev) + return -ENODEV; + } + ++ lpc_snoop->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(lpc_snoop->clk)) { ++ rc = PTR_ERR(lpc_snoop->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; ++ } ++ rc = clk_prepare_enable(lpc_snoop->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ + rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev); + if (rc) +- return rc; ++ goto err; + + rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port); + if (rc) +- return rc; ++ goto err; + + /* Configuration of 2nd snoop channel port is optional */ + if (of_property_read_u32_index(dev->of_node, "snoop-ports", + 1, &port) == 0) { + rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port); +- if (rc) ++ if (rc) { + aspeed_lpc_disable_snoop(lpc_snoop, 0); ++ goto err; ++ } + } + ++ return 0; ++ ++err: ++ clk_disable_unprepare(lpc_snoop->clk); ++ + return rc; + } + +@@ -309,6 +331,8 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev) + aspeed_lpc_disable_snoop(lpc_snoop, 0); + aspeed_lpc_disable_snoop(lpc_snoop, 1); + ++ clk_disable_unprepare(lpc_snoop->clk); ++ + return 0; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch new file mode 100644 index 000000000..1c0903d71 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch @@ -0,0 +1,273 @@ +From cd62ca008a771bd6b7aeb06526c37d8435f86648 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:36:34 -0700 +Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC KCS + driver + +If LPC KCS driver is registered ahead of lpc-ctrl module, LPC KCS +block will be enabled without heart beating of LCLK until lpc-ctrl +enables the LCLK. This issue causes improper handling on host +interrupts when the host sends interrupt in that time frame. Then +kernel eventually forcibly disables the interrupt with dumping +stack and printing a 'nobody cared this irq' message out. + +To prevent this issue, all LPC sub-nodes should enable LCLK +individually so this patch adds clock control logic into the LPC +KCS driver. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt | 3 ++ + arch/arm/boot/dts/aspeed-g4.dtsi | 35 ++++++++++++++++++++ + arch/arm/boot/dts/aspeed-g5.dtsi | 6 +++- + arch/arm/boot/dts/aspeed-g6.dtsi | 6 ++++ + drivers/char/ipmi/kcs_bmc_aspeed.c | 37 ++++++++++++++++++---- + 5 files changed, 79 insertions(+), 8 deletions(-) + +diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt +index d98a9bf45d6c..3453eb0bf8f2 100644 +--- a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt ++++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt +@@ -9,6 +9,8 @@ Required properties: + "aspeed,ast2400-kcs-bmc" + "aspeed,ast2500-kcs-bmc" + - interrupts : interrupt generated by the controller ++- clocks: contains a phandle to the syscon node describing the clocks. ++ There should then be one cell representing the clock to use. + - kcs_chan : The LPC channel number in the controller + - kcs_addr : The host CPU IO map address + +@@ -19,6 +21,7 @@ Example: + compatible = "aspeed,ast2500-kcs-bmc"; + reg = <0x0 0x80>; + interrupts = <8>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + kcs_chan = <3>; + kcs_addr = <0xCA2>; + status = "okay"; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index 24a20384b5e8..fc6f4e009db7 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -347,6 +347,33 @@ + lpc_bmc: lpc-bmc@0 { + compatible = "aspeed,ast2400-lpc-bmc"; + reg = <0x0 0x80>; ++ reg-io-width = <4>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x80>; ++ ++ kcs1: kcs1@0 { ++ compatible = "aspeed,ast2400-kcs-bmc"; ++ interrupts = <8>; ++ kcs_chan = <1>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; ++ kcs2: kcs2@0 { ++ compatible = "aspeed,ast2400-kcs-bmc"; ++ interrupts = <8>; ++ kcs_chan = <2>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; ++ kcs3: kcs3@0 { ++ compatible = "aspeed,ast2400-kcs-bmc"; ++ interrupts = <8>; ++ kcs_chan = <3>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; + }; + + lpc_host: lpc-host@80 { +@@ -358,6 +385,14 @@ + #size-cells = <1>; + ranges = <0x0 0x80 0x1e0>; + ++ kcs4: kcs4@0 { ++ compatible = "aspeed,ast2400-kcs-bmc"; ++ interrupts = <8>; ++ kcs_chan = <4>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; ++ status = "disabled"; ++ }; ++ + lpc_ctrl: lpc-ctrl@0 { + compatible = "aspeed,ast2400-lpc-ctrl"; + reg = <0x0 0x80>; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 18d2a465c0ed..751a8f0316d6 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -134,7 +134,7 @@ + }; + + vic: interrupt-controller@1e6c0080 { +- compatible = "aspeed,ast2400-vic"; ++ compatible = "aspeed,ast2500-vic"; + interrupt-controller; + #interrupt-cells = <1>; + valid-sources = <0xfefff7ff 0x0807ffff>; +@@ -439,18 +439,21 @@ + compatible = "aspeed,ast2500-kcs-bmc"; + interrupts = <8>; + kcs_chan = <1>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + kcs2: kcs2@0 { + compatible = "aspeed,ast2500-kcs-bmc"; + interrupts = <8>; + kcs_chan = <2>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + kcs3: kcs3@0 { + compatible = "aspeed,ast2500-kcs-bmc"; + interrupts = <8>; + kcs_chan = <3>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + }; +@@ -468,6 +471,7 @@ + compatible = "aspeed,ast2500-kcs-bmc"; + interrupts = <8>; + kcs_chan = <4>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 4035d7bd647e..0e35c4598df5 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -463,18 +463,23 @@ + kcs1: kcs1@0 { + compatible = "aspeed,ast2600-kcs-bmc"; + interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + kcs_chan = <1>; + status = "disabled"; + }; ++ + kcs2: kcs2@0 { + compatible = "aspeed,ast2600-kcs-bmc"; + interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + kcs_chan = <2>; + status = "disabled"; + }; ++ + kcs3: kcs3@0 { + compatible = "aspeed,ast2600-kcs-bmc"; + interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + kcs_chan = <3>; + status = "disabled"; + }; +@@ -492,6 +497,7 @@ + kcs4: kcs4@0 { + compatible = "aspeed,ast2600-kcs-bmc"; + interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + kcs_chan = <4>; + status = "disabled"; + }; +diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c +index a0a8bb89c9b3..94cfb879f520 100644 +--- a/drivers/char/ipmi/kcs_bmc_aspeed.c ++++ b/drivers/char/ipmi/kcs_bmc_aspeed.c +@@ -1,11 +1,10 @@ + // SPDX-License-Identifier: GPL-2.0 +-/* +- * Copyright (c) 2015-2018, Intel Corporation. +- */ ++// Copyright (c) 2015-2019, Intel Corporation. + + #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt + + #include <linux/atomic.h> ++#include <linux/clk.h> + #include <linux/errno.h> + #include <linux/interrupt.h> + #include <linux/io.h> +@@ -63,6 +62,7 @@ + + struct aspeed_kcs_bmc { + struct regmap *map; ++ struct clk *clk; + }; + + +@@ -264,36 +264,59 @@ static int aspeed_kcs_probe(struct platform_device *pdev) + return -ENODEV; + } + ++ priv->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ rc = PTR_ERR(priv->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; ++ } ++ rc = clk_prepare_enable(priv->clk); ++ if (rc) { ++ dev_err(dev, "couldn't enable clock\n"); ++ return rc; ++ } ++ + kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1]; + kcs_bmc->io_inputb = aspeed_kcs_inb; + kcs_bmc->io_outputb = aspeed_kcs_outb; + + dev_set_drvdata(dev, kcs_bmc); + +- aspeed_kcs_set_address(kcs_bmc, addr); +- aspeed_kcs_enable_channel(kcs_bmc, true); + rc = aspeed_kcs_config_irq(kcs_bmc, pdev); + if (rc) +- return rc; ++ goto err; + + rc = misc_register(&kcs_bmc->miscdev); + if (rc) { + dev_err(dev, "Unable to register device\n"); +- return rc; ++ goto err; + } + ++ aspeed_kcs_set_address(kcs_bmc, addr); ++ aspeed_kcs_enable_channel(kcs_bmc, true); ++ + pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n", + chan, addr, + kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str); + + return 0; ++ ++err: ++ aspeed_kcs_enable_channel(kcs_bmc, false); ++ clk_disable_unprepare(priv->clk); ++ ++ return rc; + } + + static int aspeed_kcs_remove(struct platform_device *pdev) + { + struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev); ++ struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc); + + misc_deregister(&kcs_bmc->miscdev); ++ aspeed_kcs_enable_channel(kcs_bmc, false); ++ clk_disable_unprepare(priv->clk); + + return 0; + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch new file mode 100644 index 000000000..8e9c793ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch @@ -0,0 +1,43 @@ +From 5473931df3348b7284c16fac3e7d336c9d0c4294 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 13 Mar 2019 15:57:08 -0700 +Subject: [PATCH] misc: Block error printing on probe defer case in Aspeed LPC + ctrl + +This commit adds a checking code when it gets -EPROBE_DEFER while +getting a clock resource. In this case it doesn't need to print +out an error message because the probing will be re-visited. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/soc/aspeed/aspeed-lpc-ctrl.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c +index f4ac14c40518..432128b8db87 100644 +--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c ++++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c +@@ -265,8 +265,10 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) + + lpc_ctrl->clk = devm_clk_get(dev, NULL); + if (IS_ERR(lpc_ctrl->clk)) { +- dev_err(dev, "couldn't get clock\n"); +- return PTR_ERR(lpc_ctrl->clk); ++ rc = PTR_ERR(lpc_ctrl->clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(dev, "couldn't get clock\n"); ++ return rc; + } + rc = clk_prepare_enable(lpc_ctrl->clk); + if (rc) { +@@ -288,6 +290,7 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) + + err: + clk_disable_unprepare(lpc_ctrl->clk); ++ + return rc; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch new file mode 100644 index 000000000..4a87f2d76 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch @@ -0,0 +1,52 @@ +From 5b9ec5081492b461710cb82e7ecc93fd3af8ad34 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 18 Mar 2019 14:06:36 -0700 +Subject: [PATCH] Suppress excessive HID gadget error logs + +HID events can be sent even when the host disconnects the HID +device according to the current graphic mode. For an example, if +KVM mouse events are sent when the host is in text mode, queueing +of end point messages will be dropped with this message: + +configfs-gadget gadget: usb_ep_queue error on int endpoint -108 + +This case is very usual case in BMC since BMC can control power +status of the host, so this commit suppress the error printing outs +with making HID gadget driver drop events quietly in the case. + +This should be a downstream only customization. Do not upstream it. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/usb/gadget/function/f_hid.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c +index f3816a5c861e..c96c0f6f1df0 100644 +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -320,7 +320,7 @@ static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) + struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; + unsigned long flags; + +- if (req->status != 0) { ++ if (req->status != 0 && req->status != -ESHUTDOWN) { + ERROR(hidg->func.config->cdev, + "End Point Request ERROR: %d\n", req->status); + } +@@ -395,8 +395,10 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, + + status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC); + if (status < 0) { +- ERROR(hidg->func.config->cdev, +- "usb_ep_queue error on int endpoint %zd\n", status); ++ if (status != -ESHUTDOWN) ++ ERROR(hidg->func.config->cdev, ++ "usb_ep_queue error on int endpoint %zd\n", ++ status); + goto release_write_pending; + } else { + status = count; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch new file mode 100644 index 000000000..c3c1eb509 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch @@ -0,0 +1,35 @@ +From fe860284fb5e062b430dc7b882144f69cb605353 Mon Sep 17 00:00:00 2001 +From: "Hunt, Bryan" <bryan.hunt@intel.com> +Date: Mon, 6 May 2019 10:02:14 -0700 +Subject: [PATCH] Add AST2500 JTAG device + +Adding aspeed jtag device + +Signed-off-by: Hunt, Bryan <bryan.hunt@intel.com> +--- + arch/arm/boot/dts/aspeed-g5.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 751a8f0316d6..eb1f9c9d9cca 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -418,6 +418,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..484c576b9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch @@ -0,0 +1,920 @@ +From ea6fa8fd6e36c776d560b4f69d1ede4a3bbe5f6b Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Fri, 7 Jun 2019 07:37:39 -0800 +Subject: [PATCH v29 1/6] drivers: jtag: Add JTAG core driver + +JTAG class driver provide infrastructure to support hardware/software +JTAG platform drivers. It provide user layer API interface for flashing +and debugging external devices which equipped with JTAG interface +using standard transactions. + +Driver exposes set of IOCTL to user space for: +- XFER: + SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan); + SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan); +- GIOCSTATUS read the current TAPC state of the JTAG controller +- SIOCSTATE Forces the JTAG TAPC to go into a particular state. +- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency. +- IOCBITBANG for low level control of JTAG signals. + +Driver core provides set of internal APIs for allocation and +registration: +- jtag_register; +- jtag_unregister; +- jtag_alloc; +- jtag_free; + +Platform driver on registration with jtag-core creates the next +entry in dev folder: +/dev/jtagX + +Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com> +Signed-off-by: Jiri Pirko <jiri@mellanox.com> +Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com> +Acked-by: Philippe Ombredanne <pombredanne@nexb.com> +Cc: Vadim Pasternak <vadimp@mellanox.com> +Cc: Masahiro Yamada <yamada.masahiro@socionext.com> +Cc: Paul Burton <paul.burton@mips.com> +Cc: Thomas Gleixner <tglx@linutronix.de> +Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Boris Brezillon <bbrezillon@kernel.org> +Cc: Randy Dunlap <rdunlap@infradead.org> +Cc: Johan Hovold <johan@kernel.org> +Cc: Jens Axboe <axboe@kernel.dk> +Cc: Joel Stanley <joel@jms.id.au> +Cc: Palmer Dabbelt <palmer@sifive.com> +Cc: Kees Cook <keescook@chromium.org> +Cc: Steven A Filary <steven.a.filary@intel.com> +Cc: Bryan Hunt <bryan.hunt@intel.com> +--- +v28->v29 +Comments pointed by Steven Filary <steven.a.filary@intel.com> +- Expand bitbang function to accept multiples bitbang operations within a + single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS + values and it is expected that driver fills TDO fields with its + corresponding output value for every transaction. +- Always setup JTAG controller to master mode but disable JTAG output when + the driver is not in use to allow other HW to own the JTAG bus. Remove SCU + register accesses. This register controls the JTAG controller mode + (master/slave). +- Fix static analysis issues +- Add support for multichain. Set tap state and xfer operations now include + two tap state arguments: current state and end state. + +v27->v28 +Comments pointed by Steven Filary <steven.a.filary@intel.com> +- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC + end states in SW mode using a lookup table to navigate across states. +- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER). +- Support for switching JTAG controller mode between slave and master + mode. +- Setup JTAG controller mode to master only when the driver is opened, + letting + other HW to own the JTAG bus when it isn't in use. +- Include JTAG bit bang IOCTL for low level JTAG control usage + (JTAG_IOCBITBANG). + +v24->v25 +Comments pointed by Greg KH <gregkh@linuxfoundation.org> +- set values to enums in jtag.h + +v23->v24 +Notifications from kbuild test robot <lkp@intel.com> +- Add include types.h header to jtag.h +- remove unecessary jtag_release + +v22->v23 +Comments pointed by Greg KH <gregkh@linuxfoundation.org> +- remove restriction of allocated JTAG devs- +- add validation fo idle values +- remove unnecessary blank line +- change retcode for xfer +- remove unecessary jtag_release callback +- remove unecessary defined fron jtag.h +- align in one line define JTAG_IOCRUNTEST + +v21->v22 +Comments pointed by Andy Shevchenko <andy.shevchenko@gmail.com> +- Fix 0x0f -> 0x0F in ioctl-number.txt +- Add description to #define MAX_JTAG_NAME_LEN +- Remove unnecessary entry *dev from struct jtag +- Remove redundant parens +- Described mandatory callbacks and removed unnecessary +- Set JTAG_MAX_XFER_DATA_LEN to power of 2 +- rework driver alloc/register to devm_ variant +- increasing line length up to 84 in order to improve readability. + +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- fix spell in ABI doccumentation + +v20->v21 + Comments pointed by Randy Dunlap <rdunlap@infradead.org> + - Fix JTAG dirver help in Kconfig + +v19->v20 +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- Fix JTAG dirver help in Kconfig + +Notifications from kbuild test robot <lkp@intel.com> +- fix incompatible type casts + +v18->v19 +Comments pointed by Julia Cartwright <juliac@eso.teric.us> +- Fix memory leak on jtag_alloc exit + +v17->v18 +Comments pointed by Julia Cartwright <juliac@eso.teric.us> +- Change to return -EOPNOTSUPP in case of error in JTAG_GIOCFREQ +- Add ops callbacks check to jtag_alloc +- Add err check for copy_to_user +- Move the kfree() above the if (err) in JTAG_IOCXFER +- remove unnecessary check for error after put_user +- add padding to struct jtag_xfer + +v16->v17 +Comments pointed by Julia Cartwright <juliac@eso.teric.us> +- Fix memory allocation on jtag alloc +- Move out unnecessary form lock on jtag open +- Rework jtag register behavior + +v15->v16 +Comments pointed by Florian Fainelli <f.fainelli@gmail.com> +- move check jtag->ops->* in ioctl before get_user() +- change error type -EINVAL --> -EBUSY on open already opened jtag +- remove unnecessary ARCH_DMA_MINALIGN flag from kzalloc +- remove define ARCH_DMA_MINALIGN + +v14->v15 +v13->v14 +Comments pointed by Philippe Ombredanne <pombredanne@nexb.com> +- Change style of head block comment from /**/ to // + +v12->v13 +Comments pointed by Philippe Ombredanne <pombredanne@nexb.com> +- Change jtag.c licence type to + SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + and reorder line with license in description + +v11->v12 +Comments pointed by Greg KH <gregkh@linuxfoundation.org> +- Change jtag.h licence type to + SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + and reorder line with license in description + +Comments pointed by Chip Bilbrey <chip@bilbrey.org> +- Remove Apeed reference from uapi jtag.h header +- Remove access mode from xfer and idle transactions +- Add new ioctl JTAG_SIOCMODE for set hw mode +- Add single open per device blocking + +v10->v11 +Notifications from kbuild test robot <lkp@intel.com> +- Add include types.h header to jtag.h +- fix incompatible type of xfer callback +- remove rdundant class defination +- Fix return order in case of xfer error + +V9->v10 +Comments pointed by Greg KH <gregkh@linuxfoundation.org> +- remove unnecessary alignment for pirv data +- move jtag_copy_to_user and jtag_copy_from_user code just to ioctl +- move int jtag_run_test_idle_op and jtag_xfer_op code + just to ioctl +- change return error codes to more applicable +- add missing error checks +- fix error check order in ioctl +- remove unnecessary blank lines +- add param validation to ioctl +- remove compat_ioctl +- remove only one open per JTAG port blocking. + User will care about this. +- Fix idr memory leak on jtag_exit +- change cdev device type to misc + +V8->v9 +Comments pointed by Arnd Bergmann <arnd@arndb.de> +- use get_user() instead of __get_user(). +- change jtag->open type from int to atomic_t +- remove spinlock on jtg_open +- remove mutex on jtag_register +- add unregister_chrdev_region on jtag_init err +- add unregister_chrdev_region on jtag_exit +- remove unnecessary pointer casts +- add *data parameter to xfer function prototype + +v7->v8 +Comments pointed by Moritz Fischer <moritz.fischer@ettus.com> +- Fix misspelling s/friver/driver + +v6->v7 +Notifications from kbuild test robot <lkp@intel.com> +- Remove include asm/types.h from jtag.h +- Add include <linux/types.h> to jtag.c + +v5->v6 +v4->v5 + +v3->v4 +Comments pointed by Arnd Bergmann <arnd@arndb.de> +- change transaction pointer tdio type to __u64 +- change internal status type from enum to __u32 +- reorder jtag_xfer members to avoid the implied padding +- add __packed attribute to jtag_xfer and jtag_run_test_idle + +v2->v3 +Notifications from kbuild test robot <lkp@intel.com> +- Change include path to <linux/types.h> in jtag.h + +v1->v2 +Comments pointed by Greg KH <gregkh@linuxfoundation.org> +- Change license type from GPLv2/BSD to GPLv2 +- Change type of variables which crossed user/kernel to __type +- Remove "default n" from Kconfig + +Comments pointed by Andrew Lunn <andrew@lunn.ch> +- Change list_add_tail in jtag_unregister to list_del + +Comments pointed by Neil Armstrong <narmstrong@baylibre.com> +- Add SPDX-License-Identifier instead of license text + +Comments pointed by Arnd Bergmann <arnd@arndb.de> +- Change __copy_to_user to memdup_user +- Change __put_user to put_user +- Change type of variables to __type for compatible 32 and 64-bit systems +- Add check for maximum xfer data size +- Change lookup data mechanism to get jtag data from inode +- Add .compat_ioctl to file ops +- Add mem alignment for jtag priv data + +Comments pointed by Tobias Klauser <tklauser@distanz.ch> +- Change function names to avoid match with variable types +- Fix description for jtag_ru_test_idle in uapi jtag.h +- Fix misprints IDEL/IDLE, trough/through +--- + drivers/Kconfig | 1 + + drivers/Makefile | 1 + + drivers/jtag/Kconfig | 17 +++ + drivers/jtag/Makefile | 1 + + drivers/jtag/jtag.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/jtag.h | 47 +++++++ + include/uapi/linux/jtag.h | 214 +++++++++++++++++++++++++++++++ + 7 files changed, 602 insertions(+) + create mode 100644 drivers/jtag/Kconfig + create mode 100644 drivers/jtag/Makefile + create mode 100644 drivers/jtag/jtag.c + create mode 100644 include/linux/jtag.h + create mode 100644 include/uapi/linux/jtag.h + +diff --git a/drivers/Kconfig b/drivers/Kconfig +index 4322efa37732..e5e4fe21b5d9 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -230,4 +230,5 @@ source "drivers/counter/Kconfig" + + source "drivers/peci/Kconfig" + ++source "drivers/jtag/Kconfig" + endmenu +diff --git a/drivers/Makefile b/drivers/Makefile +index 82f78cfedf69..297047d4ed9b 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -187,3 +187,4 @@ obj-$(CONFIG_GNSS) += gnss/ + obj-$(CONFIG_INTERCONNECT) += interconnect/ + obj-$(CONFIG_COUNTER) += counter/ + obj-$(CONFIG_PECI) += peci/ ++obj-$(CONFIG_JTAG_ASPEED) += jtag/ +diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig +new file mode 100644 +index 000000000000..47771fcd3c5b +--- /dev/null ++++ b/drivers/jtag/Kconfig +@@ -0,0 +1,17 @@ ++menuconfig JTAG ++ tristate "JTAG support" ++ help ++ This provides basic core functionality support for JTAG class devices. ++ Hardware that is equipped with a JTAG microcontroller can be ++ supported by using this driver's interfaces. ++ This driver exposes a set of IOCTLs to the user space for ++ the following commands: ++ SDR: Performs an IEEE 1149.1 Data Register scan ++ SIR: Performs an IEEE 1149.1 Instruction Register scan. ++ RUNTEST: Forces the IEEE 1149.1 bus to a run state for a specified ++ number of clocks or a specified time period. ++ ++ If you want this support, you should say Y here. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called jtag. +diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile +new file mode 100644 +index 000000000000..af374939a9e6 +--- /dev/null ++++ b/drivers/jtag/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_JTAG) += jtag.o +diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c +new file mode 100644 +index 000000000000..39a4d88a9c21 +--- /dev/null ++++ b/drivers/jtag/jtag.c +@@ -0,0 +1,321 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Copyright (c) 2018 Mellanox Technologies. All rights reserved. ++// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> ++// Copyright (c) 2019 Intel Corporation ++ ++#include <linux/cdev.h> ++#include <linux/device.h> ++#include <linux/jtag.h> ++#include <linux/kernel.h> ++#include <linux/list.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/rtnetlink.h> ++#include <linux/spinlock.h> ++#include <linux/types.h> ++#include <uapi/linux/jtag.h> ++ ++struct jtag { ++ struct miscdevice miscdev; ++ const struct jtag_ops *ops; ++ int id; ++ unsigned long priv[0]; ++}; ++ ++static DEFINE_IDA(jtag_ida); ++ ++void *jtag_priv(struct jtag *jtag) ++{ ++ return jtag->priv; ++} ++EXPORT_SYMBOL_GPL(jtag_priv); ++ ++static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct jtag *jtag = file->private_data; ++ struct jtag_tap_state tapstate; ++ struct jtag_xfer xfer; ++ struct bitbang_packet bitbang; ++ struct tck_bitbang *bitbang_data; ++ struct jtag_mode mode; ++ u8 *xfer_data; ++ u32 data_size; ++ u32 value; ++ int err; ++ ++ if (!arg) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case JTAG_GIOCFREQ: ++ if (!jtag->ops->freq_get) ++ return -EOPNOTSUPP; ++ ++ err = jtag->ops->freq_get(jtag, &value); ++ if (err) ++ break; ++ ++ if (put_user(value, (__u32 __user *)arg)) ++ err = -EFAULT; ++ break; ++ ++ case JTAG_SIOCFREQ: ++ if (!jtag->ops->freq_set) ++ return -EOPNOTSUPP; ++ ++ if (get_user(value, (__u32 __user *)arg)) ++ return -EFAULT; ++ if (value == 0) ++ return -EINVAL; ++ ++ err = jtag->ops->freq_set(jtag, value); ++ break; ++ ++ case JTAG_SIOCSTATE: ++ if (copy_from_user(&tapstate, (const void __user *)arg, ++ sizeof(struct jtag_tap_state))) ++ return -EFAULT; ++ ++ if (tapstate.from > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (tapstate.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (tapstate.reset > JTAG_FORCE_RESET) ++ return -EINVAL; ++ ++ err = jtag->ops->status_set(jtag, &tapstate); ++ break; ++ ++ case JTAG_IOCXFER: ++ if (copy_from_user(&xfer, (const void __user *)arg, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ ++ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; ++ ++ if (xfer.type > JTAG_SDR_XFER) ++ return -EINVAL; ++ ++ if (xfer.direction > JTAG_READ_WRITE_XFER) ++ return -EINVAL; ++ ++ if (xfer.from > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (xfer.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); ++ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size); ++ if (IS_ERR(xfer_data)) ++ return -EFAULT; ++ ++ err = jtag->ops->xfer(jtag, &xfer, xfer_data); ++ if (err) { ++ kfree(xfer_data); ++ return err; ++ } ++ ++ err = copy_to_user(u64_to_user_ptr(xfer.tdio), ++ (void *)xfer_data, data_size); ++ kfree(xfer_data); ++ if (err) ++ return -EFAULT; ++ ++ if (copy_to_user((void __user *)arg, (void *)&xfer, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ break; ++ ++ case JTAG_GIOCSTATUS: ++ err = jtag->ops->status_get(jtag, &value); ++ if (err) ++ break; ++ ++ err = put_user(value, (__u32 __user *)arg); ++ break; ++ case JTAG_IOCBITBANG: ++ if (copy_from_user(&bitbang, (const void __user *)arg, ++ sizeof(struct bitbang_packet))) ++ return -EFAULT; ++ ++ if (bitbang.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; ++ ++ data_size = bitbang.length * sizeof(struct tck_bitbang); ++ bitbang_data = memdup_user((void __user *)bitbang.data, ++ data_size); ++ if (IS_ERR(bitbang_data)) ++ return -EFAULT; ++ ++ err = jtag->ops->bitbang(jtag, &bitbang, bitbang_data); ++ if (err) { ++ kfree(bitbang_data); ++ return err; ++ } ++ err = copy_to_user((void __user *)bitbang.data, ++ (void *)bitbang_data, data_size); ++ kfree(bitbang_data); ++ if (err) ++ return -EFAULT; ++ break; ++ case JTAG_SIOCMODE: ++ if (!jtag->ops->mode_set) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(&mode, (const void __user *)arg, ++ sizeof(struct jtag_mode))) ++ return -EFAULT; ++ ++ err = jtag->ops->mode_set(jtag, &mode); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ return err; ++} ++ ++static int jtag_open(struct inode *inode, struct file *file) ++{ ++ struct jtag *jtag = container_of(file->private_data, ++ struct jtag, ++ miscdev); ++ ++ file->private_data = jtag; ++ if (jtag->ops->enable(jtag)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++static int jtag_release(struct inode *inode, struct file *file) ++{ ++ struct jtag *jtag = file->private_data; ++ ++ if (jtag->ops->disable(jtag)) ++ return -EBUSY; ++ return 0; ++} ++ ++static const struct file_operations jtag_fops = { ++ .owner = THIS_MODULE, ++ .open = jtag_open, ++ .llseek = noop_llseek, ++ .unlocked_ioctl = jtag_ioctl, ++ .release = jtag_release, ++}; ++ ++struct jtag *jtag_alloc(struct device *host, size_t priv_size, ++ const struct jtag_ops *ops) ++{ ++ struct jtag *jtag; ++ ++ if (!host) ++ return NULL; ++ ++ if (!ops) ++ return NULL; ++ ++ if (!ops->status_set || !ops->status_get || !ops->xfer) ++ return NULL; ++ ++ jtag = kzalloc(sizeof(*jtag) + priv_size, GFP_KERNEL); ++ if (!jtag) ++ return NULL; ++ ++ jtag->ops = ops; ++ jtag->miscdev.parent = host; ++ ++ return jtag; ++} ++EXPORT_SYMBOL_GPL(jtag_alloc); ++ ++void jtag_free(struct jtag *jtag) ++{ ++ kfree(jtag); ++} ++EXPORT_SYMBOL_GPL(jtag_free); ++ ++static int jtag_register(struct jtag *jtag) ++{ ++ struct device *dev = jtag->miscdev.parent; ++ int err; ++ int id; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); ++ if (id < 0) ++ return id; ++ ++ jtag->id = id; ++ ++ jtag->miscdev.fops = &jtag_fops; ++ jtag->miscdev.minor = MISC_DYNAMIC_MINOR; ++ jtag->miscdev.name = kasprintf(GFP_KERNEL, "jtag%d", id); ++ if (!jtag->miscdev.name) { ++ err = -ENOMEM; ++ goto err_jtag_alloc; ++ } ++ ++ err = misc_register(&jtag->miscdev); ++ if (err) { ++ dev_err(jtag->miscdev.parent, "Unable to register device\n"); ++ goto err_jtag_name; ++ } ++ return 0; ++ ++err_jtag_name: ++ kfree(jtag->miscdev.name); ++err_jtag_alloc: ++ ida_simple_remove(&jtag_ida, id); ++ return err; ++} ++ ++static void jtag_unregister(struct jtag *jtag) ++{ ++ misc_deregister(&jtag->miscdev); ++ kfree(jtag->miscdev.name); ++ ida_simple_remove(&jtag_ida, jtag->id); ++} ++ ++static void devm_jtag_unregister(struct device *dev, void *res) ++{ ++ jtag_unregister(*(struct jtag **)res); ++} ++ ++int devm_jtag_register(struct device *dev, struct jtag *jtag) ++{ ++ struct jtag **ptr; ++ int ret; ++ ++ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *), ++ GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; ++ ++ ret = jtag_register(jtag); ++ if (!ret) { ++ *ptr = jtag; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(devm_jtag_register); ++ ++static void __exit jtag_exit(void) ++{ ++ ida_destroy(&jtag_ida); ++} ++ ++module_exit(jtag_exit); ++ ++MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>"); ++MODULE_DESCRIPTION("Generic jtag support"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/jtag.h b/include/linux/jtag.h +new file mode 100644 +index 000000000000..fab12dc4fc5e +--- /dev/null ++++ b/include/linux/jtag.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */ ++/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */ ++/* Copyright (c) 2019 Intel Corporation */ ++ ++#ifndef __LINUX_JTAG_H ++#define __LINUX_JTAG_H ++ ++#include <linux/types.h> ++#include <uapi/linux/jtag.h> ++ ++#define JTAG_MAX_XFER_DATA_LEN 65535 ++ ++struct jtag; ++/** ++ * struct jtag_ops - callbacks for JTAG control functions: ++ * ++ * @freq_get: get frequency function. Filled by dev driver ++ * @freq_set: set frequency function. Filled by dev driver ++ * @status_get: get JTAG TAPC state function. Mandatory, Filled by dev driver ++ * @status_set: set JTAG TAPC state function. Mandatory, Filled by dev driver ++ * @xfer: send JTAG xfer function. Mandatory func. Filled by dev driver ++ * @mode_set: set specific work mode for JTAG. Filled by dev driver ++ * @bitbang: set low level bitbang operations. Filled by dev driver ++ * @enable: enables JTAG interface in master mode. Filled by dev driver ++ * @disable: disables JTAG interface master mode. Filled by dev driver ++ */ ++struct jtag_ops { ++ int (*freq_get)(struct jtag *jtag, u32 *freq); ++ int (*freq_set)(struct jtag *jtag, u32 freq); ++ int (*status_get)(struct jtag *jtag, u32 *state); ++ int (*status_set)(struct jtag *jtag, struct jtag_tap_state *endst); ++ int (*xfer)(struct jtag *jtag, struct jtag_xfer *xfer, u8 *xfer_data); ++ int (*mode_set)(struct jtag *jtag, struct jtag_mode *jtag_mode); ++ int (*bitbang)(struct jtag *jtag, struct bitbang_packet *bitbang, ++ struct tck_bitbang *bitbang_data); ++ int (*enable)(struct jtag *jtag); ++ int (*disable)(struct jtag *jtag); ++}; ++ ++void *jtag_priv(struct jtag *jtag); ++int devm_jtag_register(struct device *dev, struct jtag *jtag); ++struct jtag *jtag_alloc(struct device *host, size_t priv_size, ++ const struct jtag_ops *ops); ++void jtag_free(struct jtag *jtag); ++ ++#endif /* __LINUX_JTAG_H */ +diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h +new file mode 100644 +index 000000000000..315e59577a17 +--- /dev/null ++++ b/include/uapi/linux/jtag.h +@@ -0,0 +1,214 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */ ++/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */ ++/* Copyright (c) 2019 Intel Corporation */ ++ ++#ifndef __UAPI_LINUX_JTAG_H ++#define __UAPI_LINUX_JTAG_H ++ ++/* ++ * JTAG_XFER_MODE: JTAG transfer mode. Used to set JTAG controller transfer mode ++ * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE ++ */ ++#define JTAG_XFER_MODE 0 ++/* ++ * JTAG_CONTROL_MODE: JTAG controller mode. Used to set JTAG controller mode ++ * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE ++ */ ++#define JTAG_CONTROL_MODE 1 ++/* ++ * JTAG_MASTER_OUTPUT_DISABLE: JTAG master mode output disable, it is used to ++ * enable other devices to own the JTAG bus. ++ * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE ++ */ ++#define JTAG_MASTER_OUTPUT_DISABLE 0 ++/* ++ * JTAG_MASTER_MODE: JTAG master mode. Used to set JTAG controller master mode ++ * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE ++ */ ++#define JTAG_MASTER_MODE 1 ++/* ++ * JTAG_XFER_HW_MODE: JTAG hardware mode. Used to set HW drived or bitbang ++ * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE ++ */ ++#define JTAG_XFER_HW_MODE 1 ++/* ++ * JTAG_XFER_SW_MODE: JTAG software mode. Used to set SW drived or bitbang ++ * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE ++ */ ++#define JTAG_XFER_SW_MODE 0 ++ ++/** ++ * enum jtag_tapstate: ++ * ++ * @JTAG_STATE_TLRESET: JTAG state machine Test Logic Reset state ++ * @JTAG_STATE_IDLE: JTAG state machine IDLE state ++ * @JTAG_STATE_SELECTDR: JTAG state machine SELECT_DR state ++ * @JTAG_STATE_CAPTUREDR: JTAG state machine CAPTURE_DR state ++ * @JTAG_STATE_SHIFTDR: JTAG state machine SHIFT_DR state ++ * @JTAG_STATE_EXIT1DR: JTAG state machine EXIT-1 DR state ++ * @JTAG_STATE_PAUSEDR: JTAG state machine PAUSE_DR state ++ * @JTAG_STATE_EXIT2DR: JTAG state machine EXIT-2 DR state ++ * @JTAG_STATE_UPDATEDR: JTAG state machine UPDATE DR state ++ * @JTAG_STATE_SELECTIR: JTAG state machine SELECT_IR state ++ * @JTAG_STATE_CAPTUREIR: JTAG state machine CAPTURE_IR state ++ * @JTAG_STATE_SHIFTIR: JTAG state machine SHIFT_IR state ++ * @JTAG_STATE_EXIT1IR: JTAG state machine EXIT-1 IR state ++ * @JTAG_STATE_PAUSEIR: JTAG state machine PAUSE_IR state ++ * @JTAG_STATE_EXIT2IR: JTAG state machine EXIT-2 IR state ++ * @JTAG_STATE_UPDATEIR: JTAG state machine UPDATE IR state ++ * @JTAG_STATE_CURRENT: JTAG current state, saved by driver ++ */ ++enum jtag_tapstate { ++ JTAG_STATE_TLRESET, ++ JTAG_STATE_IDLE, ++ JTAG_STATE_SELECTDR, ++ JTAG_STATE_CAPTUREDR, ++ JTAG_STATE_SHIFTDR, ++ JTAG_STATE_EXIT1DR, ++ JTAG_STATE_PAUSEDR, ++ JTAG_STATE_EXIT2DR, ++ JTAG_STATE_UPDATEDR, ++ JTAG_STATE_SELECTIR, ++ JTAG_STATE_CAPTUREIR, ++ JTAG_STATE_SHIFTIR, ++ JTAG_STATE_EXIT1IR, ++ JTAG_STATE_PAUSEIR, ++ JTAG_STATE_EXIT2IR, ++ JTAG_STATE_UPDATEIR, ++ JTAG_STATE_CURRENT ++}; ++ ++/** ++ * enum jtag_reset: ++ * ++ * @JTAG_NO_RESET: JTAG run TAP from current state ++ * @JTAG_FORCE_RESET: JTAG force TAP to reset state ++ */ ++enum jtag_reset { ++ JTAG_NO_RESET = 0, ++ JTAG_FORCE_RESET = 1, ++}; ++ ++/** ++ * enum jtag_xfer_type: ++ * ++ * @JTAG_SIR_XFER: SIR transfer ++ * @JTAG_SDR_XFER: SDR transfer ++ */ ++enum jtag_xfer_type { ++ JTAG_SIR_XFER = 0, ++ JTAG_SDR_XFER = 1, ++}; ++ ++/** ++ * enum jtag_xfer_direction: ++ * ++ * @JTAG_READ_XFER: read transfer ++ * @JTAG_WRITE_XFER: write transfer ++ * @JTAG_READ_WRITE_XFER: read & write transfer ++ */ ++enum jtag_xfer_direction { ++ JTAG_READ_XFER = 1, ++ JTAG_WRITE_XFER = 2, ++ JTAG_READ_WRITE_XFER = 3, ++}; ++ ++/** ++ * struct jtag_tap_state - forces JTAG state machine to go into a TAPC ++ * state ++ * ++ * @reset: 0 - run IDLE/PAUSE from current state ++ * 1 - go through TEST_LOGIC/RESET state before IDLE/PAUSE ++ * @end: completion flag ++ * @tck: clock counter ++ * ++ * Structure provide interface to JTAG device for JTAG set state execution. ++ */ ++struct jtag_tap_state { ++ __u8 reset; ++ __u8 from; ++ __u8 endstate; ++ __u8 tck; ++}; ++ ++/** ++ * struct jtag_xfer - jtag xfer: ++ * ++ * @type: transfer type ++ * @direction: xfer direction ++ * @from: xfer current state ++ * @endstate: xfer end state ++ * @padding: xfer padding ++ * @length: xfer bits length ++ * @tdio : xfer data array ++ * ++ * Structure provide interface to JTAG device for JTAG SDR/SIR xfer execution. ++ */ ++struct jtag_xfer { ++ __u8 type; ++ __u8 direction; ++ __u8 from; ++ __u8 endstate; ++ __u8 padding; ++ __u32 length; ++ __u64 tdio; ++}; ++ ++/** ++ * struct bitbang_packet - jtag bitbang array packet: ++ * ++ * @data: JTAG Bitbang struct array pointer(input/output) ++ * @length: array size (input) ++ * ++ * Structure provide interface to JTAG device for JTAG bitbang bundle execution ++ */ ++struct bitbang_packet { ++ struct tck_bitbang *data; ++ __u32 length; ++} __attribute__((__packed__)); ++ ++/** ++ * struct jtag_bitbang - jtag bitbang: ++ * ++ * @tms: JTAG TMS ++ * @tdi: JTAG TDI (input) ++ * @tdo: JTAG TDO (output) ++ * ++ * Structure provide interface to JTAG device for JTAG bitbang execution. ++ */ ++struct tck_bitbang { ++ __u8 tms; ++ __u8 tdi; ++ __u8 tdo; ++} __attribute__((__packed__)); ++ ++/** ++ * struct jtag_mode - jtag mode: ++ * ++ * @feature: 0 - JTAG feature setting selector for JTAG controller HW/SW ++ * 1 - JTAG feature setting selector for controller bus master ++ * mode output (enable / disable). ++ * @mode: (0 - SW / 1 - HW) for JTAG_XFER_MODE feature(0) ++ * (0 - output disable / 1 - output enable) for JTAG_CONTROL_MODE ++ * feature(1) ++ * ++ * Structure provide configuration modes to JTAG device. ++ */ ++struct jtag_mode { ++ __u32 feature; ++ __u32 mode; ++}; ++ ++/* ioctl interface */ ++#define __JTAG_IOCTL_MAGIC 0xb2 ++ ++#define JTAG_SIOCSTATE _IOW(__JTAG_IOCTL_MAGIC, 0, struct jtag_tap_state) ++#define JTAG_SIOCFREQ _IOW(__JTAG_IOCTL_MAGIC, 1, unsigned int) ++#define JTAG_GIOCFREQ _IOR(__JTAG_IOCTL_MAGIC, 2, unsigned int) ++#define JTAG_IOCXFER _IOWR(__JTAG_IOCTL_MAGIC, 3, struct jtag_xfer) ++#define JTAG_GIOCSTATUS _IOWR(__JTAG_IOCTL_MAGIC, 4, enum jtag_tapstate) ++#define JTAG_SIOCMODE _IOW(__JTAG_IOCTL_MAGIC, 5, unsigned int) ++#define JTAG_IOCBITBANG _IOW(__JTAG_IOCTL_MAGIC, 6, unsigned int) ++ ++#endif /* __UAPI_LINUX_JTAG_H */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch new file mode 100644 index 000000000..1ffaf7646 --- /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,1293 @@ +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] Add Aspeed SoC 24xx and 25xx families JTAG + +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..12073da02 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch @@ -0,0 +1,107 @@ +From 2a22feac440070b7feaf0a6fe7e7e555d57ca19b Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Wed, 10 Mar 2019 11:45:04 -0800 +Subject: [PATCH] Documentation: jtag: Add bindings for Aspeed SoC + +It has been tested on Mellanox system with BMC equipped with +Aspeed 2520 SoC for programming CPLD devices. + +It also has been tested on Intel systems with BMC equipped with +Aspeed 25x0 SoC for JTAG board communication. + +Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com> +Signed-off-by: Jiri Pirko <jiri@mellanox.com> +Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com> +Acked-by: Rob Herring <robh@kernel.org> +Cc: Mark Rutland <mark.rutland@arm.com> +Cc: Joel Stanley <joel@jms.id.au> +Cc: Andrew Jeffery <andrew@aj.id.au> +Cc: Steven A Filary <steven.a.filary@intel.com> +Cc: Bryan Hunt <bryan.hunt@intel.com> +--- +v28->v29 +v27->v28 +v26->v27 +v25->v26 +v24->v25 +v23->v24 +v22->v23 +v21->v22 +v20->v21 +v19->v20 +v18->v19 + +v17->v18 +v16->v17 +v15->v16 +Comments pointed by Joel Stanley <joel.stan@gmail.com> +- change clocks = <&clk_apb> to proper clocks = <&syscon ASPEED_CLK_APB> +- add reset descriptions in bindings file + +v14->v15 +v13->v14 +v12->v13 +v11->v12 +v10->v11 +v9->v10 +v8->v9 +v7->v8 +Comments pointed by pointed by Joel Stanley <joel.stan@gmail.com> +- Change compatible string to ast2400 and ast2000 + +V6->v7 +Comments pointed by Tobias Klauser <tklauser@distanz.ch> + - Fix spell "Doccumentation" -> "Documentation" + +v5->v6 +Comments pointed by Tobias Klauser <tklauser@distanz.ch> +- Small nit: s/documentation/Documentation/ + +v4->v5 + +V3->v4 +Comments pointed by Rob Herring <robh@kernel.org> +- delete unnecessary "status" and "reg-shift" descriptions in + bindings file + +v2->v3 +Comments pointed by Rob Herring <robh@kernel.org> +- split Aspeed jtag driver and binding to separate patches +- delete unnecessary "status" and "reg-shift" descriptions in + bindings file +--- + .../devicetree/bindings/jtag/aspeed-jtag.txt | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 Documentation/devicetree/bindings/jtag/aspeed-jtag.txt + +diff --git a/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt +new file mode 100644 +index 0000000..7c36eb6 +--- /dev/null ++++ b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt +@@ -0,0 +1,22 @@ ++Aspeed JTAG driver for ast2400 and ast2500 SoC ++ ++Required properties: ++- compatible: Should be one of ++ - "aspeed,ast2400-jtag" ++ - "aspeed,ast2500-jtag" ++- reg contains the offset and length of the JTAG memory ++ region ++- clocks root clock of bus, should reference the APB ++ clock in the second cell ++- resets phandle to reset controller with the reset number in ++ the second cell ++- interrupts should contain JTAG controller interrupt ++ ++Example: ++jtag: jtag@1e6e4000 { ++ compatible = "aspeed,ast2500-jtag"; ++ reg = <0x1e6e4000 0x1c>; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ resets = <&syscon ASPEED_RESET_JTAG_MASTER>; ++ interrupts = <43>; ++}; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch new file mode 100644 index 000000000..1e4142035 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch @@ -0,0 +1,310 @@ +From d4c55bd4eeb6d9290025fa353d1787f18bca6ade Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Sun, 10 Mar 2019 11:47:40 -0800 +Subject: [PATCH v29 4/6] Documentation: jtag: Add ABI documentation + +Added document that describe the ABI for JTAG class driver + +Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com> +Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Cc: Jonathan Corbet <corbet@lwn.net> +Cc: Jiri Pirko <jiri@mellanox.com> +Cc: Vadim Pasternak <vadimp@mellanox.com> +Cc: Steven A Filary <steven.a.filary@intel.com> +Cc: Bryan Hunt <bryan.hunt@intel.com> +--- +v28->v29 +Comments pointed by Steven Filary <steven.a.filary@intel.com> +- Expand bitbang function to accept multiples bitbang operations within a + single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS + values and it is expected that driver fills TDO fields with its + corresponding output value for every transaction. + +v27->v28 +Comments pointed by Steven Filary <steven.a.filary@intel.com> +- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC + end states in SW mode using a lookup table to navigate across states. +- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER). +- Support for switching JTAG controller mode between slave and master + mode. +- Setup JTAG controller mode to master only when the driver is opened, + letting other HW to own the JTAG bus when it isn't in use. +- Include JTAG bit bang IOCTL for low level JTAG control usage + (JTAG_IOCBITBANG). + +v26->v27 +v25->v26 +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- fix spell in ABI documentation + +v24->v25 +Comments pointed by Greg KH <gregkh@linuxfoundation.org> +- Fixed documentation according to new open() behavior + +v23->v24 +v22->v23 +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- fix spell in ABI doccumentation + +v21->v22 +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- fix spell in ABI doccumentation + +v20->v21 +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- Fix JTAG dirver help in Kconfig + +v19->v20 +Comments pointed by Randy Dunlap <rdunlap@infradead.org> +- Fix JTAG doccumentation + +v18->v19 +Pavel Machek <pavel@ucw.cz> +- Added JTAG doccumentation to Documentation/jtag + +v17->v18 +v16->v17 +v15->v16 +v14->v15 +v13->v14 +v12->v13 +v11->v12 Tobias Klauser <tklauser@distanz.ch> +Comments pointed by +- rename /Documentation/ABI/testing/jatg-dev -> jtag-dev +- Typo: s/interfase/interface +v10->v11 +v9->v10 +Fixes added by Oleksandr: +- change jtag-cdev to jtag-dev in documentation +- update KernelVersion and Date in jtag-dev documentation; +v8->v9 +v7->v8 +v6->v7 +Comments pointed by Pavel Machek <pavel@ucw.cz> +- Added jtag-cdev documentation to Documentation/ABI/testing folder +--- + Documentation/ABI/testing/jtag-dev | 23 ++++++ + Documentation/jtag/overview | 27 +++++++ + Documentation/jtag/transactions | 145 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 195 insertions(+) + create mode 100644 Documentation/ABI/testing/jtag-dev + create mode 100644 Documentation/jtag/overview + create mode 100644 Documentation/jtag/transactions + +diff --git a/Documentation/ABI/testing/jtag-dev b/Documentation/ABI/testing/jtag-dev +new file mode 100644 +index 000000000000..423baab18761 +--- /dev/null ++++ b/Documentation/ABI/testing/jtag-dev +@@ -0,0 +1,23 @@ ++What: /dev/jtag[0-9]+ ++Date: July 2018 ++KernelVersion: 4.20 ++Contact: oleksandrs@mellanox.com ++Description: ++ The misc device files /dev/jtag* are the interface ++ between JTAG master interface and userspace. ++ ++ The ioctl(2)-based ABI is defined and documented in ++ [include/uapi]<linux/jtag.h>. ++ ++ The following file operations are supported: ++ ++ open(2) ++ Opens and allocates file descriptor. ++ ++ ioctl(2) ++ Initiate various actions. ++ See the inline documentation in [include/uapi]<linux/jtag.h> ++ for descriptions of all ioctls. ++ ++Users: ++ userspace tools which wants to access to JTAG bus +diff --git a/Documentation/jtag/overview b/Documentation/jtag/overview +new file mode 100644 +index 000000000000..6a5ec335e313 +--- /dev/null ++++ b/Documentation/jtag/overview +@@ -0,0 +1,27 @@ ++Linux kernel JTAG support ++========================= ++ ++JTAG is an industry standard for verifying hardware. JTAG provides access to ++many logic signals of a complex integrated circuit, including the device pins. ++ ++A JTAG interface is a special interface added to a chip. ++Depending on the version of JTAG, two, four, or five pins are added. ++ ++The connector pins are: ++ TDI (Test Data In) ++ TDO (Test Data Out) ++ TCK (Test Clock) ++ TMS (Test Mode Select) ++ TRST (Test Reset) optional ++ ++JTAG interface is designed to have two parts - basic core driver and ++hardware specific driver. The basic driver introduces a general interface ++which is not dependent of specific hardware. It provides communication ++between user space and hardware specific driver. ++Each JTAG device is represented as a char device from (jtag0, jtag1, ...). ++Access to a JTAG device is performed through IOCTL calls. ++ ++Call flow example: ++User: open -> /dev/jatgX -> JTAG core driver -> JTAG hardware specific driver ++User: ioctl -> /dev/jtagX -> JTAG core driver -> JTAG hardware specific driver ++User: close -> /dev/jatgX -> JTAG core driver -> JTAG hardware specific driver +diff --git a/Documentation/jtag/transactions b/Documentation/jtag/transactions +new file mode 100644 +index 000000000000..f5d4a1ded6cf +--- /dev/null ++++ b/Documentation/jtag/transactions +@@ -0,0 +1,145 @@ ++The JTAG API ++============= ++ ++JTAG master devices can be accessed through a character misc-device. ++Each JTAG master interface can be accessed by using /dev/jtagN. ++ ++JTAG system calls set: ++- SIR (Scan Instruction Register, IEEE 1149.1 Instruction Register scan); ++- SDR (Scan Data Register, IEEE 1149.1 Data Register scan); ++- RUNTEST (Forces the IEEE 1149.1 bus to a run state for a specified ++number of clocks. ++ ++open(), close() ++------- ++open() opens JTAG device. ++ ++Open/Close device: ++- jtag_fd = open("/dev/jtag0", O_RDWR); ++- close(jtag_fd); ++ ++ioctl() ++------- ++All access operations to JTAG devices are performed through ioctl interface. ++The IOCTL interface supports these requests: ++ JTAG_SIOCSTATE - Force JTAG state machine to go into a TAPC state ++ JTAG_SIOCFREQ - Set JTAG TCK frequency ++ JTAG_GIOCFREQ - Get JTAG TCK frequency ++ JTAG_IOCXFER - send/receive JTAG data Xfer ++ JTAG_GIOCSTATUS - get current JTAG TAP state ++ JTAG_SIOCMODE - set JTAG mode flags. ++ JTAG_IOCBITBANG - JTAG bitbang low level control. ++ ++JTAG_SIOCFREQ, JTAG_GIOCFREQ ++------ ++Set/Get JTAG clock speed: ++ ++ unsigned int jtag_fd; ++ ioctl(jtag_fd, JTAG_SIOCFREQ, &frq); ++ ioctl(jtag_fd, JTAG_GIOCFREQ, &frq); ++ ++JTAG_SIOCSTATE ++------ ++Force JTAG state machine to go into a TAPC state ++ ++struct jtag_tap_state { ++ __u8 reset; ++ __u8 from; ++ __u8 endstate; ++ __u8 tck; ++}; ++ ++reset: ++ JTAG_NO_RESET - go through selected endstate from current state ++ JTAG_FORCE_RESET - go through TEST_LOGIC/RESET state before selected endstate ++endstate: completion flag ++tck: clock counter ++ ++Example: ++ struct jtag_tap_state tap_state; ++ ++ tap_state.from = JTAG_STATE_TLRESET; ++ tap_state.endstate = JTAG_STATE_IDLE; ++ tap_state.reset = 0; ++ tap_state.tck = data_p->tck; ++ usleep(25 * 1000); ++ ioctl(jtag_fd, JTAG_SIOCSTATE, &tap_state); ++ ++JTAG_GIOCSTATUS ++------ ++Get JTAG TAPC machine state ++ ++ unsigned int jtag_fd; ++ jtag_tapstate tapstate; ++ ioctl(jtag_fd, JTAG_GIOCSTATUS, &tapstate); ++ ++JTAG_IOCXFER ++------ ++Send SDR/SIR transaction ++ ++struct jtag_xfer { ++ __u8 type; ++ __u8 direction; ++ __u8 from; ++ __u8 endstate; ++ __u8 padding; ++ __u32 length; ++ __u64 tdio; ++}; ++ ++type: transfer type - JTAG_SIR_XFER/JTAG_SDR_XFER ++direction: xfer direction - JTAG_READ_XFER/JTAG_WRITE_XFER/JTAG_READ_WRITE_XFER ++length: xfer data length in bits ++tdio : xfer data array ++from: xfer from state can be current JTAG tap state saved by the driver ++ JTAG_STATE_CURRENT or in a multichain environment any state listed in ++ jtag_tapstate struct saved by your multichain controller software. ++endstate: xfer end state after transaction finish ++ can be: any state listed in jtag_tapstate struct ++ ++Example: ++ struct jtag_xfer xfer; ++ static char buf[64]; ++ static unsigned int buf_len = 0; ++ [...] ++ xfer.type = JTAG_SDR_XFER; ++ xfer.tdio = (__u64)buf; ++ xfer.length = buf_len; ++ xfer.from = JTAG_STATE_TLRESET; ++ xfer.endstate = JTAG_STATE_IDLE; ++ ++ if (is_read) ++ xfer.direction = JTAG_READ_XFER; ++ else if (is_write) ++ xfer.direction = JTAG_WRITE_XFER; ++ else ++ xfer.direction = JTAG_READ_WRITE_XFER; ++ ++ ioctl(jtag_fd, JTAG_IOCXFER, &xfer); ++ ++JTAG_SIOCMODE ++------ ++If hardware driver can support different running modes you can change it. ++ ++Example: ++ struct jtag_mode mode; ++ mode.feature = JTAG_XFER_MODE; ++ mode.mode = JTAG_XFER_HW_MODE; ++ ioctl(jtag_fd, JTAG_SIOCMODE, &mode); ++ ++JTAG_IOCBITBANG ++------ ++JTAG Bitbang low level operation. ++ ++Example: ++ struct bitbang_packet bitbang; ++ struct tck_bitbang bitbang_data[2]; ++ bitbang_data[0].tms = 0; ++ bitbang_data[0].tdi = 1; ++ bitbang_data[1].tms = 0; ++ bitbang_data[1].tdi = 1; ++ bitbang.data = bitbang_data; ++ bitbang.length = 2; ++ ioctl(jtag_fd, JTAG_IOCBITBANG, &bitbang); ++ tdo0 = bitbang_data[0].tdo; ++ tdo1 = bitbang_data[1].tdo; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch new file mode 100644 index 000000000..99cc318ab --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch @@ -0,0 +1,57 @@ +From 8618c2cd920d10681859bacf8af56c71f168b5a2 Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Sun, 10 Mar 2019 11:48:18 -0800 +Subject: [PATCH] Documentation jtag: Add JTAG core driver ioctl number + +JTAG class driver provide infrastructure to support hardware/software +JTAG platform drivers. It provide user layer API interface for flashing +and debugging external devices which equipped with JTAG interface +using standard transactions. + +Driver exposes set of IOCTL to user space for: +- XFER: + SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan); + SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan); +- GIOCSTATUS read the current TAPC state of the JTAG controller +- SIOCSTATE Forces the JTAG TAPC to go into a particular state. +- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency. +- IOCBITBANG for low level control of JTAG signals. + +Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com> +Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com> +Acked-by: Philippe Ombredanne <pombredanne@nexb.com> +Cc: Jiri Pirko <jiri@mellanox.com> +Cc: Vadim Pasternak <vadimp@mellanox.com> +Cc: Jonathan Corbet <corbet@lwn.net> +Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com> +Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> +Cc: Kishon Vijay Abraham I <kishon@ti.com> +Cc: Darrick J. Wong <darrick.wong@oracle.com> +Cc: Bryant G. Ly <bryantly@linux.vnet.ibm.com> +Cc: Eric Sandeen <sandeen@redhat.com> +Cc: Randy Dunlap <rdunlap@infradead.org> +Cc: Tomohiro Kusumi <kusumi.tomohiro@gmail.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Steven A Filary <steven.a.filary@intel.com> +Cc: Bryan Hunt <bryan.hunt@intel.com> +--- + Documentation/ioctl/ioctl-number.rst | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst +index de23fc0f0fce..339d198c5adf 100644 +--- a/Documentation/ioctl/ioctl-number.rst ++++ b/Documentation/ioctl/ioctl-number.rst +@@ -333,6 +333,8 @@ Code Seq# Include File Comments + <mailto:vgo@ratio.de> + 0xB1 00-1F PPPoX + <mailto:mostrows@styx.uwaterloo.ca> ++0xB2 00-0F linux/jtag.h JTAG driver ++ <mailto:oleksandrs@mellanox.com> + 0xB3 00 linux/mmc/ioctl.h + 0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org> + 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org> +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch new file mode 100644 index 000000000..9ff92d8ec --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch @@ -0,0 +1,50 @@ +From fcf8f7fd3cb4e0b08cb1540f9ff9e5988cd285d1 Mon Sep 17 00:00:00 2001 +From: "Corona, Ernesto" <ernesto.corona@intel.com> +Date: Sun, 10 Mar 2019 11:49:37 -0800 +Subject: [PATCH] drivers: jtag: Add JTAG core driver Maintainers + +JTAG class driver provide infrastructure to support hardware/software +JTAG platform drivers. It provide user layer API interface for flashing +and debugging external devices which equipped with JTAG interface +using standard transactions. + +Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com> +Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Cc: Jiri Pirko <jiri@mellanox.com> +Cc: Vadim Pasternak <vadimp@mellanox.com> +Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> +Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Cc: David S. Miller <davem@davemloft.net> +Cc: Nicolas Ferre <nicolas.ferre@microchip.com> +Cc: Steven A Filary <steven.a.filary@intel.com> +Cc: Bryan Hunt <bryan.hunt@intel.com> +--- + MAINTAINERS | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 3bbdae50eb7e..34ab3522801c 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -8819,6 +8819,17 @@ L: linux-serial@vger.kernel.org + S: Orphan + F: drivers/tty/serial/jsm/ + ++JTAG SUBSYSTEM ++M: Oleksandr Shamray <oleksandrs@mellanox.com> ++M: Vadim Pasternak <vadimp@mellanox.com> ++M Ernesto Corona <ernesto.corona@intel.com> ++S: Maintained ++F: include/linux/jtag.h ++F: include/uapi/linux/jtag.h ++F: drivers/jtag/ ++F: Documentation/devicetree/bindings/jtag/ ++F: Documentation/ABI/testing/jtag-dev ++ + K10TEMP HARDWARE MONITORING DRIVER + M: Clemens Ladisch <clemens@ladisch.de> + L: linux-hwmon@vger.kernel.org +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch new file mode 100644 index 000000000..fbf422a35 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch @@ -0,0 +1,1148 @@ +From b8d7d0f3513abdf014345b240a79d23c63409c4c Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 11 Jun 2019 15:07:08 -0700 +Subject: [PATCH] i2c: aspeed: add buffer mode transfer support + +Byte mode currently this driver uses makes lots of interrupt call +which isn't good for performance and it makes the driver very +timing sensitive. To improve performance of the driver, this commit +adds buffer mode transfer support which uses I2C SRAM buffer +instead of using a single byte buffer. + +AST2400: +It has 2 KBytes (256 Bytes x 8 pages) of I2C SRAM buffer pool from +0x1e78a800 to 0x1e78afff that can be used for all busses with +buffer pool manipulation. To simplify implementation for supporting +both AST2400 and AST2500, it assigns each 128 Bytes per bus without +using buffer pool manipulation so total 1792 Bytes of I2C SRAM +buffer will be used. + +AST2500: +It has 16 Bytes of individual I2C SRAM buffer per each bus and its +range is from 0x1e78a200 to 0x1e78a2df, so it doesn't have 'buffer +page selection' bit field in the Function control register, and +neither 'base address pointer' bit field in the Pool buffer control +register it has. To simplify implementation for supporting both +AST2400 and AST2500, it writes zeros on those register bit fields +but it's okay because it does nothing in AST2500. + +It provides buffer based master and slave data transfer. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 40 ++- + arch/arm/boot/dts/aspeed-g4.dtsi | 47 +-- + arch/arm/boot/dts/aspeed-g5.dtsi | 47 +-- + arch/arm/boot/dts/aspeed-g6.dtsi | 32 +- + drivers/i2c/busses/i2c-aspeed.c | 376 +++++++++++++++++++-- + 5 files changed, 451 insertions(+), 91 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index 7da7e813b2b0..0ff3539cee95 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -3,7 +3,10 @@ Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs. + Required Properties: + - #address-cells : should be 1 + - #size-cells : should be 0 +-- reg : address offset and range of bus ++- reg : Address offset and range of bus registers. ++ An additional SRAM buffer address offset and range is ++ optional in case of enabling I2C dedicated SRAM for ++ buffer mode transfer support. + - compatible : should be "aspeed,ast2400-i2c-bus" + or "aspeed,ast2500-i2c-bus" + - clocks : root clock of bus, should reference the APB +@@ -28,12 +31,21 @@ i2c { + #size-cells = <1>; + ranges = <0 0x1e78a000 0x1000>; + +- i2c_ic: interrupt-controller@0 { +- #interrupt-cells = <1>; +- compatible = "aspeed,ast2400-i2c-ic"; ++ i2c_gr: i2c-global-regs@0 { ++ compatible = "aspeed,ast2500-i2c-gr", "syscon"; + reg = <0x0 0x40>; +- interrupts = <12>; +- interrupt-controller; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x40>; ++ ++ i2c_ic: interrupt-controller@0 { ++ #interrupt-cells = <1>; ++ compatible = "aspeed,ast2500-i2c-ic"; ++ reg = <0x0 0x4>; ++ interrupts = <12>; ++ interrupt-controller; ++ }; + }; + + i2c0: i2c-bus@40 { +@@ -41,11 +53,25 @@ i2c { + #size-cells = <0>; + #interrupt-cells = <1>; + reg = <0x40 0x40>; +- compatible = "aspeed,ast2400-i2c-bus"; ++ compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; + bus-frequency = <100000>; + interrupts = <0>; + interrupt-parent = <&i2c_ic>; + }; ++ ++ /* buffer mode transfer enabled */ ++ i2c1: i2c-bus@80 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x80 0x40>, <0x210 0x10>; ++ compatible = "aspeed,ast2500-i2c-bus"; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ resets = <&syscon ASPEED_RESET_I2C>; ++ bus-frequency = <100000>; ++ interrupts = <1>; ++ interrupt-parent = <&i2c_ic>; ++ }; + }; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index fc6f4e009db7..0b30c8546e64 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -518,12 +518,21 @@ + }; + + &i2c { +- i2c_ic: interrupt-controller@0 { +- #interrupt-cells = <1>; +- compatible = "aspeed,ast2400-i2c-ic"; ++ i2c_gr: i2c-global-regs@0 { ++ compatible = "aspeed,ast2400-i2c-gr", "syscon"; + reg = <0x0 0x40>; +- interrupts = <12>; +- interrupt-controller; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x40>; ++ ++ i2c_ic: interrupt-controller@0 { ++ #interrupt-cells = <1>; ++ compatible = "aspeed,ast2400-i2c-ic"; ++ reg = <0x0 0x4>; ++ interrupts = <12>; ++ interrupt-controller; ++ }; + }; + + i2c0: i2c-bus@40 { +@@ -531,7 +540,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x40 0x40>; ++ reg = <0x40 0x40>, <0x800 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -547,7 +556,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x80 0x40>; ++ reg = <0x80 0x40>, <0x880 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -563,7 +572,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0xc0 0x40>; ++ reg = <0xc0 0x40>, <0x900 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -580,7 +589,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x100 0x40>; ++ reg = <0x100 0x40>, <0x980 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -597,7 +606,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x140 0x40>; ++ reg = <0x140 0x40>, <0xa00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -614,7 +623,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x180 0x40>; ++ reg = <0x180 0x40>, <0xa80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -631,7 +640,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x1c0 0x40>; ++ reg = <0x1c0 0x40>, <0xb00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -648,7 +657,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x300 0x40>; ++ reg = <0x300 0x40>, <0xb80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -665,7 +674,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x340 0x40>; ++ reg = <0x340 0x40>, <0xc00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -682,7 +691,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x380 0x40>; ++ reg = <0x380 0x40>, <0xc80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -699,7 +708,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x3c0 0x40>; ++ reg = <0x3c0 0x40>, <0xd00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -716,7 +725,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x400 0x40>; ++ reg = <0x400 0x40>, <0xd80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -733,7 +742,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x440 0x40>; ++ reg = <0x440 0x40>, <0xe00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -750,7 +759,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x480 0x40>; ++ reg = <0x480 0x40>, <0xe80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index eb1f9c9d9cca..51593a0a8a23 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -615,12 +615,21 @@ + }; + + &i2c { +- i2c_ic: interrupt-controller@0 { +- #interrupt-cells = <1>; +- compatible = "aspeed,ast2500-i2c-ic"; ++ i2c_gr: i2c-global-regs@0 { ++ compatible = "aspeed,ast2500-i2c-gr", "syscon"; + reg = <0x0 0x40>; +- interrupts = <12>; +- interrupt-controller; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x40>; ++ ++ i2c_ic: interrupt-controller@0 { ++ #interrupt-cells = <1>; ++ compatible = "aspeed,ast2500-i2c-ic"; ++ reg = <0x0 0x4>; ++ interrupts = <12>; ++ interrupt-controller; ++ }; + }; + + i2c0: i2c-bus@40 { +@@ -628,7 +637,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x40 0x40>; ++ reg = <0x40 0x40>, <0x200 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -644,7 +653,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x80 0x40>; ++ reg = <0x80 0x40>, <0x210 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -660,7 +669,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0xc0 0x40>; ++ reg = <0xc0 0x40>, <0x220 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -677,7 +686,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x100 0x40>; ++ reg = <0x100 0x40>, <0x230 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -694,7 +703,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x140 0x40>; ++ reg = <0x140 0x40>, <0x240 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -711,7 +720,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x180 0x40>; ++ reg = <0x180 0x40>, <0x250 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -728,7 +737,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x1c0 0x40>; ++ reg = <0x1c0 0x40>, <0x260 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -745,7 +754,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x300 0x40>; ++ reg = <0x300 0x40>, <0x270 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -762,7 +771,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x340 0x40>; ++ reg = <0x340 0x40>, <0x280 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -779,7 +788,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x380 0x40>; ++ reg = <0x380 0x40>, <0x290 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -796,7 +805,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x3c0 0x40>; ++ reg = <0x3c0 0x40>, <0x2a0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -813,7 +822,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x400 0x40>; ++ reg = <0x400 0x40>, <0x2b0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -830,7 +839,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x440 0x40>; ++ reg = <0x440 0x40>, <0x2c0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -847,7 +856,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x480 0x40>; ++ reg = <0x480 0x40>, <0x2d0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index f92a2aa999d1..3ef312543269 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -712,7 +712,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x80 0x80>; ++ reg = <0x80 0x80>, <0xc00 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -727,7 +727,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x100 0x80>; ++ reg = <0x100 0x80>, <0xc20 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -742,7 +742,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x180 0x80>; ++ reg = <0x180 0x80>, <0xc40 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -757,7 +757,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x200 0x80>; ++ reg = <0x200 0x80>, <0xc60 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -772,7 +772,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x280 0x80>; ++ reg = <0x280 0x80>, <0xc80 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -787,7 +787,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x300 0x80>; ++ reg = <0x300 0x80>, <0xca0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -802,7 +802,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x380 0x80>; ++ reg = <0x380 0x80>, <0xcc0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -817,7 +817,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x400 0x80>; ++ reg = <0x400 0x80>, <0xce0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -832,7 +832,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x480 0x80>; ++ reg = <0x480 0x80>, <0xd00 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -847,7 +847,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x500 0x80>; ++ reg = <0x500 0x80>, <0xd20 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -862,7 +862,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x580 0x80>; ++ reg = <0x580 0x80>, <0xd40 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -877,7 +877,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x600 0x80>; ++ reg = <0x600 0x80>, <0xd60 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -892,7 +892,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x680 0x80>; ++ reg = <0x680 0x80>, <0xd80 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -907,7 +907,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x700 0x80>; ++ reg = <0x700 0x80>, <0xda0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -922,7 +922,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x780 0x80>; ++ reg = <0x780 0x80>, <0xdc0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -937,7 +937,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x800 0x80>; ++ reg = <0x800 0x80>, <0xde0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_I2C>; +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 7becfcd67142..bf72e151d11f 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -7,6 +7,7 @@ + * Copyright 2017 Google, Inc. + */ + ++#include <linux/bitfield.h> + #include <linux/clk.h> + #include <linux/completion.h> + #include <linux/err.h> +@@ -19,15 +20,24 @@ + #include <linux/irqchip/chained_irq.h> + #include <linux/irqdomain.h> + #include <linux/kernel.h> ++#include <linux/mfd/syscon.h> + #include <linux/module.h> + #include <linux/of_address.h> + #include <linux/of_irq.h> + #include <linux/of_platform.h> + #include <linux/platform_device.h> ++#include <linux/regmap.h> + #include <linux/reset.h> + #include <linux/slab.h> + +-/* I2C Register */ ++/* I2C Global Registers */ ++/* 0x00 : I2CG Interrupt Status Register */ ++/* 0x08 : I2CG Interrupt Target Assignment */ ++/* 0x0c : I2CG Global Control Register (AST2500) */ ++#define ASPEED_I2CG_GLOBAL_CTRL_REG 0x0c ++#define ASPEED_I2CG_SRAM_BUFFER_EN BIT(0) ++ ++/* I2C Bus Registers */ + #define ASPEED_I2C_FUN_CTRL_REG 0x00 + #define ASPEED_I2C_AC_TIMING_REG1 0x04 + #define ASPEED_I2C_AC_TIMING_REG2 0x08 +@@ -35,14 +45,12 @@ + #define ASPEED_I2C_INTR_STS_REG 0x10 + #define ASPEED_I2C_CMD_REG 0x14 + #define ASPEED_I2C_DEV_ADDR_REG 0x18 ++#define ASPEED_I2C_BUF_CTRL_REG 0x1c + #define ASPEED_I2C_BYTE_BUF_REG 0x20 + +-/* Global Register Definition */ +-/* 0x00 : I2C Interrupt Status Register */ +-/* 0x08 : I2C Interrupt Target Assignment */ +- + /* Device Register Definition */ + /* 0x00 : I2CD Function Control Register */ ++#define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20) + #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15) + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) +@@ -102,6 +110,8 @@ + #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) + + /* Command Bit */ ++#define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) ++#define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) + #define ASPEED_I2CD_M_STOP_CMD BIT(5) + #define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4) + #define ASPEED_I2CD_M_RX_CMD BIT(3) +@@ -118,6 +128,13 @@ + /* 0x18 : I2CD Slave Device Address Register */ + #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) + ++/* 0x1c : I2CD Buffer Control Register */ ++/* Use 8-bits or 6-bits wide bit fileds to support both AST2400 and AST2500 */ ++#define ASPEED_I2CD_BUF_RX_COUNT_MASK GENMASK(31, 24) ++#define ASPEED_I2CD_BUF_RX_SIZE_MASK GENMASK(23, 16) ++#define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) ++#define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) ++ + enum aspeed_i2c_master_state { + ASPEED_I2C_MASTER_INACTIVE, + ASPEED_I2C_MASTER_PENDING, +@@ -163,6 +180,11 @@ struct aspeed_i2c_bus { + int master_xfer_result; + /* Multi-master */ + bool multi_master; ++ /* Buffer mode */ ++ void __iomem *buf_base; ++ u8 buf_offset; ++ u8 buf_page; ++ size_t buf_size; + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; +@@ -255,6 +277,77 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) + } + + #if IS_ENABLED(CONFIG_I2C_SLAVE) ++static inline void ++aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status, ++ u8 *value) ++{ ++ if (bus->buf_base && ++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && ++ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) ++ *value = readb(bus->buf_base); ++ else ++ *value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; ++} ++ ++static inline void ++aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status, ++ u8 *value) ++{ ++ int i, len; ++ ++ if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && ++ irq_status & ASPEED_I2CD_INTR_RX_DONE) { ++ if (bus->buf_base) { ++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, ++ readl(bus->base + ++ ASPEED_I2C_BUF_CTRL_REG)); ++ for (i = 0; i < len; i++) { ++ *value = readb(bus->buf_base + i); ++ i2c_slave_event(bus->slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ value); ++ } ++ } ++ } ++} ++ ++static inline void ++aspeed_i2c_slave_handle_write_requested(struct aspeed_i2c_bus *bus, u8 *value) ++{ ++ if (bus->buf_base) { ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ bus->buf_size - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ writel(ASPEED_I2CD_RX_BUFF_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } ++} ++ ++static inline void ++aspeed_i2c_slave_handle_write_received(struct aspeed_i2c_bus *bus, u8 *value) ++{ ++ int i, len; ++ ++ if (bus->buf_base) { ++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, ++ readl(bus->base + ++ ASPEED_I2C_BUF_CTRL_REG)); ++ for (i = 1; i < len; i++) { ++ *value = readb(bus->buf_base + i); ++ i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED, ++ value); ++ } ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ bus->buf_size - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ writel(ASPEED_I2CD_RX_BUFF_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } ++} ++ + static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + { + u32 command, irq_handled = 0; +@@ -281,7 +374,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + + /* Slave was sent something. */ + if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { +- value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; ++ aspeed_i2c_slave_handle_rx_done(bus, irq_status, &value); + /* Handle address frame. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_START) { + if (value & 0x1) +@@ -296,9 +389,11 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + + /* Slave was asked to stop. */ + if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { ++ aspeed_i2c_slave_handle_normal_stop(bus, irq_status, &value); + irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; + bus->slave_state = ASPEED_I2C_SLAVE_STOP; + } ++ + if (irq_status & ASPEED_I2CD_INTR_TX_NAK && + bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) { + irq_handled |= ASPEED_I2CD_INTR_TX_NAK; +@@ -328,9 +423,11 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + case ASPEED_I2C_SLAVE_WRITE_REQUESTED: + bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); ++ aspeed_i2c_slave_handle_write_requested(bus, &value); + break; + case ASPEED_I2C_SLAVE_WRITE_RECEIVED: + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); ++ aspeed_i2c_slave_handle_write_received(bus, &value); + break; + case ASPEED_I2C_SLAVE_STOP: + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); +@@ -350,12 +447,76 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + } + #endif /* CONFIG_I2C_SLAVE */ + ++static inline u32 ++aspeed_i2c_prepare_rx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) ++{ ++ u32 command = 0; ++ int len; ++ ++ if (msg->len > bus->buf_size) { ++ len = bus->buf_size; ++ } else { ++ len = msg->len; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ if (bus->buf_base) { ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } ++ ++ return command; ++} ++ ++static inline u32 ++aspeed_i2c_prepare_tx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) ++{ ++ u8 slave_addr = i2c_8bit_addr_from_msg(msg); ++ u32 command = 0; ++ int len; ++ ++ if (msg->len + 1 > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len + 1; ++ ++ if (bus->buf_base) { ++ u8 wbuf[4]; ++ int i; ++ ++ command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ ++ /* ++ * Yeah, it looks bad but byte writing on remapped I2C SRAM ++ * causes corruption so use this way to make dword writings. ++ */ ++ wbuf[0] = slave_addr; ++ for (i = 1; i < len; i++) { ++ wbuf[i % 4] = msg->buf[i - 1]; ++ if (i % 4 == 3) ++ writel(*(u32 *)wbuf, bus->buf_base + i - 3); ++ } ++ if (--i % 4 != 3) ++ writel(*(u32 *)wbuf, bus->buf_base + i - (i % 4)); ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } ++ ++ bus->buf_index = len - 1; ++ ++ return command; ++} ++ + /* precondition: bus.lock has been acquired. */ + static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + { + u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; + struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; +- u8 slave_addr = i2c_8bit_addr_from_msg(msg); + + #if IS_ENABLED(CONFIG_I2C_SLAVE) + /* +@@ -374,12 +535,21 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + + if (msg->flags & I2C_M_RD) { + command |= ASPEED_I2CD_M_RX_CMD; +- /* Need to let the hardware know to NACK after RX. */ +- if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) +- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ if (!(msg->flags & I2C_M_RECV_LEN)) { ++ if (msg->len && bus->buf_base) ++ command |= aspeed_i2c_prepare_rx_buf(bus, msg); ++ ++ /* Need to let the hardware know to NACK after RX. */ ++ if (msg->len <= 1) ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ } else if (msg->len && bus->buf_base) { ++ command |= aspeed_i2c_prepare_tx_buf(bus, msg); + } + +- writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); ++ if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) ++ writel(i2c_8bit_addr_from_msg(msg), ++ bus->base + ASPEED_I2C_BYTE_BUF_REG); + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } + +@@ -414,6 +584,104 @@ static int aspeed_i2c_is_irq_error(u32 irq_status) + return 0; + } + ++static inline u32 ++aspeed_i2c_master_handle_tx_first(struct aspeed_i2c_bus *bus, ++ struct i2c_msg *msg) ++{ ++ u32 command = 0; ++ ++ if (bus->buf_base) { ++ u8 wbuf[4]; ++ int len; ++ int i; ++ ++ if (msg->len - bus->buf_index > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len - bus->buf_index; ++ ++ ++ command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ ++ if (msg->len - bus->buf_index > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len - bus->buf_index; ++ ++ for (i = 0; i < len; i++) { ++ wbuf[i % 4] = msg->buf[bus->buf_index + i]; ++ if (i % 4 == 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - 3); ++ } ++ if (--i % 4 != 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - (i % 4)); ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ ++ bus->buf_index += len; ++ } else { ++ writel(msg->buf[bus->buf_index++], ++ bus->base + ASPEED_I2C_BYTE_BUF_REG); ++ } ++ ++ return command; ++} ++ ++static inline void ++aspeed_i2c_master_handle_rx(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) ++{ ++ u8 recv_byte; ++ int len; ++ ++ if (bus->buf_base) { ++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, ++ readl(bus->base + ASPEED_I2C_BUF_CTRL_REG)); ++ memcpy_fromio(msg->buf + bus->buf_index, bus->buf_base, len); ++ bus->buf_index += len; ++ } else { ++ recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; ++ msg->buf[bus->buf_index++] = recv_byte; ++ } ++} ++ ++static inline u32 ++aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus, ++ struct i2c_msg *msg) ++{ ++ u32 command = 0; ++ ++ if (bus->buf_base) { ++ int len; ++ ++ if (msg->len - bus->buf_index > bus->buf_size) { ++ len = bus->buf_size; ++ } else { ++ len = msg->len - bus->buf_index; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } else { ++ if (bus->buf_index + 1 == msg->len) ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ return command; ++} ++ + static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + { + u32 irq_handled = 0, command = 0; +@@ -522,11 +790,10 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + /* fall through */ + case ASPEED_I2C_MASTER_TX_FIRST: + if (bus->buf_index < msg->len) { ++ command = ASPEED_I2CD_M_TX_CMD; ++ command |= aspeed_i2c_master_handle_tx_first(bus, msg); ++ writel(command, bus->base + ASPEED_I2C_CMD_REG); + bus->master_state = ASPEED_I2C_MASTER_TX; +- writel(msg->buf[bus->buf_index++], +- bus->base + ASPEED_I2C_BYTE_BUF_REG); +- writel(ASPEED_I2CD_M_TX_CMD, +- bus->base + ASPEED_I2C_CMD_REG); + } else { + aspeed_i2c_next_msg_or_stop(bus); + } +@@ -543,26 +810,26 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + +- recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; +- msg->buf[bus->buf_index++] = recv_byte; +- + if (msg->flags & I2C_M_RECV_LEN) { ++ recv_byte = readl(bus->base + ++ ASPEED_I2C_BYTE_BUF_REG) >> 8; + if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { + bus->cmd_err = -EPROTO; + aspeed_i2c_do_stop(bus); + goto out_no_complete; + } +- msg->len = recv_byte + +- ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); ++ msg->len = recv_byte + ((msg->flags & I2C_CLIENT_PEC) ? ++ 2 : 1); + msg->flags &= ~I2C_M_RECV_LEN; ++ } else if (msg->len) { ++ aspeed_i2c_master_handle_rx(bus, msg); + } + + if (bus->buf_index < msg->len) { +- bus->master_state = ASPEED_I2C_MASTER_RX; + command = ASPEED_I2CD_M_RX_CMD; +- if (bus->buf_index + 1 == msg->len) +- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ command |= aspeed_i2c_master_handle_rx_next(bus, msg); + writel(command, bus->base + ASPEED_I2C_CMD_REG); ++ bus->master_state = ASPEED_I2C_MASTER_RX; + } else { + aspeed_i2c_next_msg_or_stop(bus); + } +@@ -924,6 +1191,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + if (ret < 0) + return ret; + ++ fun_ctrl_reg |= FIELD_PREP(ASPEED_I2CD_BUFFER_PAGE_SEL_MASK, ++ bus->buf_page); ++ + if (of_property_read_bool(pdev->dev.of_node, "multi-master")) + bus->multi_master = true; + else +@@ -964,6 +1234,52 @@ static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus) + return ret; + } + ++static void aspeed_i2c_set_xfer_mode(struct aspeed_i2c_bus *bus) ++{ ++ struct platform_device *pdev = to_platform_device(bus->dev); ++ bool sram_enabled = true; ++ int ret; ++ ++ /* ++ * Enable I2C SRAM in case of AST2500. ++ * SRAM is enabled by default in AST2400 and AST2600. ++ */ ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2500-i2c-bus")) { ++ struct regmap *gr_regmap = syscon_regmap_lookup_by_compatible("aspeed,ast2500-i2c-gr"); ++ ++ if (IS_ERR(gr_regmap)) ++ ret = PTR_ERR(gr_regmap); ++ else ++ ret = regmap_update_bits(gr_regmap, ++ ASPEED_I2CG_GLOBAL_CTRL_REG, ++ ASPEED_I2CG_SRAM_BUFFER_EN, ++ ASPEED_I2CG_SRAM_BUFFER_EN); ++ ++ if (ret) ++ sram_enabled = false; ++ } ++ ++ if (sram_enabled) { ++ struct resource *res = platform_get_resource(pdev, ++ IORESOURCE_MEM, 1); ++ ++ if (res && resource_size(res) >= 2) ++ bus->buf_base = devm_ioremap_resource(&pdev->dev, res); ++ ++ if (!IS_ERR_OR_NULL(bus->buf_base)) { ++ bus->buf_size = resource_size(res); ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2400-i2c-bus")) { ++ bus->buf_page = ((res->start >> 8) & ++ GENMASK(3, 0)) - 8; ++ bus->buf_offset = (res->start >> 2) & ++ ASPEED_I2CD_BUF_OFFSET_MASK; ++ } ++ } ++ } ++} ++ + static const struct of_device_id aspeed_i2c_bus_of_table[] = { + { + .compatible = "aspeed,ast2400-i2c-bus", +@@ -986,18 +1302,18 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + const struct of_device_id *match; + struct aspeed_i2c_bus *bus; + struct clk *parent_clk; +- struct resource *res; + int irq, ret; + + bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- bus->base = devm_ioremap_resource(&pdev->dev, res); ++ bus->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(bus->base)) + return PTR_ERR(bus->base); + ++ bus->dev = &pdev->dev; ++ + parent_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(parent_clk)) + return PTR_ERR(parent_clk); +@@ -1028,6 +1344,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + bus->get_clk_reg_val = (u32 (*)(struct device *, u32)) + match->data; + ++ aspeed_i2c_set_xfer_mode(bus); ++ + /* Initialize the I2C adapter */ + spin_lock_init(&bus->lock); + init_completion(&bus->cmd_complete); +@@ -1038,8 +1356,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + strlcpy(bus->adap.name, pdev->name, sizeof(bus->adap.name)); + i2c_set_adapdata(&bus->adap, bus); + +- bus->dev = &pdev->dev; +- + /* Clean up any left over interrupt state. */ + writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG); + writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG); +@@ -1063,8 +1379,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + + platform_set_drvdata(pdev, bus); + +- dev_info(bus->dev, "i2c bus %d registered, irq %d\n", +- bus->adap.nr, irq); ++ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", ++ bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); + + return 0; + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch new file mode 100644 index 000000000..994c20b18 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch @@ -0,0 +1,491 @@ +From 5bf7a202eb0af455675a85a4f1bdad863fd8805d Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 18 Jun 2019 08:47:50 -0700 +Subject: [PATCH] i2c: aspeed: add DMA mode transfer support + +This commit adds DMA mode transfer support. + +Only AST2500 supports DMA mode under some limitations: +I2C is sharing the DMA H/W with UHCI host controller and MCTP +controller. Since those controllers operate with DMA mode only, I2C +has to use buffer mode or byte mode instead if one of those +controllers is enabled. Also make sure that if SD/eMMC or Port80 +snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't +use DMA mode. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 25 ++ + drivers/i2c/busses/i2c-aspeed.c | 253 +++++++++++++++++---- + 2 files changed, 234 insertions(+), 44 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index 0ff3539cee95..d3f4a39f7ba6 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -22,6 +22,16 @@ Optional Properties: + - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not + specified. + - #retries : Number of retries for master transfer. ++- aspeed,dma-buf-size : size of DMA buffer (from 2 to 4095 in case of AST2500) ++ Only AST2500 supports DMA mode under some limitations: ++ I2C is sharing the DMA H/W with UHCI host controller ++ and MCTP controller. Since those controllers operate ++ with DMA mode only, I2C has to use buffer mode or byte ++ mode instead if one of those controllers is enabled. ++ Also make sure that if SD/eMMC or Port80 snoop uses ++ DMA mode instead of PIO or FIFO respectively, I2C ++ can't use DMA mode. IF both DMA and buffer modes are ++ enabled, DMA mode will be selected. + + Example: + +@@ -74,4 +84,19 @@ i2c { + interrupts = <1>; + interrupt-parent = <&i2c_ic>; + }; ++ ++ /* DMA mode transfer enabled */ ++ i2c2: i2c-bus@c0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0xc0 0x40>; ++ aspeed,dma-buf-size = <4095>; ++ compatible = "aspeed,ast2500-i2c-bus"; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ resets = <&syscon ASPEED_RESET_I2C>; ++ bus-frequency = <100000>; ++ interrupts = <2>; ++ interrupt-parent = <&i2c_ic>; ++ }; + }; +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index bf72e151d11f..3c9e491cbe4e 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -10,6 +10,8 @@ + #include <linux/bitfield.h> + #include <linux/clk.h> + #include <linux/completion.h> ++#include <linux/dma-mapping.h> ++#include <linux/dmapool.h> + #include <linux/err.h> + #include <linux/errno.h> + #include <linux/i2c.h> +@@ -47,6 +49,8 @@ + #define ASPEED_I2C_DEV_ADDR_REG 0x18 + #define ASPEED_I2C_BUF_CTRL_REG 0x1c + #define ASPEED_I2C_BYTE_BUF_REG 0x20 ++#define ASPEED_I2C_DMA_ADDR_REG 0x24 ++#define ASPEED_I2C_DMA_LEN_REG 0x28 + + /* Device Register Definition */ + /* 0x00 : I2CD Function Control Register */ +@@ -110,6 +114,8 @@ + #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) + + /* Command Bit */ ++#define ASPEED_I2CD_RX_DMA_ENABLE BIT(9) ++#define ASPEED_I2CD_TX_DMA_ENABLE BIT(8) + #define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) + #define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) + #define ASPEED_I2CD_M_STOP_CMD BIT(5) +@@ -135,6 +141,14 @@ + #define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) + #define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) + ++/* 0x24 : I2CD DMA Mode Buffer Address Register */ ++#define ASPEED_I2CD_DMA_ADDR_MASK GENMASK(31, 2) ++#define ASPEED_I2CD_DMA_ALIGN 4 ++ ++/* 0x28 : I2CD DMA Transfer Length Register */ ++#define ASPEED_I2CD_DMA_LEN_SHIFT 0 ++#define ASPEED_I2CD_DMA_LEN_MASK GENMASK(11, 0) ++ + enum aspeed_i2c_master_state { + ASPEED_I2C_MASTER_INACTIVE, + ASPEED_I2C_MASTER_PENDING, +@@ -184,6 +198,12 @@ struct aspeed_i2c_bus { + void __iomem *buf_base; + u8 buf_offset; + u8 buf_page; ++ /* DMA mode */ ++ struct dma_pool *dma_pool; ++ dma_addr_t dma_handle; ++ u8 *dma_buf; ++ size_t dma_len; ++ /* Buffer/DMA mode */ + size_t buf_size; + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; +@@ -281,7 +301,11 @@ static inline void + aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status, + u8 *value) + { +- if (bus->buf_base && ++ if (bus->dma_buf && ++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && ++ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) ++ *value = bus->dma_buf[0]; ++ else if (bus->buf_base && + bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && + !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) + *value = readb(bus->buf_base); +@@ -297,7 +321,18 @@ aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status, + + if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && + irq_status & ASPEED_I2CD_INTR_RX_DONE) { +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ len = bus->buf_size - ++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, ++ readl(bus->base + ++ ASPEED_I2C_DMA_LEN_REG)); ++ for (i = 0; i < len; i++) { ++ *value = bus->dma_buf[i]; ++ i2c_slave_event(bus->slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ value); ++ } ++ } else if (bus->buf_base) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + + ASPEED_I2C_BUF_CTRL_REG)); +@@ -314,7 +349,14 @@ aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status, + static inline void + aspeed_i2c_slave_handle_write_requested(struct aspeed_i2c_bus *bus, u8 *value) + { +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, bus->buf_size), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ writel(ASPEED_I2CD_RX_DMA_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } else if (bus->buf_base) { + writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, + bus->buf_size - 1) | + FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, +@@ -330,7 +372,23 @@ aspeed_i2c_slave_handle_write_received(struct aspeed_i2c_bus *bus, u8 *value) + { + int i, len; + +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ len = bus->buf_size - ++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, ++ readl(bus->base + ++ ASPEED_I2C_DMA_LEN_REG)); ++ for (i = 1; i < len; i++) { ++ *value = bus->dma_buf[i]; ++ i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED, ++ value); ++ } ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, bus->buf_size), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ writel(ASPEED_I2CD_RX_DMA_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } else if (bus->buf_base) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + + ASPEED_I2C_BUF_CTRL_REG)); +@@ -460,7 +518,15 @@ aspeed_i2c_prepare_rx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) + command |= ASPEED_I2CD_M_S_RX_CMD_LAST; + } + +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_RX_DMA_ENABLE; ++ ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else { + command |= ASPEED_I2CD_RX_BUFF_ENABLE; + + writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, len - 1) | +@@ -483,7 +549,18 @@ aspeed_i2c_prepare_tx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) + else + len = msg->len + 1; + +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_TX_DMA_ENABLE; ++ ++ bus->dma_buf[0] = slave_addr; ++ memcpy(bus->dma_buf + 1, msg->buf, len); ++ ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else { + u8 wbuf[4]; + int i; + +@@ -536,18 +613,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + if (msg->flags & I2C_M_RD) { + command |= ASPEED_I2CD_M_RX_CMD; + if (!(msg->flags & I2C_M_RECV_LEN)) { +- if (msg->len && bus->buf_base) ++ if (msg->len && (bus->dma_buf || bus->buf_base)) + command |= aspeed_i2c_prepare_rx_buf(bus, msg); + + /* Need to let the hardware know to NACK after RX. */ + if (msg->len <= 1) + command |= ASPEED_I2CD_M_S_RX_CMD_LAST; + } +- } else if (msg->len && bus->buf_base) { ++ } else if (msg->len && (bus->dma_buf || bus->buf_base)) { + command |= aspeed_i2c_prepare_tx_buf(bus, msg); + } + +- if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) ++ if (!(command & (ASPEED_I2CD_TX_BUFF_ENABLE | ++ ASPEED_I2CD_TX_DMA_ENABLE))) + writel(i2c_8bit_addr_from_msg(msg), + bus->base + ASPEED_I2C_BYTE_BUF_REG); + writel(command, bus->base + ASPEED_I2C_CMD_REG); +@@ -590,39 +668,52 @@ aspeed_i2c_master_handle_tx_first(struct aspeed_i2c_bus *bus, + { + u32 command = 0; + +- if (bus->buf_base) { +- u8 wbuf[4]; ++ if (bus->dma_buf || bus->buf_base) { + int len; +- int i; + + if (msg->len - bus->buf_index > bus->buf_size) + len = bus->buf_size; + else + len = msg->len - bus->buf_index; + ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_TX_DMA_ENABLE; + +- command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ memcpy(bus->dma_buf, msg->buf + bus->buf_index, len); + +- if (msg->len - bus->buf_index > bus->buf_size) +- len = bus->buf_size; +- else +- len = msg->len - bus->buf_index; + +- for (i = 0; i < len; i++) { +- wbuf[i % 4] = msg->buf[bus->buf_index + i]; +- if (i % 4 == 3) ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else { ++ u8 wbuf[4]; ++ int i; ++ ++ command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ ++ if (msg->len - bus->buf_index > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len - bus->buf_index; ++ ++ for (i = 0; i < len; i++) { ++ wbuf[i % 4] = msg->buf[bus->buf_index + i]; ++ if (i % 4 == 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - 3); ++ } ++ if (--i % 4 != 3) + writel(*(u32 *)wbuf, +- bus->buf_base + i - 3); +- } +- if (--i % 4 != 3) +- writel(*(u32 *)wbuf, +- bus->buf_base + i - (i % 4)); ++ bus->buf_base + i - (i % 4)); + +- writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, +- len - 1) | +- FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, +- bus->buf_offset), +- bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } + + bus->buf_index += len; + } else { +@@ -639,7 +730,14 @@ aspeed_i2c_master_handle_rx(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) + u8 recv_byte; + int len; + +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ len = bus->dma_len - ++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, ++ readl(bus->base + ASPEED_I2C_DMA_LEN_REG)); ++ ++ memcpy(msg->buf + bus->buf_index, bus->dma_buf, len); ++ bus->buf_index += len; ++ } else if (bus->buf_base) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + ASPEED_I2C_BUF_CTRL_REG)); + memcpy_fromio(msg->buf + bus->buf_index, bus->buf_base, len); +@@ -656,7 +754,7 @@ aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus, + { + u32 command = 0; + +- if (bus->buf_base) { ++ if (bus->dma_buf || bus->buf_base) { + int len; + + if (msg->len - bus->buf_index > bus->buf_size) { +@@ -666,14 +764,24 @@ aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus, + command |= ASPEED_I2CD_M_S_RX_CMD_LAST; + } + +- command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_RX_DMA_ENABLE; + +- writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, +- len - 1) | +- FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) | +- FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, +- bus->buf_offset), +- bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else { ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } + } else { + if (bus->buf_index + 1 == msg->len) + command |= ASPEED_I2CD_M_S_RX_CMD_LAST; +@@ -1260,7 +1368,51 @@ static void aspeed_i2c_set_xfer_mode(struct aspeed_i2c_bus *bus) + sram_enabled = false; + } + +- if (sram_enabled) { ++ /* ++ * Only AST2500 and AST2600 support DMA mode under some limitations: ++ * I2C is sharing the DMA H/W with UHCI host controller and MCTP ++ * controller. Since those controllers operate with DMA mode only, I2C ++ * has to use buffer mode or byte mode instead if one of those ++ * controllers is enabled. Also make sure that if SD/eMMC or Port80 ++ * snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't ++ * use DMA mode. ++ */ ++ if (sram_enabled && !IS_ENABLED(CONFIG_USB_UHCI_ASPEED) && ++ !of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2400-i2c-bus")) { ++ u32 dma_len_max = ASPEED_I2CD_DMA_LEN_MASK >> ++ ASPEED_I2CD_DMA_LEN_SHIFT; ++ ++ ret = device_property_read_u32(&pdev->dev, ++ "aspeed,dma-buf-size", ++ &bus->buf_size); ++ if (!ret && bus->buf_size > dma_len_max) ++ bus->buf_size = dma_len_max; ++ } ++ ++ if (bus->buf_size) { ++ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { ++ dev_warn(&pdev->dev, "No suitable DMA available\n"); ++ } else { ++ bus->dma_pool = dma_pool_create("i2c-aspeed", ++ &pdev->dev, ++ bus->buf_size, ++ ASPEED_I2CD_DMA_ALIGN, ++ 0); ++ if (bus->dma_pool) ++ bus->dma_buf = dma_pool_alloc(bus->dma_pool, ++ GFP_KERNEL, ++ &bus->dma_handle); ++ ++ if (!bus->dma_buf) { ++ dev_warn(&pdev->dev, ++ "Cannot allocate DMA buffer\n"); ++ dma_pool_destroy(bus->dma_pool); ++ } ++ } ++ } ++ ++ if (!bus->dma_buf && sram_enabled) { + struct resource *res = platform_get_resource(pdev, + IORESOURCE_MEM, 1); + +@@ -1365,24 +1517,33 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + */ + ret = aspeed_i2c_init(bus, pdev); + if (ret < 0) +- return ret; ++ goto out_free_dma_buf; + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq, + 0, dev_name(&pdev->dev), bus); + if (ret < 0) +- return ret; ++ goto out_free_dma_buf; + + ret = i2c_add_adapter(&bus->adap); + if (ret < 0) +- return ret; ++ goto out_free_dma_buf; + + platform_set_drvdata(pdev, bus); + + dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", +- bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); ++ bus->adap.nr, bus->dma_buf ? "dma" : ++ bus->buf_base ? "buffer" : "byte", ++ irq); + + return 0; ++ ++out_free_dma_buf: ++ if (bus->dma_buf) ++ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); ++ dma_pool_destroy(bus->dma_pool); ++ ++ return ret; + } + + static int aspeed_i2c_remove_bus(struct platform_device *pdev) +@@ -1400,6 +1561,10 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) + + reset_control_assert(bus->rst); + ++ if (bus->dma_buf) ++ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); ++ dma_pool_destroy(bus->dma_pool); ++ + i2c_del_adapter(&bus->adap); + + return 0; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch new file mode 100644 index 000000000..899924f61 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch @@ -0,0 +1,180 @@ +From d731b53de05b8d69ea739f02275416126cf5fe4e Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 1 May 2019 13:27:34 -0700 +Subject: [PATCH] i2c: aspeed: add general call support + +This commit adds general call support into Aspeed I2C driver. +This is downstream only customization so it should not go into +upstream. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 1 + + drivers/i2c/busses/i2c-aspeed.c | 39 ++++++++++++++++++++++ + drivers/i2c/i2c-slave-mqueue.c | 4 ++- + include/linux/i2c.h | 1 + + 4 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index d3f4a39f7ba6..c1ee99398517 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -19,6 +19,7 @@ Optional Properties: + - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not + specified + - multi-master : states that there is another master active on this bus. ++- general-call : enables general call receiving. + - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not + specified. + - #retries : Number of retries for master transfer. +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 3c9e491cbe4e..4420899e2c2d 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -59,6 +59,7 @@ + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) + #define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6) ++#define ASPEED_I2CD_GCALL_EN BIT(2) + #define ASPEED_I2CD_SLAVE_EN BIT(1) + #define ASPEED_I2CD_MASTER_EN BIT(0) + +@@ -83,6 +84,7 @@ + */ + #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) + #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) ++#define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8) + #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) + #define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6) + #define ASPEED_I2CD_INTR_ABNORMAL BIT(5) +@@ -167,6 +169,8 @@ enum aspeed_i2c_slave_state { + ASPEED_I2C_SLAVE_READ_PROCESSED, + ASPEED_I2C_SLAVE_WRITE_REQUESTED, + ASPEED_I2C_SLAVE_WRITE_RECEIVED, ++ ASPEED_I2C_SLAVE_GCALL_START, ++ ASPEED_I2C_SLAVE_GCALL_REQUESTED, + ASPEED_I2C_SLAVE_STOP, + }; + +@@ -208,6 +212,8 @@ struct aspeed_i2c_bus { + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; ++ /* General call */ ++ bool general_call; + #endif /* CONFIG_I2C_SLAVE */ + }; + +@@ -423,6 +429,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + bus->slave_state = ASPEED_I2C_SLAVE_START; + } + ++ /* General call was requested, restart state machine. */ ++ if (irq_status & ASPEED_I2CD_INTR_GCALL_ADDR) { ++ irq_handled |= ASPEED_I2CD_INTR_GCALL_ADDR; ++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_START; ++ } ++ + /* Slave is not currently active, irq was for someone else. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) + return irq_handled; +@@ -441,6 +453,21 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + else + bus->slave_state = + ASPEED_I2C_SLAVE_WRITE_REQUESTED; ++ } else if (bus->slave_state == ASPEED_I2C_SLAVE_GCALL_START) { ++ /* ++ * I2C spec defines the second byte meaning like below. ++ * 0x06 : Reset and write programmable part of slave ++ * address by hardware. ++ * 0x04 : Write programmable part of slave address by ++ * hardware. ++ * 0x00 : No allowed. ++ * ++ * But in OpenBMC, we are going to use this ++ * 'General call' feature for IPMB message broadcasting ++ * so it delivers all data as is without any specific ++ * handling of the second byte. ++ */ ++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_REQUESTED; + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + } +@@ -487,11 +514,16 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); + aspeed_i2c_slave_handle_write_received(bus, &value); + break; ++ case ASPEED_I2C_SLAVE_GCALL_REQUESTED: ++ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; ++ i2c_slave_event(slave, I2C_SLAVE_GCALL_REQUESTED, &value); ++ break; + case ASPEED_I2C_SLAVE_STOP: + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; + break; + case ASPEED_I2C_SLAVE_START: ++ case ASPEED_I2C_SLAVE_GCALL_START: + /* Slave was just started. Waiting for the next event. */; + break; + default: +@@ -1127,6 +1159,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr) + /* Turn on slave mode. */ + func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); + func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN; ++ if (bus->general_call) ++ func_ctrl_reg_val |= ASPEED_I2CD_GCALL_EN; + writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + } + +@@ -1165,6 +1199,8 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client) + /* Turn off slave mode. */ + func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); + func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN; ++ if (bus->general_call) ++ func_ctrl_reg_val &= ~ASPEED_I2CD_GCALL_EN; + writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + + bus->slave = NULL; +@@ -1312,6 +1348,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + bus->base + ASPEED_I2C_FUN_CTRL_REG); + + #if IS_ENABLED(CONFIG_I2C_SLAVE) ++ if (of_property_read_bool(pdev->dev.of_node, "general-call")) ++ bus->general_call = true; ++ + /* If slave has already been registered, re-enable it. */ + if (bus->slave) + __aspeed_i2c_reg_slave(bus, bus->slave->addr); +diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c +index 2c7a6038409c..1d4db584b393 100644 +--- a/drivers/i2c/i2c-slave-mqueue.c ++++ b/drivers/i2c/i2c-slave-mqueue.c +@@ -56,10 +56,12 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_WRITE_REQUESTED: ++ case I2C_SLAVE_GCALL_REQUESTED: + mq->truncated = 0; + + msg->len = 1; +- msg->buf[0] = client->addr << 1; ++ msg->buf[0] = event == I2C_SLAVE_GCALL_REQUESTED ? ++ 0 : client->addr << 1; + break; + + case I2C_SLAVE_WRITE_RECEIVED: +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index b4055d133338..52369ea150b4 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -365,6 +365,7 @@ enum i2c_slave_event { + I2C_SLAVE_WRITE_REQUESTED, + I2C_SLAVE_READ_PROCESSED, + I2C_SLAVE_WRITE_RECEIVED, ++ I2C_SLAVE_GCALL_REQUESTED, + I2C_SLAVE_STOP, + }; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch new file mode 100644 index 000000000..925880eff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch @@ -0,0 +1,34 @@ +From 7854a5e094ac49bebf9b2bfdd44db2f8cdd37543 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Fri, 31 May 2019 15:05:13 -0700 +Subject: [PATCH] set idle-disconnect to true in all cases + +From sysfs this parameter can't be set. We want the +muxes to clean themselves up if possible. Set this to +true. + +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + drivers/i2c/muxes/i2c-mux-pca954x.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c +index 923aa3a5a3dc..084c10951890 100644 +--- a/drivers/i2c/muxes/i2c-mux-pca954x.c ++++ b/drivers/i2c/muxes/i2c-mux-pca954x.c +@@ -474,8 +474,12 @@ static int pca954x_probe(struct i2c_client *client, + data->last_chan = 0; /* force the first selection */ + data->idle_state = MUX_IDLE_AS_IS; + ++#if 1 /* Forcibly set the self-disconnect flag */ ++ idle_disconnect_dt = true; ++#else + idle_disconnect_dt = np && + of_property_read_bool(np, "i2c-mux-idle-disconnect"); ++#endif + if (idle_disconnect_dt) + data->idle_state = MUX_IDLE_DISCONNECT; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch new file mode 100644 index 000000000..0e8a2b101 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch @@ -0,0 +1,191 @@ +From b429cf11ecb2f6009dd9e062ea5e053718802d93 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 11 Jul 2019 13:53:34 -0700 +Subject: [PATCH] i2c: aspeed: add H/W timeout support + +This commit adds I2C H/W timeout support. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 82 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 76 insertions(+), 6 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 4420899e2c2d..830b3d2cabad 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -55,6 +55,7 @@ + /* Device Register Definition */ + /* 0x00 : I2CD Function Control Register */ + #define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20) ++#define ASPEED_I2CD_BUS_AUTO_RECOVERY_EN BIT(17) + #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15) + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) +@@ -71,10 +72,14 @@ + #define ASPEED_I2CD_TIME_SCL_HIGH_MASK GENMASK(19, 16) + #define ASPEED_I2CD_TIME_SCL_LOW_SHIFT 12 + #define ASPEED_I2CD_TIME_SCL_LOW_MASK GENMASK(15, 12) ++#define ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_SHIFT 8 ++#define ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK GENMASK(9, 8) + #define ASPEED_I2CD_TIME_BASE_DIVISOR_MASK GENMASK(3, 0) + #define ASPEED_I2CD_TIME_SCL_REG_MAX GENMASK(3, 0) ++ + /* 0x08 : I2CD Clock and AC Timing Control Register #2 */ +-#define ASPEED_NO_TIMEOUT_CTRL 0 ++#define ASPEED_I2CD_TIMEOUT_CYCLES_SHIFT 0 ++#define ASPEED_I2CD_TIMEOUT_CYCLES_MASK GENMASK(4, 0) + + /* 0x0c : I2CD Interrupt Control Register & + * 0x10 : I2CD Interrupt Status Register +@@ -82,6 +87,7 @@ + * These share bit definitions, so use the same values for the enable & + * status bits. + */ ++#define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15) + #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) + #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) + #define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8) +@@ -98,8 +104,11 @@ + ASPEED_I2CD_INTR_SCL_TIMEOUT | \ + ASPEED_I2CD_INTR_ABNORMAL | \ + ASPEED_I2CD_INTR_ARBIT_LOSS) ++#define ASPEED_I2CD_INTR_SLAVE_ERRORS \ ++ ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT + #define ASPEED_I2CD_INTR_ALL \ +- (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \ ++ (ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT | \ ++ ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \ + ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \ + ASPEED_I2CD_INTR_SCL_TIMEOUT | \ + ASPEED_I2CD_INTR_ABNORMAL | \ +@@ -186,6 +195,7 @@ struct aspeed_i2c_bus { + u32 divisor); + unsigned long parent_clk_frequency; + u32 bus_frequency; ++ u32 hw_timeout_ms; + /* Transaction state. */ + enum aspeed_i2c_master_state master_state; + struct i2c_msg *msgs; +@@ -303,6 +313,14 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) + } + + #if IS_ENABLED(CONFIG_I2C_SLAVE) ++static int aspeed_i2c_check_slave_error(u32 irq_status) ++{ ++ if (irq_status & ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT) ++ return -EIO; ++ ++ return 0; ++} ++ + static inline void + aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status, + u8 *value) +@@ -421,6 +439,14 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (!slave) + return 0; + ++ if (aspeed_i2c_check_slave_error(irq_status)) { ++ dev_dbg(bus->dev, "received slave error interrupt: 0x%08x\n", ++ irq_status); ++ irq_handled |= (irq_status & ASPEED_I2CD_INTR_SLAVE_ERRORS); ++ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; ++ return irq_handled; ++ } ++ + command = readl(bus->base + ASPEED_I2C_CMD_REG); + + /* Slave was requested, restart state machine. */ +@@ -681,7 +707,7 @@ static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus) + } + } + +-static int aspeed_i2c_is_irq_error(u32 irq_status) ++static int aspeed_i2c_check_master_error(u32 irq_status) + { + if (irq_status & ASPEED_I2CD_INTR_ARBIT_LOSS) + return -EAGAIN; +@@ -840,9 +866,9 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + * should clear the command queue effectively taking us back to the + * INACTIVE state. + */ +- ret = aspeed_i2c_is_irq_error(irq_status); ++ ret = aspeed_i2c_check_master_error(irq_status); + if (ret) { +- dev_dbg(bus->dev, "received error interrupt: 0x%08x\n", ++ dev_dbg(bus->dev, "received master error interrupt: 0x%08x\n", + irq_status); + irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS); + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) { +@@ -1307,6 +1333,7 @@ static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor) + /* precondition: bus.lock has been acquired. */ + static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) + { ++ u32 timeout_base_divisor, timeout_tick_us, timeout_cycles; + u32 divisor, clk_reg_val; + + divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency); +@@ -1315,8 +1342,46 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) + ASPEED_I2CD_TIME_THDSTA_MASK | + ASPEED_I2CD_TIME_TACST_MASK); + clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor); ++ ++ if (bus->hw_timeout_ms) { ++ u8 div_max = ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK >> ++ ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_SHIFT; ++ u8 cycles_max = ASPEED_I2CD_TIMEOUT_CYCLES_MASK >> ++ ASPEED_I2CD_TIMEOUT_CYCLES_SHIFT; ++ ++ timeout_base_divisor = 0; ++ ++ do { ++ timeout_tick_us = 1000 * (16384 << ++ (timeout_base_divisor << 1)) / ++ (bus->parent_clk_frequency / 1000); ++ ++ if (timeout_base_divisor == div_max || ++ timeout_tick_us * ASPEED_I2CD_TIMEOUT_CYCLES_MASK >= ++ bus->hw_timeout_ms * 1000) ++ break; ++ } while (timeout_base_divisor++ < div_max); ++ ++ if (timeout_tick_us) { ++ timeout_cycles = DIV_ROUND_UP(bus->hw_timeout_ms * 1000, ++ timeout_tick_us); ++ if (timeout_cycles == 0) ++ timeout_cycles = 1; ++ else if (timeout_cycles > cycles_max) ++ timeout_cycles = cycles_max; ++ } else { ++ timeout_cycles = 0; ++ } ++ } else { ++ timeout_base_divisor = 0; ++ timeout_cycles = 0; ++ } ++ ++ clk_reg_val |= FIELD_PREP(ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK, ++ timeout_base_divisor); ++ + writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1); +- writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2); ++ writel(timeout_cycles, bus->base + ASPEED_I2C_AC_TIMING_REG2); + + return 0; + } +@@ -1331,6 +1396,11 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + /* Disable everything. */ + writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG); + ++ device_property_read_u32(&pdev->dev, "aspeed,hw-timeout-ms", ++ &bus->hw_timeout_ms); ++ if (bus->hw_timeout_ms) ++ fun_ctrl_reg |= ASPEED_I2CD_BUS_AUTO_RECOVERY_EN; ++ + ret = aspeed_i2c_init_clk(bus); + if (ret < 0) + return ret; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch new file mode 100644 index 000000000..104279ace --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch @@ -0,0 +1,50 @@ +From b43bdeb5f3aa297549655e67f0e6a5db5f592e34 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 11 Jul 2019 14:04:39 -0700 +Subject: [PATCH] i2c: aspeed: add SLAVE_ADDR_RECEIVED_PENDING interrupt + handling + +If a peer master sends messages too quickly before it processes +previous slave DMA data handling, this indicator will be set. It's +just a indicator and driver can't recover this case so just ignore +it. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 830b3d2cabad..a308d5896632 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -87,6 +87,7 @@ + * These share bit definitions, so use the same values for the enable & + * status bits. + */ ++#define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(30) + #define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15) + #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) + #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) +@@ -468,6 +469,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n", + irq_status, command); + ++ /* ++ * If a peer master sends messages too quickly before it processes ++ * previous slave DMA data handling, this indicator will be set. It's ++ * just a indicator and driver can't recover this case so just ignore ++ * it. ++ */ ++ if (unlikely(irq_status & ++ ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING)) { ++ dev_dbg(bus->dev, "A slave addr match interrupt is pending.\n"); ++ irq_handled |= ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING; ++ } ++ + /* Slave was sent something. */ + if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { + aspeed_i2c_slave_handle_rx_done(bus, irq_status, &value); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch new file mode 100644 index 000000000..5c3e35016 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch @@ -0,0 +1,44 @@ +From 0bda96c5fe3064c71f190bc484e2ce59c51d5585 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 19 Jul 2019 12:54:38 -0700 +Subject: [PATCH] gpio: aspeed: temporary fix for gpiochip range setting + +Since we are still using fixed indices for gpio line numbers for sysfs +interface, this commit set the gpiochip range as fixed temporariliy +til we replace all index based gpio uses with name based uses. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/gpio/gpio-aspeed.c | 2 +- + drivers/gpio/sgpio-aspeed.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c +index 39c50c53dae3..05945470bd89 100644 +--- a/drivers/gpio/gpio-aspeed.c ++++ b/drivers/gpio/gpio-aspeed.c +@@ -1181,7 +1181,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) + gpio->chip.set = aspeed_gpio_set; + gpio->chip.set_config = aspeed_gpio_set_config; + gpio->chip.label = dev_name(&pdev->dev); +- gpio->chip.base = -1; ++ gpio->chip.base = 0; + + /* Allocate a cache of the output registers */ + banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); +diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c +index 5028e9144a75..850539da43f5 100644 +--- a/drivers/gpio/sgpio-aspeed.c ++++ b/drivers/gpio/sgpio-aspeed.c +@@ -681,7 +681,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) + gpio->chip.set = aspeed_sgpio_set; + gpio->chip.set_config = aspeed_sgpio_set_config; + gpio->chip.label = dev_name(&pdev->dev); +- gpio->chip.base = -1; ++ gpio->chip.base = gpio->config->nr_pgpios; + + rc = aspeed_sgpio_setup_irqs(gpio, pdev); + if (rc < 0) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch new file mode 100644 index 000000000..40a9272e0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch @@ -0,0 +1,88 @@ +From e360a6c2a3f15bfc8900c7262c56f9bcd5e0f16e Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Thu, 8 Aug 2019 10:38:00 -0700 +Subject: [PATCH] pmbus: add 'fault' and 'beep' attributes + +This commit adds two more attirbutes to reflect MFR_SPECIFIC bit in +the STATUS_WORD and 'Unit Off For Insufficient Input Voltage' bit in +the STATUS_INPUT into 'fault' and 'beep' attributes respectively. + +The attributes will be enumerated as 'inX_fault' and 'inX_beep' in +a 'vin' group. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/hwmon/pmbus/pmbus.h | 1 + + drivers/hwmon/pmbus/pmbus_core.c | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+) + +diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h +index d198af3a92b6..09e6fe01c304 100644 +--- a/drivers/hwmon/pmbus/pmbus.h ++++ b/drivers/hwmon/pmbus/pmbus.h +@@ -303,6 +303,7 @@ enum pmbus_fan_mode { percent = 0, rpm }; + #define PB_PIN_OP_WARNING BIT(0) + #define PB_IIN_OC_WARNING BIT(1) + #define PB_IIN_OC_FAULT BIT(2) ++#define PB_UNIT_OFF_FOR_INSUF_VIN BIT(3) + + /* + * STATUS_TEMPERATURE +diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c +index 898d7378f4f8..85295a45c3ba 100644 +--- a/drivers/hwmon/pmbus/pmbus_core.c ++++ b/drivers/hwmon/pmbus/pmbus_core.c +@@ -1163,6 +1163,8 @@ struct pmbus_limit_attr { + struct pmbus_sensor_attr { + u16 reg; /* sensor register */ + u16 gbit; /* generic status bit */ ++ u16 gfbit; /* generic fault status bit */ ++ u16 sbbit; /* beep status bit */ + u8 nlimit; /* # of limit registers */ + enum pmbus_sensor_classes class;/* sensor class */ + const char *label; /* sensor label */ +@@ -1264,6 +1266,32 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, + return ret; + } + } ++ /* ++ * Add fault attribute if there is a generic fault bit, and if ++ * the generic status register (word or byte, depending on which global ++ * bit is set) for this page is accessible. ++ */ ++ if (attr->gfbit) { ++ upper = !!(attr->gfbit & 0xff00); /* need to check STATUS_WORD */ ++ if ((!upper || (upper && data->has_status_word)) && ++ pmbus_check_status_register(client, page)) { ++ ret = pmbus_add_boolean(data, name, "fault", index, ++ NULL, NULL, ++ PB_STATUS_BASE + page, ++ attr->gfbit); ++ if (ret) ++ return ret; ++ } ++ } ++ /* Add beep attribute if there is a beep status bit. */ ++ if (attr->sbbit) { ++ ret = pmbus_add_boolean(data, name, "beep", index, ++ NULL, NULL, ++ attr->sbase + page, ++ attr->sbbit); ++ if (ret) ++ return ret; ++ } + return 0; + } + +@@ -1435,6 +1463,8 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { + .gbit = PB_STATUS_VIN_UV, + .limit = vin_limit_attrs, + .nlimit = ARRAY_SIZE(vin_limit_attrs), ++ .gfbit = PB_STATUS_WORD_MFR, ++ .sbbit = PB_UNIT_OFF_FOR_INSUF_VIN, + }, { + .reg = PMBUS_VIRT_READ_VMON, + .class = PSC_VOLTAGE_IN, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch new file mode 100644 index 000000000..1056b3beb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch @@ -0,0 +1,155 @@ +From 5c82e0b33f2a373d5e19569635f108cfa096f53e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Adrian=20Ambro=C5=BCewicz?= <adrian.ambrozewicz@intel.com> +Date: Mon, 29 Jul 2019 10:19:00 +0200 +Subject: [PATCH] Add IO statistics to USB Mass storage gadget +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduces new attribute to Mass Storage Gadget ConfigFS : stats. +It's read-only attribute which contains statistics of read/write operations +based on LUN transaction counters (IO number and bytes transferred). + +Goal is to provide a way to observe whether simulated device is actually +used by host. Statistics on hosted file / nbd level are not always viable +due to page cache having severe impact on actual IO statistics. +This attribute should provide information about host IO on USB Gadget as +close to endpoint as possible. + +Attribute is tied completely to configFS implementation and it's lifecycle +is managed by Kernel and user. Driver implements a handler which populates +output buffer on read. + +Tests performed: +- mounted USB Mass Storage gadget, new attribute showed up in gadget tree +- attribute was monitored for changes during IO performed on host machine +- removed device, attribute (along with other device attributes) was gone + +Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@intel.com> +--- + drivers/usb/gadget/function/f_mass_storage.c | 12 ++++++++++++ + drivers/usb/gadget/function/storage_common.c | 9 +++++++++ + drivers/usb/gadget/function/storage_common.h | 29 ++++++++++++++++++++++++++++ + 3 files changed, 50 insertions(+) + +diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c +index 7c96c4665178..ecc3c68a7882 100644 +--- a/drivers/usb/gadget/function/f_mass_storage.c ++++ b/drivers/usb/gadget/function/f_mass_storage.c +@@ -710,6 +710,8 @@ static int do_read(struct fsg_common *common) + amount_left -= nread; + common->residue -= nread; + ++ fsg_stats_rd_attempt(&curlun->stats, nread); ++ + /* + * Except at the end of the transfer, nread will be + * equal to the buffer size, which is divisible by the +@@ -907,6 +909,8 @@ static int do_write(struct fsg_common *common) + amount_left_to_write -= nwritten; + common->residue -= nwritten; + ++ fsg_stats_wr_attempt(&curlun->stats, nwritten); ++ + /* If an error occurred, report it and its position */ + if (nwritten < amount) { + curlun->sense_data = SS_WRITE_ERROR; +@@ -3122,6 +3126,13 @@ static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item, + + CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string); + ++static ssize_t fsg_lun_opts_stats_show(struct config_item *item, char *page) ++{ ++ return fsg_show_stats(to_fsg_lun_opts(item)->lun, page); ++} ++ ++CONFIGFS_ATTR_RO(fsg_lun_opts_, stats); ++ + static struct configfs_attribute *fsg_lun_attrs[] = { + &fsg_lun_opts_attr_file, + &fsg_lun_opts_attr_ro, +@@ -3129,6 +3140,7 @@ static struct configfs_attribute *fsg_lun_attrs[] = { + &fsg_lun_opts_attr_cdrom, + &fsg_lun_opts_attr_nofua, + &fsg_lun_opts_attr_inquiry_string, ++ &fsg_lun_opts_attr_stats, + NULL, + }; + +diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c +index f7e6c42558eb..2325b97961df 100644 +--- a/drivers/usb/gadget/function/storage_common.c ++++ b/drivers/usb/gadget/function/storage_common.c +@@ -371,6 +371,15 @@ ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf) + } + EXPORT_SYMBOL_GPL(fsg_show_inquiry_string); + ++ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf) ++{ ++ return sprintf(buf, "read cnt: %u\n" "read sum: %llu\n" ++ "write cnt: %u\n" "write sum: %llu\n", ++ curlun->stats.read.count, curlun->stats.read.bytes, ++ curlun->stats.write.count, curlun->stats.write.bytes); ++} ++EXPORT_SYMBOL_GPL(fsg_show_stats); ++ + /* + * The caller must hold fsg->filesem for reading when calling this function. + */ +diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h +index e5e3a2553aaa..447021ba821a 100644 +--- a/drivers/usb/gadget/function/storage_common.h ++++ b/drivers/usb/gadget/function/storage_common.h +@@ -95,6 +95,32 @@ do { \ + */ + #define INQUIRY_STRING_LEN ((size_t) (8 + 16 + 4 + 1)) + ++struct fsg_stats_cnt { ++ u64 bytes; ++ u32 count; ++}; ++ ++struct fsg_stats { ++ struct fsg_stats_cnt read; ++ struct fsg_stats_cnt write; ++}; ++ ++static inline void fsg_stats_update(struct fsg_stats_cnt *cnt, u64 diff) ++{ ++ cnt->count++; ++ cnt->bytes += diff; ++} ++ ++static inline void fsg_stats_wr_attempt(struct fsg_stats *stats, u64 b_written) ++{ ++ fsg_stats_update(&stats->write, b_written); ++} ++ ++static inline void fsg_stats_rd_attempt(struct fsg_stats *stats, u64 b_read) ++{ ++ fsg_stats_update(&stats->read, b_read); ++} ++ + struct fsg_lun { + struct file *filp; + loff_t file_length; +@@ -120,6 +146,8 @@ struct fsg_lun { + const char *name; /* "lun.name" */ + const char **name_pfx; /* "function.name" */ + char inquiry_string[INQUIRY_STRING_LEN]; ++ ++ struct fsg_stats stats; + }; + + static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +@@ -213,6 +241,7 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, + ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf); + ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf); + ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf); ++ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf); + ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, + const char *buf, size_t count); + ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch new file mode 100644 index 000000000..52c3617d6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch @@ -0,0 +1,64 @@ +From 93ba2aeb9ad3899e2b72877daa47376a6bf192b6 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Mon, 23 Sep 2019 13:48:49 -0700 +Subject: [PATCH] Refine initialization flow in I2C driver + +Since we enabled I2C busses in u-boot, we need to disable the I2C +bus and clear all garbage interrupts when kernel probes the bus. +This commit refines the initialization flow by adding a bus reset +at the beginning of probe function and by moving bus init function +after interrupt handling setup. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index a308d5896632..b32611088c82 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -1588,6 +1588,11 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + + bus->dev = &pdev->dev; + ++ /* Disable bus and clean up any left over interrupt state. */ ++ writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG); ++ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG); ++ writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG); ++ + parent_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(parent_clk)) + return PTR_ERR(parent_clk); +@@ -1630,17 +1635,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + strlcpy(bus->adap.name, pdev->name, sizeof(bus->adap.name)); + i2c_set_adapdata(&bus->adap, bus); + +- /* Clean up any left over interrupt state. */ +- writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG); +- writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG); +- /* +- * bus.lock does not need to be held because the interrupt handler has +- * not been enabled yet. +- */ +- ret = aspeed_i2c_init(bus, pdev); +- if (ret < 0) +- goto out_free_dma_buf; +- + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq, + 0, dev_name(&pdev->dev), bus); +@@ -1653,6 +1647,10 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + + platform_set_drvdata(pdev, bus); + ++ ret = aspeed_i2c_init(bus, pdev); ++ if (ret < 0) ++ goto out_free_dma_buf; ++ + dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", + bus->adap.nr, bus->dma_buf ? "dma" : + bus->buf_base ? "buffer" : "byte", +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch new file mode 100644 index 000000000..9515a1a89 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch @@ -0,0 +1,1107 @@ +From a17a084c4889dcc7cb43ef5f93032997cfcee4f0 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@intel.com> +Date: Fri, 27 Sep 2019 13:09:48 -0700 +Subject: [PATCH] arm: ast2600: add pwm_tacho driver from aspeed + +Add the pwm_tacho driver from Aspeed to get pwm working until an +upstream PWM/Tacho driver is available. This was copied from the v5.02 +BSP from Aspeed. + +Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> +--- + arch/arm/boot/dts/aspeed-g6.dtsi | 10 + + drivers/hwmon/Kconfig | 11 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/aspeed-g6-pwm-tacho.c | 1025 +++++++++++++++++++++++++++++++++++ + 4 files changed, 1047 insertions(+) + create mode 100644 drivers/hwmon/aspeed-g6-pwm-tacho.c + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index eeace4b7b725..33fcd89db6b8 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -278,6 +278,16 @@ + #size-cells = <1>; + ranges; + ++ pwm_tacho: pwm-tacho-controller@1e610000 { ++ compatible = "aspeed,ast2600-pwm-tacho"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x1e610000 0x100>; ++ clocks = <&syscon ASPEED_CLK_AHB>; ++ resets = <&syscon ASPEED_RESET_PWM>; ++ status = "disabled"; ++ }; ++ + syscon: syscon@1e6e2000 { + compatible = "aspeed,ast2600-scu", "syscon", "simple-mfd"; + reg = <0x1e6e2000 0x1000>; +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index e244a7901392..8312b3798b82 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -371,6 +371,17 @@ config SENSORS_ASPEED + This driver can also be built as a module. If so, the module + will be called aspeed_pwm_tacho. + ++config SENSORS_ASPEED_G6 ++ tristate "ASPEED AST2600 PWM and Fan tach driver" ++ depends on THERMAL || THERMAL=n ++ select REGMAP ++ help ++ This driver provides support for ASPEED AST2600 PWM ++ and Fan Tacho controllers. ++ ++ This driver can also be built as a module. If so, the module ++ will be called aspeed_g6_pwm_tacho. ++ + config SENSORS_ATXP1 + tristate "Attansic ATXP1 VID controller" + depends on I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 1c7ab361adc7..e74ea925fb56 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o + obj-$(CONFIG_SENSORS_AS370) += as370-hwmon.o + obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o + obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o ++obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tacho.o + obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o + obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o + obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o +diff --git a/drivers/hwmon/aspeed-g6-pwm-tacho.c b/drivers/hwmon/aspeed-g6-pwm-tacho.c +new file mode 100644 +index 000000000000..1894f6ad5edb +--- /dev/null ++++ b/drivers/hwmon/aspeed-g6-pwm-tacho.c +@@ -0,0 +1,1025 @@ ++/* ++ * Copyright (C) ASPEED Technology Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 or later as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/errno.h> ++#include <linux/gpio/consumer.h> ++#include <linux/delay.h> ++#include <linux/hwmon.h> ++#include <linux/hwmon-sysfs.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of_platform.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/sysfs.h> ++#include <linux/reset.h> ++#include <linux/regmap.h> ++#include <linux/thermal.h> ++ ++#define ASPEED_PWM_CTRL 0x00 //PWM0 General Register ++#define ASPEED_PWM_CTRL_CH(x) ((x * 0x10) + 0x00) ++#define PWM_LOAD_AS_WDT BIT(19) //load selection as WDT ++#define PWM_DUTY_LOAD_AS_WDT_EN BIT(18) //enable PWM duty load as WDT ++#define PWM_DUTY_SYNC_DIS BIT(17) //disable PWM duty sync ++#define PWM_CLK_ENABLE BIT(16) //enable PWM clock ++#define PWM_LEVEL_OUTPUT BIT(15) //output PWM level ++#define PWM_INVERSE BIT(14) //inverse PWM pin ++#define PWM_OPEN_DRAIN_EN BIT(13) //enable open-drain ++#define PWM_PIN_EN BIT(12) //enable PWM pin ++#define PWM_CLK_DIV_H_MASK (0xf << 8) //PWM clock division H bit [3:0] ++#define PWM_CLK_DIV_L_MASK (0xff) //PWM clock division H bit [3:0] ++ ++/* ++\xregmid {11:8 }{RW}{PWM clock division H bit [3:0]}{ ++ 0: divide 1 \n ++ 1: divide 2 \n ++ 2: divide 4 \n ++ 3: divide 8 \n ++ ... \n ++ F: divide 32768} ++\xregmid {7 :0 }{RW}{PWM clock division L bit [7:0]}{ ++ 00: divide 1 \n ++ 01: divide 2 \n ++ 02: divide 3 \n ++ 03: divide 4 \n ++ ... \n ++ FF: divide 256} ++*/ ++ ++#define ASPEED_PWM_DUTY_CYCLE 0x04 //PWM0 Duty Cycle Register ++#define ASPEED_PWM_DUTY_CYCLE_CH(x) ((x * 0x10) + 0x04) ++#define PWM_LOOP_BIT_MASK (0xf << 24) //loop bit [7:0] ++#define PWM_PERIOD_BIT (24) //pwm period bit [7:0] ++#define PWM_PERIOD_BIT_MASK (0xff << 24) //pwm period bit [7:0] ++#define PWM_RISING_FALLING_AS_WDT_BIT (16) ++#define PWM_RISING_FALLING_AS_WDT_MASK (0xff << 16) //pwm rising/falling point bit [7:0] as WDT ++#define PWM_RISING_FALLING_MASK (0xffff) ++#define PWM_RISING_FALLING_BIT (8) //pwm falling point bit [7:0] ++#define PWM_RISING_RISING_BIT (0) //pwm rising point bit [7:0] ++ ++#define ASPEED_TACHO_CTRL 0x08 //TACH0 General Register ++#define ASPEED_TACHO_CTRL_CH(x) ((x * 0x10) + 0x08) ++#define TACHO_IER BIT(31) //enable tacho interrupt ++#define TACHO_INVERS_LIMIT BIT(30) //inverse tacho limit comparison ++#define TACHO_LOOPBACK BIT(29) //tacho loopback ++#define TACHO_ENABLE BIT(28) //{enable tacho} ++#define TACHO_DEBOUNCE_BIT (26) //{tacho de-bounce} ++#define TACHO_DEBOUNCE_MASK (0x3 << 26) //{tacho de-bounce} ++#define TECHIO_EDGE_MASK (0x3 << 24) //tacho edge} ++#define TECHIO_EDGE_BIT (24) //tacho edge} ++#define TACHO_CLK_DIV_T_MASK (0xf << 20) ++#define TACHO_CLK_DIV_BIT (20) ++#define TACHO_THRESHOLD_MASK (0xfffff) //tacho threshold bit ++/* ++\xregmid {23:20}{RW}{tacho clock division T bit [3:0]}{ ++ 0: divide 1 \n ++ 1: divide 4 \n ++ 2: divide 16 \n ++ 3: divide 64 \n ++ ... \n ++ B: divide 4194304 \n ++ others: reserved} ++\xregmidb{19 :0 }{RW}{tacho threshold bit [19:0]} ++*/ ++ ++#define ASPEED_TACHO_STS 0x0C //TACH0 Status Register ++#define ASPEED_TACHO_STS_CH(x) ((x * 0x10) + 0x0C) ++#define TACHO_ISR BIT(31) //interrupt status and clear ++#define PWM_OUT BIT(25) //{pwm_out} ++#define PWM_OEN BIT(24) //{pwm_oeN} ++#define TACHO_DEB_INPUT BIT(23) //tacho deB input ++#define TACHO_RAW_INPUT BIT(22) //tacho raw input} ++#define TACHO_VALUE_UPDATE BIT(21) //tacho value updated since the last read ++#define TACHO_FULL_MEASUREMENT BIT(20) //{tacho full measurement} ++#define TACHO_VALUE_MASK 0xfffff //tacho value bit [19:0]} ++ ++#define MAX_CDEV_NAME_LEN 16 ++ ++struct aspeed_pwm_channel_params { ++ int load_wdt_rising_falling_pt; ++ int load_wdt_selection; //0: rising , 1: falling ++ int load_wdt_enable; ++ int duty_sync_enable; ++ int invert_pin; ++ u8 divide_h; ++ u8 divide_l; ++ u8 period; ++ u8 rising; ++ u8 falling; ++}; ++ ++static struct aspeed_pwm_channel_params default_pwm_params[] = { ++ [0] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 1, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [1] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [2] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [3] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [4] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [5] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [6] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [7] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [8] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [9] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [10] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [11] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [12] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [13] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [14] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++ [15] = { ++ .load_wdt_rising_falling_pt = 0x10, ++ .load_wdt_selection = 0, ++ .load_wdt_enable = 0, ++ .duty_sync_enable = 0, ++ .invert_pin = 0, ++ .divide_h = 0x5, ++ .divide_l = 0x6, ++ .period = 0x13, //5% ~~ ++ .rising = 0x00, ++ .falling = 0x0a, ++ }, ++}; ++ ++/* ++ * 5:4 fan tach edge mode selection bit: ++ * 00: falling ++ * 01: rising ++ * 10: both ++ * 11: reserved. ++ */ ++ ++struct aspeed_tacho_channel_params { ++ int limited_inverse; ++ u16 threshold; ++ u8 tacho_edge; ++ u8 tacho_debounce; ++ u8 divide; ++}; ++ ++ ++static struct aspeed_tacho_channel_params default_tacho_params[] = { ++ [0] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [1] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [2] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [3] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [4] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [5] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [6] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [7] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [8] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [9] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [10] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [11] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [12] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [13] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [14] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++ [15] = { ++ .limited_inverse = 0, ++ .threshold = 0, ++ .tacho_edge = 0, ++ .tacho_debounce = 0, ++ .divide = 8, ++ }, ++}; ++ ++struct aspeed_pwm_tachometer_data { ++ struct regmap *regmap; ++ unsigned long clk_freq; ++ struct reset_control *reset; ++ bool pwm_present[16]; ++ bool fan_tach_present[16]; ++ struct aspeed_pwm_channel_params *pwm_channel; ++ struct aspeed_tacho_channel_params *tacho_channel; ++ struct aspeed_cooling_device *cdev[8]; ++ const struct attribute_group *groups[3]; ++}; ++ ++struct aspeed_cooling_device { ++ char name[16]; ++ struct aspeed_pwm_tachometer_data *priv; ++ struct thermal_cooling_device *tcdev; ++ int pwm_channel; ++ u8 *cooling_levels; ++ u8 max_state; ++ u8 cur_state; ++}; ++ ++static int regmap_aspeed_pwm_tachometer_reg_write(void *context, unsigned int reg, ++ unsigned int val) ++{ ++ void __iomem *regs = (void __iomem *)context; ++ ++ writel(val, regs + reg); ++ return 0; ++} ++ ++static int regmap_aspeed_pwm_tachometer_reg_read(void *context, unsigned int reg, ++ unsigned int *val) ++{ ++ void __iomem *regs = (void __iomem *)context; ++ ++ *val = readl(regs + reg); ++ return 0; ++} ++ ++static const struct regmap_config aspeed_pwm_tachometer_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = 0x100, ++ .reg_write = regmap_aspeed_pwm_tachometer_reg_write, ++ .reg_read = regmap_aspeed_pwm_tachometer_reg_read, ++ .fast_io = true, ++}; ++ ++static void aspeed_set_pwm_channel_enable(struct regmap *regmap, u8 pwm_channel, ++ bool enable) ++{ ++ regmap_update_bits(regmap, ASPEED_PWM_CTRL_CH(pwm_channel), (PWM_CLK_ENABLE | PWM_PIN_EN), enable ? (PWM_CLK_ENABLE | PWM_PIN_EN) : 0); ++} ++ ++static void aspeed_set_fan_tach_ch_enable(struct aspeed_pwm_tachometer_data *priv, u8 fan_tach_ch, ++ bool enable) ++{ ++ u32 i = 0, j; ++ u32 divide_val = 0; ++ u32 reg_value = 0; ++ ++ if(enable) { ++ //4 ^ n ++ //check pwm clk and to change tacho devide 25KZ ++ for(i = 0; i < 12; i++) { ++ divide_val = 1; ++ for (j = 1; j <= i; j++) ++ divide_val *= 4; ++// printk("i : %d , priv->clk_freq/divide_val %d ",i, priv->clk_freq/divide_val); ++ if((priv->clk_freq/divide_val) < 250000) ++ break; ++ } ++ i--; ++ divide_val = ((1 << i) * (1 << i)); ++// printk("tacho divide_val %d , i %x max tacho clk %d \n", divide_val, i, priv->clk_freq / divide_val); ++ priv->tacho_channel[fan_tach_ch].divide = i; ++ ++ reg_value = TACHO_ENABLE | ++ (priv->tacho_channel[fan_tach_ch].tacho_edge << TECHIO_EDGE_BIT) | ++ (priv->tacho_channel[fan_tach_ch].divide << TACHO_CLK_DIV_BIT) | ++ (priv->tacho_channel[fan_tach_ch].tacho_debounce << TACHO_DEBOUNCE_BIT); ++ ++ if(priv->tacho_channel[fan_tach_ch].limited_inverse) ++ reg_value |= TACHO_INVERS_LIMIT; ++ ++ if(priv->tacho_channel[fan_tach_ch].threshold) ++ reg_value |= (TACHO_IER | priv->tacho_channel[fan_tach_ch].threshold); ++ ++ regmap_write(priv->regmap, ASPEED_TACHO_CTRL_CH(fan_tach_ch), reg_value); ++ } else ++ regmap_update_bits(priv->regmap, ASPEED_TACHO_CTRL_CH(fan_tach_ch), TACHO_ENABLE, 0); ++} ++ ++static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *priv, ++ u8 index, u8 fan_ctrl) ++{ ++ u32 duty_value, ctrl_value; ++ ++ if (fan_ctrl == 0) { ++ aspeed_set_pwm_channel_enable(priv->regmap, index, false); ++ } else { ++ duty_value = (priv->pwm_channel[index].period << PWM_PERIOD_BIT) | ++ (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT); ++ ++ ctrl_value = (priv->pwm_channel[index].divide_h << 8) | priv->pwm_channel[index].divide_l; ++ ++ if (priv->pwm_channel[index].load_wdt_enable) { ++ ctrl_value |= PWM_DUTY_LOAD_AS_WDT_EN; ++ if(priv->pwm_channel[index].load_wdt_selection) { ++ ctrl_value |= PWM_LOAD_AS_WDT; ++ duty_value |= (priv->pwm_channel[index].load_wdt_rising_falling_pt << PWM_RISING_FALLING_AS_WDT_BIT); ++ } else { ++ duty_value |= (priv->pwm_channel[index].load_wdt_rising_falling_pt << PWM_RISING_FALLING_AS_WDT_BIT); ++ } ++ } ++ ++ regmap_write(priv->regmap, ASPEED_PWM_DUTY_CYCLE_CH(index), duty_value); ++ ++ regmap_write(priv->regmap, ASPEED_PWM_CTRL_CH(index), ctrl_value); ++// printk("pwm clk is %d \n", priv->clk_freq / (priv->pwm_channel[index].period + 1)); ++ aspeed_set_pwm_channel_enable(priv->regmap, index, true); ++ } ++} ++ ++#define BOTH_EDGES 0x02 /* 10b */ ++ ++static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv, ++ u8 fan_tach_ch) ++{ ++ u32 raw_data, tach_div, clk_source, val; ++ u8 mode, both; ++ int i, retries = 3; ++ ++ for(i = 0; i < retries; i++) { ++ regmap_read(priv->regmap, ASPEED_TACHO_STS_CH(fan_tach_ch), &val); ++ if (TACHO_FULL_MEASUREMENT & val) ++ break; ++ } ++ ++ raw_data = val & TACHO_VALUE_MASK; ++ if(raw_data == 0xfffff) ++ return 0; ++ ++ tach_div = priv->tacho_channel[fan_tach_ch].divide; ++ /* ++ * We need the mode to determine if the raw_data is double (from ++ * counting both edges). ++ */ ++ mode = priv->tacho_channel[fan_tach_ch].tacho_edge; ++ both = (mode & BOTH_EDGES) ? 1 : 0; ++// printk("clk %ld, raw_data %x , tach_div %x both %x \n", priv->clk_freq, raw_data, tach_div, both); ++ ++ tach_div = (tach_div * 2) * (0x1 << both); ++ clk_source = priv->clk_freq; ++ ++ if (raw_data == 0) ++ return 0; ++ ++ return (clk_source * 60) / (2 * raw_data * tach_div); ++ ++} ++ ++static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int index = sensor_attr->index; ++ int ret; ++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); ++ long fan_ctrl; ++ ++ ret = kstrtol(buf, 10, &fan_ctrl); ++ if (ret != 0) ++ return ret; ++ ++ if (fan_ctrl < 0 || fan_ctrl > priv->pwm_channel[index].period) ++ return -EINVAL; ++ ++ if (priv->pwm_channel[index].falling == fan_ctrl) ++ return count; ++ ++ priv->pwm_channel[index].falling = fan_ctrl; ++ aspeed_set_pwm_channel_fan_ctrl(priv, index, fan_ctrl); ++ ++ return count; ++} ++ ++static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int index = sensor_attr->index; ++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", priv->pwm_channel[index].falling); ++} ++ ++static ssize_t show_rpm(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int index = sensor_attr->index; ++ int rpm; ++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); ++ ++ rpm = aspeed_get_fan_tach_ch_rpm(priv, index); ++ if (rpm < 0) ++ return rpm; ++ ++ return sprintf(buf, "%d\n", rpm); ++} ++ ++static umode_t pwm_is_visible(struct kobject *kobj, ++ struct attribute *a, int index) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); ++ ++ if (!priv->pwm_present[index]) ++ return 0; ++ return a->mode; ++} ++ ++static umode_t fan_dev_is_visible(struct kobject *kobj, ++ struct attribute *a, int index) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); ++ ++ if (!priv->fan_tach_present[index]) ++ return 0; ++ return a->mode; ++} ++ ++static SENSOR_DEVICE_ATTR(pwm0, 0644, ++ show_pwm, set_pwm, 0); ++static SENSOR_DEVICE_ATTR(pwm1, 0644, ++ show_pwm, set_pwm, 1); ++static SENSOR_DEVICE_ATTR(pwm2, 0644, ++ show_pwm, set_pwm, 2); ++static SENSOR_DEVICE_ATTR(pwm3, 0644, ++ show_pwm, set_pwm, 3); ++static SENSOR_DEVICE_ATTR(pwm4, 0644, ++ show_pwm, set_pwm, 4); ++static SENSOR_DEVICE_ATTR(pwm5, 0644, ++ show_pwm, set_pwm, 5); ++static SENSOR_DEVICE_ATTR(pwm6, 0644, ++ show_pwm, set_pwm, 6); ++static SENSOR_DEVICE_ATTR(pwm7, 0644, ++ show_pwm, set_pwm, 7); ++static SENSOR_DEVICE_ATTR(pwm8, 0644, ++ show_pwm, set_pwm, 8); ++static SENSOR_DEVICE_ATTR(pwm9, 0644, ++ show_pwm, set_pwm, 9); ++static SENSOR_DEVICE_ATTR(pwm10, 0644, ++ show_pwm, set_pwm, 10); ++static SENSOR_DEVICE_ATTR(pwm11, 0644, ++ show_pwm, set_pwm, 11); ++static SENSOR_DEVICE_ATTR(pwm12, 0644, ++ show_pwm, set_pwm, 12); ++static SENSOR_DEVICE_ATTR(pwm13, 0644, ++ show_pwm, set_pwm, 13); ++static SENSOR_DEVICE_ATTR(pwm14, 0644, ++ show_pwm, set_pwm, 14); ++static SENSOR_DEVICE_ATTR(pwm15, 0644, ++ show_pwm, set_pwm, 15); ++static struct attribute *pwm_dev_attrs[] = { ++ &sensor_dev_attr_pwm0.dev_attr.attr, ++ &sensor_dev_attr_pwm1.dev_attr.attr, ++ &sensor_dev_attr_pwm2.dev_attr.attr, ++ &sensor_dev_attr_pwm3.dev_attr.attr, ++ &sensor_dev_attr_pwm4.dev_attr.attr, ++ &sensor_dev_attr_pwm5.dev_attr.attr, ++ &sensor_dev_attr_pwm6.dev_attr.attr, ++ &sensor_dev_attr_pwm7.dev_attr.attr, ++ &sensor_dev_attr_pwm8.dev_attr.attr, ++ &sensor_dev_attr_pwm9.dev_attr.attr, ++ &sensor_dev_attr_pwm10.dev_attr.attr, ++ &sensor_dev_attr_pwm11.dev_attr.attr, ++ &sensor_dev_attr_pwm12.dev_attr.attr, ++ &sensor_dev_attr_pwm13.dev_attr.attr, ++ &sensor_dev_attr_pwm14.dev_attr.attr, ++ &sensor_dev_attr_pwm15.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group pwm_dev_group = { ++ .attrs = pwm_dev_attrs, ++ .is_visible = pwm_is_visible, ++}; ++ ++static SENSOR_DEVICE_ATTR(fan0_input, 0444, ++ show_rpm, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan1_input, 0444, ++ show_rpm, NULL, 1); ++static SENSOR_DEVICE_ATTR(fan2_input, 0444, ++ show_rpm, NULL, 2); ++static SENSOR_DEVICE_ATTR(fan3_input, 0444, ++ show_rpm, NULL, 3); ++static SENSOR_DEVICE_ATTR(fan4_input, 0444, ++ show_rpm, NULL, 4); ++static SENSOR_DEVICE_ATTR(fan5_input, 0444, ++ show_rpm, NULL, 5); ++static SENSOR_DEVICE_ATTR(fan6_input, 0444, ++ show_rpm, NULL, 6); ++static SENSOR_DEVICE_ATTR(fan7_input, 0444, ++ show_rpm, NULL, 7); ++static SENSOR_DEVICE_ATTR(fan8_input, 0444, ++ show_rpm, NULL, 8); ++static SENSOR_DEVICE_ATTR(fan9_input, 0444, ++ show_rpm, NULL, 9); ++static SENSOR_DEVICE_ATTR(fan10_input, 0444, ++ show_rpm, NULL, 10); ++static SENSOR_DEVICE_ATTR(fan11_input, 0444, ++ show_rpm, NULL, 11); ++static SENSOR_DEVICE_ATTR(fan12_input, 0444, ++ show_rpm, NULL, 12); ++static SENSOR_DEVICE_ATTR(fan13_input, 0444, ++ show_rpm, NULL, 13); ++static SENSOR_DEVICE_ATTR(fan14_input, 0444, ++ show_rpm, NULL, 14); ++static SENSOR_DEVICE_ATTR(fan15_input, 0444, ++ show_rpm, NULL, 15); ++static struct attribute *fan_dev_attrs[] = { ++ &sensor_dev_attr_fan0_input.dev_attr.attr, ++ &sensor_dev_attr_fan1_input.dev_attr.attr, ++ &sensor_dev_attr_fan2_input.dev_attr.attr, ++ &sensor_dev_attr_fan3_input.dev_attr.attr, ++ &sensor_dev_attr_fan4_input.dev_attr.attr, ++ &sensor_dev_attr_fan5_input.dev_attr.attr, ++ &sensor_dev_attr_fan6_input.dev_attr.attr, ++ &sensor_dev_attr_fan7_input.dev_attr.attr, ++ &sensor_dev_attr_fan8_input.dev_attr.attr, ++ &sensor_dev_attr_fan9_input.dev_attr.attr, ++ &sensor_dev_attr_fan10_input.dev_attr.attr, ++ &sensor_dev_attr_fan11_input.dev_attr.attr, ++ &sensor_dev_attr_fan12_input.dev_attr.attr, ++ &sensor_dev_attr_fan13_input.dev_attr.attr, ++ &sensor_dev_attr_fan14_input.dev_attr.attr, ++ &sensor_dev_attr_fan15_input.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group fan_dev_group = { ++ .attrs = fan_dev_attrs, ++ .is_visible = fan_dev_is_visible, ++}; ++ ++static void aspeed_create_pwm_channel(struct aspeed_pwm_tachometer_data *priv, ++ u8 pwm_channel) ++{ ++ priv->pwm_present[pwm_channel] = true; ++ ++ //use default ++ aspeed_set_pwm_channel_fan_ctrl(priv, pwm_channel, priv->pwm_channel[pwm_channel].falling); ++} ++ ++static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tachometer_data *priv, ++ u8 *fan_tach_ch, ++ int count) ++{ ++ u8 val, index; ++ ++ for (val = 0; val < count; val++) { ++ index = fan_tach_ch[val]; ++ priv->fan_tach_present[index] = true; ++ aspeed_set_fan_tach_ch_enable(priv, index, true); ++ } ++} ++ ++static int ++aspeed_pwm_cz_get_max_state(struct thermal_cooling_device *tcdev, ++ unsigned long *state) ++{ ++ struct aspeed_cooling_device *cdev = tcdev->devdata; ++ ++ *state = cdev->max_state; ++ ++ return 0; ++} ++ ++static int ++aspeed_pwm_cz_get_cur_state(struct thermal_cooling_device *tcdev, ++ unsigned long *state) ++{ ++ struct aspeed_cooling_device *cdev = tcdev->devdata; ++ ++ *state = cdev->cur_state; ++ ++ return 0; ++} ++ ++static int ++aspeed_pwm_cz_set_cur_state(struct thermal_cooling_device *tcdev, ++ unsigned long state) ++{ ++ struct aspeed_cooling_device *cdev = tcdev->devdata; ++ ++ if (state > cdev->max_state) ++ return -EINVAL; ++ ++ cdev->cur_state = state; ++ cdev->priv->pwm_channel[cdev->pwm_channel].falling = ++ cdev->cooling_levels[cdev->cur_state]; ++ aspeed_set_pwm_channel_fan_ctrl(cdev->priv, cdev->pwm_channel, ++ cdev->cooling_levels[cdev->cur_state]); ++ ++ return 0; ++} ++ ++static const struct thermal_cooling_device_ops aspeed_pwm_cool_ops = { ++ .get_max_state = aspeed_pwm_cz_get_max_state, ++ .get_cur_state = aspeed_pwm_cz_get_cur_state, ++ .set_cur_state = aspeed_pwm_cz_set_cur_state, ++}; ++ ++static int aspeed_create_pwm_cooling(struct device *dev, ++ struct device_node *child, ++ struct aspeed_pwm_tachometer_data *priv, ++ u32 pwm_channel, u8 num_levels) ++{ ++ int ret; ++ struct aspeed_cooling_device *cdev; ++ ++ cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL); ++ if (!cdev) ++ return -ENOMEM; ++ ++ cdev->cooling_levels = devm_kzalloc(dev, num_levels, GFP_KERNEL); ++ if (!cdev->cooling_levels) ++ return -ENOMEM; ++ ++ cdev->max_state = num_levels - 1; ++ ret = of_property_read_u8_array(child, "cooling-levels", ++ cdev->cooling_levels, ++ num_levels); ++ if (ret) { ++ dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); ++ return ret; ++ } ++ snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%s%d", child->name, pwm_channel); ++ ++ cdev->tcdev = thermal_of_cooling_device_register(child, ++ cdev->name, ++ cdev, ++ &aspeed_pwm_cool_ops); ++ if (IS_ERR(cdev->tcdev)) ++ return PTR_ERR(cdev->tcdev); ++ ++ cdev->priv = priv; ++ cdev->pwm_channel = pwm_channel; ++ ++ priv->cdev[pwm_channel] = cdev; ++ ++ return 0; ++} ++ ++static int aspeed_pwm_create_fan(struct device *dev, ++ struct device_node *child, ++ struct aspeed_pwm_tachometer_data *priv) ++{ ++ u8 *fan_tach_ch; ++ u32 pwm_channel; ++ int ret, count; ++ ++ ret = of_property_read_u32(child, "reg", &pwm_channel); ++ if (ret) ++ return ret; ++ ++ aspeed_create_pwm_channel(priv, (u8)pwm_channel); ++ ++ ret = of_property_count_u8_elems(child, "cooling-levels"); ++ if (ret > 0) { ++ ret = aspeed_create_pwm_cooling(dev, child, priv, pwm_channel, ++ ret); ++ if (ret) ++ return ret; ++ } ++ ++ count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch"); ++ if (count < 1) ++ return -EINVAL; ++ ++ fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count, ++ GFP_KERNEL); ++ if (!fan_tach_ch) ++ return -ENOMEM; ++ ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch", ++ fan_tach_ch, count); ++ if (ret) ++ return ret; ++ ++ aspeed_create_fan_tach_channel(priv, fan_tach_ch, count); ++ ++ return 0; ++} ++ ++static int aspeed_pwm_tachometer_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np, *child; ++ struct aspeed_pwm_tachometer_data *priv; ++ void __iomem *regs; ++ struct resource *res; ++ struct device *hwmon; ++ struct clk *clk; ++ int ret; ++ ++ np = dev->of_node; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->pwm_channel = default_pwm_params; ++ priv->tacho_channel = default_tacho_params; ++ priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs, ++ &aspeed_pwm_tachometer_regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(clk)) ++ return -ENODEV; ++ priv->clk_freq = clk_get_rate(clk); ++ ++ priv->reset = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->reset)) { ++ dev_err(&pdev->dev, "can't get aspeed_pwm_tacho reset\n"); ++ return PTR_ERR(priv->reset); ++ } ++ ++ //scu init ++ reset_control_assert(priv->reset); ++ reset_control_deassert(priv->reset); ++ ++ for_each_child_of_node(np, child) { ++ ret = aspeed_pwm_create_fan(dev, child, priv); ++ if (ret) { ++ of_node_put(child); ++ return ret; ++ } ++ } ++ ++ priv->groups[0] = &pwm_dev_group; ++ priv->groups[1] = &fan_dev_group; ++ priv->groups[2] = NULL; ++ hwmon = devm_hwmon_device_register_with_groups(dev, ++ "aspeed_g6_pwm_tacho", ++ priv, priv->groups); ++ ++ return PTR_ERR_OR_ZERO(hwmon); ++} ++ ++static const struct of_device_id of_pwm_tachometer_match_table[] = { ++ { .compatible = "aspeed,ast2600-pwm-tacho", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, of_pwm_tachometer_match_table); ++ ++static struct platform_driver aspeed_pwm_tachometer_driver = { ++ .probe = aspeed_pwm_tachometer_probe, ++ .driver = { ++ .name = "aspeed_g6_pwm_tacho", ++ .of_match_table = of_pwm_tachometer_match_table, ++ }, ++}; ++ ++module_platform_driver(aspeed_pwm_tachometer_driver); ++ ++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>"); ++MODULE_DESCRIPTION("ASPEED PWM and Fan Tachometer device driver"); ++MODULE_LICENSE("GPL"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch new file mode 100644 index 000000000..7ea00a4a2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch @@ -0,0 +1,47 @@ +From f2d62c90f2ea05b1abf9a1887502122eefb5906d Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Wed, 16 Oct 2019 15:11:06 +0800 +Subject: [PATCH] soc: aspeed: Add read-only property support + +Add a read-only property, to support export register bits as read-only. + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + drivers/soc/aspeed/aspeed-bmc-misc.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/soc/aspeed/aspeed-bmc-misc.c b/drivers/soc/aspeed/aspeed-bmc-misc.c +index 314007b..bf88376 100644 +--- a/drivers/soc/aspeed/aspeed-bmc-misc.c ++++ b/drivers/soc/aspeed/aspeed-bmc-misc.c +@@ -15,6 +15,7 @@ struct aspeed_bmc_ctrl { + u32 offset; + u32 mask; + u32 shift; ++ bool read_only; + struct regmap *map; + struct kobj_attribute attr; + }; +@@ -55,6 +56,8 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child, + if (rc < 0) + return rc; + ++ ctrl->read_only = of_property_read_bool(child, "read-only"); ++ + ctrl->mask <<= ctrl->shift; + + return 0; +@@ -116,6 +119,10 @@ static ssize_t aspeed_bmc_misc_store(struct kobject *kobj, + return rc; + + ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr); ++ ++ if (ctrl->read_only) ++ return -EROFS; ++ + val <<= ctrl->shift; + rc = regmap_update_bits(ctrl->map, ctrl->offset, ctrl->mask, val); + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch new file mode 100644 index 000000000..09a957860 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch @@ -0,0 +1,70 @@ +From 3eaf814c51f85aaad0d181d27ff686ce35b31d6a Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Tue, 29 Oct 2019 11:28:29 +0800 +Subject: [PATCH] Fix NCSI driver issue caused by host shutdown due to + overheated. + +NCSI device cannot be recovered when host shutdown due to overheated. + +Tested: +Heat host till shutdown due to overheated and then +run the ipmi command like power status + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + net/ncsi/ncsi-manage.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c +index 70fe02697544..4e16a0015f26 100644 +--- a/net/ncsi/ncsi-manage.c ++++ b/net/ncsi/ncsi-manage.c +@@ -132,18 +132,15 @@ static void ncsi_channel_monitor(struct timer_list *t) + netdev_err(ndp->ndev.dev, "NCSI Channel %d timed out!\n", + nc->id); + ncsi_report_link(ndp, true); +- ndp->flags |= NCSI_DEV_RESHUFFLE; + + ncsi_stop_channel_monitor(nc); + +- ncm = &nc->modes[NCSI_MODE_LINK]; + spin_lock_irqsave(&nc->lock, flags); +- nc->state = NCSI_CHANNEL_INVISIBLE; +- ncm->data[2] &= ~0x1; ++ nc->state = NCSI_CHANNEL_INACTIVE; + spin_unlock_irqrestore(&nc->lock, flags); + + spin_lock_irqsave(&ndp->lock, flags); +- nc->state = NCSI_CHANNEL_ACTIVE; ++ ndp->flags |= NCSI_DEV_RESHUFFLE | NCSI_DEV_RESET; + list_add_tail_rcu(&nc->link, &ndp->channel_queue); + spin_unlock_irqrestore(&ndp->lock, flags); + ncsi_process_next_channel(ndp); +@@ -424,6 +421,7 @@ static void ncsi_request_timeout(struct timer_list *t) + { + struct ncsi_request *nr = from_timer(nr, t, timer); + struct ncsi_dev_priv *ndp = nr->ndp; ++ struct ncsi_dev *nd = &ndp->ndev; + struct ncsi_cmd_pkt *cmd; + struct ncsi_package *np; + struct ncsi_channel *nc; +@@ -438,6 +436,16 @@ static void ncsi_request_timeout(struct timer_list *t) + spin_unlock_irqrestore(&ndp->lock, flags); + return; + } ++ if (nd->state == ncsi_dev_state_suspend || ++ nd->state == ncsi_dev_state_suspend_select || ++ nd->state == ncsi_dev_state_suspend_gls || ++ nd->state == ncsi_dev_state_suspend_dcnt || ++ nd->state == ncsi_dev_state_suspend_dc || ++ nd->state == ncsi_dev_state_suspend_deselect || ++ nd->state == ncsi_dev_state_suspend_done) { ++ ndp->flags |= NCSI_DEV_RESET; ++ nd->state = ncsi_dev_state_suspend_done; ++ } + spin_unlock_irqrestore(&ndp->lock, flags); + + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch new file mode 100644 index 000000000..89e7b894f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch @@ -0,0 +1,56 @@ +From a90b8f7dfcfcab2d40d1a575e3948ef3a34f643f Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 8 Nov 2019 15:57:27 -0800 +Subject: [PATCH] i2c: aspeed: filter garbage interrupts out + +AST2600 makes a garbage interrupt which is decribed as 'reserved' +in datasheet so filter them out. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/i2c/busses/i2c-aspeed.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 62b803e15ce2..c24cecdcfe89 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -87,7 +87,11 @@ + * These share bit definitions, so use the same values for the enable & + * status bits. + */ ++#if defined(CONFIG_MACH_ASPEED_G6) ++#define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(29) ++#else + #define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(30) ++#endif + #define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15) + #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) + #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) +@@ -118,6 +122,11 @@ + ASPEED_I2CD_INTR_RX_DONE | \ + ASPEED_I2CD_INTR_TX_NAK | \ + ASPEED_I2CD_INTR_TX_ACK) ++#define ASPEED_I2CD_INTR_STATUS_MASK \ ++ (ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING | \ ++ ASPEED_I2CD_INTR_GCALL_ADDR | \ ++ ASPEED_I2CD_INTR_SLAVE_MATCH | \ ++ ASPEED_I2CD_INTR_ALL) + + /* 0x14 : I2CD Command/Status Register */ + #define ASPEED_I2CD_SCL_LINE_STS BIT(18) +@@ -1021,6 +1030,11 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) + /* Ack all interrupts except for Rx done */ + writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE, + bus->base + ASPEED_I2C_INTR_STS_REG); ++ /* ++ * AST2600 makes a garbage interrupt which is decribed as 'reserved' ++ * in datasheet so filter them out. ++ */ ++ irq_received &= ASPEED_I2CD_INTR_STATUS_MASK; + irq_remaining = irq_received; + + #if IS_ENABLED(CONFIG_I2C_SLAVE) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch new file mode 100644 index 000000000..f578d0f04 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch @@ -0,0 +1,35 @@ +From 523bbaaf9f9d064c9cf1f627d64dd7ba169d175d Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 20 Nov 2019 15:01:06 -0800 +Subject: [PATCH] ARM: dts: aspeed-g6: add GFX node + +This commit adds GFX node for AST2600 SoC. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/boot/dts/aspeed-g6.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index b880e8e8f999..3e2153416e11 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -330,6 +330,15 @@ + quality = <100>; + }; + ++ gfx: display@1e6e6000 { ++ compatible = "aspeed,ast2600-gfx", "syscon"; ++ reg = <0x1e6e6000 0x1000>; ++ reg-io-width = <4>; ++ clocks = <&syscon ASPEED_CLK_GATE_D1CLK>; ++ status = "disabled"; ++ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ + adc: adc@1e6e9000 { + compatible = "aspeed,ast2500-adc"; + reg = <0x1e6e9000 0x100>; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch new file mode 100644 index 000000000..259720e87 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch @@ -0,0 +1,105 @@ +From 195cd60ff2fe38b18ebdea90245b908548f4e985 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Wed, 20 Nov 2019 14:58:24 -0800 +Subject: [PATCH] drm: add AST2600 GFX support + +This commit adds support for AST2600 GFX. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/gpu/drm/aspeed/aspeed_gfx.h | 4 ++++ + drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 6 +++--- + drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 18 +++++++++++------- + 3 files changed, 18 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h +index a10358bb61ec..eebd72eb1220 100644 +--- a/drivers/gpu/drm/aspeed/aspeed_gfx.h ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h +@@ -13,11 +13,15 @@ struct aspeed_gfx { + struct drm_simple_display_pipe pipe; + struct drm_connector connector; + struct drm_fbdev_cma *fbdev; ++ u32 scu_misc_offset; + }; + + int aspeed_gfx_create_pipe(struct drm_device *drm); + int aspeed_gfx_create_output(struct drm_device *drm); + ++#define SCU_MISC_AST2500 0x2c /* SCU Misc of AST2500 */ ++#define SCU_MISC_AST2600 0xc0 /* SCU Misc1 of AST2600 */ ++ + #define CRT_CTRL1 0x60 /* CRT Control I */ + #define CRT_CTRL2 0x64 /* CRT Control II */ + #define CRT_STATUS 0x68 /* CRT Status */ +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +index 2184b8be6fd4..86359a0fe05f 100644 +--- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +@@ -59,8 +59,8 @@ static void aspeed_gfx_enable_controller(struct aspeed_gfx *priv) + u32 ctrl1 = readl(priv->base + CRT_CTRL1); + u32 ctrl2 = readl(priv->base + CRT_CTRL2); + +- /* SCU2C: set DAC source for display output to Graphics CRT (GFX) */ +- regmap_update_bits(priv->scu, 0x2c, BIT(16), BIT(16)); ++ /* Set DAC source for display output to Graphics CRT (GFX) */ ++ regmap_update_bits(priv->scu, priv->scu_misc_offset, BIT(16), BIT(16)); + + writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1); + writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); +@@ -74,7 +74,7 @@ static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv) + writel(ctrl1 & ~CRT_CTRL_EN, priv->base + CRT_CTRL1); + writel(ctrl2 & ~CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); + +- regmap_update_bits(priv->scu, 0x2c, BIT(16), 0); ++ regmap_update_bits(priv->scu, priv->scu_misc_offset, BIT(16), 0); + } + + static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) +diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +index ada2f6aca906..92bc9b475e0f 100644 +--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c ++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +@@ -112,8 +112,14 @@ static int aspeed_gfx_load(struct drm_device *drm) + + priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu"); + if (IS_ERR(priv->scu)) { +- dev_err(&pdev->dev, "failed to find SCU regmap\n"); +- return PTR_ERR(priv->scu); ++ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2600-scu"); ++ if (IS_ERR(priv->scu)) { ++ dev_err(&pdev->dev, "failed to find SCU regmap\n"); ++ return PTR_ERR(priv->scu); ++ } ++ priv->scu_misc_offset = SCU_MISC_AST2600; ++ } else { ++ priv->scu_misc_offset = SCU_MISC_AST2500; + } + + ret = of_reserved_mem_device_init(drm->dev); +@@ -130,12 +136,9 @@ static int aspeed_gfx_load(struct drm_device *drm) + } + + priv->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (IS_ERR(priv->rst)) { +- dev_err(&pdev->dev, +- "missing or invalid reset controller device tree entry"); +- return PTR_ERR(priv->rst); ++ if (!IS_ERR_OR_NULL(priv->rst)) { ++ reset_control_deassert(priv->rst); + } +- reset_control_deassert(priv->rst); + + priv->clk = devm_clk_get(drm->dev, NULL); + if (IS_ERR(priv->clk)) { +@@ -211,6 +214,7 @@ static struct drm_driver aspeed_gfx_driver = { + + static const struct of_device_id aspeed_gfx_match[] = { + { .compatible = "aspeed,ast2500-gfx" }, ++ { .compatible = "aspeed,ast2600-gfx" }, + { } + }; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch new file mode 100644 index 000000000..4dde9fb06 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch @@ -0,0 +1,271 @@ +From 278db13a36f128b84f76fc0f0f13860b5bf62588 Mon Sep 17 00:00:00 2001 +From: Chen Yugang <yugang.chen@linux.intel.com> +Date: Tue, 3 Dec 2019 13:41:37 +0800 +Subject: [PATCH] ADC linux driver for AST2600 + +Tested: +it's tested with DC input. + +Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com> +--- + arch/arm/boot/dts/aspeed-g6.dtsi | 14 +++++- + drivers/iio/adc/aspeed_adc.c | 99 +++++++++++++++++++++++++++++++++++----- + 2 files changed, 99 insertions(+), 14 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 3e2153416e11..5acc1085526d 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -339,12 +339,22 @@ + interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; + }; + +- adc: adc@1e6e9000 { +- compatible = "aspeed,ast2500-adc"; ++ adc0: adc@1e6e9000 { ++ compatible = "aspeed,ast2600-adc"; + reg = <0x1e6e9000 0x100>; + clocks = <&syscon ASPEED_CLK_APB2>; ++ resets = <&syscon ASPEED_RESET_ADC>; + interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; ++ #io-channel-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ adc1: adc@1e6e9100 { ++ compatible = "aspeed,ast2600-adc"; ++ reg = <0x1e6e9100 0x100>; ++ clocks = <&syscon ASPEED_CLK_APB2>; + resets = <&syscon ASPEED_RESET_ADC>; ++ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; + #io-channel-cells = <1>; + status = "disabled"; + }; +diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c +index d3fc39df535d..1dd5a97a16bc 100644 +--- a/drivers/iio/adc/aspeed_adc.c ++++ b/drivers/iio/adc/aspeed_adc.c +@@ -1,8 +1,12 @@ +-// SPDX-License-Identifier: GPL-2.0-only + /* +- * Aspeed AST2400/2500 ADC ++ * Aspeed AST2400/2500/2600 ADC + * + * Copyright (C) 2017 Google, Inc. ++ * Copyright (C) ASPEED Technology Inc. ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * + */ + + #include <linux/clk.h> +@@ -30,6 +34,14 @@ + #define ASPEED_REG_CLOCK_CONTROL 0x0C + #define ASPEED_REG_MAX 0xC0 + ++/* ast2600 */ ++#define REF_VLOTAGE_2500mV 0 ++#define REF_VLOTAGE_1200mV GENMASK(6, 6) ++#define REF_VLOTAGE_1550mV GENMASK(7, 7) ++#define REF_VLOTAGE_900mV GENMASK(7, 6) ++ ++#define ASPEED_AUTOPENSATING BIT(5) ++ + #define ASPEED_OPERATION_MODE_POWER_DOWN (0x0 << 1) + #define ASPEED_OPERATION_MODE_STANDBY (0x1 << 1) + #define ASPEED_OPERATION_MODE_NORMAL (0x7 << 1) +@@ -45,8 +57,10 @@ struct aspeed_adc_model_data { + const char *model_name; + unsigned int min_sampling_rate; // Hz + unsigned int max_sampling_rate; // Hz +- unsigned int vref_voltage; // mV ++ u32 vref_voltage; // mV + bool wait_init_sequence; ++ struct iio_chan_spec const *channels; ++ int num_channels; + }; + + struct aspeed_adc_data { +@@ -56,6 +70,7 @@ struct aspeed_adc_data { + struct clk_hw *clk_prescaler; + struct clk_hw *clk_scaler; + struct reset_control *rst; ++ int cv; + }; + + #define ASPEED_CHAN(_idx, _data_reg_addr) { \ +@@ -87,6 +102,17 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = { + ASPEED_CHAN(15, 0x2E), + }; + ++static const struct iio_chan_spec ast2600_adc_iio_channels[] = { ++ ASPEED_CHAN(0, 0x10), ++ ASPEED_CHAN(1, 0x12), ++ ASPEED_CHAN(2, 0x14), ++ ASPEED_CHAN(3, 0x16), ++ ASPEED_CHAN(4, 0x18), ++ ASPEED_CHAN(5, 0x1A), ++ ASPEED_CHAN(6, 0x1C), ++ ASPEED_CHAN(7, 0x1E), ++}; ++ + static int aspeed_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +@@ -175,7 +201,10 @@ static int aspeed_adc_probe(struct platform_device *pdev) + const struct aspeed_adc_model_data *model_data; + struct resource *res; + const char *clk_parent_name; ++ char prescaler_clk_name[32]; ++ char scaler_clk_name[32]; + int ret; ++ u32 eng_ctrl = 0; + u32 adc_engine_control_reg_val; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); +@@ -194,19 +223,21 @@ static int aspeed_adc_probe(struct platform_device *pdev) + spin_lock_init(&data->clk_lock); + clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0); + ++ snprintf(prescaler_clk_name, sizeof(prescaler_clk_name), "prescaler-%s", pdev->name); + data->clk_prescaler = clk_hw_register_divider( +- &pdev->dev, "prescaler", clk_parent_name, 0, ++ &pdev->dev, prescaler_clk_name, clk_parent_name, 0, + data->base + ASPEED_REG_CLOCK_CONTROL, + 17, 15, 0, &data->clk_lock); + if (IS_ERR(data->clk_prescaler)) + return PTR_ERR(data->clk_prescaler); + ++ snprintf(scaler_clk_name, sizeof(scaler_clk_name), "scaler-%s", pdev->name); + /* + * Register ADC clock scaler downstream from the prescaler. Allow rate + * setting to adjust the prescaler as well. + */ + data->clk_scaler = clk_hw_register_divider( +- &pdev->dev, "scaler", "prescaler", ++ &pdev->dev, scaler_clk_name, prescaler_clk_name, + CLK_SET_RATE_PARENT, + data->base + ASPEED_REG_CLOCK_CONTROL, + 0, 10, 0, &data->clk_lock); +@@ -215,7 +246,7 @@ static int aspeed_adc_probe(struct platform_device *pdev) + goto scaler_error; + } + +- data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); ++ data->rst = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(data->rst)) { + dev_err(&pdev->dev, + "invalid or missing reset controller device tree entry"); +@@ -225,11 +256,26 @@ static int aspeed_adc_probe(struct platform_device *pdev) + reset_control_deassert(data->rst); + + model_data = of_device_get_match_data(&pdev->dev); ++ if (!of_property_read_u32(pdev->dev.of_node, "ref_voltage", (u32 *)&model_data->vref_voltage)) { ++ if (model_data->vref_voltage == 2500) ++ eng_ctrl = REF_VLOTAGE_2500mV; ++ else if (model_data->vref_voltage == 1200) ++ eng_ctrl = REF_VLOTAGE_1200mV; ++ else if ((model_data->vref_voltage >= 1550) && (model_data->vref_voltage <= 2700)) ++ eng_ctrl = REF_VLOTAGE_1550mV; ++ else if ((model_data->vref_voltage >= 900) && (model_data->vref_voltage <= 1650)) ++ eng_ctrl = REF_VLOTAGE_900mV; ++ else { ++ printk("error ref voltage %d \n", model_data->vref_voltage); ++ eng_ctrl = 0; ++ } ++ } else ++ eng_ctrl = 0; + + if (model_data->wait_init_sequence) { + /* Enable engine in normal mode. */ +- writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE, +- data->base + ASPEED_REG_ENGINE_CONTROL); ++ eng_ctrl |= ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE; ++ writel(eng_ctrl, data->base + ASPEED_REG_ENGINE_CONTROL); + + /* Wait for initial sequence complete. */ + ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL, +@@ -242,12 +288,26 @@ static int aspeed_adc_probe(struct platform_device *pdev) + goto poll_timeout_error; + } + ++ /* do compensating calculation use ch 0 */ ++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | ++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL); ++ ++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | BIT(16) | ++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL); ++ mdelay(1); ++ ++ data->cv = 0x200 - (readl(data->base + 0x10) & GENMASK(9, 0)); ++ ++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | ++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL); ++ printk(KERN_INFO "aspeed_adc: cv %d \n", data->cv); ++ + /* Start all channels in normal mode. */ + ret = clk_prepare_enable(data->clk_scaler->clk); + if (ret) + goto clk_enable_error; + +- adc_engine_control_reg_val = GENMASK(31, 16) | ++ adc_engine_control_reg_val = eng_ctrl | GENMASK(31, 16) | + ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE; + writel(adc_engine_control_reg_val, + data->base + ASPEED_REG_ENGINE_CONTROL); +@@ -257,8 +317,8 @@ static int aspeed_adc_probe(struct platform_device *pdev) + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &aspeed_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; +- indio_dev->channels = aspeed_adc_iio_channels; +- indio_dev->num_channels = ARRAY_SIZE(aspeed_adc_iio_channels); ++ indio_dev->channels = model_data->channels; ++ indio_dev->num_channels = model_data->num_channels; + + ret = iio_device_register(indio_dev); + if (ret) +@@ -301,6 +361,8 @@ static const struct aspeed_adc_model_data ast2400_model_data = { + .vref_voltage = 2500, // mV + .min_sampling_rate = 10000, + .max_sampling_rate = 500000, ++ .channels = aspeed_adc_iio_channels, ++ .num_channels = 16, + }; + + static const struct aspeed_adc_model_data ast2500_model_data = { +@@ -309,11 +371,24 @@ static const struct aspeed_adc_model_data ast2500_model_data = { + .min_sampling_rate = 1, + .max_sampling_rate = 1000000, + .wait_init_sequence = true, ++ .channels = aspeed_adc_iio_channels, ++ .num_channels = 16, ++}; ++ ++static const struct aspeed_adc_model_data ast2600_model_data = { ++ .model_name = "ast2500-adc", ++ .vref_voltage = 1800, /* mV --> can be 1.2v or 2.5 or ext 1.55~2.7v, 0.9v ~1.65v */ ++ .min_sampling_rate = 1, ++ .max_sampling_rate = 1000000, ++ .wait_init_sequence = true, ++ .channels = ast2600_adc_iio_channels, ++ .num_channels = 8, + }; + + static const struct of_device_id aspeed_adc_matches[] = { + { .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data }, + { .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data }, ++ { .compatible = "aspeed,ast2600-adc", .data = &ast2600_model_data }, + {}, + }; + MODULE_DEVICE_TABLE(of, aspeed_adc_matches); +@@ -330,5 +405,5 @@ static struct platform_driver aspeed_adc_driver = { + module_platform_driver(aspeed_adc_driver); + + MODULE_AUTHOR("Rick Altherr <raltherr@google.com>"); +-MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver"); ++MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver"); + MODULE_LICENSE("GPL"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch new file mode 100644 index 000000000..221800720 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch @@ -0,0 +1,36 @@ +From 90c72bbe5f1ac2c8d62736c44492bd8bbc4fcab0 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 26 Nov 2019 16:37:36 -0800 +Subject: [PATCH] ARM: dts: aspeed-g6: add video node + +This commit adds video node. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + arch/arm/boot/dts/aspeed-g6.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 5acc1085526d..b0283e03e9ff 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -359,6 +359,16 @@ + status = "disabled"; + }; + ++ video: video@1e700000 { ++ compatible = "aspeed,ast2600-video-engine"; ++ reg = <0x1e700000 0x1000>; ++ clocks = <&syscon ASPEED_CLK_GATE_VCLK>, ++ <&syscon ASPEED_CLK_GATE_ECLK>; ++ clock-names = "vclk", "eclk"; ++ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ + gpio0: gpio@1e780000 { + #gpio-cells = <2>; + gpio-controller; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch new file mode 100644 index 000000000..1d8b722de --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch @@ -0,0 +1,63 @@ +From 1765cb18bacff9d1f48b833f44da198a09f7d5cb Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 26 Nov 2019 16:39:16 -0800 +Subject: [PATCH] media: aspeed: add aspeed,ast2600-video-engine compatible + string + +This commit adds "aspeed,ast2600-video-engine" compatible string +to support AST2600 video engine H/W. Also. it adds G6 specific +register handling flow. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/media/platform/aspeed-video.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c +index db45502774b1..fe70ad408375 100644 +--- a/drivers/media/platform/aspeed-video.c ++++ b/drivers/media/platform/aspeed-video.c +@@ -72,8 +72,8 @@ + #define VE_SEQ_CTRL_CAP_BUSY BIT(16) + #define VE_SEQ_CTRL_COMP_BUSY BIT(18) + +-#ifdef CONFIG_MACH_ASPEED_G5 +-#define VE_SEQ_CTRL_JPEG_MODE BIT(13) /* AST2500 */ ++#if defined(CONFIG_MACH_ASPEED_G5) || defined(CONFIG_MACH_ASPEED_G6) ++#define VE_SEQ_CTRL_JPEG_MODE BIT(13) /* AST2500/2600 */ + #else + #define VE_SEQ_CTRL_JPEG_MODE BIT(8) /* AST2400 */ + #endif /* CONFIG_MACH_ASPEED_G5 */ +@@ -135,6 +135,12 @@ + + #define VE_OFFSET_COMP_STREAM 0x078 + ++#ifdef CONFIG_MACH_ASPEED_G6 ++#define VE_JPEG_COMP_SIZE_READ_BACK 0x084 /* AST2600 */ ++#else ++#define VE_JPEG_COMP_SIZE_READ_BACK VE_OFFSET_COMP_STREAM ++#endif ++ + #define VE_SRC_LR_EDGE_DET 0x090 + #define VE_SRC_LR_EDGE_DET_LEFT GENMASK(11, 0) + #define VE_SRC_LR_EDGE_DET_NO_V BIT(12) +@@ -572,7 +578,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) + if (sts & VE_INTERRUPT_COMP_COMPLETE) { + struct aspeed_video_buffer *buf; + u32 frame_size = aspeed_video_read(video, +- VE_OFFSET_COMP_STREAM); ++ VE_JPEG_COMP_SIZE_READ_BACK); + + spin_lock(&video->lock); + clear_bit(VIDEO_FRAME_INPRG, &video->flags); +@@ -1718,6 +1724,7 @@ static int aspeed_video_remove(struct platform_device *pdev) + static const struct of_device_id aspeed_video_of_match[] = { + { .compatible = "aspeed,ast2400-video-engine" }, + { .compatible = "aspeed,ast2500-video-engine" }, ++ { .compatible = "aspeed,ast2600-video-engine" }, + {} + }; + MODULE_DEVICE_TABLE(of, aspeed_video_of_match); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch new file mode 100644 index 000000000..34df0882b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch @@ -0,0 +1,30 @@ +From 37efef00064a228c3e723b0eece22d72f2632705 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Fri, 6 Dec 2019 13:51:37 -0800 +Subject: [PATCH] clk: ast2600: enable ESPICLK always + +To support continous eSPI H/W handshaking, this patch enables +ESPICLK always so that there discontinuity of eSPI handshaking while +boot BMC. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/clk/clk-ast2600.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c +index 8201d65..21967bc 100644 +--- a/drivers/clk/clk-ast2600.c ++++ b/drivers/clk/clk-ast2600.c +@@ -87,7 +87,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { + [ASPEED_CLK_GATE_EMMCCLK] = { 27, 16, "emmcclk-gate", NULL, 0 }, /* For card clk */ + /* Reserved 28/29/30 */ + [ASPEED_CLK_GATE_LCLK] = { 32, 32, "lclk-gate", NULL, 0 }, /* LPC */ +- [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ ++ [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, CLK_IS_CRITICAL }, /* eSPI */ + [ASPEED_CLK_GATE_REF1CLK] = { 34, -1, "ref1clk-gate", "clkin", CLK_IS_CRITICAL }, + /* Reserved 35 */ + [ASPEED_CLK_GATE_SDCLK] = { 36, 56, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch new file mode 100644 index 000000000..962d42e6f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch @@ -0,0 +1,97 @@ +From 054391014d04e5b97ae62e1bf5e6aed005f3c67a Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 13 Dec 2019 16:15:16 +0800 +Subject: [PATCH] ast2600: enable high speed uart in kernel. + +Tested: +1. Config baud rate to 921600 in BIOS setup page +2. BMC could change env variable "hostserialcfg" to 1. +3. BMC is force to reboot and SPA baud rate is changed to 921600 successfully. +4. It is same for back to 115200. + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + drivers/clk/clk-ast2600.c | 26 +++++++++++++++++++------- + include/dt-bindings/clock/ast2600-clock.h | 2 ++ + 2 files changed, 21 insertions(+), 7 deletions(-) + +diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c +index c7236e39ef85..af908b2dbeb6 100644 +--- a/drivers/clk/clk-ast2600.c ++++ b/drivers/clk/clk-ast2600.c +@@ -15,7 +15,7 @@ + + #include "clk-aspeed.h" + +-#define ASPEED_G6_NUM_CLKS 71 ++#define ASPEED_G6_NUM_CLKS ASPEED_CLK_MAX + + #define ASPEED_G6_SILICON_REV 0x004 + +@@ -43,6 +43,9 @@ + #define ASPEED_MAC12_CLK_DLY 0x340 + #define ASPEED_MAC34_CLK_DLY 0x350 + ++#define ASPEED_G6_GEN_UART_REF 0x338 ++#define UART_192MHZ_R_N_VALUE 0x3c38e ++ + /* Globally visible clocks */ + static DEFINE_SPINLOCK(aspeed_g6_clk_lock); + +@@ -76,7 +79,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { + /* Reserved 11/12 */ + [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */ + [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */ +- [ASPEED_CLK_GATE_UART5CLK] = { 15, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */ ++ [ASPEED_CLK_GATE_UART5CLK] = { 15, -1, "uart5clk-gate", "uart5", 0 }, /* UART5 */ + /* Reserved 16/19 */ + [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac12", 0 }, /* MAC1 */ + [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac12", 0 }, /* MAC2 */ +@@ -437,17 +440,26 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev) + return ret; + } + +- /* UART clock div13 setting */ +- regmap_read(map, ASPEED_G6_MISC_CTRL, &val); +- if (val & UART_DIV13_EN) +- rate = 24000000 / 13; ++ /* UART clock setting */ ++ regmap_read(map, ASPEED_G6_GEN_UART_REF, &val); ++ if (val == UART_192MHZ_R_N_VALUE){ ++ rate = 192000000 / 13; ++ dev_err(dev, "192Mhz baud rate 921600\n"); ++ } + else +- rate = 24000000; ++ rate = 24000000 / 13; + hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_g6_clk_data->hws[ASPEED_CLK_UART] = hw; + ++ /* UART5 clock setting */ ++ rate = 24000000 / 13; ++ hw = clk_hw_register_fixed_rate(dev, "uart5", NULL, 0, rate); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ aspeed_g6_clk_data->hws[ASPEED_CLK_UART5] = hw; ++ + /* UART6~13 clock div13 setting */ + regmap_read(map, 0x80, &val); + if (val & BIT(31)) +diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h +index 3d90582a813f..4952f7683be7 100644 +--- a/include/dt-bindings/clock/ast2600-clock.h ++++ b/include/dt-bindings/clock/ast2600-clock.h +@@ -87,6 +87,8 @@ + #define ASPEED_CLK_MAC2RCLK 68 + #define ASPEED_CLK_MAC3RCLK 69 + #define ASPEED_CLK_MAC4RCLK 70 ++#define ASPEED_CLK_UART5 71 ++#define ASPEED_CLK_MAX 72 + + /* Only list resets here that are not part of a gate */ + #define ASPEED_RESET_ADC 55 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch new file mode 100644 index 000000000..475e9611f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch @@ -0,0 +1,405 @@ +From e40f7d10d5306c075e2fc7e538ce1efc70eeb448 Mon Sep 17 00:00:00 2001 +From: ZhikuiRen <zhikui.ren@intel.com> +Date: Thu, 9 Jan 2020 10:48:00 -0800 +Subject: [PATCH] Add peci-cpupower driver + +peci-cpupower reads CPU energy counter through peci +and computes average power in mW since last read. + +Signed-off-by: ZhikuiRen <zhikui.ren@intel.com> +--- + Documentation/hwmon/index.rst | 1 + + Documentation/hwmon/peci-cpupower.rst | 52 ++++++++ + arch/arm/configs/aspeed_g5_defconfig | 1 + + drivers/hwmon/Kconfig | 14 +++ + drivers/hwmon/Makefile | 1 + + drivers/hwmon/peci-cpupower.c | 231 ++++++++++++++++++++++++++++++++++ + drivers/mfd/intel-peci-client.c | 1 + + include/uapi/linux/peci-ioctl.h | 1 + + 8 files changed, 302 insertions(+) + create mode 100644 Documentation/hwmon/peci-cpupower.rst + create mode 100644 drivers/hwmon/peci-cpupower.c + +diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst +index 7d894c9..0bde0ef 100644 +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -130,6 +130,7 @@ Hardware Monitoring Kernel Drivers + pcf8591 + peci-cputemp + peci-dimmtemp ++ peci-cpupower + pmbus + powr1220 + pxe1610 +diff --git a/Documentation/hwmon/peci-cpupower.rst b/Documentation/hwmon/peci-cpupower.rst +new file mode 100644 +index 0000000..4d7bd61 +--- /dev/null ++++ b/Documentation/hwmon/peci-cpupower.rst +@@ -0,0 +1,52 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Kernel driver peci-cpupower ++========================== ++ ++:Copyright: |copy| 2018-2020 Intel Corporation ++ ++Supported chips: ++ One of Intel server CPUs listed below which is connected to a PECI bus. ++ * Intel Xeon E5/E7 v3 server processors ++ Intel Xeon E5-14xx v3 family ++ Intel Xeon E5-24xx v3 family ++ Intel Xeon E5-16xx v3 family ++ Intel Xeon E5-26xx v3 family ++ Intel Xeon E5-46xx v3 family ++ Intel Xeon E7-48xx v3 family ++ Intel Xeon E7-88xx v3 family ++ * Intel Xeon E5/E7 v4 server processors ++ Intel Xeon E5-16xx v4 family ++ Intel Xeon E5-26xx v4 family ++ Intel Xeon E5-46xx v4 family ++ Intel Xeon E7-48xx v4 family ++ Intel Xeon E7-88xx v4 family ++ * Intel Xeon Scalable server processors ++ Intel Xeon D family ++ Intel Xeon Bronze family ++ Intel Xeon Silver family ++ Intel Xeon Gold family ++ Intel Xeon Platinum family ++ ++ Addresses scanned: PECI client address 0x30 - 0x37 ++ Datasheet: Available from http://www.intel.com/design/literature.htm ++ ++Author: ++ Zhikui Ren <zhikui.ren@.intel.com> ++ ++Description ++----------- ++ ++This driver implements a generic PECI hwmon feature which provides ++average power consumption readings of the CPU package based on energy counter ++accessible using the PECI Client Command Suite via the processor PECI client. ++ ++Power values are average power since last measure given in milli Watt and ++will be measurable only when the target CPU is powered on. ++ ++``sysfs`` interface ++------------------- ++======================= ======================================================= ++power1_average Provides average power since last read in milli Watt. ++power1_label Provides string "Average Power". ++======================= ======================================================= +diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig +index 1e589a0..0e50040 100644 +--- a/arch/arm/configs/aspeed_g5_defconfig ++++ b/arch/arm/configs/aspeed_g5_defconfig +@@ -177,6 +177,7 @@ CONFIG_SENSORS_OCC_P8_I2C=y + CONFIG_SENSORS_OCC_P9_SBE=y + CONFIG_SENSORS_PECI_CPUTEMP=y + CONFIG_SENSORS_PECI_DIMMTEMP=y ++CONFIG_SENSORS_PECI_CPUPOWER=y + CONFIG_PMBUS=y + CONFIG_SENSORS_ADM1275=y + CONFIG_SENSORS_IBM_CFFPS=y +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 8312b37..07d8826 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1361,6 +1361,20 @@ config SENSORS_PECI_DIMMTEMP + This driver can also be built as a module. If so, the module + will be called peci-dimmtemp. + ++config SENSORS_PECI_CPUPOWER ++ tristate "PECI CPU power monitoring support" ++ depends on PECI ++ select MFD_INTEL_PECI_CLIENT ++ help ++ If you say yes here you get support for the generic Intel PECI ++ cputemp driver which provides average engergy ++ readings of the CPU package using ++ the PECI Client Command Suite via the processor PECI client. ++ Check Documentation/hwmon/peci-cpupower for details. ++ ++ This driver can also be built as a module. If so, the module ++ will be called peci-cpupower. ++ + source "drivers/hwmon/pmbus/Kconfig" + + config SENSORS_PWM_FAN +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index e74ea92..fab43fd 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -144,6 +144,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o + obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o + obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o + obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o ++obj-$(CONFIG_SENSORS_PECI_CPUPOWER) += peci-cpupower.o + obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o + obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o + obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o +diff --git a/drivers/hwmon/peci-cpupower.c b/drivers/hwmon/peci-cpupower.c +new file mode 100644 +index 0000000..6907696 +--- /dev/null ++++ b/drivers/hwmon/peci-cpupower.c +@@ -0,0 +1,231 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2020 Intel Corporation ++ ++#include <linux/hwmon.h> ++#include <linux/jiffies.h> ++#include <linux/mfd/intel-peci-client.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include "peci-hwmon.h" ++ ++#define POWER_DEFAULT_CHANNEL_NUMS 1 ++ ++struct peci_cpupower { ++ struct peci_client_manager *mgr; ++ struct device *dev; ++ char name[PECI_NAME_SIZE]; ++ const struct cpu_gen_info *gen_info; ++ struct peci_sensor_data energy; ++ long avg_power_val; ++ u64 core_mask; ++ u32 power_config[POWER_DEFAULT_CHANNEL_NUMS + 1]; ++ uint config_idx; ++ struct hwmon_channel_info power_info; ++ const struct hwmon_channel_info *info[2]; ++ struct hwmon_chip_info chip; ++}; ++ ++enum cpupower_channels { ++ average_power, ++}; ++ ++static const u32 config_table[POWER_DEFAULT_CHANNEL_NUMS] = { ++ /* average power */ ++ HWMON_P_LABEL | HWMON_P_AVERAGE, ++}; ++ ++static const char *cpupower_label[POWER_DEFAULT_CHANNEL_NUMS] = { ++ "Average Power", ++}; ++ ++static int get_average_power(struct peci_cpupower *priv) ++{ ++ u8 pkg_cfg[4]; ++ int ret; ++ ++ if (!peci_sensor_need_update(&priv->energy)) ++ return 0; ++ ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_TDP_UNITS, ++ PECI_PKG_ID_PKG_ENERGY_STATUS, ++ pkg_cfg); ++ ++ u32 power_unit = ((le32_to_cpup((__le32 *)pkg_cfg)) & 0x1f00) >> 8; ++ ++ dev_dbg(priv->dev, "cpupower units %d (1J/pow(2, unit))\n", ++ power_unit); ++ ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_ENERGY_COUNTER, ++ PECI_PKG_ID_PKG_ENERGY_STATUS, ++ pkg_cfg); ++ if (!ret) { ++ u32 energy_cnt = le32_to_cpup((__le32 *)pkg_cfg); ++ ulong jif = jiffies; ++ ulong elapsed = (jif - priv->energy.last_updated); ++ long power_val = 0; ++ /* ++ * Don't calculate average power for first counter read or ++ * counter wrapped around or last counter read was more than ++ * 60 minutes ago (jiffies did not wrap and power calculation ++ * does not overflow or underflow ++ */ ++ if (priv->energy.last_updated > 0 && ++ energy_cnt > priv->energy.value && ++ (elapsed < (HZ * 3600))) { ++ power_val = (long)(energy_cnt - priv->energy.value) ++ / elapsed * HZ; ++ dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, raw powerValue %d scale to %d mW\n", ++ (long)(energy_cnt - priv->energy.value), ++ elapsed, power_val, ++ power_val >> (power_unit - 10)); ++ } else { ++ dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, skipping calculate power, try agin\n", ++ (long)(energy_cnt - priv->energy.value), ++ elapsed); ++ ret = -EAGAIN; ++ } ++ ++ priv->energy.value = energy_cnt; ++ priv->avg_power_val = power_val >> ((power_unit - 10)); ++ peci_sensor_mark_updated(&priv->energy); ++ ++ dev_dbg(priv->dev, "energy counter 0x%8x, average power %dmW, jif %u, HZ is %d jiffies\n", ++ priv->energy.value, priv->avg_power_val, ++ jif, HZ); ++ } ++ return ret; ++} ++ ++static int cpupower_read_string(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, const char **str) ++{ ++ if (attr != hwmon_power_label) ++ return -EOPNOTSUPP; ++ if (channel >= POWER_DEFAULT_CHANNEL_NUMS) ++ return -EOPNOTSUPP; ++ *str = cpupower_label[channel]; ++ ++ return 0; ++} ++ ++static int cpupower_read(struct device *dev, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct peci_cpupower *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ if (channel >= POWER_DEFAULT_CHANNEL_NUMS || ++ !(priv->power_config[channel] & BIT(attr))) ++ return -EOPNOTSUPP; ++ ++ switch (attr) { ++ case hwmon_power_average: ++ switch (channel) { ++ case average_power: ++ ret = get_average_power(priv); ++ if (ret) ++ break; ++ ++ *val = priv->avg_power_val; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ return ret; ++} ++ ++static umode_t cpupower_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct peci_cpupower *priv = data; ++ ++ if (channel < POWER_DEFAULT_CHANNEL_NUMS || ++ (priv->power_config[channel] & BIT(attr))) ++ return 0444; ++ ++ return 0; ++} ++ ++static const struct hwmon_ops cpupower_ops = { ++ .is_visible = cpupower_is_visible, ++ .read_string = cpupower_read_string, ++ .read = cpupower_read, ++}; ++ ++static int peci_cpupower_probe(struct platform_device *pdev) ++{ ++ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); ++ struct device *dev = &pdev->dev; ++ struct peci_cpupower *priv; ++ struct device *hwmon_dev; ++ ++ if ((mgr->client->adapter->cmd_mask & ++ (BIT(PECI_CMD_RD_PKG_CFG))) != ++ (BIT(PECI_CMD_RD_PKG_CFG))) { ++ return -ENODEV; ++ } ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ priv->mgr = mgr; ++ priv->dev = dev; ++ priv->gen_info = mgr->gen_info; ++ ++ snprintf(priv->name, PECI_NAME_SIZE, "peci_cpupower.cpu%d", ++ mgr->client->addr - PECI_BASE_ADDR); ++ ++ priv->power_config[priv->config_idx++] = config_table[average_power]; ++ ++ priv->chip.ops = &cpupower_ops; ++ priv->chip.info = priv->info; ++ ++ priv->info[0] = &priv->power_info; ++ ++ priv->power_info.type = hwmon_power; ++ priv->power_info.config = priv->power_config; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, ++ priv->name, ++ priv, ++ &priv->chip, ++ NULL); ++ ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name); ++ ++ return 0; ++} ++ ++static const struct platform_device_id peci_cpupower_ids[] = { ++ { .name = "peci-cpupower", .driver_data = 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(platform, peci_cpupower_ids); ++ ++static struct platform_driver peci_cpupower_driver = { ++ .probe = peci_cpupower_probe, ++ .id_table = peci_cpupower_ids, ++ .driver = { .name = KBUILD_MODNAME, }, ++}; ++module_platform_driver(peci_cpupower_driver); ++ ++MODULE_AUTHOR("Zhikui Ren <zhikui.ren@intel.com>"); ++MODULE_DESCRIPTION("PECI cpupower driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c +index 9751b04..0c62ad6 100644 +--- a/drivers/mfd/intel-peci-client.c ++++ b/drivers/mfd/intel-peci-client.c +@@ -21,6 +21,7 @@ + static struct mfd_cell peci_functions[] = { + { .name = "peci-cputemp", }, + { .name = "peci-dimmtemp", }, ++ { .name = "peci-cpupower", }, + }; + + static const struct cpu_gen_info cpu_gen_info_table[] = { +diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h +index 843930f..d16f7c9 100644 +--- a/include/uapi/linux/peci-ioctl.h ++++ b/include/uapi/linux/peci-ioctl.h +@@ -231,6 +231,7 @@ struct peci_rd_pkg_cfg_msg { + #define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ + #define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ + #define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ ++#define PECI_PKG_ID_PKG_ENERGY_STATUS 0x00ff /* Average Energy */ + + __u8 rx_len; + __u8 cc; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch new file mode 100644 index 000000000..2717d367f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch @@ -0,0 +1,136 @@ +From 9f1eea1fb639a0554195e29c488cefb36a04910e Mon Sep 17 00:00:00 2001 +From: arun-pm <arun.p.m@linux.intel.com> +Date: Tue, 3 Dec 2019 17:22:28 +0530 +Subject: [PATCH] SPI Quad IO driver support AST2600 + +This commit adds spi driver quad io support for AST2600 + +Note:- Removed n25q00 Quad I/O support for the time being due to clock issue + with chip 'Micron 8UA15 - rw182 (128MB)' while enabling Quad I/O mode. + +Signed-off-by: arun-pm <arun.p.m@linux.intel.com> +--- + drivers/mtd/spi-nor/aspeed-smc.c | 49 ++++++++++++++++++++++++++++++++++------ + drivers/mtd/spi-nor/spi-nor.c | 7 +++++- + 2 files changed, 48 insertions(+), 8 deletions(-) + +diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c +index 0805dcab8cb1..305c1940e822 100644 +--- a/drivers/mtd/spi-nor/aspeed-smc.c ++++ b/drivers/mtd/spi-nor/aspeed-smc.c +@@ -21,6 +21,11 @@ + #include <linux/sysfs.h> + + #define DEVICE_NAME "aspeed-smc" ++#define AST2600A0 0x05000303 ++#define AST2600A0_MAX_FREQ 50000000 ++#define AST2600A0_SAFE_FREQ 40000000 ++#define AST_MAX_FREQ 100000000 ++#define AST2600_REVISION_ID_SCU 0x1e6e2004 + + /* + * The driver only support SPI flash +@@ -542,6 +547,10 @@ static int aspeed_smc_get_io_mode(struct aspeed_smc_chip *chip) + return CONTROL_IO_DUAL_DATA; + case SNOR_PROTO_1_2_2: + return CONTROL_IO_DUAL_ADDR_DATA; ++ case SNOR_PROTO_1_1_4: ++ return CONTROL_IO_QUAD_DATA; ++ case SNOR_PROTO_1_4_4: ++ return CONTROL_IO_QUAD_ADDR_DATA; + default: + dev_err(chip->nor.dev, "unsupported SPI read mode\n"); + return -EINVAL; +@@ -573,7 +582,7 @@ static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, + aspeed_smc_write_to_ahb(chip->ahb_base, &dummy, sizeof(dummy)); + + /* Set IO mode only for data */ +- if (io_mode == CONTROL_IO_DUAL_DATA) ++ if (io_mode == CONTROL_IO_DUAL_DATA || io_mode == CONTROL_IO_QUAD_DATA) + aspeed_smc_set_io_mode(chip, io_mode); + + aspeed_smc_read_from_ahb(read_buf, chip->ahb_base, len); +@@ -1222,20 +1231,35 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip) + return 0; + } + ++static void aspeed_allowed_max_freq(struct aspeed_smc_chip *chip) ++{ ++ void __iomem *scu_ast_revision_id = ioremap(AST2600_REVISION_ID_SCU, 4); ++ u32 rev_id = readl(scu_ast_revision_id); ++ ++ /*Limit max spi frequency less than 50MHz on AST2600-A0 due ++ * to FWSPICLK signal quality issue. ++ */ ++ if(rev_id == AST2600A0 && chip->clk_rate >= AST2600A0_MAX_FREQ) ++ chip->clk_rate = AST2600A0_SAFE_FREQ; ++} ++ ++static u32 get_hwcaps(unsigned int tx_width){ ++ if(tx_width == 4) ++ return SNOR_HWCAPS_READ_1_1_4; ++ else ++ return SNOR_HWCAPS_READ_1_1_2; ++} ++ + static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller, + struct device_node *np, struct resource *r) + { +- const struct spi_nor_hwcaps hwcaps = { +- .mask = SNOR_HWCAPS_READ | +- SNOR_HWCAPS_READ_FAST | +- SNOR_HWCAPS_READ_1_1_2 | +- SNOR_HWCAPS_PP, +- }; ++ struct spi_nor_hwcaps hwcaps; + const struct aspeed_smc_info *info = controller->info; + struct device *dev = controller->dev; + struct device_node *child; + unsigned int cs; + int ret = -ENODEV; ++ unsigned int spi_tx_width; + + for_each_available_child_of_node(np, child) { + struct aspeed_smc_chip *chip; +@@ -1276,9 +1300,20 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller, + &chip->clk_rate)) { + chip->clk_rate = ASPEED_SPI_DEFAULT_FREQ; + } ++ aspeed_allowed_max_freq(chip); + dev_info(dev, "Using %d MHz SPI frequency\n", + chip->clk_rate / 1000000); + ++ if (of_property_read_u32(child, "spi-tx-bus-width", ++ &spi_tx_width)) { ++ spi_tx_width = 2; ++ } ++ dev_info(dev, "tx width: %ld\n", spi_tx_width); ++ ++ hwcaps.mask = SNOR_HWCAPS_READ | ++ SNOR_HWCAPS_READ_FAST | ++ get_hwcaps(spi_tx_width) | ++ SNOR_HWCAPS_PP; + chip->controller = controller; + chip->ctl = controller->regs + info->ctl0 + cs * 4; + chip->cs = cs; +diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c +index 3668a862d37d..50904876cb09 100644 +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2315,7 +2315,12 @@ static const struct flash_info spi_nor_ids[] = { + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | + SPI_NOR_QUAD_READ) }, +- { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, ++ /* Removed n25q00 Quad I/O support for the time being due to clock issue with chip 'Micron 8UA15 - rw182 (128MB)' ++ * while enabling Quad I/O mode. As this chip is default shipped in platforms, marking it ++ * as Not supported for the time being. Once all chips are replaced with the new model, this can be enabled ++ * back(Note:- Certain other chips having same name(n25q00) but different part number has no issues). ++ */ ++ { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | NO_CHIP_ERASE) }, + { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096, + SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch new file mode 100644 index 000000000..4b3b6b838 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch @@ -0,0 +1,37 @@ +From 8be7c34e78bd09fa95ce9972332c8c2bb950ec03 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 28 Jan 2020 16:14:07 -0800 +Subject: [PATCH] ipmi: ipmb_dev_int: add quick fix for raw I2C type + registration + +This commit adds quick fix for cases of run time registration +through sysfs. It should be fixed later by adding parsing code for +ipmb_id instead. + +This is a temporary fix. Do not upstream it. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/char/ipmi/ipmb_dev_int.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c +index 382e4a1df510..c5db37266724 100644 +--- a/drivers/char/ipmi/ipmb_dev_int.c ++++ b/drivers/char/ipmi/ipmb_dev_int.c +@@ -328,8 +328,12 @@ static int ipmb_probe(struct i2c_client *client, + if (ret) + return ret; + ++#if 1 /* FIXME: Quick fix. Need to add parsing code for ipmb_id instead */ ++ ipmb_dev->is_i2c_protocol = true; ++#else + ipmb_dev->is_i2c_protocol + = device_property_read_bool(&client->dev, "i2c-protocol"); ++#endif + + ipmb_dev->client = client; + i2c_set_clientdata(client, ipmb_dev); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch new file mode 100644 index 000000000..3e426edcd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch @@ -0,0 +1,57 @@ +From f280c15c79e7d13e4a59d413a3091eb21b56dd92 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Mon, 27 Jan 2020 09:03:56 -0800 +Subject: [PATCH] Return link speed and duplex settings for the NCSI channel + +The ftgmac100_open function initializes state for the NCSI +channel. The get link settings function does not return this +data. This caused the link speed, and the duplex value to be returned +incorrectly by the PHY driver (0 Mbps, and duplex off). + +Update the driver to return either the PHY settings when not using +NCSI, or the NCSI values that were assigned when the driver is opened. + +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + drivers/net/ethernet/faraday/ftgmac100.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c +index 8ed85037f021..a53878eecfc8 100644 +--- a/drivers/net/ethernet/faraday/ftgmac100.c ++++ b/drivers/net/ethernet/faraday/ftgmac100.c +@@ -1218,10 +1218,30 @@ static int ftgmac100_set_pauseparam(struct net_device *netdev, + return 0; + } + ++int ftgmac100_ethtool_get_link_ksettings(struct net_device *netdev, ++ struct ethtool_link_ksettings *cmd) ++{ ++ struct phy_device *phydev = netdev->phydev; ++ struct ftgmac100 *priv = netdev_priv(netdev); ++ int retval = 0; ++ ++ if (phydev) { ++ phy_ethtool_ksettings_get(phydev, cmd); ++ } else if (priv->use_ncsi) { ++ cmd->base.speed = priv->cur_speed; ++ cmd->base.duplex = priv->cur_duplex; ++ cmd->base.autoneg = 0; ++ } else { ++ retval = -ENODEV; ++ } ++ ++ return retval; ++} ++ + static const struct ethtool_ops ftgmac100_ethtool_ops = { + .get_drvinfo = ftgmac100_get_drvinfo, + .get_link = ethtool_op_get_link, +- .get_link_ksettings = phy_ethtool_get_link_ksettings, ++ .get_link_ksettings = ftgmac100_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .nway_reset = phy_ethtool_nway_reset, + .get_ringparam = ftgmac100_get_ringparam, +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch new file mode 100644 index 000000000..377ec2b36 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch @@ -0,0 +1,783 @@ +From 0301f9b2bc948069aaad2899e15e6c94a07ca818 Mon Sep 17 00:00:00 2001 +From: Ayushi Smriti <smriti.ayushi@intel.com> +Date: Mon, 2 Mar 2020 22:51:46 +0530 +Subject: [PATCH] pwm and tach driver changes for ast2600 + +This commit includes additions/changes in driver code +to support 9 PWM outputs and 9 fan tachometer inputs for +ast2600 + +Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com> +--- + drivers/hwmon/aspeed-g6-pwm-tacho.c | 328 +++++++++++++++------------- + 1 file changed, 171 insertions(+), 157 deletions(-) + +diff --git a/drivers/hwmon/aspeed-g6-pwm-tacho.c b/drivers/hwmon/aspeed-g6-pwm-tacho.c +index 1894f6ad5edb..1ff788bf1133 100644 +--- a/drivers/hwmon/aspeed-g6-pwm-tacho.c ++++ b/drivers/hwmon/aspeed-g6-pwm-tacho.c +@@ -64,6 +64,8 @@ + #define PWM_RISING_FALLING_BIT (8) //pwm falling point bit [7:0] + #define PWM_RISING_RISING_BIT (0) //pwm rising point bit [7:0] + ++#define DEF_PWM_PERIOD 0xff ++ + #define ASPEED_TACHO_CTRL 0x08 //TACH0 General Register + #define ASPEED_TACHO_CTRL_CH(x) ((x * 0x10) + 0x08) + #define TACHO_IER BIT(31) //enable tacho interrupt +@@ -72,8 +74,7 @@ + #define TACHO_ENABLE BIT(28) //{enable tacho} + #define TACHO_DEBOUNCE_BIT (26) //{tacho de-bounce} + #define TACHO_DEBOUNCE_MASK (0x3 << 26) //{tacho de-bounce} +-#define TECHIO_EDGE_MASK (0x3 << 24) //tacho edge} +-#define TECHIO_EDGE_BIT (24) //tacho edge} ++#define TACHIO_EDGE_BIT (24) /*tacho edge}*/ + #define TACHO_CLK_DIV_T_MASK (0xf << 20) + #define TACHO_CLK_DIV_BIT (20) + #define TACHO_THRESHOLD_MASK (0xfffff) //tacho threshold bit +@@ -102,211 +103,183 @@ + + #define MAX_CDEV_NAME_LEN 16 + ++#define DEFAULT_TARGET_PWM_FREQ 25000 ++#define DEFAULT_MIN_RPM 2900 ++ ++#define PWM_FALLING_VALUE 0xff ++ + struct aspeed_pwm_channel_params { ++ int target_freq; ++ int pwm_freq; + int load_wdt_rising_falling_pt; + int load_wdt_selection; //0: rising , 1: falling + int load_wdt_enable; + int duty_sync_enable; + int invert_pin; +- u8 divide_h; +- u8 divide_l; +- u8 period; + u8 rising; + u8 falling; + }; + + static struct aspeed_pwm_channel_params default_pwm_params[] = { + [0] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 1, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [1] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [2] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [3] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [4] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [5] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [6] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [7] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [8] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [9] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [10] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [11] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [12] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [13] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [14] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + [15] = { ++ .target_freq = 25000, + .load_wdt_rising_falling_pt = 0x10, + .load_wdt_selection = 0, + .load_wdt_enable = 0, + .duty_sync_enable = 0, + .invert_pin = 0, +- .divide_h = 0x5, +- .divide_l = 0x6, +- .period = 0x13, //5% ~~ + .rising = 0x00, +- .falling = 0x0a, ++ .falling = PWM_FALLING_VALUE, + }, + }; + +@@ -318,125 +291,146 @@ static struct aspeed_pwm_channel_params default_pwm_params[] = { + * 11: reserved. + */ + ++#define F2F_EDGES 0x00 ++#define R2R_EDGES 0x01 ++#define BOTH_EDGES 0x02 ++ + struct aspeed_tacho_channel_params { ++ u32 min_rpm; + int limited_inverse; + u16 threshold; + u8 tacho_edge; + u8 tacho_debounce; +- u8 divide; ++ u32 divide; + }; + + + static struct aspeed_tacho_channel_params default_tacho_params[] = { + [0] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [1] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [2] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [3] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [4] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [5] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [6] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [7] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [8] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [9] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [10] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [11] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [12] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [13] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [14] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, + [15] = { ++ .min_rpm = 2900, + .limited_inverse = 0, + .threshold = 0, +- .tacho_edge = 0, ++ .tacho_edge = F2F_EDGES, + .tacho_debounce = 0, + .divide = 8, + }, +@@ -501,29 +495,28 @@ static void aspeed_set_pwm_channel_enable(struct regmap *regmap, u8 pwm_channel, + static void aspeed_set_fan_tach_ch_enable(struct aspeed_pwm_tachometer_data *priv, u8 fan_tach_ch, + bool enable) + { +- u32 i = 0, j; ++ u32 i; + u32 divide_val = 0; ++ u32 target_div; + u32 reg_value = 0; + + if(enable) { +- //4 ^ n +- //check pwm clk and to change tacho devide 25KZ +- for(i = 0; i < 12; i++) { ++ /*RPM calculation as per ast2600 datasheet*/ ++ target_div = (priv->clk_freq * 60 / priv->tacho_channel[fan_tach_ch].min_rpm * 2) / (0xfffff + 1); ++ if (target_div) { ++ for (i = 0; i < 12; i++) { ++ divide_val = BIT(i) * BIT(i); ++ if (divide_val > target_div) ++ break; ++ } ++ } else { + divide_val = 1; +- for (j = 1; j <= i; j++) +- divide_val *= 4; +-// printk("i : %d , priv->clk_freq/divide_val %d ",i, priv->clk_freq/divide_val); +- if((priv->clk_freq/divide_val) < 250000) +- break; + } +- i--; +- divide_val = ((1 << i) * (1 << i)); +-// printk("tacho divide_val %d , i %x max tacho clk %d \n", divide_val, i, priv->clk_freq / divide_val); +- priv->tacho_channel[fan_tach_ch].divide = i; ++ priv->tacho_channel[fan_tach_ch].divide = divide_val; + + reg_value = TACHO_ENABLE | +- (priv->tacho_channel[fan_tach_ch].tacho_edge << TECHIO_EDGE_BIT) | +- (priv->tacho_channel[fan_tach_ch].divide << TACHO_CLK_DIV_BIT) | ++ (priv->tacho_channel[fan_tach_ch].tacho_edge << TACHIO_EDGE_BIT) | ++ (i << TACHO_CLK_DIV_BIT) | + (priv->tacho_channel[fan_tach_ch].tacho_debounce << TACHO_DEBOUNCE_BIT); + + if(priv->tacho_channel[fan_tach_ch].limited_inverse) +@@ -541,14 +534,28 @@ static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *p + u8 index, u8 fan_ctrl) + { + u32 duty_value, ctrl_value; ++ u32 div_h, div_l, cal_freq; + + if (fan_ctrl == 0) { + aspeed_set_pwm_channel_enable(priv->regmap, index, false); + } else { +- duty_value = (priv->pwm_channel[index].period << PWM_PERIOD_BIT) | +- (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT); ++ cal_freq = priv->clk_freq / (DEF_PWM_PERIOD + 1); ++ /*calculate for target frequence*/ ++ for (div_l = 0; div_l < 0x100; div_l++) { ++ for (div_h = 0; div_h < 0x10; div_h++) { ++ if ((cal_freq / (BIT(div_h) * (div_l + 1))) < priv->pwm_channel[index].target_freq) ++ break; ++ } ++ if ((cal_freq / (BIT(div_h) * (div_l + 1))) < priv->pwm_channel[index].target_freq) ++ break; ++ } ++ ++ priv->pwm_channel[index].pwm_freq = cal_freq / (BIT(div_h) * (div_l + 1)); + +- ctrl_value = (priv->pwm_channel[index].divide_h << 8) | priv->pwm_channel[index].divide_l; ++ ctrl_value = (div_h << 8) | div_l; ++ ++ duty_value = (DEF_PWM_PERIOD << PWM_PERIOD_BIT) | ++ (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT); + + if (priv->pwm_channel[index].load_wdt_enable) { + ctrl_value |= PWM_DUTY_LOAD_AS_WDT_EN; +@@ -568,13 +575,11 @@ static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *p + } + } + +-#define BOTH_EDGES 0x02 /* 10b */ +- + static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv, + u8 fan_tach_ch) + { + u32 raw_data, tach_div, clk_source, val; +- u8 mode, both; ++ u8 multiplier = 2; + int i, retries = 3; + + for(i = 0; i < retries; i++) { +@@ -587,22 +592,15 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv, + if(raw_data == 0xfffff) + return 0; + +- tach_div = priv->tacho_channel[fan_tach_ch].divide; +- /* +- * We need the mode to determine if the raw_data is double (from +- * counting both edges). +- */ +- mode = priv->tacho_channel[fan_tach_ch].tacho_edge; +- both = (mode & BOTH_EDGES) ? 1 : 0; +-// printk("clk %ld, raw_data %x , tach_div %x both %x \n", priv->clk_freq, raw_data, tach_div, both); ++ raw_data += 1; ++ tach_div = raw_data * (priv->tacho_channel[fan_tach_ch].divide) * (multiplier); + +- tach_div = (tach_div * 2) * (0x1 << both); + clk_source = priv->clk_freq; + + if (raw_data == 0) + return 0; + +- return (clk_source * 60) / (2 * raw_data * tach_div); ++ return (clk_source / tach_div * 60); + + } + +@@ -614,19 +612,27 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + int ret; + struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev); + long fan_ctrl; ++ u8 org_falling = priv->pwm_channel[index].falling; + + ret = kstrtol(buf, 10, &fan_ctrl); + if (ret != 0) + return ret; + +- if (fan_ctrl < 0 || fan_ctrl > priv->pwm_channel[index].period) ++ if (fan_ctrl < 0 || fan_ctrl > DEF_PWM_PERIOD) + return -EINVAL; + + if (priv->pwm_channel[index].falling == fan_ctrl) + return count; + + priv->pwm_channel[index].falling = fan_ctrl; +- aspeed_set_pwm_channel_fan_ctrl(priv, index, fan_ctrl); ++ ++ if (fan_ctrl == 0) ++ aspeed_set_pwm_channel_enable(priv->regmap, index, false); ++ else ++ regmap_update_bits(priv->regmap, ASPEED_PWM_DUTY_CYCLE_CH(index), GENMASK(15, 8), (fan_ctrl << PWM_RISING_FALLING_BIT)); ++ ++ if (org_falling == 0) ++ aspeed_set_pwm_channel_enable(priv->regmap, index, true); + + return count; + } +@@ -678,40 +684,39 @@ static umode_t fan_dev_is_visible(struct kobject *kobj, + return a->mode; + } + +-static SENSOR_DEVICE_ATTR(pwm0, 0644, +- show_pwm, set_pwm, 0); + static SENSOR_DEVICE_ATTR(pwm1, 0644, +- show_pwm, set_pwm, 1); ++ show_pwm, set_pwm, 0); + static SENSOR_DEVICE_ATTR(pwm2, 0644, +- show_pwm, set_pwm, 2); ++ show_pwm, set_pwm, 1); + static SENSOR_DEVICE_ATTR(pwm3, 0644, +- show_pwm, set_pwm, 3); ++ show_pwm, set_pwm, 2); + static SENSOR_DEVICE_ATTR(pwm4, 0644, +- show_pwm, set_pwm, 4); ++ show_pwm, set_pwm, 3); + static SENSOR_DEVICE_ATTR(pwm5, 0644, +- show_pwm, set_pwm, 5); ++ show_pwm, set_pwm, 4); + static SENSOR_DEVICE_ATTR(pwm6, 0644, +- show_pwm, set_pwm, 6); ++ show_pwm, set_pwm, 5); + static SENSOR_DEVICE_ATTR(pwm7, 0644, +- show_pwm, set_pwm, 7); ++ show_pwm, set_pwm, 6); + static SENSOR_DEVICE_ATTR(pwm8, 0644, +- show_pwm, set_pwm, 8); ++ show_pwm, set_pwm, 7); + static SENSOR_DEVICE_ATTR(pwm9, 0644, +- show_pwm, set_pwm, 9); ++ show_pwm, set_pwm, 8); + static SENSOR_DEVICE_ATTR(pwm10, 0644, +- show_pwm, set_pwm, 10); ++ show_pwm, set_pwm, 9); + static SENSOR_DEVICE_ATTR(pwm11, 0644, +- show_pwm, set_pwm, 11); ++ show_pwm, set_pwm, 10); + static SENSOR_DEVICE_ATTR(pwm12, 0644, +- show_pwm, set_pwm, 12); ++ show_pwm, set_pwm, 11); + static SENSOR_DEVICE_ATTR(pwm13, 0644, +- show_pwm, set_pwm, 13); ++ show_pwm, set_pwm, 12); + static SENSOR_DEVICE_ATTR(pwm14, 0644, +- show_pwm, set_pwm, 14); ++ show_pwm, set_pwm, 13); + static SENSOR_DEVICE_ATTR(pwm15, 0644, ++ show_pwm, set_pwm, 14); ++static SENSOR_DEVICE_ATTR(pwm16, 0644, + show_pwm, set_pwm, 15); + static struct attribute *pwm_dev_attrs[] = { +- &sensor_dev_attr_pwm0.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, +@@ -727,6 +732,7 @@ static struct attribute *pwm_dev_attrs[] = { + &sensor_dev_attr_pwm13.dev_attr.attr, + &sensor_dev_attr_pwm14.dev_attr.attr, + &sensor_dev_attr_pwm15.dev_attr.attr, ++ &sensor_dev_attr_pwm16.dev_attr.attr, + NULL, + }; + +@@ -735,40 +741,39 @@ static const struct attribute_group pwm_dev_group = { + .is_visible = pwm_is_visible, + }; + +-static SENSOR_DEVICE_ATTR(fan0_input, 0444, +- show_rpm, NULL, 0); + static SENSOR_DEVICE_ATTR(fan1_input, 0444, +- show_rpm, NULL, 1); ++ show_rpm, NULL, 0); + static SENSOR_DEVICE_ATTR(fan2_input, 0444, +- show_rpm, NULL, 2); ++ show_rpm, NULL, 1); + static SENSOR_DEVICE_ATTR(fan3_input, 0444, +- show_rpm, NULL, 3); ++ show_rpm, NULL, 2); + static SENSOR_DEVICE_ATTR(fan4_input, 0444, +- show_rpm, NULL, 4); ++ show_rpm, NULL, 3); + static SENSOR_DEVICE_ATTR(fan5_input, 0444, +- show_rpm, NULL, 5); ++ show_rpm, NULL, 4); + static SENSOR_DEVICE_ATTR(fan6_input, 0444, +- show_rpm, NULL, 6); ++ show_rpm, NULL, 5); + static SENSOR_DEVICE_ATTR(fan7_input, 0444, +- show_rpm, NULL, 7); ++ show_rpm, NULL, 6); + static SENSOR_DEVICE_ATTR(fan8_input, 0444, +- show_rpm, NULL, 8); ++ show_rpm, NULL, 7); + static SENSOR_DEVICE_ATTR(fan9_input, 0444, +- show_rpm, NULL, 9); ++ show_rpm, NULL, 8); + static SENSOR_DEVICE_ATTR(fan10_input, 0444, +- show_rpm, NULL, 10); ++ show_rpm, NULL, 9); + static SENSOR_DEVICE_ATTR(fan11_input, 0444, +- show_rpm, NULL, 11); ++ show_rpm, NULL, 10); + static SENSOR_DEVICE_ATTR(fan12_input, 0444, +- show_rpm, NULL, 12); ++ show_rpm, NULL, 11); + static SENSOR_DEVICE_ATTR(fan13_input, 0444, +- show_rpm, NULL, 13); ++ show_rpm, NULL, 12); + static SENSOR_DEVICE_ATTR(fan14_input, 0444, +- show_rpm, NULL, 14); ++ show_rpm, NULL, 13); + static SENSOR_DEVICE_ATTR(fan15_input, 0444, ++ show_rpm, NULL, 14); ++static SENSOR_DEVICE_ATTR(fan16_input, 0444, + show_rpm, NULL, 15); + static struct attribute *fan_dev_attrs[] = { +- &sensor_dev_attr_fan0_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, +@@ -784,6 +789,7 @@ static struct attribute *fan_dev_attrs[] = { + &sensor_dev_attr_fan13_input.dev_attr.attr, + &sensor_dev_attr_fan14_input.dev_attr.attr, + &sensor_dev_attr_fan15_input.dev_attr.attr, ++ &sensor_dev_attr_fan16_input.dev_attr.attr, + NULL + }; + +@@ -802,14 +808,14 @@ static void aspeed_create_pwm_channel(struct aspeed_pwm_tachometer_data *priv, + } + + static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tachometer_data *priv, +- u8 *fan_tach_ch, +- int count) ++ u8 *fan_tach_ch, int count, u32 min_rpm) + { + u8 val, index; + + for (val = 0; val < count; val++) { + index = fan_tach_ch[val]; + priv->fan_tach_present[index] = true; ++ priv->tacho_channel[index].min_rpm = min_rpm; + aspeed_set_fan_tach_ch_enable(priv, index, true); + } + } +@@ -906,13 +912,19 @@ static int aspeed_pwm_create_fan(struct device *dev, + struct aspeed_pwm_tachometer_data *priv) + { + u8 *fan_tach_ch; ++ u32 fan_min_rpm; + u32 pwm_channel; ++ u32 target_pwm_freq; + int ret, count; + + ret = of_property_read_u32(child, "reg", &pwm_channel); + if (ret) + return ret; + ++ ret = of_property_read_u32(child, "aspeed,target_pwm", &target_pwm_freq); ++ if (ret) ++ target_pwm_freq = DEFAULT_TARGET_PWM_FREQ; ++ + aspeed_create_pwm_channel(priv, (u8)pwm_channel); + + ret = of_property_count_u8_elems(child, "cooling-levels"); +@@ -935,9 +947,11 @@ static int aspeed_pwm_create_fan(struct device *dev, + fan_tach_ch, count); + if (ret) + return ret; ++ ret = of_property_read_u32(child, "aspeed,min_rpm", &fan_min_rpm); ++ if (ret) ++ fan_min_rpm = DEFAULT_MIN_RPM; + +- aspeed_create_fan_tach_channel(priv, fan_tach_ch, count); +- ++ aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, fan_min_rpm); + return 0; + } + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch new file mode 100644 index 000000000..e2196c629 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch @@ -0,0 +1,40 @@ +From 7555448ab0676ea974ef67ef0c8ebe5d68b73d25 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Tue, 18 Feb 2020 14:17:22 -0800 +Subject: [PATCH] Fix truncated WrEndPointConfig MMIO command + +When address type is 6, the driver is reducing the msg buffer to +the base size and truncating the additional command data. + +This removes the line that sets the msg buffer size to the base +size. The correct buffer size is already set. + +Tested: +Ran this command: +peci_cmds WrEndpointConfigMMIO 6 0 0 0x7e 0x1a 0x0 0x224e0 0x5f5a56 + +and got the full buffer in the driver log: +[ 795.207278] peci_aspeed 1e78b000.peci-bus: HEAD : 0x00011730 +[ 795.212980] TX : c5 00 05 00 00 00 06 00 d0 7e e0 24 02 00 00 00 .........~.$.... +[ 795.220556] TX : 00 00 56 5a 5f 00 a8 ..VZ_.. + +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + drivers/peci/peci-core.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index 9aedb74..efb73b0 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -1040,7 +1040,6 @@ static int peci_cmd_wr_end_pt_cfg(struct peci_adapter *adapter, void *vmsg) + >> 24); /* MSB - DWORD Register Offset */ + if (umsg->params.mmio.addr_type == + PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) { +- msg->tx_len = PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE; + msg->tx_buf[14] = (u8)(umsg->params.mmio.offset + >> 32); /* Register Offset */ + msg->tx_buf[15] = (u8)(umsg->params.mmio.offset +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg new file mode 100644 index 000000000..bbc7fa5b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg @@ -0,0 +1,2 @@ +CONFIG_DEVMEM = y +CONFIG_DEVMEM_BOOTPARAM = n diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg new file mode 100644 index 000000000..5f453510a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg @@ -0,0 +1,89 @@ +CONFIG_BLK_DEV_RAM=y +CONFIG_HWMON=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_IIO=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_ASPEED_ADC=y +CONFIG_SGPIO_ASPEED=y +CONFIG_CRC8=y +CONFIG_PECI=y +CONFIG_PECI_CHARDEV=y +CONFIG_PECI_ASPEED=y +CONFIG_SENSORS_PECI_CPUTEMP=y +CONFIG_SENSORS_PECI_DIMMTEMP=y +CONFIG_SENSORS_PECI_CPUPOWER=y +CONFIG_CONFIGFS_FS=y +CONFIG_BLK_DEV_RAM_SIZE=49152 +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_ASPEED_ESPI_SLAVE=y +CONFIG_ASPEED_KCS_IPMI_BMC=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_MQUEUE=y +CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE=256 +CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE=32 +CONFIG_ASPEED_BT_IPMI_BMC=n +CONFIG_ASPEED_LPC_CTRL=n +CONFIG_ASPEED_LPC_MBOX=y +CONFIG_ASPEED_LPC_SIO=y +CONFIG_JTAG=y +CONFIG_JTAG_ASPEED=y +CONFIG_FRAME_VECTOR=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_ASPEED=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_V4L2=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_HID=y +CONFIG_USB_GADGET=y +CONFIG_U_SERIAL_CONSOLE=y +CONFIG_USB_ASPEED_VHUB=y +CONFIG_USB_MASS_STORAGE=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_ASPEED_UART_ROUTING=y +CONFIG_ASPEED_VGA_SHAREDMEM=y +CONFIG_PWM=y +CONFIG_PWM_FTTMR010=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PWM_BEEPER=y +CONFIG_VFAT_FS=y +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_UTF8=y +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_CIFS=y +CONFIG_CIFS_XATTR=y +CONFIG_PSTORE=y +CONFIG_PSTORE_ZLIB_COMPRESS=y +CONFIG_PSTORE_RAM=y +CONFIG_FSI=n +CONFIG_FSI_MASTER_HUB=n +CONFIG_FSI_MASTER_ASPEED=n +CONFIG_FSI_SCOM=n +CONFIG_FSI_SBEFIFO=n +CONFIG_FSI_OCC=n +CONFIG_ASPEED_P2A_CTRL=n +CONFIG_USB=n +CONFIG_USB_ANNOUNCE_NEW_DEVICES=n +CONFIG_USB_DYNAMIC_MINORS=n +CONFIG_USB_EHCI_HCD=n +CONFIG_USB_EHCI_ROOT_HUB_TT=n +CONFIG_USB_EHCI_HCD_PLATFORM=n +CONFIG_IPMB_DEVICE_INTERFACE=y diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend new file mode 100644 index 000000000..57df89699 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -0,0 +1,76 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +do_compile_prepend(){ + # device tree compiler flags + export DTC_FLAGS=-@ +} + +SRC_URI += " \ + file://intel.cfg \ + file://0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch \ + file://0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch \ + file://0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch \ + file://0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch \ + file://0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch \ + file://0006-Allow-monitoring-of-power-control-input-GPIOs.patch \ + file://0007-aspeed-pwm-tacho-change-default-fan-speed.patch \ + file://0014-arm-dts-aspeed-g5-add-espi.patch \ + file://0015-New-flash-map-for-intel.patch \ + file://0016-Add-ASPEED-SGPIO-driver.patch \ + file://0017-SGPIO-DT-and-pinctrl-fixup.patch \ + file://0019-Add-I2C-IPMB-support.patch \ + file://0020-misc-aspeed-add-lpc-mbox-driver.patch \ + file://0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch \ + file://0022-Add-AST2500-eSPI-driver.patch \ + file://0028-Add-AST2500-JTAG-driver.patch \ + file://0030-Add-dump-debug-code-into-I2C-drivers.patch \ + file://0031-Add-high-speed-baud-rate-support-for-UART.patch \ + file://0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch \ + file://0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch \ + file://0035-Implement-a-memory-driver-share-memory.patch \ + file://0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch \ + file://0040-i2c-Add-mux-hold-unhold-msg-types.patch \ + file://0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch \ + file://0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch \ + file://0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch \ + file://0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch \ + file://0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch \ + file://0049-Suppress-excessive-HID-gadget-error-logs.patch \ + file://0051-Add-AST2500-JTAG-device.patch \ + file://0052-drivers-jtag-Add-JTAG-core-driver.patch \ + file://0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch \ + file://0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch \ + file://0055-Documentation-jtag-Add-ABI-documentation.patch \ + file://0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch \ + file://0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch \ + file://0061-i2c-aspeed-add-buffer-mode-transfer-support.patch \ + file://0062-i2c-aspeed-add-DMA-mode-transfer-support.patch \ + file://0063-i2c-aspeed-add-general-call-support.patch \ + file://0064-set-idle-disconnect-to-true-in-all-cases.patch \ + file://0068-i2c-aspeed-add-H-W-timeout-support.patch \ + file://0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch \ + file://0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch \ + file://0072-pmbus-add-fault-and-beep-attributes.patch \ + file://0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch \ + file://0075-Refine-initialization-flow-in-I2C-driver.patch \ + file://0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch \ + file://0077-soc-aspeed-Add-read-only-property-support.patch \ + file://0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch \ + file://0080-i2c-aspeed-filter-garbage-interrupts-out.patch \ + file://0084-ARM-dts-aspeed-g6-add-GFX-node.patch \ + file://0085-drm-add-AST2600-GFX-support.patch \ + file://0086-ADC-linux-driver-for-AST2600.patch \ + file://0086-ARM-dts-aspeed-g6-add-video-node.patch \ + file://0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch \ + file://0088-clk-ast2600-enable-ESPICLK-always.patch \ + file://0089-ast2600-enable-high-speed-uart-in-kernel.patch \ + file://0090-peci-cpupower-driver-1.patch \ + file://0092-SPI-Quad-IO-driver-support-AST2600.patch \ + file://0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch \ + file://0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch \ + file://0095-pwm-and-tach-driver-changes-for-ast2600.patch \ + file://0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch \ + " + +SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}" +SRC_URI += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', 'file://debug.cfg', '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch new file mode 100644 index 000000000..53f381af8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch @@ -0,0 +1,405 @@ +From 8a127e2054683479d3999ad99ba7ff76c193aa1a Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Wed, 5 Sep 2018 14:16:54 +0530 +Subject: [PATCH] Adding channel specific privilege to network + + - Adding the channel access information to the network + interface object. This privilege will be used in + channel specific authorization. + - Get supported priv from user manager service dynamically. + - Signal handling for capturing the supported priv list + changes from user managerment. + +Tested-by: +Verified channel access through ipmitool get/set channel +access command + +Change-Id: I3b592a19363eef684e31d5f7c34dad8f2f9211df +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + ethernet_interface.cpp | 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 2375482..c3edd4b 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -37,6 +37,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, +@@ -56,6 +59,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); ++ getChannelPrivilege(intfName); + + // Emit deferred signal. + if (emitSignal) +@@ -823,5 +827,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 60c56e3..3e4cf12 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -2,11 +2,14 @@ + + #include "types.hpp" + #include "util.hpp" ++#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp" + #include "xyz/openbmc_project/Network/IP/Create/server.hpp" + #include "xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp" + + #include <experimental/filesystem> ++#include <nlohmann/json.hpp> + #include <sdbusplus/bus.hpp> ++#include <sdbusplus/bus/match.hpp> + #include <sdbusplus/server/object.hpp> + #include <string> + #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp> +@@ -23,7 +26,8 @@ using Ifaces = sdbusplus::server::object::object< + sdbusplus::xyz::openbmc_project::Network::server::MACAddress, + sdbusplus::xyz::openbmc_project::Network::IP::server::Create, + sdbusplus::xyz::openbmc_project::Network::Neighbor::server::CreateStatic, +- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>; ++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll, ++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess>; + + using IP = sdbusplus::xyz::openbmc_project::Network::server::IP; + +@@ -31,10 +35,15 @@ using EthernetInterfaceIntf = + sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; + using MacAddressIntf = + sdbusplus::xyz::openbmc_project::Network::server::MACAddress; ++using ChannelAccessIntf = ++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess; + + using ServerList = std::vector<std::string>; + using ObjectPath = sdbusplus::message::object_path; + ++using DbusVariant = ++ sdbusplus::message::variant<std::string, std::vector<std::string>>; ++ + namespace fs = std::experimental::filesystem; + + class Manager; // forward declaration of network manager. +@@ -195,6 +204,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; +@@ -291,6 +308,26 @@ class EthernetInterface : public Ifaces + std::string objPath; + + friend class TestEthernetInterface; ++ ++ /** @brief gets the channel privilege. ++ * @param[in] interfaceName - Network interface name. ++ * @returns privilege of the interface ++ */ ++ std::string getChannelPrivilege(const std::string& interfaceName); ++ ++ /** @brief reads the channel access info from file. ++ * @param[in] configFile - channel access filename ++ * @returns json file data ++ */ ++ nlohmann::json readJsonFile(const std::string& configFile); ++ ++ /** @brief writes the channel access info to file. ++ * @param[in] configFile - channel access filename ++ * @param[in] jsonData - json data to write ++ * @returns success or failure ++ */ ++ int writeJsonFile(const std::string& configFile, ++ const nlohmann::json& jsonData); + }; + + } // namespace network +diff --git a/network_manager.cpp b/network_manager.cpp +index 043d7a2..75f4e5f 100644 +--- a/network_manager.cpp ++++ b/network_manager.cpp +@@ -34,6 +34,13 @@ extern std::unique_ptr<Timer> restartTimer; + using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + ++static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user"; ++static constexpr const char* userMgrInterface = ++ "xyz.openbmc_project.User.Manager"; ++static constexpr const char* propNameAllPrivileges = "AllPrivileges"; ++ ++std::unique_ptr<sdbusplus::bus::match_t> usrMgmtSignal(nullptr); ++ + Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, + const std::string& path) : + details::VLANCreateIface(bus, objPath, true), +@@ -41,6 +48,103 @@ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, + { + fs::path confDir(path); + setConfDir(confDir); ++ initSupportedPrivilges(); ++} ++ ++std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf, ++ const std::string& path) ++{ ++ auto mapperCall = ++ bus.new_method_call("xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject"); ++ ++ mapperCall.append(path); ++ mapperCall.append(std::vector<std::string>({intf})); ++ ++ auto mapperResponseMsg = bus.call(mapperCall); ++ ++ std::map<std::string, std::vector<std::string>> mapperResponse; ++ mapperResponseMsg.read(mapperResponse); ++ ++ if (mapperResponse.begin() == mapperResponse.end()) ++ { ++ throw std::runtime_error("ERROR in reading the mapper response"); ++ } ++ ++ return mapperResponse.begin()->first; ++} ++ ++std::string Manager::getUserServiceName() ++{ ++ static std::string userMgmtService; ++ if (userMgmtService.empty()) ++ { ++ try ++ { ++ userMgmtService = ++ getUserService(bus, userMgrInterface, userMgrObjBasePath); ++ } ++ catch (const std::exception& e) ++ { ++ log<level::ERR>("Exception caught in getUserServiceName."); ++ userMgmtService.clear(); ++ } ++ } ++ return userMgmtService; ++} ++ ++void Manager::initSupportedPrivilges() ++{ ++ std::string userServiceName = getUserServiceName(); ++ if (!userServiceName.empty()) ++ { ++ auto method = bus.new_method_call( ++ getUserServiceName().c_str(), userMgrObjBasePath, ++ "org.freedesktop.DBus.Properties", "Get"); ++ method.append(userMgrInterface, propNameAllPrivileges); ++ ++ auto reply = bus.call(method); ++ if (reply.is_method_error()) ++ { ++ log<level::DEBUG>("get-property AllPrivileges failed", ++ entry("OBJPATH:%s", userMgrObjBasePath), ++ entry("INTERFACE:%s", userMgrInterface)); ++ return; ++ } ++ ++ sdbusplus::message::variant<std::vector<std::string>> result; ++ reply.read(result); ++ ++ supportedPrivList = ++ sdbusplus::message::variant_ns::get<std::vector<std::string>>( ++ result); ++ } ++ ++ // Resgister the signal ++ if (usrMgmtSignal == nullptr) ++ { ++ log<level::DEBUG>("Registering User.Manager propertychange signal."); ++ usrMgmtSignal = std::make_unique<sdbusplus::bus::match_t>( ++ bus, ++ sdbusplus::bus::match::rules::propertiesChanged(userMgrObjBasePath, ++ userMgrInterface), ++ [&](sdbusplus::message::message& msg) { ++ log<level::DEBUG>("UserMgr properties changed signal"); ++ std::map<std::string, DbusVariant> props; ++ std::string iface; ++ msg.read(iface, props); ++ for (const auto& t : props) ++ { ++ if (t.first == propNameAllPrivileges) ++ { ++ supportedPrivList = sdbusplus::message::variant_ns::get< ++ std::vector<std::string>>(t.second); ++ } ++ } ++ }); ++ } ++ return; + } + + bool Manager::createDefaultNetworkFiles(bool force) +diff --git a/network_manager.hpp b/network_manager.hpp +index edb341f..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.21.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch new file mode 100644 index 000000000..b6cf8f77d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0004-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch @@ -0,0 +1,504 @@ +From 42f361622a9c029221c8a90f92104703166e48c2 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Thu, 30 Jan 2020 15:07:39 -0800 +Subject: [PATCH] Enhance DHCP beyond just OFF and IPv4/IPv6 enabled. + +DHCP is not a binary option. The network interface can have DHCP +disabled, IPv4 only, IPv6 only, and IPv4/IPv6. + +Tested: +Using dbus-send or busctl: +Disabled DHCP, and confirmed only link local addresses were present. + +Assigned only static addresses. Both with/and without the gateway set +to 0.0.0.0 + +Deleted static IPv4 addresses. +Reassigned static addresses. + +Enabled DHCP for ipv4 only, and witnessed a DHCP server assign a valid +address. + +Assigned static IPv4 address. +Assigned static IPv6 address. +Confirmed both IPv4 and IPv6 static addresses are active. + +Enabled DHCP for ipv6 only, and confirmed the static v4 address +remains. The ipv6 address is removed, waiting for a DHCP6 server. + +Enabled DHCP for both ipv4 and ipv6. IPv4 address was assigned. IPv6 +address is assumed to succeed, as systemd config file enables IPv6 +DHCP. + +Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162 +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + Makefile.am | 1 + + configure.ac | 1 + + ethernet_interface.cpp | 147 ++++++++++++++++++++++--------- + ethernet_interface.hpp | 31 ++++++- + test/test_ethernet_interface.cpp | 3 +- + test/test_vlan_interface.cpp | 3 +- + types.hpp | 3 + + util.cpp | 16 +++- + util.hpp | 7 +- + vlan_interface.cpp | 2 +- + vlan_interface.hpp | 4 +- + 11 files changed, 165 insertions(+), 53 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1c47747..ff252fc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -97,6 +97,7 @@ phosphor_network_manager_CXXFLAGS = \ + $(SDEVENTPLUS_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) \ ++ -DBOOST_ASIO_DISABLE_THREADS \ + -flto + if FEATURE_NIC_ETHTOOL + phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL +diff --git a/configure.ac b/configure.ac +index 12d6caa..fed3e09 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++]) + PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging]) + PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces]) + PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0]) ++AC_CHECK_HEADER(boost/algorithm/string/split.hpp, [], [AC_MSG_ERROR([Could not find boost/algorithm/string/split.hpp])]) + + # Checks for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,\ +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 73fd8fe..ba6195e 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -3,7 +3,6 @@ + #include "ethernet_interface.hpp" + + #include "config_parser.hpp" +-#include "ipaddress.hpp" + #include "neighbor.hpp" + #include "network_manager.hpp" + #include "vlan_interface.hpp" +@@ -40,9 +39,12 @@ using Argument = xyz::openbmc_project::Common::InvalidArgument; + static constexpr const char* networkChannelCfgFile = + "/var/channel_intf_data.json"; + static constexpr const char* defaultChannelPriv = "priv-admin"; ++std::map<std::string, std::string> mapDHCPToSystemd = { ++ {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; ++ + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal) : + Ifaces(bus, objPath.c_str(), true), + bus(bus), manager(parent), objPath(objPath) +@@ -83,6 +85,65 @@ static IP::Protocol convertFamily(int family) + throw std::invalid_argument("Bad address family"); + } + ++void EthernetInterface::disableDHCP(IP::Protocol protocol) ++{ ++ DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled(); ++ if (dhcpState == EthernetInterface::DHCPConf::both) ++ { ++ if (protocol == IP::Protocol::IPv4) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v6); ++ } ++ else if (protocol == IP::Protocol::IPv6) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v4); ++ } ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v4) && ++ (protocol == IP::Protocol::IPv4)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v6) && ++ (protocol == IP::Protocol::IPv6)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++} ++ ++bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol) ++{ ++ return ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::both) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v6) && ++ ((family == IP::Protocol::IPv6) || ignoreProtocol)) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v4) && ++ ((family == IP::Protocol::IPv4) || ignoreProtocol))); ++} ++ ++bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family, ++ std::string& nextDHCPState) ++{ ++ return ((nextDHCPState == "true") || ++ ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) || ++ ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4))); ++} ++ ++bool EthernetInterface::addressIsStatic(IP::AddressOrigin origin) ++{ ++ return ( ++#ifdef LINK_LOCAL_AUTOCONFIGURATION ++ (origin == IP::AddressOrigin::Static) ++#else ++ (origin == IP::AddressOrigin::Static || ++ origin == IP::AddressOrigin::LinkLocal) ++#endif ++ ++ ); ++} ++ + void EthernetInterface::createIPAddressObjects() + { + addrs.clear(); +@@ -93,7 +154,7 @@ void EthernetInterface::createIPAddressObjects() + { + IP::Protocol addressType = convertFamily(addr.addrType); + IP::AddressOrigin origin = IP::AddressOrigin::Static; +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(addressType)) + { + origin = IP::AddressOrigin::DHCP; + } +@@ -154,11 +215,11 @@ ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress, + uint8_t prefixLength, std::string gateway) + { + +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(protType)) + { + log<level::INFO>("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +- dHCPEnabled(false); ++ disableDHCP(protType); + } + + IP::AddressOrigin origin = IP::AddressOrigin::Static; +@@ -441,7 +502,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value) + return value; + } + +-bool EthernetInterface::dHCPEnabled(bool value) ++EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) + { + if (value == EthernetInterfaceIntf::dHCPEnabled()) + { +@@ -508,7 +569,7 @@ void EthernetInterface::loadVLAN(VlanId id) + std::string path = objPath; + path += "_" + std::to_string(id); + +- auto dhcpEnabled = ++ DHCPConf dhcpEnabled = + getDHCPValue(manager.getConfDir().string(), vlanInterfaceName); + + auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>( +@@ -530,7 +591,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id) + path += "_" + std::to_string(id); + + auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>( +- bus, path.c_str(), false, id, *this, manager); ++ bus, path.c_str(), EthernetInterface::DHCPConf::none, id, *this, ++ manager); + + // write the device file for the vlan interface. + vlanIntf->writeDeviceFile(); +@@ -603,8 +665,6 @@ void EthernetInterface::writeConfigurationFile() + // write all the static ip address in the systemd-network conf file + + using namespace std::string_literals; +- using AddressOrigin = +- sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin; + namespace fs = std::experimental::filesystem; + + // if there is vlan interafce then write the configuration file +@@ -673,42 +733,45 @@ void EthernetInterface::writeConfigurationFile() + } + + // Add the DHCP entry +- auto value = dHCPEnabled() ? "true"s : "false"s; +- stream << "DHCP="s + value + "\n"; ++ std::string value = convertForMessage(EthernetInterfaceIntf::dHCPEnabled()); ++ std::string::size_type loc = value.rfind("."); ++ std::string requestedDHCPState = value.substr(loc + 1); ++ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState]; ++ stream << "DHCP="s + mappedDHCPState + "\n"; ++ ++ bool dhcpv6Requested = dhcpToBeEnabled(IP::Protocol::IPv6, mappedDHCPState); ++ bool dhcpv4Requested = dhcpToBeEnabled(IP::Protocol::IPv4, mappedDHCPState); ++ // Static IP addresses ++ for (const auto& addr : addrs) ++ { ++ bool isValidIPv4 = isValidIP(AF_INET, addr.second->address()); ++ bool isValidIPv6 = isValidIP(AF_INET6, addr.second->address()); ++ if (((!dhcpv4Requested && isValidIPv4) || ++ (!dhcpv6Requested && isValidIPv6)) && ++ addressIsStatic(addr.second->origin())) ++ { ++ // Process all static addresses ++ std::string address = addr.second->address() + "/" + ++ std::to_string(addr.second->prefixLength()); ++ ++ // build the address entries. Do not use [Network] shortcuts to ++ // insert address entries. ++ stream << "[Address]\n"; ++ stream << "Address=" << address << "\n"; ++ } ++ } + +- // When the interface configured as dhcp, we don't need below given entries +- // in config file. +- if (dHCPEnabled() == false) ++ if (manager.getSystemConf()) + { +- // Static +- for (const auto& addr : addrs) ++ const auto& gateway = manager.getSystemConf()->defaultGateway(); ++ if (!gateway.empty()) + { +- if (addr.second->origin() == AddressOrigin::Static +-#ifndef LINK_LOCAL_AUTOCONFIGURATION +- || addr.second->origin() == AddressOrigin::LinkLocal +-#endif +- ) +- { +- std::string address = +- addr.second->address() + "/" + +- std::to_string(addr.second->prefixLength()); +- +- stream << "Address=" << address << "\n"; +- } ++ stream << "Gateway=" << gateway << "\n"; + } +- +- if (manager.getSystemConf()) ++ const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); ++ if (!gateway6.empty()) + { +- const auto& gateway = manager.getSystemConf()->defaultGateway(); +- if (!gateway.empty()) +- { +- stream << "Gateway=" << gateway << "\n"; +- } +- const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); +- if (!gateway6.empty()) +- { +- stream << "Gateway=" << gateway6 << "\n"; +- } ++ stream << "Gateway=" << gateway6 << "\n"; + } + } + +@@ -819,7 +882,7 @@ std::string EthernetInterface::mACAddress(std::string value) + + void EthernetInterface::deleteAll() + { +- if (EthernetInterfaceIntf::dHCPEnabled()) ++ if (dhcpIsEnabled(IP::Protocol::IPv4, true)) + { + log<level::INFO>("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index 3e4cf12..a962751 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -91,7 +91,7 @@ class EthernetInterface : public Ifaces + * send. + */ + EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal = true); + + /** @brief Function to create ipaddress dbus object. +@@ -157,7 +157,34 @@ class EthernetInterface : public Ifaces + } + + /** Set value of DHCPEnabled */ +- bool dHCPEnabled(bool value) override; ++ DHCPConf dHCPEnabled(DHCPConf value) override; ++ ++ /** @brief Determines if DHCP is active for the IP::Protocol supplied. ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] ignoreProtocol - Allows IPv4 and IPv6 to be checked using a ++ * single call. ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpIsEnabled(IP::Protocol protocol, bool ignoreProtocol = false); ++ ++ /** @brief Determines if DHCP will be active following next reconfig ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] nextDHCPState - The new DHCP mode to take affect ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpToBeEnabled(IP::Protocol family, std::string& nextDHCPState); ++ ++ /** @brief Determines if the address is manually assigned ++ * @param[in] origin - The origin entry of the IP::Address ++ * @returns true/false value if the address is static ++ */ ++ bool addressIsStatic(IP::AddressOrigin origin); ++ ++ /** @brief Selectively disables DHCP ++ * @param[in] protocol - The IPv4 or IPv6 protocol to return to static ++ * addressing mode ++ */ ++ void disableDHCP(IP::Protocol protocol); + + /** @brief sets the MAC address. + * @param[in] value - MAC address which needs to be set on the system. +diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp +index 30dee8a..87fd68d 100644 +--- a/test/test_ethernet_interface.cpp ++++ b/test/test_ethernet_interface.cpp +@@ -58,7 +58,8 @@ class TestEthernetInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1, mac); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + int countIPObjects() +diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp +index 1dffc7e..e49b43f 100644 +--- a/test/test_vlan_interface.cpp ++++ b/test/test_vlan_interface.cpp +@@ -50,7 +50,8 @@ class TestVlanInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + void setConfDir() +diff --git a/types.hpp b/types.hpp +index 123067a..c4409fe 100644 +--- a/types.hpp ++++ b/types.hpp +@@ -1,5 +1,7 @@ + #pragma once + ++#include "ipaddress.hpp" ++ + #include <ifaddrs.h> + #include <netinet/in.h> + #include <systemd/sd-event.h> +@@ -50,6 +52,7 @@ struct AddrInfo + { + uint8_t addrType; + std::string ipaddress; ++ IP::AddressOrigin origin; + uint16_t prefix; + }; + +diff --git a/util.cpp b/util.cpp +index 13a607f..554d7f6 100644 +--- a/util.cpp ++++ b/util.cpp +@@ -410,9 +410,11 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf) + return "eth" + std::to_string(idx) + "addr"; + } + +-bool getDHCPValue(const std::string& confDir, const std::string& intf) ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf) + { +- bool dhcp = false; ++ EthernetInterfaceIntf::DHCPConf dhcp = ++ EthernetInterfaceIntf::DHCPConf::none; + // Get the interface mode value from systemd conf + // using namespace std::string_literals; + fs::path confPath = confDir; +@@ -434,7 +436,15 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf) + // There will be only single value for DHCP key. + if (values[0] == "true") + { +- dhcp = true; ++ dhcp = EthernetInterfaceIntf::DHCPConf::both; ++ } ++ else if (values[0] == "ipv4") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v4; ++ } ++ else if (values[0] == "ipv6") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v6; + } + return dhcp; + } +diff --git a/util.hpp b/util.hpp +index 251aa0d..ee11f4e 100644 +--- a/util.hpp ++++ b/util.hpp +@@ -13,12 +13,16 @@ + #include <sdbusplus/bus.hpp> + #include <string> + #include <string_view> ++#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp> + + namespace phosphor + { + namespace network + { + ++using EthernetInterfaceIntf = ++ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; ++ + constexpr auto IPV4_MIN_PREFIX_LENGTH = 1; + constexpr auto IPV4_MAX_PREFIX_LENGTH = 32; + constexpr auto IPV6_MAX_PREFIX_LENGTH = 64; +@@ -156,7 +160,8 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf); + * @param[in] confDir - Network configuration directory. + * @param[in] intf - Interface name. + */ +-bool getDHCPValue(const std::string& confDir, const std::string& intf); ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf); + + namespace internal + { +diff --git a/vlan_interface.cpp b/vlan_interface.cpp +index 73de4e8..26282cb 100644 +--- a/vlan_interface.cpp ++++ b/vlan_interface.cpp +@@ -22,7 +22,7 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + + VlanInterface::VlanInterface(sdbusplus::bus::bus& bus, +- const std::string& objPath, bool dhcpEnabled, ++ const std::string& objPath, DHCPConf dhcpEnabled, + uint32_t vlanID, EthernetInterface& intf, + Manager& parent) : + VlanIface(bus, objPath.c_str()), +diff --git a/vlan_interface.hpp b/vlan_interface.hpp +index a994d05..37ae7ee 100644 +--- a/vlan_interface.hpp ++++ b/vlan_interface.hpp +@@ -45,8 +45,8 @@ class VlanInterface : public VlanIface, + * @param[in] manager - network manager object. + */ + VlanInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, uint32_t vlanID, EthernetInterface& intf, +- Manager& manager); ++ DHCPConf dhcpEnabled, uint32_t vlanID, ++ EthernetInterface& intf, Manager& manager); + + /** @brief Delete this d-bus object. + */ +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch new file mode 100644 index 000000000..c05088990 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch @@ -0,0 +1,120 @@ +From 6d3d50c506e2d6b4982ff6040af9fd61edaa8beb Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Fri, 24 Jan 2020 13:30:39 -0800 +Subject: [PATCH] Enable conditional use of ETHTOOL features in the NIC driver + +The retrieval of the NIC speed, duplex, and autonegotiation +capabilities using the ETHTOOL driver extensions is not supported in +every NIC. + +Depending on the driver, the use of the ETHTOOL_GSET command may +result in undesirable messages being printed by the kernel. In order +to avoid these kernel messages a compile time switch is added. By +default the switch disables the use of the ETHTOOL features. Enable +the ETHTOOL feature by adding: + EXTRA_OECONF_append = " --enable-nic-ethtool=yes" +to the phosphor-network bbappend file. + +Tested: +Compiled the source without changing the bbappend file. The code +compiled as is, and after code was added that would cause a compile +time failure. +Loaded the code, and performed a Redfish read of the NIC. The +SpeedMbps field was confirmed to be set to 0. + +Enabled compiling the code by adding the EXTRA_OECONF entry to the +bbappend file. The code compiled as is, and failed to compile after +adding invalid code to the protected blocks. +Loaded the code, and performed a Redfish read of the NIC. The +SpeedMbps reported the correct link speed. + +Change-Id: If03e7d473d439ebb4a01b5d3f45e37ede2a5a84f +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + Makefile.am | 3 +++ + configure.ac | 10 ++++++++++ + ethernet_interface.cpp | 13 ++++++++----- + 3 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 2a54797..ff252fc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -99,6 +99,9 @@ phosphor_network_manager_CXXFLAGS = \ + $(PHOSPHOR_LOGGING_CFLAGS) \ + -DBOOST_ASIO_DISABLE_THREADS \ + -flto ++if FEATURE_NIC_ETHTOOL ++phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL ++endif + + xyz/openbmc_project/Network/VLAN/Create/server.cpp: xyz/openbmc_project/Network/VLAN/Create.interface.yaml xyz/openbmc_project/Network/VLAN/Create/server.hpp + @mkdir -p `dirname $@` +diff --git a/configure.ac b/configure.ac +index 00b23bc..fed3e09 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -114,6 +114,16 @@ AC_SUBST(DEFAULT_BUSNAME, ["$DEFAULT_BUSNAME"]) + AC_ARG_VAR(SYSTEMD_TARGET, "Target for starting this service") + AS_IF([test "x$SYSTEMD_TARGET" == "x"], [SYSTEMD_TARGET="multi-user.target"]) + ++AC_ARG_ENABLE([nic_ethtool], ++ [ --enable-nic-ethtool Enable/disable the use of ETHTOOL features in the NIC driver], ++ [case "${enableval}" in ++ yes) nic_ethtool=true ;; ++ no) nic_ethtool=false ;; ++ *) AC_MSG_ERROR([bad value ${nic_ethtool} for --enable-nic-ethtool]) ;; ++ esac],[nic_ethtool=false] ++ ) ++AM_CONDITIONAL([FEATURE_NIC_ETHTOOL], [test x$nic_ethtool = xtrue]) ++ + # Create configured output. + AC_CONFIG_FILES([Makefile test/Makefile]) + AC_CONFIG_FILES([xyz.openbmc_project.Network.service]) +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 7f81003..ba6195e 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -57,10 +57,12 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + MacAddressIntf::mACAddress(getMACAddress(intfName)); + EthernetInterfaceIntf::nTPServers(getNTPServersFromConf()); + EthernetInterfaceIntf::nameservers(getNameServerFromConf()); ++#if NIC_SUPPORTS_ETHTOOL + InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo(); + + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); ++#endif + getChannelPrivilege(intfName); + + // Emit deferred signal. +@@ -283,13 +285,13 @@ ObjectPath EthernetInterface::neighbor(std::string iPAddress, + return objectPath; + } + ++#if NIC_SUPPORTS_ETHTOOL + /* +-Note: We don't have support for ethtool now +-will enable this code once we bring the ethtool +-in the image. +-TODO: https://github.com/openbmc/openbmc/issues/1484 ++ Enable this code if your NIC driver supports the ETHTOOL features. ++ Do this by adding the following to your phosphor-network*.bbappend file. ++ EXTRA_OECONF_append = " --enable-nic-ethtool=yes" ++ The default compile mode is to omit getInterfaceInfo() + */ +- + InterfaceInfo EthernetInterface::getInterfaceInfo() const + { + int sock{-1}; +@@ -330,6 +332,7 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + } + return std::make_tuple(speed, duplex, autoneg); + } ++#endif + + /** @brief get the mac address of the interface. + * @return macaddress on success +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch new file mode 100644 index 000000000..e1972e815 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0008-Added-enable-disable-control-of-the-Network-Interfac.patch @@ -0,0 +1,191 @@ +From 0e415f23b7a97e9a0f0fa616b6bcccec6035bbed Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Tue, 29 Oct 2019 16:20:28 -0700 +Subject: [PATCH] Added enable/disable control of the Network Interface Card + +Implemented enable/disable function to perform +"ip link set eth(x) up" +"ip link set eth(x) down" +functionality from DBus. + +Tested: + +Confirmed Redfish PATCH commands on the InterfaceEnabled property +changes the NIC state. Confirmed the NIC is DOWN/UP using "ip link". +Confirmed "ip link" state changes can be obsserved from dbus-send +commands, and from Redfish GET actions. + +Confirmed the link is inactive after a reboot. + +Confirmed link stays down despite assigning an IP manually. + +Confirmed link stays down despite enabling DHCP. + +Change-Id: I4152b53055e6546f7a6ca81b5a5eef6f689bcc66 +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + ethernet_interface.cpp | 70 ++++++++++++++++++++++++++++++++++++++++-- + ethernet_interface.hpp | 7 ++++- + 2 files changed, 74 insertions(+), 3 deletions(-) + +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index ba6195e..671e8c4 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -60,6 +60,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + #if NIC_SUPPORTS_ETHTOOL + InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo(); + ++ EthernetInterfaceIntf::nICEnabled(std::get<3>(ifInfo)); + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); + #endif +@@ -300,6 +301,7 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + LinkSpeed speed{0}; + Autoneg autoneg{0}; + DuplexMode duplex{0}; ++ NICEnabled nicEnabled{false}; + do + { + sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); +@@ -324,13 +326,21 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + speed = edata.speed; + duplex = edata.duplex; + autoneg = edata.autoneg; ++ ++ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) ++ { ++ log<level::ERR>("ioctl failed for SIOCGIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ nicEnabled = static_cast<bool>(ifr.ifr_flags & IFF_UP); + } while (0); + +- if (sock) ++ if (sock >= 0) + { + close(sock); + } +- return std::make_tuple(speed, duplex, autoneg); ++ return std::make_tuple(speed, duplex, autoneg, nicEnabled); + } + #endif + +@@ -355,9 +365,11 @@ std::string + { + log<level::ERR>("ioctl failed for SIOCGIFHWADDR:", + entry("ERROR=%s", strerror(errno))); ++ close(sock); + elog<InternalFailure>(); + } + ++ close(sock); + static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr)); + std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data), + sizeof(ifr.ifr_hwaddr.sa_data)); +@@ -514,6 +526,55 @@ EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) + return value; + } + ++bool EthernetInterface::nICEnabled(bool value) ++{ ++ if (value == EthernetInterfaceIntf::nICEnabled()) ++ { ++ return value; ++ } ++ ++ int sock{-1}; ++ ifreq ifr{0}; ++ EthernetInterfaceIntf::nICEnabled(value); ++ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); ++ if (sock < 0) ++ { ++ log<level::ERR>("socket creation failed:", ++ entry("ERROR=%s", strerror(errno))); ++ return value; ++ } ++ ++ do ++ { ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE); ++ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) ++ { ++ log<level::ERR>("ioctl failed for SIOCGIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ ++ ifr.ifr_flags &= ~IFF_UP; ++ if (value) ++ { ++ ifr.ifr_flags |= IFF_UP; ++ } ++ ++ if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) ++ { ++ log<level::ERR>("ioctl failed for SIOCSIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ break; ++ } ++ } while (0); ++ ++ close(sock); ++ writeConfigurationFile(); ++ manager.restartSystemdUnit(networkdService); ++ ++ return value; ++} ++ + ServerList EthernetInterface::nameservers(ServerList value) + { + for (const auto& nameserverip : value) +@@ -704,6 +765,11 @@ void EthernetInterface::writeConfigurationFile() + stream << "MACAddress=" << mac << "\n"; + } + ++ if (!nICEnabled()) ++ { ++ stream << "Unmanaged=yes\n"; ++ } ++ + // write the network section + stream << "[Network]\n"; + #ifdef LINK_LOCAL_AUTOCONFIGURATION +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index a962751..3dee311 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -59,9 +59,10 @@ class Neighbor; + using LinkSpeed = uint16_t; + using DuplexMode = uint8_t; + using Autoneg = uint8_t; ++using NICEnabled = bool; + using VlanId = uint32_t; + using InterfaceName = std::string; +-using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg>; ++using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg, NICEnabled>; + using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>; + using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>; + using VlanInterfaceMap = +@@ -186,6 +187,9 @@ class EthernetInterface : public Ifaces + */ + void disableDHCP(IP::Protocol protocol); + ++ /** Set value of NICEnabled */ ++ bool nICEnabled(bool value) override; ++ + /** @brief sets the MAC address. + * @param[in] value - MAC address which needs to be set on the system. + * @returns macAddress of the interface or throws an error. +@@ -241,6 +245,7 @@ class EthernetInterface : public Ifaces + using ChannelAccessIntf::maxPrivilege; + using EthernetInterfaceIntf::dHCPEnabled; + using EthernetInterfaceIntf::interfaceName; ++ using EthernetInterfaceIntf::nICEnabled; + using MacAddressIntf::mACAddress; + + /** @brief Absolute path of the resolv conf file */ +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch new file mode 100644 index 000000000..b6cf8f77d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch @@ -0,0 +1,504 @@ +From 42f361622a9c029221c8a90f92104703166e48c2 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Thu, 30 Jan 2020 15:07:39 -0800 +Subject: [PATCH] Enhance DHCP beyond just OFF and IPv4/IPv6 enabled. + +DHCP is not a binary option. The network interface can have DHCP +disabled, IPv4 only, IPv6 only, and IPv4/IPv6. + +Tested: +Using dbus-send or busctl: +Disabled DHCP, and confirmed only link local addresses were present. + +Assigned only static addresses. Both with/and without the gateway set +to 0.0.0.0 + +Deleted static IPv4 addresses. +Reassigned static addresses. + +Enabled DHCP for ipv4 only, and witnessed a DHCP server assign a valid +address. + +Assigned static IPv4 address. +Assigned static IPv6 address. +Confirmed both IPv4 and IPv6 static addresses are active. + +Enabled DHCP for ipv6 only, and confirmed the static v4 address +remains. The ipv6 address is removed, waiting for a DHCP6 server. + +Enabled DHCP for both ipv4 and ipv6. IPv4 address was assigned. IPv6 +address is assumed to succeed, as systemd config file enables IPv6 +DHCP. + +Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162 +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + Makefile.am | 1 + + configure.ac | 1 + + ethernet_interface.cpp | 147 ++++++++++++++++++++++--------- + ethernet_interface.hpp | 31 ++++++- + test/test_ethernet_interface.cpp | 3 +- + test/test_vlan_interface.cpp | 3 +- + types.hpp | 3 + + util.cpp | 16 +++- + util.hpp | 7 +- + vlan_interface.cpp | 2 +- + vlan_interface.hpp | 4 +- + 11 files changed, 165 insertions(+), 53 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 1c47747..ff252fc 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -97,6 +97,7 @@ phosphor_network_manager_CXXFLAGS = \ + $(SDEVENTPLUS_CFLAGS) \ + $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ + $(PHOSPHOR_LOGGING_CFLAGS) \ ++ -DBOOST_ASIO_DISABLE_THREADS \ + -flto + if FEATURE_NIC_ETHTOOL + phosphor_network_manager_CXXFLAGS += -DNIC_SUPPORTS_ETHTOOL +diff --git a/configure.ac b/configure.ac +index 12d6caa..fed3e09 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++]) + PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging]) + PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces]) + PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0]) ++AC_CHECK_HEADER(boost/algorithm/string/split.hpp, [], [AC_MSG_ERROR([Could not find boost/algorithm/string/split.hpp])]) + + # Checks for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,\ +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 73fd8fe..ba6195e 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -3,7 +3,6 @@ + #include "ethernet_interface.hpp" + + #include "config_parser.hpp" +-#include "ipaddress.hpp" + #include "neighbor.hpp" + #include "network_manager.hpp" + #include "vlan_interface.hpp" +@@ -40,9 +39,12 @@ using Argument = xyz::openbmc_project::Common::InvalidArgument; + static constexpr const char* networkChannelCfgFile = + "/var/channel_intf_data.json"; + static constexpr const char* defaultChannelPriv = "priv-admin"; ++std::map<std::string, std::string> mapDHCPToSystemd = { ++ {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; ++ + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal) : + Ifaces(bus, objPath.c_str(), true), + bus(bus), manager(parent), objPath(objPath) +@@ -83,6 +85,65 @@ static IP::Protocol convertFamily(int family) + throw std::invalid_argument("Bad address family"); + } + ++void EthernetInterface::disableDHCP(IP::Protocol protocol) ++{ ++ DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled(); ++ if (dhcpState == EthernetInterface::DHCPConf::both) ++ { ++ if (protocol == IP::Protocol::IPv4) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v6); ++ } ++ else if (protocol == IP::Protocol::IPv6) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::v4); ++ } ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v4) && ++ (protocol == IP::Protocol::IPv4)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++ else if ((dhcpState == EthernetInterface::DHCPConf::v6) && ++ (protocol == IP::Protocol::IPv6)) ++ { ++ dHCPEnabled(EthernetInterface::DHCPConf::none); ++ } ++} ++ ++bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol) ++{ ++ return ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::both) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v6) && ++ ((family == IP::Protocol::IPv6) || ignoreProtocol)) || ++ ((EthernetInterfaceIntf::dHCPEnabled() == ++ EthernetInterface::DHCPConf::v4) && ++ ((family == IP::Protocol::IPv4) || ignoreProtocol))); ++} ++ ++bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family, ++ std::string& nextDHCPState) ++{ ++ return ((nextDHCPState == "true") || ++ ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) || ++ ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4))); ++} ++ ++bool EthernetInterface::addressIsStatic(IP::AddressOrigin origin) ++{ ++ return ( ++#ifdef LINK_LOCAL_AUTOCONFIGURATION ++ (origin == IP::AddressOrigin::Static) ++#else ++ (origin == IP::AddressOrigin::Static || ++ origin == IP::AddressOrigin::LinkLocal) ++#endif ++ ++ ); ++} ++ + void EthernetInterface::createIPAddressObjects() + { + addrs.clear(); +@@ -93,7 +154,7 @@ void EthernetInterface::createIPAddressObjects() + { + IP::Protocol addressType = convertFamily(addr.addrType); + IP::AddressOrigin origin = IP::AddressOrigin::Static; +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(addressType)) + { + origin = IP::AddressOrigin::DHCP; + } +@@ -154,11 +215,11 @@ ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress, + uint8_t prefixLength, std::string gateway) + { + +- if (dHCPEnabled()) ++ if (dhcpIsEnabled(protType)) + { + log<level::INFO>("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +- dHCPEnabled(false); ++ disableDHCP(protType); + } + + IP::AddressOrigin origin = IP::AddressOrigin::Static; +@@ -441,7 +502,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value) + return value; + } + +-bool EthernetInterface::dHCPEnabled(bool value) ++EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value) + { + if (value == EthernetInterfaceIntf::dHCPEnabled()) + { +@@ -508,7 +569,7 @@ void EthernetInterface::loadVLAN(VlanId id) + std::string path = objPath; + path += "_" + std::to_string(id); + +- auto dhcpEnabled = ++ DHCPConf dhcpEnabled = + getDHCPValue(manager.getConfDir().string(), vlanInterfaceName); + + auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>( +@@ -530,7 +591,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id) + path += "_" + std::to_string(id); + + auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>( +- bus, path.c_str(), false, id, *this, manager); ++ bus, path.c_str(), EthernetInterface::DHCPConf::none, id, *this, ++ manager); + + // write the device file for the vlan interface. + vlanIntf->writeDeviceFile(); +@@ -603,8 +665,6 @@ void EthernetInterface::writeConfigurationFile() + // write all the static ip address in the systemd-network conf file + + using namespace std::string_literals; +- using AddressOrigin = +- sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin; + namespace fs = std::experimental::filesystem; + + // if there is vlan interafce then write the configuration file +@@ -673,42 +733,45 @@ void EthernetInterface::writeConfigurationFile() + } + + // Add the DHCP entry +- auto value = dHCPEnabled() ? "true"s : "false"s; +- stream << "DHCP="s + value + "\n"; ++ std::string value = convertForMessage(EthernetInterfaceIntf::dHCPEnabled()); ++ std::string::size_type loc = value.rfind("."); ++ std::string requestedDHCPState = value.substr(loc + 1); ++ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState]; ++ stream << "DHCP="s + mappedDHCPState + "\n"; ++ ++ bool dhcpv6Requested = dhcpToBeEnabled(IP::Protocol::IPv6, mappedDHCPState); ++ bool dhcpv4Requested = dhcpToBeEnabled(IP::Protocol::IPv4, mappedDHCPState); ++ // Static IP addresses ++ for (const auto& addr : addrs) ++ { ++ bool isValidIPv4 = isValidIP(AF_INET, addr.second->address()); ++ bool isValidIPv6 = isValidIP(AF_INET6, addr.second->address()); ++ if (((!dhcpv4Requested && isValidIPv4) || ++ (!dhcpv6Requested && isValidIPv6)) && ++ addressIsStatic(addr.second->origin())) ++ { ++ // Process all static addresses ++ std::string address = addr.second->address() + "/" + ++ std::to_string(addr.second->prefixLength()); ++ ++ // build the address entries. Do not use [Network] shortcuts to ++ // insert address entries. ++ stream << "[Address]\n"; ++ stream << "Address=" << address << "\n"; ++ } ++ } + +- // When the interface configured as dhcp, we don't need below given entries +- // in config file. +- if (dHCPEnabled() == false) ++ if (manager.getSystemConf()) + { +- // Static +- for (const auto& addr : addrs) ++ const auto& gateway = manager.getSystemConf()->defaultGateway(); ++ if (!gateway.empty()) + { +- if (addr.second->origin() == AddressOrigin::Static +-#ifndef LINK_LOCAL_AUTOCONFIGURATION +- || addr.second->origin() == AddressOrigin::LinkLocal +-#endif +- ) +- { +- std::string address = +- addr.second->address() + "/" + +- std::to_string(addr.second->prefixLength()); +- +- stream << "Address=" << address << "\n"; +- } ++ stream << "Gateway=" << gateway << "\n"; + } +- +- if (manager.getSystemConf()) ++ const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); ++ if (!gateway6.empty()) + { +- const auto& gateway = manager.getSystemConf()->defaultGateway(); +- if (!gateway.empty()) +- { +- stream << "Gateway=" << gateway << "\n"; +- } +- const auto& gateway6 = manager.getSystemConf()->defaultGateway6(); +- if (!gateway6.empty()) +- { +- stream << "Gateway=" << gateway6 << "\n"; +- } ++ stream << "Gateway=" << gateway6 << "\n"; + } + } + +@@ -819,7 +882,7 @@ std::string EthernetInterface::mACAddress(std::string value) + + void EthernetInterface::deleteAll() + { +- if (EthernetInterfaceIntf::dHCPEnabled()) ++ if (dhcpIsEnabled(IP::Protocol::IPv4, true)) + { + log<level::INFO>("DHCP enabled on the interface"), + entry("INTERFACE=%s", interfaceName().c_str()); +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index 3e4cf12..a962751 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -91,7 +91,7 @@ class EthernetInterface : public Ifaces + * send. + */ + EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, Manager& parent, ++ DHCPConf dhcpEnabled, Manager& parent, + bool emitSignal = true); + + /** @brief Function to create ipaddress dbus object. +@@ -157,7 +157,34 @@ class EthernetInterface : public Ifaces + } + + /** Set value of DHCPEnabled */ +- bool dHCPEnabled(bool value) override; ++ DHCPConf dHCPEnabled(DHCPConf value) override; ++ ++ /** @brief Determines if DHCP is active for the IP::Protocol supplied. ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] ignoreProtocol - Allows IPv4 and IPv6 to be checked using a ++ * single call. ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpIsEnabled(IP::Protocol protocol, bool ignoreProtocol = false); ++ ++ /** @brief Determines if DHCP will be active following next reconfig ++ * @param[in] protocol - Either IPv4 or IPv6 ++ * @param[in] nextDHCPState - The new DHCP mode to take affect ++ * @returns true/false value if DHCP is active for the input protocol ++ */ ++ bool dhcpToBeEnabled(IP::Protocol family, std::string& nextDHCPState); ++ ++ /** @brief Determines if the address is manually assigned ++ * @param[in] origin - The origin entry of the IP::Address ++ * @returns true/false value if the address is static ++ */ ++ bool addressIsStatic(IP::AddressOrigin origin); ++ ++ /** @brief Selectively disables DHCP ++ * @param[in] protocol - The IPv4 or IPv6 protocol to return to static ++ * addressing mode ++ */ ++ void disableDHCP(IP::Protocol protocol); + + /** @brief sets the MAC address. + * @param[in] value - MAC address which needs to be set on the system. +diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp +index 30dee8a..87fd68d 100644 +--- a/test/test_ethernet_interface.cpp ++++ b/test/test_ethernet_interface.cpp +@@ -58,7 +58,8 @@ class TestEthernetInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1, mac); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + int countIPObjects() +diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp +index 1dffc7e..e49b43f 100644 +--- a/test/test_vlan_interface.cpp ++++ b/test/test_vlan_interface.cpp +@@ -50,7 +50,8 @@ class TestVlanInterface : public testing::Test + { + mock_clear(); + mock_addIF("test0", 1); +- return {bus, "/xyz/openbmc_test/network/test0", false, manager}; ++ return {bus, "/xyz/openbmc_test/network/test0", ++ EthernetInterface::DHCPConf::none, manager}; + } + + void setConfDir() +diff --git a/types.hpp b/types.hpp +index 123067a..c4409fe 100644 +--- a/types.hpp ++++ b/types.hpp +@@ -1,5 +1,7 @@ + #pragma once + ++#include "ipaddress.hpp" ++ + #include <ifaddrs.h> + #include <netinet/in.h> + #include <systemd/sd-event.h> +@@ -50,6 +52,7 @@ struct AddrInfo + { + uint8_t addrType; + std::string ipaddress; ++ IP::AddressOrigin origin; + uint16_t prefix; + }; + +diff --git a/util.cpp b/util.cpp +index 13a607f..554d7f6 100644 +--- a/util.cpp ++++ b/util.cpp +@@ -410,9 +410,11 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf) + return "eth" + std::to_string(idx) + "addr"; + } + +-bool getDHCPValue(const std::string& confDir, const std::string& intf) ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf) + { +- bool dhcp = false; ++ EthernetInterfaceIntf::DHCPConf dhcp = ++ EthernetInterfaceIntf::DHCPConf::none; + // Get the interface mode value from systemd conf + // using namespace std::string_literals; + fs::path confPath = confDir; +@@ -434,7 +436,15 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf) + // There will be only single value for DHCP key. + if (values[0] == "true") + { +- dhcp = true; ++ dhcp = EthernetInterfaceIntf::DHCPConf::both; ++ } ++ else if (values[0] == "ipv4") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v4; ++ } ++ else if (values[0] == "ipv6") ++ { ++ dhcp = EthernetInterfaceIntf::DHCPConf::v6; + } + return dhcp; + } +diff --git a/util.hpp b/util.hpp +index 251aa0d..ee11f4e 100644 +--- a/util.hpp ++++ b/util.hpp +@@ -13,12 +13,16 @@ + #include <sdbusplus/bus.hpp> + #include <string> + #include <string_view> ++#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp> + + namespace phosphor + { + namespace network + { + ++using EthernetInterfaceIntf = ++ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; ++ + constexpr auto IPV4_MIN_PREFIX_LENGTH = 1; + constexpr auto IPV4_MAX_PREFIX_LENGTH = 32; + constexpr auto IPV6_MAX_PREFIX_LENGTH = 64; +@@ -156,7 +160,8 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf); + * @param[in] confDir - Network configuration directory. + * @param[in] intf - Interface name. + */ +-bool getDHCPValue(const std::string& confDir, const std::string& intf); ++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir, ++ const std::string& intf); + + namespace internal + { +diff --git a/vlan_interface.cpp b/vlan_interface.cpp +index 73de4e8..26282cb 100644 +--- a/vlan_interface.cpp ++++ b/vlan_interface.cpp +@@ -22,7 +22,7 @@ using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + + VlanInterface::VlanInterface(sdbusplus::bus::bus& bus, +- const std::string& objPath, bool dhcpEnabled, ++ const std::string& objPath, DHCPConf dhcpEnabled, + uint32_t vlanID, EthernetInterface& intf, + Manager& parent) : + VlanIface(bus, objPath.c_str()), +diff --git a/vlan_interface.hpp b/vlan_interface.hpp +index a994d05..37ae7ee 100644 +--- a/vlan_interface.hpp ++++ b/vlan_interface.hpp +@@ -45,8 +45,8 @@ class VlanInterface : public VlanIface, + * @param[in] manager - network manager object. + */ + VlanInterface(sdbusplus::bus::bus& bus, const std::string& objPath, +- bool dhcpEnabled, uint32_t vlanID, EthernetInterface& intf, +- Manager& manager); ++ DHCPConf dhcpEnabled, uint32_t vlanID, ++ EthernetInterface& intf, Manager& manager); + + /** @brief Delete this d-bus object. + */ +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch new file mode 100644 index 000000000..51957ffff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0010-Enable-the-network-link-carrier-state-to-be-reported.patch @@ -0,0 +1,282 @@ +From 8f6f3ccb1f5a4af8065485c2e683402ec2b38abf Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Wed, 8 Jan 2020 10:38:58 -0800 +Subject: [PATCH] Enable the network link carrier state to be reported. + +This change allows networkd to keep track of, and report, the state of +the network carrier signal. When a NIC cable is pulled, or inserted, a +DBus client is able identify the condition. + +Tested: +ip link set down dev eth0 # take eth0 down +Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = LinkDown + # InterfaceEnabled = false +ip link set up dev eth0 # bring eth0 back +Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = Linkup + # InterfaceEnabled = true +Pull eth0 cable +Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = LinkDown + # InterfaceEnabled = true +Insert eth0 cable +Get bmc/EthernetInterfaces/eth0 from Redfish # LinkStatus = Linkup + # InterfaceEnabled = true + +Change-Id: I5530cf7882cfbfdba1436dd34b3219c735047c5e +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + ethernet_interface.cpp | 141 +++++++++++++++++++++++++---------------- + ethernet_interface.hpp | 8 ++- + 2 files changed, 92 insertions(+), 57 deletions(-) + +diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp +index 671e8c4..018f2e1 100644 +--- a/ethernet_interface.cpp ++++ b/ethernet_interface.cpp +@@ -42,6 +42,28 @@ static constexpr const char* defaultChannelPriv = "priv-admin"; + std::map<std::string, std::string> mapDHCPToSystemd = { + {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}}; + ++struct EthernetIntfSocket ++{ ++ EthernetIntfSocket(int domain, int type, int protocol) ++ { ++ if ((sock = socket(domain, type, protocol)) < 0) ++ { ++ log<level::ERR>("socket creation failed:", ++ entry("ERROR=%s", strerror(errno))); ++ } ++ } ++ ++ ~EthernetIntfSocket() ++ { ++ if (sock > 0) ++ { ++ close(sock); ++ } ++ } ++ ++ int sock{-1}; ++}; ++ + EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + const std::string& objPath, + DHCPConf dhcpEnabled, Manager& parent, +@@ -57,12 +79,12 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, + MacAddressIntf::mACAddress(getMACAddress(intfName)); + EthernetInterfaceIntf::nTPServers(getNTPServersFromConf()); + EthernetInterfaceIntf::nameservers(getNameServerFromConf()); +-#if NIC_SUPPORTS_ETHTOOL + InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo(); +- +- EthernetInterfaceIntf::nICEnabled(std::get<3>(ifInfo)); ++#if NIC_SUPPORTS_ETHTOOL + EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); + EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); ++ EthernetInterfaceIntf::nICEnabled(std::get<3>(ifInfo)); ++ EthernetInterfaceIntf::linkUp(std::get<4>(ifInfo)); + #endif + getChannelPrivilege(intfName); + +@@ -286,63 +308,47 @@ ObjectPath EthernetInterface::neighbor(std::string iPAddress, + return objectPath; + } + +-#if NIC_SUPPORTS_ETHTOOL +-/* +- Enable this code if your NIC driver supports the ETHTOOL features. +- Do this by adding the following to your phosphor-network*.bbappend file. +- EXTRA_OECONF_append = " --enable-nic-ethtool=yes" +- The default compile mode is to omit getInterfaceInfo() +-*/ + InterfaceInfo EthernetInterface::getInterfaceInfo() const + { +- int sock{-1}; +- ifreq ifr{0}; +- ethtool_cmd edata{0}; + LinkSpeed speed{0}; + Autoneg autoneg{0}; + DuplexMode duplex{0}; + NICEnabled nicEnabled{false}; +- do +- { +- sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); +- if (sock < 0) +- { +- log<level::ERR>("socket creation failed:", +- entry("ERROR=%s", strerror(errno))); +- break; +- } ++ LinkUp linkState{false}; + +- strcpy(ifr.ifr_name, interfaceName().c_str()); +- ifr.ifr_data = reinterpret_cast<char*>(&edata); ++#if NIC_SUPPORTS_ETHTOOL ++ /* ++ Enable this code if your NIC driver supports the ETHTOOL features. ++ Do this by adding the following to your phosphor-network*.bbappend ++ file. EXTRA_OECONF_append = " --enable-nic-ethtool=yes" The ++ default compile mode is to omit getInterfaceInfo() ++ */ ++ ifreq ifr{0}; ++ ethtool_cmd edata{0}; ++ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + +- edata.cmd = ETHTOOL_GSET; ++ if (eifSocket.sock < 0) ++ { ++ return std::make_tuple(speed, duplex, autoneg, nicEnabled, linkState); ++ } + +- if (ioctl(sock, SIOCETHTOOL, &ifr) < 0) +- { +- log<level::ERR>("ioctl failed for SIOCETHTOOL:", +- entry("ERROR=%s", strerror(errno))); +- break; +- } ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1); ++ ifr.ifr_data = reinterpret_cast<char*>(&edata); ++ ++ edata.cmd = ETHTOOL_GSET; ++ if (ioctl(eifSocket.sock, SIOCETHTOOL, &ifr) >= 0) ++ { + speed = edata.speed; + duplex = edata.duplex; + autoneg = edata.autoneg; ++ } ++#endif + +- if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) +- { +- log<level::ERR>("ioctl failed for SIOCGIFFLAGS:", +- entry("ERROR=%s", strerror(errno))); +- break; +- } +- nicEnabled = static_cast<bool>(ifr.ifr_flags & IFF_UP); +- } while (0); ++ nicEnabled = nICEnabled(); ++ linkState = linkUp(); + +- if (sock >= 0) +- { +- close(sock); +- } +- return std::make_tuple(speed, duplex, autoneg, nicEnabled); ++ return std::make_tuple(speed, duplex, autoneg, nicEnabled, linkState); + } +-#endif + + /** @brief get the mac address of the interface. + * @return macaddress on success +@@ -351,25 +357,23 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const + std::string + EthernetInterface::getMACAddress(const std::string& interfaceName) const + { +- ifreq ifr{}; +- int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); +- if (sock < 0) ++ std::string activeMACAddr = MacAddressIntf::mACAddress(); ++ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); ++ ++ if (eifSocket.sock < 0) + { +- log<level::ERR>("socket creation failed:", +- entry("ERROR=%s", strerror(errno))); +- elog<InternalFailure>(); ++ return activeMACAddr; + } + +- std::strcpy(ifr.ifr_name, interfaceName.c_str()); +- if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) ++ ifreq ifr{0}; ++ std::strncpy(ifr.ifr_name, interfaceName.c_str(), IFNAMSIZ - 1); ++ if (ioctl(eifSocket.sock, SIOCGIFHWADDR, &ifr) != 0) + { + log<level::ERR>("ioctl failed for SIOCGIFHWADDR:", + entry("ERROR=%s", strerror(errno))); +- close(sock); + elog<InternalFailure>(); + } + +- close(sock); + static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= sizeof(ether_addr)); + std::string_view hwaddr(reinterpret_cast<char*>(ifr.ifr_hwaddr.sa_data), + sizeof(ifr.ifr_hwaddr.sa_data)); +@@ -546,7 +550,7 @@ bool EthernetInterface::nICEnabled(bool value) + + do + { +- std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE); ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1); + if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) + { + log<level::ERR>("ioctl failed for SIOCGIFFLAGS:", +@@ -575,6 +579,31 @@ bool EthernetInterface::nICEnabled(bool value) + return value; + } + ++bool EthernetInterface::linkUp() const ++{ ++ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP); ++ bool value = EthernetInterfaceIntf::linkUp(); ++ ++ if (eifSocket.sock < 0) ++ { ++ return value; ++ } ++ ++ ifreq ifr{0}; ++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1); ++ if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0) ++ { ++ value = static_cast<bool>(ifr.ifr_flags & IFF_RUNNING); ++ } ++ else ++ { ++ log<level::ERR>("ioctl failed for SIOCGIFFLAGS:", ++ entry("ERROR=%s", strerror(errno))); ++ } ++ ++ return value; ++} ++ + ServerList EthernetInterface::nameservers(ServerList value) + { + for (const auto& nameserverip : value) +diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp +index 3dee311..83d7cb5 100644 +--- a/ethernet_interface.hpp ++++ b/ethernet_interface.hpp +@@ -60,9 +60,11 @@ using LinkSpeed = uint16_t; + using DuplexMode = uint8_t; + using Autoneg = uint8_t; + using NICEnabled = bool; ++using LinkUp = bool; + using VlanId = uint32_t; + using InterfaceName = std::string; +-using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg, NICEnabled>; ++using InterfaceInfo = ++ std::tuple<LinkSpeed, DuplexMode, Autoneg, NICEnabled, LinkUp>; + using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>; + using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>; + using VlanInterfaceMap = +@@ -190,6 +192,9 @@ class EthernetInterface : public Ifaces + /** Set value of NICEnabled */ + bool nICEnabled(bool value) override; + ++ /** Retrieve Link State */ ++ bool linkUp() const override; ++ + /** @brief sets the MAC address. + * @param[in] value - MAC address which needs to be set on the system. + * @returns macAddress of the interface or throws an error. +@@ -245,6 +250,7 @@ class EthernetInterface : public Ifaces + using ChannelAccessIntf::maxPrivilege; + using EthernetInterfaceIntf::dHCPEnabled; + using EthernetInterfaceIntf::interfaceName; ++ using EthernetInterfaceIntf::linkUp; + using EthernetInterfaceIntf::nICEnabled; + using MacAddressIntf::mACAddress; + +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend new file mode 100644 index 000000000..5279b2e52 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend @@ -0,0 +1,14 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += "nlohmann-json boost" + +SRC_URI += "git://github.com/openbmc/phosphor-networkd" +SRC_URI += "file://0003-Adding-channel-specific-privilege-to-network.patch \ + file://0005-Enable-conditional-use-of-ETHTOOL-features-in-the-NI.patch \ + file://0008-Added-enable-disable-control-of-the-Network-Interfac.patch \ + file://0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch \ + file://0010-Enable-the-network-link-carrier-state-to-be-reported.patch \ + " +SRCREV = "dbd328d7e037b1af13fb0f20f3708e2261b9e0b6" + +EXTRA_OECONF_append = " --enable-nic-ethtool=yes" diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb new file mode 100644 index 000000000..0dab0fc1a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb @@ -0,0 +1,24 @@ +SUMMARY = "Enforce static MAC addresses" +DESCRIPTION = "Set a priority on MAC addresses to run with: \ + factory-specified > u-boot-specified > random" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PV = "1.0" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRC_URI = "\ + file://mac-check \ + file://${PN}.service \ + " + +inherit obmc-phosphor-systemd + +SYSTEMD_SERVICE_${PN} += "${PN}.service" + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/mac-check ${D}${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check new file mode 100644 index 000000000..639b6c5ee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check @@ -0,0 +1,79 @@ +#!/bin/sh +# Copyright 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +read_hw_mac() { + local iface="$1" + cat /sys/class/net/"$iface"/address +} + +set_hw_mac() { + local iface="$1" + local mac="$2" + ip link show dev "$iface" | grep -q "${iface}:.*\<UP\>" 2>/dev/null + local up=$? + [[ $up -eq 0 ]] && ip link set dev "$iface" down + ip link set dev "$iface" address "$mac" + [[ $up -eq 0 ]] && ip link set dev "$iface" up +} + +SOFS_MNT=/var/sofs +read_sofs_mac() { + local iface="$1" + cat "${SOFS_MNT}/factory-settings/network/mac/${iface}" 2>/dev/null +} + +read_fw_env_mac() { + local envname="$1" + fw_printenv "$envname" 2>/dev/null | sed "s/^$envname=//" +} + +set_fw_env_mac() { + local envname="$1" + local mac="$2" + fw_setenv "$envname" "$mac" +} + +mac_check() { + local iface="$1" + local envname="$2" + + # read current HW MAC addr + local hw_mac=$(read_hw_mac "$iface") + + # read saved sofs MAC addr + local sofs_mac=$(read_sofs_mac "$iface") + + # if set and not the same as HW addr, set HW addr + if [ -n "$sofs_mac" ] && [ "$hw_mac" != "$sofs_mac" ]; then + set_hw_mac "$iface" "$sofs_mac" + hw_mac="$sofs_mac" + fi + + # read saved fw_env MAC addr + local fw_env_mac=$(read_fw_env_mac "$envname") + + # save to fw_env if not the same as HW addr + if [ -z "$fw_env_mac" ] || [ "$fw_env_mac" != "$hw_mac" ]; then + set_fw_env_mac "$envname" "$hw_mac" + fi +} + +mkdir -p ${SOFS_MNT}/factory-settings/network/mac +while read IFACE UBDEV; do + mac_check "$IFACE" "$UBDEV" +done <<-END_CONF + eth0 eth1addr + eth1 ethaddr +END_CONF diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service new file mode 100644 index 000000000..86371db11 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service @@ -0,0 +1,11 @@ +[Unit] +Description=Enforce Static MAC addr mapping + +[Service] +Type=oneshot +Restart=no +ExecStart=/usr/bin/mac-check + +[Install] +WantedBy=network.target + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb new file mode 100644 index 000000000..1bf81d953 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb @@ -0,0 +1,25 @@ + +SUMMARY = "Beep code manager service" +DESCRIPTION = "The beep code manager service will provide a method for beep code" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://beepcode_mgr.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +SYSTEMD_SERVICE_${PN} = "beepcode-mgr.service" + +inherit cmake +inherit obmc-phosphor-systemd + +DEPENDS += " \ + sdbusplus \ + phosphor-logging \ + boost \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt new file mode 100644 index 000000000..472257279 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (beepcode-mgr CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +add_executable (beepcode-mgr beepcode_mgr.cpp) + +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES} + phosphor_logging) + +install (TARGETS beepcode-mgr DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service new file mode 100644 index 000000000..8099e2541 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service @@ -0,0 +1,12 @@ +[Unit] +Description=Beep code manager + +[Service] +Restart=always +RestartSec=2 +ExecStart=/usr/bin/beepcode-mgr +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp new file mode 100644 index 000000000..2940610da --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp @@ -0,0 +1,325 @@ +/* Copyright 2019 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <linux/input.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <chrono> +#include <iostream> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> + +static constexpr uint32_t defaultBeepFrequence = 2000; +static constexpr uint32_t defaultBeepDurationMs = 300; +// Duration between two beeps +static constexpr uint32_t defaultInterBeepDurationMs = 300; +// Duration between two 4-bit digitals +static constexpr uint32_t defaultInterDigitBeepDurationMs = 800; +// Duration between two patterns +static constexpr uint32_t defaultPostBeepDurationMs = 1000; + +static constexpr uint8_t offBeepState = 0; +static constexpr uint8_t onBeepState = 1; +// finish 1 bit beep +static constexpr uint8_t interBeepState = 2; +// finish 4 bits beep +static constexpr uint8_t interDigitBeepState = 3; +// finish all bits beep +static constexpr uint8_t postBeepState = 4; + +static const std::vector<uint32_t> beepDelayTable = { + 0, defaultBeepDurationMs, defaultInterBeepDurationMs, + defaultInterDigitBeepDurationMs, defaultPostBeepDurationMs}; + +static constexpr uint32_t bpBitCount = 4; +static constexpr uint32_t bpShiftCount = 32; +static constexpr uint32_t bpMask = 0xf0000000; + +// beep code priority +static constexpr uint8_t beepOff = 0; +static constexpr uint8_t beepVRWatchdogTimeout = 1; +static constexpr uint8_t beepPSUFailure = 2; +static constexpr uint8_t beepCPUMIssing = 3; +static constexpr uint8_t beepCPUCatError = 4; +static constexpr uint8_t beepCPUErr2 = 5; +static constexpr uint8_t beepVoltageMismatch = 6; +static constexpr uint8_t beepCPUConfigError = 7; +static constexpr uint8_t beepPowerFail = 8; +static constexpr uint8_t beepPowerGoodTimeOut = 9; +static constexpr uint8_t beepMax = 10; + +// priority, abbrev name map +static const std::map<uint8_t, std::string> beepCodeNameList = { + {beepVRWatchdogTimeout, "VRWatchdogTimeout"}, + {beepPSUFailure, "PSUFailure"}, + {beepCPUMIssing, "CPUMissing"}, + {beepCPUCatError, "CPUCatError"}, + {beepCPUErr2, "CPUErr2"}, + {beepVoltageMismatch, "VoltageMismatch"}, + {beepCPUConfigError, "CPUConfigError"}, + {beepPowerFail, "PowerFail"}, + {beepPowerGoodTimeOut, "PowerGoodTimeOut"}, +}; + +// priority, code pattern map +static const std::map<uint8_t, std::string> beepCodePatternList = { + {beepVRWatchdogTimeout, "1-5-1-2"}, {beepPSUFailure, "1-5-1-4"}, + {beepCPUMIssing, "1-5-2-1"}, {beepCPUCatError, "1-5-2-2"}, + {beepCPUErr2, "1-5-2-3"}, {beepVoltageMismatch, "1-5-2-4"}, + {beepCPUConfigError, "1-5-2-5"}, {beepPowerFail, "1-5-4-2"}, + {beepPowerGoodTimeOut, "1-5-4-4"}, +}; + +static const std::vector<uint32_t> beepCodeTable = { + 0, 0x1512, 0x1514, 0x1521, 0x1522, 0x1523, 0x1524, 0x1525, 0x1542, 0x1544}; + +static constexpr char bpDevName[] = "/dev/input/event0"; +static constexpr char bpBusName[] = "xyz.openbmc_project.BeepCode"; +static constexpr char bpObjName[] = "/xyz/openbmc_project/BeepCode"; +static constexpr char bpIntfName[] = "xyz.openbmc_project.BeepCode"; +static constexpr char bpMethodName[] = "Beep"; + +static std::shared_ptr<sdbusplus::asio::dbus_interface> bpIface; +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); + +class Beeper +{ + public: + Beeper(boost::asio::io_service& io) + { + timer = std::make_unique<boost::asio::steady_timer>(io); + fdBeepDev = -1; + currentCount = 0; + currentBeepCode = 0; + currentMask = bpMask; + currentShift = bpShiftCount; + currentState = offBeepState; + timerRunning = false; + } + + ~Beeper() + { + } + + void beep(const uint8_t& beepPriority) + { + if (timerRunning) + { + pendingList.push_back(beepPriority); + pendingList.sort(std::greater<uint8_t>()); + return; + } + + performBeep(beepPriority); + } + + private: + void performBeep(const uint8_t& beepPriority) + { + currentBeepCode = beepCodeTable[beepPriority]; + currentCount = 0; + currentMask = bpMask; + currentShift = bpShiftCount; + getCurrentCount(); + startBeep(defaultBeepFrequence); + currentState = onBeepState; + currentCount--; + timerRunning = true; + startBeepTimer(); + } + + void startBeepTimer() + { + timer->expires_after( + std::chrono::milliseconds(beepDelayTable[currentState])); + timer->async_wait([this](const boost::system::error_code& ec) { + // timer timeout + switch (currentState) + { + case onBeepState: + stopBeep(); + if (currentCount == 0) + { + // finished the current 4-bit + if (currentBeepCode == 0) + { + // finished all bits + currentState = postBeepState; + } + else + { + // start next 4-bit + currentState = interDigitBeepState; + getCurrentCount(); + currentCount--; + } + } + else + { + // still in 4-bit processing + currentCount--; + currentState = interBeepState; + } + startBeepTimer(); + break; + + case interBeepState: + case interDigitBeepState: + startBeep(defaultBeepFrequence); + currentState = onBeepState; + startBeepTimer(); + break; + case postBeepState: + if (pendingList.size() != 0) + { + // continue the next new beepcode + uint8_t beepPriority = pendingList.front(); + pendingList.pop_front(); + performBeep(beepPriority); + } + else + { + timerRunning = false; + } + break; + + default: + std::cerr << "Incorrect beepState: " + << static_cast<unsigned int>(currentState) + << std::endl; + break; + } + }); + } + + void startBeep(uint32_t freq) + { + if (fdBeepDev != -1) + { + std::cerr << "beep device is opening already!" << std::endl; + ::close(fdBeepDev); + fdBeepDev = -1; + } + + if ((fdBeepDev = ::open(bpDevName, O_RDWR | O_CLOEXEC)) < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Failed to open input device"); + return; + } + + struct input_event event; + event.type = EV_SND; + event.code = SND_TONE; + event.value = freq; + + if (::write(fdBeepDev, &event, sizeof(struct input_event)) != + sizeof(struct input_event)) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Failed to write a tone sound event"); + ::close(fdBeepDev); + fdBeepDev = -1; + return; + } + return; + } + + void stopBeep() + { + if (fdBeepDev == -1) + { + std::cerr << "beep device is closed!" << std::endl; + return; + } + + ::close(fdBeepDev); + fdBeepDev = -1; + } + + // Split the beep code based on bpBitCount, for example 0x1544, + // currentCount=1, 5, 4, 4 + void getCurrentCount() + { + while (currentCount == 0) + { + currentCount = currentMask & currentBeepCode; + currentShift -= bpBitCount; + currentCount >>= currentShift; + currentBeepCode = currentBeepCode & ~currentMask; + currentMask >>= bpBitCount; + if (currentMask == 0) + { + break; + } + } + } + + int fdBeepDev; + bool timerRunning; + uint32_t currentCount; + uint32_t currentBeepCode; + uint32_t currentMask; + uint32_t currentShift; + uint8_t currentState; + std::unique_ptr<boost::asio::steady_timer> timer; + std::list<uint8_t> pendingList; +}; + +static Beeper beeper(io); + +// dbus method +static void beep(const uint8_t& beepPriority) +{ + if ((beepPriority >= beepMax) || (beepPriority == beepOff)) + { + std::cerr << "Incorrect input: " + << static_cast<unsigned int>(beepPriority) << std::endl; + return; + } + + // Log into redfish event log + sd_journal_send("MESSAGE=BeepCode: Priority=%d", beepPriority, + "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", + "OpenBMC.0.1.BeepCode", "REDFISH_MESSAGE_ARGS=%d", + beepPriority, NULL); + + beeper.beep(beepPriority); + + return; +} + +int main(int argc, char** argv) +{ + phosphor::logging::log<phosphor::logging::level::INFO>( + "Starting BeepCode service"); + + conn->request_name(bpBusName); + sdbusplus::asio::object_server server = + sdbusplus::asio::object_server(conn); + bpIface = server.add_interface(bpObjName, bpIntfName); + + bpIface->register_property("BeepCodeNameList", beepCodeNameList, + sdbusplus::asio::PropertyPermission::readOnly); + bpIface->register_property("BeepCodePatternList", beepCodePatternList, + sdbusplus::asio::PropertyPermission::readOnly); + bpIface->register_method(bpMethodName, beep); + bpIface->initialize(); + + io.run(); + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend new file mode 100644 index 000000000..9a25eafa9 --- /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 = "41622a95da34e3aacbf2b70d687d3a3a7c816c8a" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +EXTRA_OECMAKE = "-DYOCTO=1 -DUSE_OVERLAYS=0" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb new file mode 100644 index 000000000..089aaf59f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb @@ -0,0 +1,26 @@ + +SUMMARY = "PCH BMC time service" +DESCRIPTION = "This service will read date/time from PCH device periodically, and set the BMC system time accordingly" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://pch-time-sync.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +SYSTEMD_SERVICE_${PN} = "pch-time-sync.service" + +inherit cmake +inherit obmc-phosphor-systemd + +DEPENDS += " \ + sdbusplus \ + phosphor-logging \ + boost \ + i2c-tools \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt new file mode 100644 index 000000000..a4cf8155f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (pch-time-sync CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +add_executable (pch-time-sync pch-time-sync.cpp) + +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES} + phosphor_logging) +target_link_libraries (${PROJECT_NAME} i2c) + +install (TARGETS pch-time-sync DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp new file mode 100644 index 000000000..0c1014589 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp @@ -0,0 +1,265 @@ +/* Copyright 2019 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <time.h> + +#include <boost/date_time/posix_time/posix_time.hpp> +#include <chrono> +#include <iostream> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> +extern "C" { +#include <i2c/smbus.h> +#include <linux/i2c-dev.h> +} + +static constexpr uint32_t syncIntervalNormalMS = 60000; +static constexpr uint32_t syncIntervalFastMS = (syncIntervalNormalMS / 2); + +static uint32_t syncIntervalMS = syncIntervalNormalMS; + +// will update bmc time if the time difference beyond this value +static constexpr uint8_t timeDiffAllowedSecond = 1; + +static inline uint8_t bcd2Decimal(uint8_t hex) +{ + uint8_t dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F); + return dec; +} + +class I2CFile +{ + private: + int fd = -1; + + public: + I2CFile(const int& i2cBus, const int& slaveAddr, const int& flags) + { + std::string i2cDev = "/dev/i2c-" + std::to_string(i2cBus); + + fd = open(i2cDev.c_str(), flags); + if (fd < 0) + { + throw std::runtime_error("Unable to open i2c device."); + } + + if (ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0) + { + close(fd); + fd = -1; + throw std::runtime_error("Unable to set i2c slave address."); + } + } + + uint8_t i2cReadByteData(const uint8_t& offset) + { + int ret = i2c_smbus_read_byte_data(fd, offset); + + if (ret < 0) + { + throw std::runtime_error("i2c read failed"); + } + return static_cast<uint8_t>(ret); + } + + ~I2CFile() + { + if (!(fd < 0)) + { + close(fd); + } + } +}; + +class PCHSync +{ + private: + bool getPCHDate(uint8_t& year, uint8_t& month, uint8_t& day, uint8_t& hour, + uint8_t& minute, uint8_t& second) + { + try + { + constexpr uint8_t pchDevI2CBusNumber = 0x03; + constexpr uint8_t pchDevI2CSlaveAddress = 0x44; + constexpr uint8_t pchDevRegRTCYear = 0x0f; + constexpr uint8_t pchDevRegRTCMonth = 0x0e; + constexpr uint8_t pchDevRegRTCDay = 0x0d; + constexpr uint8_t pchDevRegRTCHour = 0x0b; + constexpr uint8_t pchDevRegRTCMinute = 0x0a; + constexpr uint8_t pchDevRegRTCSecond = 0x09; + I2CFile pchDev(pchDevI2CBusNumber, pchDevI2CSlaveAddress, + O_RDWR | O_CLOEXEC); + year = pchDev.i2cReadByteData(pchDevRegRTCYear); + year = bcd2Decimal(year); + if (year > 99) + { + return false; + } + + month = pchDev.i2cReadByteData(pchDevRegRTCMonth); + month = bcd2Decimal(month); + if ((month < 1) || (month > 12)) + { + return false; + } + + day = pchDev.i2cReadByteData(pchDevRegRTCDay); + day = bcd2Decimal(day); + if ((day < 1) || (day > 31)) + { + return false; + } + + hour = pchDev.i2cReadByteData(pchDevRegRTCHour); + hour = bcd2Decimal(hour); + if (hour >= 24) + { + return false; + } + + minute = pchDev.i2cReadByteData(pchDevRegRTCMinute); + minute = bcd2Decimal(minute); + if (minute >= 60) + { + return false; + } + + second = pchDev.i2cReadByteData(pchDevRegRTCSecond); + second = bcd2Decimal(second); + if (second >= 60) + { + return false; + } + } + catch (const std::exception& e) + { + return false; + } + + return true; + } + + bool getSystemTime(time_t& timeSeconds) + { + struct timespec sTime = {0}; + int ret = 0; + + ret = clock_gettime(CLOCK_REALTIME, &sTime); + + if (ret != 0) + { + return false; + } + timeSeconds = sTime.tv_sec; + return true; + } + + bool setSystemTime(uint32_t timeSeconds) + { + struct timespec sTime = {0}; + int ret = 0; + + sTime.tv_sec = timeSeconds; + sTime.tv_nsec = 0; + + ret = clock_settime(CLOCK_REALTIME, &sTime); + + return (ret == 0); + } + + bool updateBMCTime() + { + int ret = 0; + time_t BMCTimeSeconds = 0; + time_t PCHTimeSeconds = 0; + struct tm tm = {0}; + + // get PCH and system time + if (!getPCHDate(year, month, day, hour, minute, second)) + { + return false; + }; + + if (!getSystemTime(BMCTimeSeconds)) + { + return false; + } + + std::string dateString = + "20" + std::to_string(year) + "-" + std::to_string(month) + "-" + + std::to_string(day) + " " + std::to_string(hour) + ":" + + std::to_string(minute) + ":" + std::to_string(second); + + strptime(dateString.c_str(), "%Y-%m-%d %H:%M:%S", &tm); + + PCHTimeSeconds = mktime(&tm); + if (PCHTimeSeconds == -1) + { + return false; + } + + if (std::abs(PCHTimeSeconds - BMCTimeSeconds) > timeDiffAllowedSecond) + { + if (!setSystemTime(PCHTimeSeconds)) + { + return false; + } + std::cout << "Update BMC time to " << dateString << std::endl; + } + + return true; + } + + void startSyncTimer() + { + if (updateBMCTime()) + { + syncIntervalMS = syncIntervalNormalMS; + } + else + { + std::cout << "Update BMC time Fail" << std::endl; + syncIntervalMS = syncIntervalFastMS; + } + + syncTimer->expires_after(std::chrono::milliseconds(syncIntervalMS)); + syncTimer->async_wait( + [this](const boost::system::error_code& ec) { startSyncTimer(); }); + } + + std::unique_ptr<boost::asio::steady_timer> syncTimer; + uint8_t year, month, day, hour, minute, second; + + public: + PCHSync(boost::asio::io_service& io) + { + syncTimer = std::make_unique<boost::asio::steady_timer>(io); + startSyncTimer(); + } + + ~PCHSync() = default; +}; + +int main(int argc, char** argv) +{ + boost::asio::io_service io; + PCHSync pchSyncer(io); + + phosphor::logging::log<phosphor::logging::level::INFO>( + "Starting PCH time sync service"); + + io.run(); + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service new file mode 100644 index 000000000..cf9c3053f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service @@ -0,0 +1,13 @@ +[Unit] +Description=PCH BMC time sync service +Conflicts=systemd-timesyncd.service + +[Service] +Restart=always +RestartSec=10 +ExecStart=/usr/bin/pch-time-sync +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=sysinit.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch new file mode 100644 index 000000000..3344c27dd --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch @@ -0,0 +1,47 @@ +From 3789a98fda6e3cafd377b0f4fa1c0c40bb94297e Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <jonathanx.mantey@intel.com> +Date: Wed, 20 Nov 2019 10:56:44 -0500 +Subject: [PATCH] Reapply: "Enhance DHCP beyond just OFF and IPv4/IPv6 + enabled." + +DHCP is not a binary option. The network interface can have DHCP +disabled, IPv4 only, IPv6 only, and IPv4/IPv6. + +Signed-off-by: Johnathan Mantey <jonathanx.mantey@intel.com> + +Reapplied -> +Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com> +Change-Id: I7654116aa3962de253225271190ce4a2fe229ce9 +--- + .../Network/EthernetInterface.interface.yaml | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml +index ee54145..56285ee 100644 +--- a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml ++++ b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml +@@ -23,7 +23,7 @@ properties: + description: > + Domain names of the ethernet interface. + - name: DHCPEnabled +- type: boolean ++ type: enum[self.DHCPConf] + description: > + Address mode of the ethernet interface. + - name: Nameservers +@@ -69,4 +69,11 @@ enumerations: + - name: v4 + - name: v6 + - name: none +- ++ - name: DHCPConf ++ description: > ++ A list of the permitted DHCP settings used by systemd. ++ values: ++ - name: both ++ - name: v4 ++ - name: v6 ++ - name: none +-- +2.21.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch new file mode 100644 index 000000000..4cfc4acc8 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch @@ -0,0 +1,65 @@ +From a30a09f58b9ebfb267c0b9cce9ae25994ea025ca Mon Sep 17 00:00:00 2001 +From: cyang29 <cheng.c.yang@intel.com> +Date: Tue, 17 Jul 2018 16:04:58 +0800 +Subject: [PATCH] Add DBUS interface of CPU properties Feature + Support: SMBIOS service interface. CPU information redfish + interface. Base on smbios spec DSP0134_3.0.0 + +Signed-off-by: cyang29 <cheng.c.yang@intel.com> +--- + .../Inventory/Item/Cpu.interface.yaml | 41 +++++++++++++++++++ + 1 files changed, 41 insertions(+) + +diff --git a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +index ab29cf3..313eada 100644 +--- a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml ++++ b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml +@@ -1,4 +1,45 @@ + description: > + Implement to provide CPU attributes. ++properties: ++ - name: ProcessorSocket ++ type: string ++ description: > ++ Processor Socket on MotherBoard ++ - name: ProcessorType ++ type: string ++ description: > ++ Processor Type of CPU ++ - name: ProcessorFamily ++ type: string ++ description: > ++ Processor Family of CPU ++ - name: ProcessorManufacturer ++ type: string ++ description: > ++ Processor Manufacturer of CPU ++ - name: ProcessorId ++ type: uint32 ++ description: > ++ Processor ID of CPU ++ - name: ProcessorVersion ++ type: string ++ description: > ++ Processor Version of CPU ++ - name: ProcessorMaxSpeed ++ type: uint16 ++ description: > ++ Max Speed CPU Can Support ++ - name: ProcessorCharacteristics ++ type: string ++ description: > ++ The Characteristics CPU Has ++ - name: ProcessorCoreCount ++ type: uint16 ++ description: > ++ The Count of Core in CPU ++ - name: ProcessorThreadCount ++ type: uint16 ++ description: > ++ The Count of Thread CPU Can Support + + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch new file mode 100644 index 000000000..c87b2d89d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch @@ -0,0 +1,32 @@ +From 49debd0955b672d591f35e74119b288bd6df2992 Mon Sep 17 00:00:00 2001 +From: "Jia, Chunhui" <chunhui.jia@intel.com> +Date: Tue, 24 Jul 2018 11:40:49 +0800 +Subject: [PATCH] [ipmi] set BIOS id + +change#2 +add new dbus interface for BIOS attributes + +Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com> +--- + xyz/openbmc_project/Inventory/Item/Bios.interface.yaml | 9 +++++++++ + 1 file changed, 9 insertions(+) + create mode 100644 xyz/openbmc_project/Inventory/Item/Bios.interface.yaml + +diff --git a/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml +new file mode 100644 +index 0000000..d7a6b95 +--- /dev/null ++++ b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml +@@ -0,0 +1,9 @@ ++description: > ++ Implement to provide BIOS attributes. ++properties: ++ - name: BiosId ++ type: string ++ description: > ++ BIOS ID (version) string ++ ++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch new file mode 100644 index 000000000..2c9344306 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch @@ -0,0 +1,34 @@ +From 631deef0ca88a77283741edeae8078d2185f414c Mon Sep 17 00:00:00 2001 +From: Yong Li <yong.b.li@linux.intel.com> +Date: Fri, 10 Aug 2018 16:23:13 +0800 +Subject: [PATCH] Increase the default watchdog timeout value + +The default timeout for poweron is 30 seconds, +but currently the host power on needs 120+ seconds +due to unimplemented ipmi commands for BIOS. + +Increase the value as a workaround, +to avoid the watchdog timeout during power on. +Will adjust this value in the future + +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index f76dbf2..402e1a8 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -37,7 +37,7 @@ properties: + type: uint64 + description: > + Time interval to arm the watchdog, in milli-second. +- default: 30000 ++ default: 600000 + - name: TimeRemaining + type: uint64 + description: > +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch new file mode 100644 index 000000000..9052435ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch @@ -0,0 +1,34 @@ +From eeac4cf4528994aeb213d549daf4c033ac9d3bbc Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Fri, 24 Aug 2018 17:55:35 +0800 +Subject: [PATCH] Add RestoreDelay interface for power restore delay + +Which provide one property "PowerRestoreDelay" + +Change-Id: I4e6d3e45948b1e288301b4aa52cc08cace4f1bc2 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../Control/Power/RestoreDelay.interface.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml +new file mode 100644 +index 0000000..55ee80a +--- /dev/null ++++ b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml +@@ -0,0 +1,11 @@ ++description: > ++ Implement to specify power transition behavior on a BMC reset. ++ The implementation based on restore policy and set a delay time ++ for power restore. ++ ++properties: ++ - name: PowerRestoreDelay ++ type: uint16 ++ description: > ++ The delay time for power restore. ++ Power Restore Delay is NOT applied on power policy is "Always Off" +-- +2.17.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch new file mode 100644 index 000000000..9471c7ab2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch @@ -0,0 +1,86 @@ +From 7260c24b201759f3a5168eebfee215072c13e641 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Thu, 30 Aug 2018 16:22:43 +0800 +Subject: [PATCH] Add ErrConfig.yaml interface for processor error + configuration. + +Which provide 3 properties: + ResetCfg + type: byte + description: > + Reset Configuration + [0]: CATERR Reset Enabled + 0b: Disabled + 1b: Enabled + [1]: ERR2 Reset Enabled + 0b: Disabled + 1b: Enabled + [7:2]: Reserved + ResetErrorOccurrenceCounts + type: byte + description: > + Reset Error Occurrence Counts + [0]: Reset CPU Error Counts + 0b: Keep CPU Error Counts + 1b: Reset all CPU Error Counts to zero + [7:1]: Reserved + CATERRStatus + type: array[byte] + description: > + For all CPUs including the non-legacy socket CPU + CPU CATERR (Core Error) occurrence + [5:0]: Error Occurrence Count + [7:6]: CPU Status + 00b: Disabled + 01b: Enabled + 11b: Not Present + +Change-Id: Ibc5a7a5e15c998e56c04e23b1043d99243a91171 +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + .../Processor/ErrConfig.interface.yaml | 33 +++++++++++++++++++ + 1 file changed, 33 insertions(+) + create mode 100644 xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml + +diff --git a/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml +new file mode 100644 +index 0000000..2304263 +--- /dev/null ++++ b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml +@@ -0,0 +1,33 @@ ++description: > ++ This defines processor error configuration. ++properties: ++ - name: ResetCfg ++ type: byte ++ description: > ++ Reset Configuration ++ [0]: CATERR Reset Enabled ++ 0b: Disabled ++ 1b: Enabled ++ [1]: ERR2 Reset Enabled ++ 0b: Disabled ++ 1b: Enabled ++ [7:2]: Reserved ++ ++ - name: ResetErrorOccurrenceCounts ++ type: byte ++ description: > ++ Reset Error Occurrence Counts ++ [0]: Reset CPU Error Counts ++ 0b: Keep CPU Error Counts ++ 1b: Reset all CPU Error Counts to zero ++ [7:1]: Reserved ++ - name: CATERRStatus ++ type: array[byte] ++ description: > ++ For all CPUs including the non-legacy socket CPU ++ CPU CATERR (Core Error) occurrence ++ [5:0]: Error Occurrence Count ++ [7:6]: CPU Status ++ 00b: Disabled ++ 01b: Enabled ++ 11b: Not Present +-- +2.17.0 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch new file mode 100644 index 000000000..67fa59090 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch @@ -0,0 +1,57 @@ +From 6e9a19c43acac7d4254910906329d98d7b59085a Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Fri, 24 May 2019 14:55:10 +0800 +Subject: [PATCH] Add the pre-timeout interrupt defined in IPMI spec + +The IPMI watchdog pre-timeout interrupt is used to set the different +pre-timeout interrupt source. Add them as a dbus property, +IPMI set/get watchdog commands will use it. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index 2fc47d8..6dfa9b9 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -33,6 +33,11 @@ properties: + description: > + The action the watchdog should perform when it expires. + default: 'HardReset' ++ - name: PreTimeoutInterrupt ++ type: enum[self.PreTimeoutInterruptAction] ++ description: > ++ The BMC generates the selected interrupt before the timer expires. ++ default: 'None' + - name: Interval + type: uint64 + description: > +@@ -73,6 +78,23 @@ enumerations: + description: > + Perform a power cycle of the system. + ++ - name: PreTimeoutInterruptAction ++ description: > ++ The type of PreTimeout Interrupt. ++ values: ++ - name: 'None' ++ description: > ++ Do nothing. ++ - name: 'SMI' ++ description: > ++ SMI. ++ - name: 'NMI' ++ description: > ++ NMI / Diagnostic Interrupt. ++ - name: 'MI' ++ description: > ++ Messaging Interrupt. ++ + - name: TimerUse + description: > + The type of timer use. +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch new file mode 100644 index 000000000..d7e66abd2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch @@ -0,0 +1,39 @@ +From b7c487750c05dcc081219ccdd4ef539beef6aa30 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Mon, 29 Jul 2019 10:51:12 +0800 +Subject: [PATCH] Add PreInterruptFlag properity in DBUS. + +PreTimeoutInterruptOccurFlag in DBUS would be set 'true' +when watchdog pre-timeout interrupt occurred. + +Tested: +Enable command(raw 0x06 0x31) that get message flag +can set right bit about watchdog, +need record PreTimeoutInterruptOccurFlag +at xyz.openbmmc_project.State.Watchdog when watchdog +pre-timeout interrupt occurred. + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + xyz/openbmc_project/State/Watchdog.interface.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml +index bf4cca0..6579368 100644 +--- a/xyz/openbmc_project/State/Watchdog.interface.yaml ++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml +@@ -59,6 +59,11 @@ properties: + description: > + The timer user at the time of expiration. + default: 'Reserved' ++ - name: PreTimeoutInterruptOccurFlag ++ type: boolean ++ description: > ++ PreTimeoutInterruptOccurFlag that preTimeoutInterrupt action occurred. ++ default: false + + enumerations: + - name: Action +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch new file mode 100644 index 000000000..36c63ec58 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch @@ -0,0 +1,55 @@ +From 0d6556539be9bda478a3cabb6127eace5764fa11 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Wed, 15 Jan 2020 10:01:04 +0800 +Subject: [PATCH] Add StandbySpare support for software inventory + +Add support to allow update for active / recovery +regions of specified firmware. This update enables +the backend modules to advertise whether the +software object is active or recovery (StandbySpare) +image. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + xyz/openbmc_project/Software/Activation.interface.yaml | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/xyz/openbmc_project/Software/Activation.interface.yaml b/xyz/openbmc_project/Software/Activation.interface.yaml +index efeeeb6..6c9ce75 100644 +--- a/xyz/openbmc_project/Software/Activation.interface.yaml ++++ b/xyz/openbmc_project/Software/Activation.interface.yaml +@@ -28,12 +28,20 @@ enumerations: + - name: Activating + description: > + The Software.Version is in the process of being Activated. ++ - name: ActivatingAsStandbySpare ++ description: > ++ The Software.Version is in the process of being processed ++ as StandbySpare. + - name: Active + description: > + The Software.Version is currently Active. + - name: Failed + description: > + The Software.Version failed during or after Activation. ++ - name: StandbySpare ++ description: > ++ The Software.Version is part of a redundancy set and awaits ++ a failover or external action to activate. + - name: Staged + description: > + The Software.Version is currently in staged flash area. +@@ -48,6 +56,10 @@ enumerations: + - name: Active + description: > + The Software.Version has been requested for Activation. ++ - name: StandbySpare ++ description: > ++ The Software.Version has been requested to be enabled as ++ StandbySpare. + # TODO: Specify "EAGAIN" type error when requested is unable to be acted on + # due to current system state. Currently, sdbusplus does not support + # errors on properties. +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend new file mode 100644 index 000000000..9690ec20f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend @@ -0,0 +1,15 @@ +SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git" +SRCREV = "79064a8e0c49b35cfa1c343cef31f21ebfd7298d" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch \ + file://0007-ipmi-set-BIOS-id.patch \ + file://0010-Increase-the-default-watchdog-timeout-value.patch \ + file://0012-Add-RestoreDelay-interface-for-power-restore-delay.patch \ + file://0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch \ + file://0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch \ + file://0025-Add-PreInterruptFlag-properity-in-DBUS.patch \ + file://0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch \ + file://0026-Add-StandbySpare-support-for-software-inventory.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service new file mode 100644 index 000000000..9af9af254 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service @@ -0,0 +1,20 @@ +[Unit] +Description=Phosphor DBus Service Discovery Manager +Before=obmc-mapper.target +After=dbus.socket + +[Service] +Restart=always +Type=dbus +ExecStart=/usr/bin/env mapperx \ + --service-namespaces="xyz. com. org." \ + --interface-namespaces="org. com. xyz." \ + --service-blacklists="org.freedesktop.systemd1" +SyslogIdentifier=phosphor-mapper +BusName={BUSNAME} +TimeoutStartSec=300 +RestartSec=5 +EnvironmentFile={envfiledir}/obmc/mapper + +[Install] +WantedBy={SYSTEMD_DEFAULT_TARGET} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend new file mode 100644 index 000000000..72d991c7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service new file mode 100644 index 000000000..0e80b554a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service @@ -0,0 +1,14 @@ +[Unit] +Description=Phosphor-Pid-Control Margin-based Fan Control Daemon +After=xyz.openbmc_project.EntityManager.service +After=xyz.openbmc_project.ObjectMapper.service + +[Service] +Restart=always +ExecStart={bindir}/swampd +RestartSec=5 +StartLimitInterval=0 +Type=simple + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend new file mode 100644 index 000000000..cbd8e1171 --- /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 = "3660b3888af789266b6c84714b4e161a32e6ea54" + +FILES_${PN} = "${bindir}/swampd ${bindir}/setsensor" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch new file mode 100644 index 000000000..2a4c7e9b6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch @@ -0,0 +1,44 @@ +From b6b3051c8078267153712ed8cf514373924fd07a Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Mon, 16 Jul 2018 19:15:04 -0700 +Subject: [PATCH 2/6] Redfish firmware activation -- Modified flash.cpp to + call to customized flash service + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I81c3185e9c4c2ee907feeb53620faa22723c04d4 +--- + ubi/flash.cpp | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/ubi/flash.cpp b/ubi/flash.cpp +index ffa9348..5af2a17 100644 +--- a/ubi/flash.cpp ++++ b/ubi/flash.cpp +@@ -15,10 +15,13 @@ void Activation::flashWrite() + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); +- method.append("obmc-flash-bmc-ubirw.service", "replace"); ++ std::string rwServiceFile = ++ "obmc-flash-bmc-ubirw@" + versionId + ".service"; ++ method.append(rwServiceFile, "replace"); + bus.call_noreply(method); + +- auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; ++ std::string roServiceFile = ++ "obmc-flash-bmc-ubiro@" + versionId + ".service"; + method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); + method.append(roServiceFile, "replace"); +@@ -37,7 +40,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- auto rwServiceFile = "obmc-flash-bmc-ubirw.service"; ++ auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service"; + auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + auto ubootVarsServiceFile = + "obmc-flash-bmc-updateubootvars@" + versionId + ".service"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch new file mode 100644 index 000000000..3fc3907ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch @@ -0,0 +1,41 @@ +From 1b00440d0c8fabfa2e3eda984a21c0f004ca2150 Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Fri, 26 Oct 2018 11:54:05 -0700 +Subject: [PATCH 4/6] Changed the condition of software version service + watching deamon + + Originally it watches only files that are "written" into /tmp/images directory. +This change modified the condition to also watch files that are "moved" into this directory. + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I3e9cf1ffc3f5350d4649d32d3d3837991322a65b +--- + watch.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/watch.cpp b/watch.cpp +index e46b8aa..eee1bc3 100644 +--- a/watch.cpp ++++ b/watch.cpp +@@ -45,7 +45,7 @@ Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) : + std::strerror(error)); + } + +- wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE); ++ wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE | IN_MOVED_TO); + if (-1 == wd) + { + auto error = errno; +@@ -96,7 +96,8 @@ int Watch::callback(sd_event_source* s, int fd, uint32_t revents, + while (offset < bytes) + { + auto event = reinterpret_cast<inotify_event*>(&buffer[offset]); +- if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR)) ++ if ((event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) && ++ !(event->mask & IN_ISDIR)) + { + auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name; + auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch new file mode 100644 index 000000000..aa5d900e0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch @@ -0,0 +1,188 @@ +From 7f29c255dd2af7fa6d38b02ad63a8b8940fbce84 Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Mon, 10 Dec 2018 10:36:44 -0800 +Subject: [PATCH 5/6] Modified firmware activation to launch fwupd.sh through + non-ubi fs code path to match more closely to the upstream design - + Added option FWUPD_SCRIPT to saperate intel customized code - Adopted + ActivationProgress from ubi fs activation code mainly for progress indicator + for ipmi update + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: Id805deea75b21fab86f6bb6edbf50ddb3be42564 +--- + activation.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ + configure.ac | 7 +++++++ + static/flash.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- + ubi/flash.cpp | 9 +++------ + 4 files changed, 93 insertions(+), 8 deletions(-) + +diff --git a/activation.cpp b/activation.cpp +index f918221..f2923ae 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -163,6 +163,50 @@ auto Activation::activation(Activations value) -> Activations + softwareServer::Activation::Activations::Active); + } + } ++#elif defined(FWUPD_SCRIPT) ++ if (!activationProgress) ++ { ++ // Enable systemd signals ++ Activation::subscribeToSystemdSignals(); ++ parent.freeSpace(*this); ++ ++ activationProgress = ++ std::make_unique<ActivationProgress>(bus, path); ++ ++#ifdef WANT_SIGNATURE_VERIFY ++ fs::path uploadDir(IMG_UPLOAD_DIR); ++ if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH)) ++ { ++ onVerifyFailed(); ++ // Stop the activation process, if fieldMode is enabled. ++ if (parent.control::FieldMode::fieldModeEnabled()) ++ { ++ return softwareServer::Activation::activation( ++ softwareServer::Activation::Activations::Failed); ++ } ++ } ++#endif ++ flashWrite(); ++ activationProgress->progress(10); ++ } ++ else if (activationProgress->progress() == 100) ++ { ++ log<level::ERR>("[Jennifer] progress == 100..."); ++ if (!redundancyPriority) ++ { ++ redundancyPriority = ++ std::make_unique<RedundancyPriority>(bus, path, *this, 0); ++ } ++ ++ // Remove version object from image manager ++ Activation::deleteImageManagerObject(); ++ ++ // Create active association ++ parent.createActiveAssociation(path); ++ ++ return softwareServer::Activation::activation( ++ softwareServer::Activation::Activations::Active); ++ } + #else // !UBIFS_LAYOUT + + #ifdef WANT_SIGNATURE_VERIFY +diff --git a/configure.ac b/configure.ac +index 2da97ad..720e704 100755 +--- a/configure.ac ++++ b/configure.ac +@@ -184,6 +184,13 @@ AS_IF([test "x$enable_ubifs_layout" == "xyes"], \ + [AC_DEFINE([UBIFS_LAYOUT],[],[Enable ubifs support.])]) + AM_CONDITIONAL([UBIFS_LAYOUT], [test "x$enable_ubifs_layout" == "xyes"]) + ++# setup fwupd script support ++AC_ARG_ENABLE([fwupd_script], ++ AS_HELP_STRING([--enable-fwupd_script], [Enable fwupd script support.])) ++AS_IF([test "x$enable_fwupd_script" == "xyes"], \ ++ [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])]) ++AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"]) ++ + # Check for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])]) + AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) +diff --git a/static/flash.cpp b/static/flash.cpp +index 82c2393..1bf29d5 100644 +--- a/static/flash.cpp ++++ b/static/flash.cpp +@@ -20,9 +20,11 @@ namespace updater + { + + namespace fs = std::experimental::filesystem; ++namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server; + + void Activation::flashWrite() + { ++#ifndef FWUPD_SCRIPT + // For static layout code update, just put images in /run/initramfs. + // It expects user to trigger a reboot and an updater script will program + // the image to flash during reboot. +@@ -33,11 +35,46 @@ void Activation::flashWrite() + fs::copy_file(uploadDir / versionId / bmcImage, toPath / bmcImage, + fs::copy_options::overwrite_existing); + } ++ ++#else ++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, ++ SYSTEMD_INTERFACE, "StartUnit"); ++ method.append("fwupd@" + versionId + ".service", "replace"); ++ bus.call_noreply(method); ++#endif + } + +-void Activation::onStateChanges(sdbusplus::message::message& /*msg*/) ++void Activation::onStateChanges(sdbusplus::message::message& msg) + { +- // Empty ++#ifndef FWUPD_SCRIPT ++ uint32_t newStateID{}; ++ sdbusplus::message::object_path newStateObjPath; ++ std::string newStateUnit{}; ++ std::string newStateResult{}; ++ ++ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); ++ ++ auto rwServiceFile = "fwupdw@" + versionId + ".service"; ++ ++ if (newStateUnit == rwServiceFile && newStateResult == "done") ++ { ++ activationProgress->progress(100); ++ } ++ ++ if (newStateUnit == rwServiceFile) ++ { ++ if (newStateResult == "failed" || newStateResult == "dependency") ++ { ++ Activation::activation( ++ softwareServer::Activation::Activations::Failed); ++ } ++ else ++ { ++ Activation::activation( ++ softwareServer::Activation::Activations::Activating); ++ } ++ } ++#endif + } + + } // namespace updater +diff --git a/ubi/flash.cpp b/ubi/flash.cpp +index 5af2a17..ffa9348 100644 +--- a/ubi/flash.cpp ++++ b/ubi/flash.cpp +@@ -15,13 +15,10 @@ void Activation::flashWrite() + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); +- std::string rwServiceFile = +- "obmc-flash-bmc-ubirw@" + versionId + ".service"; +- method.append(rwServiceFile, "replace"); ++ method.append("obmc-flash-bmc-ubirw.service", "replace"); + bus.call_noreply(method); + +- std::string roServiceFile = +- "obmc-flash-bmc-ubiro@" + versionId + ".service"; ++ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "StartUnit"); + method.append(roServiceFile, "replace"); +@@ -40,7 +37,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg) + // Read the msg and populate each variable + msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); + +- auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service"; ++ auto rwServiceFile = "obmc-flash-bmc-ubirw.service"; + auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service"; + auto ubootVarsServiceFile = + "obmc-flash-bmc-updateubootvars@" + versionId + ".service"; +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch new file mode 100644 index 000000000..2d2ac2673 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch @@ -0,0 +1,44 @@ +From 9b3c44e9fb3d907c0152f14b967e23ab964c0e0b Mon Sep 17 00:00:00 2001 +From: Jennifer Lee <jennifer1.lee@intel.com> +Date: Thu, 14 Feb 2019 14:54:45 -0800 +Subject: [PATCH 6/6] Modify the ID of software image updater object on DBus to + allow force update onto same version image + +In the original design of image update, it does not allow the same version of image to be flashed onto itself. +But this blocks validation tests and in most of the cases we don't prevent user from doing such update. + +This patch appends a random number after the version ID hash string to unblock such limitation. + +Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com> +Change-Id: I16aba4804ae1bc2e8784320f91c0419fb8b23c35 +--- + image_manager.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/image_manager.cpp b/image_manager.cpp +index 5b2ff49..e3d26e3 100644 +--- a/image_manager.cpp ++++ b/image_manager.cpp +@@ -9,6 +9,7 @@ + #include <stdlib.h> + #include <sys/stat.h> + #include <sys/wait.h> ++#include <time.h> + #include <unistd.h> + + #include <algorithm> +@@ -129,6 +130,11 @@ int Manager::processImage(const std::string& tarFilePath) + // Compute id + auto id = Version::getId(version); + ++ // Append a random number after the original version hash ++ // This will allow forcing image update onto the same version ++ srand(time(NULL)); ++ id = id + "_" + std::to_string(rand()); ++ + fs::path imageDirPath = std::string{IMG_UPLOAD_DIR}; + imageDirPath /= id; + +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch new file mode 100644 index 000000000..b63226cce --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch @@ -0,0 +1,76 @@ +From c2ae3ac444f7a5e9674a82f47086874f947bcec6 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +Date: Thu, 5 Dec 2019 12:38:21 +0530 +Subject: [PATCH] Adding StandBySpare for firmware activation + +Added new states 'StandBySpare', 'ActivatingAsStandbySpare' for +firmware activation. If the uploaded firmware image is for +backup/recovery, then it sets the "StandBySpare" value for +Activations. When backup/recovery image is in activating state, +then activations will be set to "ActivatingAsStandbySpare". + +Tested: +Tested using redfish interface. +Did the GET on "/redfish/v1/UpdateService/FirmwareInventory/<backup image>" +Response: + .... + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "StandbySpare" + } +....... + +Change-Id: I7f1608fac3196774a6d593b6128d58da3f5c88fc +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +--- + activation.cpp | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/activation.cpp b/activation.cpp +index 2966b2f..a098784 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -80,12 +80,16 @@ auto Activation::activation(Activations value) -> Activations + { + + if ((value != softwareServer::Activation::Activations::Active) && +- (value != softwareServer::Activation::Activations::Activating)) ++ (value != softwareServer::Activation::Activations::Activating) && ++ (value != ++ softwareServer::Activation::Activations::ActivatingAsStandbySpare)) + { + redundancyPriority.reset(nullptr); + } + +- if (value == softwareServer::Activation::Activations::Activating) ++ if (value == softwareServer::Activation::Activations::Activating || ++ value == ++ softwareServer::Activation::Activations::ActivatingAsStandbySpare) + { + #ifdef UBIFS_LAYOUT + if (rwVolumeCreated == false && roVolumeCreated == false) +@@ -256,6 +260,20 @@ auto Activation::requestedActivation(RequestedActivations value) + softwareServer::Activation::Activations::Activating); + } + } ++ else if ((value == ++ softwareServer::Activation::RequestedActivations::StandbySpare) && ++ (softwareServer::Activation::requestedActivation() != ++ softwareServer::Activation::RequestedActivations::StandbySpare)) ++ { ++ if ((softwareServer::Activation::activation() == ++ softwareServer::Activation::Activations::Ready) || ++ (softwareServer::Activation::activation() == ++ softwareServer::Activation::Activations::Failed)) ++ { ++ Activation::activation(softwareServer::Activation::Activations:: ++ ActivatingAsStandbySpare); ++ } ++ } + return softwareServer::Activation::requestedActivation(value); + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch new file mode 100644 index 000000000..92b3ced38 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch @@ -0,0 +1,438 @@ +From 030f918b90ea45104bccf68082c2d634c6694238 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@intel.com> +Date: Tue, 13 Aug 2019 22:43:12 +0530 +Subject: [PATCH] PFR images support in phosphor-software-manager + +This commit adds support for handling the PFR images +upload and processing. + +Testing: +tested PFR image uploads and updates + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com> +--- + Makefile.am | 18 +++- + activation.cpp | 2 +- + configure.ac | 7 ++ + item_updater.cpp | 6 +- + pfr_image_manager.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++ + pfr_image_manager.hpp | 75 +++++++++++++++ + 6 files changed, 320 insertions(+), 5 deletions(-) + create mode 100644 pfr_image_manager.cpp + create mode 100644 pfr_image_manager.hpp + +diff --git a/Makefile.am b/Makefile.am +index 6c3ec16..59ebecc 100755 +--- a/Makefile.am ++++ b/Makefile.am +@@ -6,13 +6,20 @@ noinst_HEADERS = \ + watch.hpp \ + version.hpp \ + images.hpp \ +- image_manager.hpp \ + item_updater.hpp \ + activation.hpp \ + flash.hpp \ + item_updater_helper.hpp \ + utils.hpp + ++if PFR_UPDATE ++noinst_HEADERS += \ ++ pfr_image_manager.hpp ++else ++noinst_HEADERS += \ ++ image_manager.hpp ++endif ++ + bin_PROGRAMS = \ + phosphor-version-software-manager \ + phosphor-download-manager \ +@@ -24,8 +31,15 @@ dist_bin_SCRIPTS = \ + phosphor_version_software_manager_SOURCES = \ + image_manager_main.cpp \ + watch.cpp \ +- version.cpp \ ++ version.cpp ++ ++if PFR_UPDATE ++phosphor_version_software_manager_SOURCES += \ ++ pfr_image_manager.cpp ++else ++phosphor_version_software_manager_SOURCES += \ + image_manager.cpp ++endif + + BUILT_SOURCES = \ + xyz/openbmc_project/Software/Image/error.cpp \ +diff --git a/activation.cpp b/activation.cpp +index cea1e50..7ff4196 100644 +--- a/activation.cpp ++++ b/activation.cpp +@@ -197,7 +197,7 @@ auto Activation::activation(Activations value) -> Activations + } + else if (activationProgress->progress() == 100) + { +- log<level::ERR>("[Jennifer] progress == 100..."); ++ log<level::INFO>("progress == 100..."); + if (!redundancyPriority) + { + redundancyPriority = +diff --git a/configure.ac b/configure.ac +index 720e704..e527682 100755 +--- a/configure.ac ++++ b/configure.ac +@@ -191,6 +191,13 @@ AS_IF([test "x$enable_fwupd_script" == "xyes"], \ + [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])]) + AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"]) + ++# setup pfr image update support ++AC_ARG_ENABLE([pfr_update], ++ AS_HELP_STRING([--enable-pfr_update], [Enable pfr image update support.])) ++AS_IF([test "x$enable_pfr_update" == "xyes"], \ ++ [AC_DEFINE([PFR_UPDATE],[],[Enable pfr image update support.])]) ++AM_CONDITIONAL([PFR_UPDATE], [test "x$enable_pfr_update" == "xyes"]) ++ + # Check for header files. + AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])]) + AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])]) +diff --git a/item_updater.cpp b/item_updater.cpp +index 21fb6e0..fd76a7f 100644 +--- a/item_updater.cpp ++++ b/item_updater.cpp +@@ -64,10 +64,10 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg) + auto value = SVersion::convertVersionPurposeFromString( + variant_ns::get<std::string>(property.second)); + if (value == VersionPurpose::BMC || +-#ifdef HOST_BIOS_UPGRADE ++#if defined(HOST_BIOS_UPGRADE) || defined(PFR_UPDATE) + value == VersionPurpose::Host || + #endif +- value == VersionPurpose::System) ++ value == VersionPurpose::Other) + { + purpose = value; + } +@@ -356,6 +357,7 @@ void ItemUpdater::deleteAll() + ItemUpdater::ActivationStatus + ItemUpdater::validateSquashFSImage(const std::string& filePath) + { ++#ifndef PFR_UPDATE + bool invalid = false; + + for (auto& bmcImage : bmcImages) +@@ -375,7 +377,7 @@ ItemUpdater::ActivationStatus + { + return ItemUpdater::ActivationStatus::invalid; + } +- ++#endif + return ItemUpdater::ActivationStatus::ready; + } + +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +new file mode 100644 +index 0000000..242a6ca +--- /dev/null ++++ b/pfr_image_manager.cpp +@@ -0,0 +1,217 @@ ++#include "config.h" ++ ++#include "pfr_image_manager.hpp" ++ ++#include "version.hpp" ++#include "watch.hpp" ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/stat.h> ++#include <sys/wait.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <algorithm> ++#include <cstring> ++#include <elog-errors.hpp> ++#include <filesystem> ++#include <fstream> ++#include <iomanip> ++#include <sstream> ++#include <string> ++#include <xyz/openbmc_project/Software/Image/error.hpp> ++ ++namespace phosphor ++{ ++namespace software ++{ ++namespace manager ++{ ++ ++using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; ++namespace Software = phosphor::logging::xyz::openbmc_project::Software; ++ ++static constexpr const uint32_t pfmPos = 2054; ++ ++static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, ++ std::string& version) ++{ ++ struct pfrImgBlock0 block0Data; ++ uint8_t verData[2]; ++ ++ if (std::filesystem::exists(imgPath)) ++ { ++ try ++ { ++ std::ifstream imgFile(imgPath, std::ios::binary | std::ios::in); ++ ++ if (!imgFile.good()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image file read failed"); ++ return -1; ++ } ++ ++ imgFile.read(reinterpret_cast<char*>(&block0Data), ++ sizeof(block0Data)); ++ imgType = block0Data.pcType[0]; ++ imgFile.seekg(pfmPos, ++ std::ios::beg); // Version is at 0x806 in the PFM ++ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData)); ++ imgFile.close(); ++ version = ++ std::to_string(verData[0]) + "." + std::to_string(verData[1]); ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "PFR image", ++ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]), ++ phosphor::logging::entry("VERSION=%s", version.c_str())); ++ } ++ catch (std::exception& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++int Manager::processImage(const std::string& imgFilePath) ++{ ++ std::filesystem::path imgPath(imgFilePath); ++ ++ if (!std::filesystem::exists(imgPath)) ++ return -1; ++ ++ uint8_t imgType; ++ int retry = 3; ++ std::string ver; ++ std::string purposeString; ++ ++ if (0 != getPFRImgInfo(imgFilePath, imgType, ver)) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error reading uploaded image type and version"); ++ return -1; ++ } ++ ++ if (ver.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Empty version from image file"); ++ return -1; ++ } ++ ++ if (imgType == pfrBMCUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; ++ } ++ else if (imgType == pfrPCHUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; ++ } ++ else if (imgType == pfrCPLDUpdateCap) ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; ++ } ++ else ++ { ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown"; ++ ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unknown image type"); ++ return -1; ++ } ++ ++ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose ++ purpose = Version::VersionPurpose::Unknown; ++ try ++ { ++ purpose = Version::convertVersionPurposeFromString(purposeString); ++ } ++ catch (const sdbusplus::exception::InvalidEnumString& e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: Failed to convert purpose to enum." ++ " Setting to Unknown."); ++ } ++ ++ // Compute id ++ std::string id = Version::getId(ver); ++ ++ // Append a random number after the original version hash ++ // This will allow forcing image update onto the same version ++ // with 3 retries on random number generation. ++ do ++ { ++ srand(time(NULL)); ++ id = id + "_" + std::to_string(rand()); ++ } while ((versions.find(id) != versions.end()) && retry--); ++ ++ if (versions.find(id) != versions.end()) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Software Object with the same version already exists, exiting " ++ "the update", ++ phosphor::logging::entry("VERSION_ID=%s", id.c_str())); ++ ++ return -1; ++ } ++ ++ std::filesystem::path imageDirPath(IMG_UPLOAD_DIR); ++ imageDirPath /= id; ++ ++ std::filesystem::create_directory(imageDirPath); ++ ++ std::filesystem::path newFileName = imageDirPath / "image-runtime"; ++ std::filesystem::rename(imgFilePath, newFileName); ++ ++ // Create Version object ++ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; ++ ++ auto versionPtr = std::make_unique<Version>( ++ bus, objPath, ver, purpose, imageDirPath.string(), ++ std::bind(&Manager::erase, this, std::placeholders::_1)); ++ versionPtr->deleteObject = ++ std::make_unique<phosphor::software::manager::Delete>(bus, objPath, ++ *versionPtr); ++ versions.insert(std::make_pair(id, std::move(versionPtr))); ++ ++ return 0; ++} ++ ++void Manager::erase(std::string entryId) ++{ ++ auto it = versions.find(entryId); ++ if (it == versions.end()) ++ { ++ return; ++ } ++ ++ if (it->second->isFunctional()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ ("Error: Version " + entryId + ++ " is currently running on the BMC." ++ " Unable to remove.") ++ .c_str()); ++ return; ++ } ++ ++ // Delete image dir ++ std::filesystem::path imageDirPath = (*(it->second)).path(); ++ if (std::filesystem::exists(imageDirPath)) ++ { ++ std::filesystem::remove_all(imageDirPath); ++ } ++ this->versions.erase(entryId); ++} ++ ++} // namespace manager ++} // namespace software ++} // namespace phosphor +diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp +new file mode 100644 +index 0000000..c6ee6a4 +--- /dev/null ++++ b/pfr_image_manager.hpp +@@ -0,0 +1,75 @@ ++#pragma once ++#include "version.hpp" ++ ++#include <sdbusplus/server.hpp> ++ ++namespace phosphor ++{ ++namespace software ++{ ++namespace manager ++{ ++ ++enum pfrImgPCType { ++ pfrCPLDUpdateCap = 0x00, ++ pfrPCHPFM = 0x01, ++ pfrPCHUpdateCap = 0x02, ++ pfrBMCPFM = 0x03, ++ pfrBMCUpdateCap = 0x04 ++}; ++ ++/* PFR image block 0 - As defined in HAS */ ++struct pfrImgBlock0 { ++ uint8_t tag[4]; ++ uint8_t pcLength[4]; ++ uint8_t pcType[4]; ++ uint8_t reserved1[4]; ++ uint8_t hash256[32]; ++ uint8_t hash384[48]; ++ uint8_t reserved2[32]; ++}__attribute__((packed)); ++ ++/** @class Manager ++ * @brief Contains a map of Version dbus objects. ++ * @details The software image manager class that contains the Version dbus ++ * objects and their version ids. ++ */ ++class Manager ++{ ++ public: ++ /** @brief Constructs Manager Class ++ * ++ * @param[in] bus - The Dbus bus object ++ */ ++ Manager(sdbusplus::bus::bus& bus) : bus(bus){}; ++ ++ /** ++ * @brief Verify the image and provide the image to updater. ++ * Create and populate the version and file path interfaces. ++ * ++ * @param[in] uploaded image. ++ * @param[out] result - 0 if successful. ++ */ ++ int processImage(const std::string& imageFilePath); ++ ++ /** ++ * @brief Erase specified entry d-bus object ++ * and deletes the image file. ++ * ++ * @param[in] entryId - unique identifier of the entry ++ */ ++ void erase(std::string entryId); ++ ++ private: ++ /** @brief Persistent map of Version dbus objects and their ++ * version id */ ++ std::map<std::string, std::unique_ptr<Version>> versions; ++ ++ /** @brief Persistent sdbusplus DBus bus connection. */ ++ sdbusplus::bus::bus& bus; ++ ++}; ++ ++} // namespace manager ++} // namespace software ++} // namespace phosphor +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch new file mode 100644 index 000000000..31373104f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch @@ -0,0 +1,408 @@ +From ac6e0c217a1b136d82f93b691aff1acb40009f26 Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +Date: Thu, 5 Dec 2019 11:55:36 +0530 +Subject: [PATCH] PFR image HASH verification + +This adds HASH verification on PFR images uploaded for +firmware updates + +Tested: tested firmware update with good and bad HASH images. + +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +--- + pfr_image_manager.cpp | 149 ++++++++++++++++++++++++++++++++---------- + pfr_image_manager.hpp | 112 +++++++++++++++++++++++++++++-- + 2 files changed, 221 insertions(+), 40 deletions(-) + +diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp +index 242a6ca..1a41cbe 100644 +--- a/pfr_image_manager.cpp ++++ b/pfr_image_manager.cpp +@@ -5,6 +5,8 @@ + #include "version.hpp" + #include "watch.hpp" + ++#include <fcntl.h> ++#include <openssl/err.h> + #include <stdio.h> + #include <stdlib.h> + #include <sys/stat.h> +@@ -15,9 +17,9 @@ + #include <algorithm> + #include <cstring> + #include <elog-errors.hpp> +-#include <filesystem> + #include <fstream> + #include <iomanip> ++#include <set> + #include <sstream> + #include <string> + #include <xyz/openbmc_project/Software/Image/error.hpp> +@@ -33,12 +35,21 @@ using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; + namespace Software = phosphor::logging::xyz::openbmc_project::Software; + + static constexpr const uint32_t pfmPos = 2054; ++static constexpr const uint32_t block0Magic = 0xB6EAFD19; ++static constexpr const uint32_t lengthBlk0Blk1 = 1024; + +-static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, +- std::string& version) ++int Manager::verifyPFRImage(const std::filesystem::path imgPath, ++ std::string& version, std::string& purposeString) + { +- struct pfrImgBlock0 block0Data; +- uint8_t verData[2]; ++ uint8_t imgType = 0; ++ uint32_t imgMagic = 0; ++ uint8_t verData[2] = {0}; ++ uint32_t hashLen = 0; ++ struct pfrImgBlock0 block0Data = {}; ++ ++ std::string imageName; ++ ++ EVP_MD_CTX* ctx; + + if (std::filesystem::exists(imgPath)) + { +@@ -55,17 +66,101 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, + + imgFile.read(reinterpret_cast<char*>(&block0Data), + sizeof(block0Data)); ++ ++ imgMagic = block0Data.tag; ++ ++ if (imgMagic != block0Magic) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Image magic number match failed", ++ phosphor::logging::entry("IMAGEMAGIC=0x%x", imgMagic)); ++ return -1; ++ } ++ + imgType = block0Data.pcType[0]; ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Image Type", phosphor::logging::entry( ++ "IMAGETYPE=0x%x", static_cast<int>(imgType))); ++ ++ if (imgType == pfrBMCUpdateCap || imgType == pfrBMCPFM) ++ { ++ imageName = "BMC"; ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; ++ } ++ else if (imgType == pfrPCHUpdateCap || imgType == pfrPCHPFM) ++ { ++ imageName = "BIOS"; ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; ++ } ++ else if (imgType == pfrCPLDUpdateCap) ++ { ++ imageName = "CPLD"; ++ purposeString = ++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; ++ } ++ else ++ { ++ purposeString = "xyz.openbmc_project.Software.Version." ++ "VersionPurpose.Unknown"; ++ ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unknown image type"); ++ return -1; ++ } ++ + imgFile.seekg(pfmPos, + std::ios::beg); // Version is at 0x806 in the PFM + imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData)); + imgFile.close(); +- version = +- std::to_string(verData[0]) + "." + std::to_string(verData[1]); ++ ++ auto size = std::filesystem::file_size(imgPath); ++ ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "Image Size", phosphor::logging::entry("IMAGESIZE=0x%x", ++ static_cast<int>(size))); ++ ++ // Adds all digest algorithms to the internal table ++ OpenSSL_add_all_digests(); ++ ++ ctx = EVP_MD_CTX_create(); ++ EVP_DigestInit(ctx, EVP_sha256()); ++ ++ // Hash the image file and update the digest ++ auto dataPtr = mapFile(imgPath, size); ++ ++ EVP_DigestUpdate(ctx, ((uint8_t*)dataPtr() + lengthBlk0Blk1), ++ (size - lengthBlk0Blk1)); ++ ++ std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256())); ++ std::vector<uint8_t> expectedDigest(block0Data.hash256, ++ &block0Data.hash256[0] + 32); ++ ++ EVP_DigestFinal(ctx, digest.data(), &hashLen); ++ EVP_MD_CTX_destroy(ctx); ++ ++ std::string redfishMsgID = "OpenBMC.0.1"; ++ ++ if (expectedDigest != digest) ++ { ++ redfishMsgID += ".GeneralFirmwareSecurityViolation"; ++ sd_journal_send("MESSAGE=%s", ++ "Firmware image HASH verification failed", ++ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s", ++ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s", ++ "Image HASH check fail", NULL); ++ return -1; ++ } ++ + phosphor::logging::log<phosphor::logging::level::INFO>( + "PFR image", + phosphor::logging::entry("PCType=%d", block0Data.pcType[0]), + phosphor::logging::entry("VERSION=%s", version.c_str())); ++ ++ version = ++ std::to_string(verData[0]) + "." + std::to_string(verData[1]); + } + catch (std::exception& e) + { +@@ -79,20 +174,20 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType, + + int Manager::processImage(const std::string& imgFilePath) + { ++ + std::filesystem::path imgPath(imgFilePath); + + if (!std::filesystem::exists(imgPath)) + return -1; + +- uint8_t imgType; + int retry = 3; + std::string ver; + std::string purposeString; + +- if (0 != getPFRImgInfo(imgFilePath, imgType, ver)) ++ if (0 != verifyPFRImage(imgFilePath, ver, purposeString)) + { + phosphor::logging::log<phosphor::logging::level::ERR>( +- "Error reading uploaded image type and version"); ++ "Error verifying uploaded image"); + return -1; + } + +@@ -103,31 +198,6 @@ int Manager::processImage(const std::string& imgFilePath) + return -1; + } + +- if (imgType == pfrBMCUpdateCap) +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; +- } +- else if (imgType == pfrPCHUpdateCap) +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; +- } +- else if (imgType == pfrCPLDUpdateCap) +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.Other"; +- } +- else +- { +- purposeString = +- "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown"; +- +- phosphor::logging::log<phosphor::logging::level::ERR>( +- "Unknown image type"); +- return -1; +- } +- + sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose + purpose = Version::VersionPurpose::Unknown; + try +@@ -169,6 +239,7 @@ int Manager::processImage(const std::string& imgFilePath) + std::filesystem::create_directory(imageDirPath); + + std::filesystem::path newFileName = imageDirPath / "image-runtime"; ++ + std::filesystem::rename(imgFilePath, newFileName); + + // Create Version object +@@ -212,6 +283,14 @@ void Manager::erase(std::string entryId) + this->versions.erase(entryId); + } + ++CustomMap Manager::mapFile(const std::filesystem::path& path, size_t size) ++{ ++ ++ CustomFd fd(open(path.c_str(), O_RDONLY)); ++ ++ return CustomMap(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd(), 0), ++ size); ++} + } // namespace manager + } // namespace software + } // namespace phosphor +diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp +index c6ee6a4..5b7b2c3 100644 +--- a/pfr_image_manager.hpp ++++ b/pfr_image_manager.hpp +@@ -1,6 +1,13 @@ + #pragma once + #include "version.hpp" + ++#include <openssl/evp.h> ++#include <openssl/pem.h> ++#include <openssl/rsa.h> ++#include <sys/mman.h> ++#include <unistd.h> ++ ++#include <filesystem> + #include <sdbusplus/server.hpp> + + namespace phosphor +@@ -10,7 +17,8 @@ namespace software + namespace manager + { + +-enum pfrImgPCType { ++enum pfrImgPCType ++{ + pfrCPLDUpdateCap = 0x00, + pfrPCHPFM = 0x01, + pfrPCHUpdateCap = 0x02, +@@ -19,15 +27,94 @@ enum pfrImgPCType { + }; + + /* PFR image block 0 - As defined in HAS */ +-struct pfrImgBlock0 { +- uint8_t tag[4]; ++struct pfrImgBlock0 ++{ ++ uint32_t tag; + uint8_t pcLength[4]; + uint8_t pcType[4]; + uint8_t reserved1[4]; + uint8_t hash256[32]; + uint8_t hash384[48]; + uint8_t reserved2[32]; +-}__attribute__((packed)); ++} __attribute__((packed)); ++ ++/** @struct CustomFd ++ * ++ * RAII wrapper for file descriptor. ++ */ ++struct CustomFd ++{ ++ public: ++ CustomFd() = delete; ++ CustomFd(const CustomFd&) = delete; ++ CustomFd& operator=(const CustomFd&) = delete; ++ CustomFd(CustomFd&&) = default; ++ CustomFd& operator=(CustomFd&&) = default; ++ /** @brief Saves File descriptor and uses it to do file operation ++ * ++ * @param[in] fd - File descriptor ++ */ ++ CustomFd(int fd) : fd(fd) ++ { ++ } ++ ++ ~CustomFd() ++ { ++ if (fd >= 0) ++ { ++ close(fd); ++ } ++ } ++ ++ int operator()() const ++ { ++ return fd; ++ } ++ ++ private: ++ /** @brief File descriptor */ ++ int fd = -1; ++}; ++ ++/** @struct CustomMap ++ * ++ * RAII wrapper for mmap. ++ */ ++struct CustomMap ++{ ++ private: ++ /** @brief starting address of the map */ ++ void* addr; ++ ++ /** @brief length of the mapping */ ++ size_t length; ++ ++ public: ++ CustomMap() = delete; ++ CustomMap(const CustomMap&) = delete; ++ CustomMap& operator=(const CustomMap&) = delete; ++ CustomMap(CustomMap&&) = default; ++ CustomMap& operator=(CustomMap&&) = default; ++ ++ /** @brief Saves starting address of the map and ++ * and length of the file. ++ * @param[in] addr - Starting address of the map ++ * @param[in] length - length of the map ++ */ ++ CustomMap(void* addr, size_t length) : addr(addr), length(length) ++ { ++ } ++ ++ ~CustomMap() ++ { ++ munmap(addr, length); ++ } ++ ++ void* operator()() const ++ { ++ return addr; ++ } ++}; + + /** @class Manager + * @brief Contains a map of Version dbus objects. +@@ -61,13 +148,28 @@ class Manager + void erase(std::string entryId); + + private: ++ /** ++ * @brief Memory map the file ++ * @param[in] - file path ++ * @param[in] - file size ++ * @param[out] - Custom Mmap address ++ */ ++ CustomMap mapFile(const std::filesystem::path& path, size_t size); ++ ++ /** ++ * @brief Verify the PFR image and return version and purpose ++ * @param[in] - file path ++ * @param[out] - version ++ * @param[out] - purpose ++ */ ++ int verifyPFRImage(const std::filesystem::path imgPath, ++ std::string& version, std::string& purposeString); + /** @brief Persistent map of Version dbus objects and their + * version id */ + std::map<std::string, std::unique_ptr<Version>> versions; + + /** @brief Persistent sdbusplus DBus bus connection. */ + sdbusplus::bus::bus& bus; +- + }; + + } // namespace manager +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service new file mode 100644 index 000000000..64d9a47a6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service @@ -0,0 +1,8 @@ +[Unit]
+Description=Flash BMC with fwupd script : %I
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/fwupd.sh %i
+SyslogIdentifier=fwupd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend new file mode 100644 index 000000000..96ddfc3ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend @@ -0,0 +1,19 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +EXTRA_OECONF += "--enable-fwupd_script" + +SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service" + +EXTRA_OECONF += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '--enable-pfr_update', '', d)}" + +SRC_URI += "file://0002-Redfish-firmware-activation.patch \ + file://0004-Changed-the-condition-of-software-version-service-wa.patch \ + file://0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch \ + file://0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch \ + file://0007-Adding-StandBySpare-for-firmware-activation.patch \ + " + +SRC_URI_PFR = "file://0007-PFR-images-support.patch \ + file://0008-PFR-image-HASH-verification.patch \ + " + +SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', SRC_URI_PFR, '', d)}" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb new file mode 100644 index 000000000..53cec437d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb @@ -0,0 +1,30 @@ +SUMMARY = "Default Fru" +DESCRIPTION = "Builds a default FRU file at runtime based on board ID" + +inherit systemd +inherit cmake + +SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service" + +S = "${WORKDIR}" +SRC_URI = "file://checkFru.sh \ + file://SetBaseboardFru.service \ + file://mkfru.cpp \ + file://CMakeLists.txt \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "\ + file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \ + file://mkfru.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \ + " + +RDEPENDS_${PN} = "bash" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh + + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/SetBaseboardFru.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt new file mode 100644 index 000000000..a8e633644 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(mkfru CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(mkfru mkfru.cpp) +install(TARGETS mkfru DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service new file mode 100644 index 000000000..d8c2a75ac --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service @@ -0,0 +1,9 @@ +[Unit] +Description=Check for FRU presence + +[Service] +ExecStart=/usr/bin/checkFru.sh +Type=oneshot + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh new file mode 100755 index 000000000..3bf1aedb5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# this script checks the gpio id and loads the correct baseboard fru +FRUPATH="/etc/fru" +PRODIDPATH="/var/cache/private" +fruFile="$FRUPATH/baseboard.fru.bin" +prodIDFile="$PRODIDPATH/prodID" + +if [ -f $fruFile -a -f $prodIDFile ]; then + exit 0 +fi + +read_id() { + local idx=0 + local result=0 + local value=0 + for ((idx=0; idx<6; idx++)) + do + typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N")) + value=$((value << idx)) + result=$((result | value)) + done + echo $result +} + +BOARD_ID=$(read_id) +if grep -q 'CPU part\s*: 0xb76' /proc/cpuinfo; then + # AST2500 + case $BOARD_ID in + 12) NAME="D50TNP1SB" + PRODID="0x99";; + 40) NAME="CooperCity" + PRODID="0x9d";; + 42) NAME="WilsonCity" + PRODID="0x91";; + 45) NAME="WilsonCity" + PRODID="0x91";; + 60) NAME="M50CYP2SB2U" + PRODID="0x98";; + 62) NAME="WilsonPoint" + PRODID="0x9a";; + *) NAME="S2600WFT" + PRODID="0x7b";; + esac + +elif grep -q 'CPU part\s*: 0xc07' /proc/cpuinfo; then + # AST2600 + case $BOARD_ID in + 62) NAME="ArcherCity" + PRODID="0x9c";; + *) NAME="AST2600EVB" + PRODID="0x00";; + esac + +fi + +if [ -z "$NAME" ]; then + NAME="Unknown" +fi + +if [ ! -e $prodIDFile ] +then + echo $PRODID >$prodIDFile +fi + +if [ ! -f $fruFile ] +then + cd /tmp + mkdir -p $FRUPATH + mkfru $NAME + mv $NAME.fru.bin $fruFile +fi + + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp new file mode 100644 index 000000000..afadbd324 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp @@ -0,0 +1,219 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: default FRU generation +// +*/ + +#include <fstream> +#include <iostream> +#include <iterator> +#include <numeric> +#include <string> +#include <vector> + +constexpr uint8_t fillChar = '.'; +constexpr uint8_t eof = 0xc1; +const std::string intel = "Intel Corporation"; + +// round up to nearest block size (power of 2) +constexpr size_t blockRound(size_t len, size_t blk) +{ + return ((len) + (((blk) - ((len) & ((blk)-1))) & ((blk)-1))); +} + +uint8_t mklen(uint8_t len) +{ + return static_cast<uint8_t>((0x3 << 6) | len); +} + +struct FruEntry +{ + static constexpr size_t fruBlockSize = 8; // type, length, checksum + static constexpr size_t fixedBytes = 3; // type, length, checksum + FruEntry() = delete; + FruEntry(const std::vector<uint8_t>& contents) + { + constexpr size_t verOffset = 0; + constexpr size_t lenOffset = 1; + value.resize(blockRound(fixedBytes + contents.size(), fruBlockSize)); + value[verOffset] = 1; + value[lenOffset] = blocks(); + std::copy(contents.begin(), contents.end(), value.begin() + 2); + addChecksum(); + } + + void addChecksum() + { + int sum = std::accumulate(value.begin(), value.end(), 0); + value.back() = static_cast<uint8_t>(256 - sum & 0xff); + } + + uint8_t blocks() const + { + return static_cast<uint8_t>(value.size() / 8); + } + + std::vector<uint8_t> value; +}; + +size_t fillDots(std::vector<uint8_t>::iterator start, size_t count) +{ + *start++ = mklen(count); // prefix with (0xc0 | count) + auto end = start + count++; + std::fill(start, end, '.'); + return count; +} + +size_t fillStr(std::vector<uint8_t>::iterator start, const std::string& str) +{ + size_t count = str.size(); + *start++ = mklen(count++); // prefix with (0xc0 | count) + std::copy(str.begin(), str.end(), start); + return count; +} + +std::vector<uint8_t> genChassisContents() +{ + constexpr size_t pnSize = 18; + constexpr size_t snSize = 18; + constexpr size_t amSize = 31; + constexpr size_t headerSize = 1; + constexpr size_t contentSize = headerSize + 1 + pnSize + 1 + snSize + 1 + + amSize + 1 + amSize + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0x17; + // chassis part number + offset += fillDots(data.begin() + offset, pnSize); + // chassis serial number + offset += fillDots(data.begin() + offset, snSize); + // info am1 + offset += fillDots(data.begin() + offset, amSize); + // info am2 + offset += fillDots(data.begin() + offset, amSize); + data[offset] = eof; + + return data; +} + +std::vector<uint8_t> genBoardContents(const std::string& name) +{ + constexpr size_t headerSize = 4; + constexpr size_t snSize = 12; + constexpr size_t pnSize = 10; + const std::string version = "FRU Ver 0.01"; + size_t contentSize = headerSize + 1 + name.size() + 1 + intel.size() + 1 + + snSize + 1 + pnSize + 1 + version.size() + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0; // language code + data[offset++] = 0; // mfg date/time + data[offset++] = 0; // mfg date/time + data[offset++] = 0; // mfg date/time + // manufacturer name + offset += fillStr(data.begin() + offset, intel); + // product name + offset += fillStr(data.begin() + offset, name); + // board sn + offset += fillDots(data.begin() + offset, snSize); + // board pn + offset += fillDots(data.begin() + offset, pnSize); + // fru version string + offset += fillStr(data.begin() + offset, version); + data[offset] = eof; + + return data; +} + +std::vector<uint8_t> genProductContents(const std::string& name) +{ + constexpr size_t headerSize = 1; + constexpr size_t pnSize = 10; + constexpr size_t pvSize = 20; + constexpr size_t snSize = 12; + constexpr size_t atSize = 20; + constexpr size_t idSize = 0; + const std::string version = "FRU Ver 0.01"; + size_t contentSize = headerSize + 1 + intel.size() + 1 + name.size() + 1 + + pnSize + 1 + pvSize + 1 + snSize + 1 + atSize + 1 + + idSize + sizeof(eof); + std::vector<uint8_t> data(contentSize); + size_t offset = 0; + // chassis type (main server chassis) + data[offset++] = 0; // language code + // manufacturer name + offset += fillStr(data.begin() + offset, intel); + // product name + offset += fillStr(data.begin() + offset, name); + // product part number + offset += fillDots(data.begin() + offset, pnSize); + // product version + offset += fillDots(data.begin() + offset, pvSize); + // product serial number + offset += fillDots(data.begin() + offset, snSize); + // product asset tag + offset += fillDots(data.begin() + offset, atSize); + // empty fru file id + offset += fillDots(data.begin() + offset, idSize); + data[offset] = eof; + + return data; +} + +int createFru(const std::string& name) +{ + std::vector<uint8_t> internal{1, 0, 0, 0, 0, 0, 0, 1}; // fixed data + FruEntry chassis(genChassisContents()); + FruEntry board(genBoardContents(name)); + FruEntry product(genProductContents(name)); + uint8_t offset = 1; // room for header's offset + FruEntry header({ + offset += 1, // internal size + offset += chassis.blocks(), + offset += board.blocks(), + }); + std::string filename = name + ".fru.bin"; + std::ofstream output(filename); + std::ostream_iterator<uint8_t> outputIter(output); + std::copy(header.value.begin(), header.value.end(), outputIter); + std::copy(internal.begin(), internal.end(), outputIter); + std::copy(chassis.value.begin(), chassis.value.end(), outputIter); + std::copy(board.value.begin(), board.value.end(), outputIter); + std::copy(product.value.begin(), product.value.end(), outputIter); + constexpr size_t minFruSize = 0x1ff; + size_t fruSize = header.value.size() + internal.size() + + chassis.value.size() + board.value.size() + + product.value.size(); + if (fruSize < minFruSize) + { + std::vector<uint8_t> padding(minFruSize - fruSize); + std::copy(padding.begin(), padding.end(), outputIter); + } + output.close(); + return 0; +} + +int main(int argc, const char* argv[]) +{ + if (argc != 2) + { + std::cerr << "Usage: " << argv[0] << " <'Product Name'>\n"; + return 1; + } + return createFru(argv[1]); +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend new file mode 100644 index 000000000..5326680f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend @@ -0,0 +1,6 @@ +SYSTEMD_LINK_${PN}_remove += "../op-start-host@.service:obmc-host-startmin@0.target.requires/op-start-host@0.service" +SYSTEMD_LINK_${PN}_remove += "../op-init-pnor@.service:obmc-host-startmin@0.target.requires/op-init-pnor@0.service" + +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-start-host@0.service" +FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-init-pnor@0.service"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch new file mode 100644 index 000000000..dc3ec060e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch @@ -0,0 +1,484 @@ +From 17caf10b048450979dcd95a9f9333bbaa8c307ec Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Fri, 10 Jan 2020 08:16:10 +0530 +Subject: [PATCH] Firmware update support for StandBySpare + +Firmware update support for StandBySpare. This will +have support for adding 'HttpPushUriTargets' and +'HttpPushUriTargetsBusy' attributes. These attributes enables +'HttpPushUri' to distinguish between the firmware update targets. + +Tested: + - GET on "/redfish/v1/UpdateService", got below response +......... + "HttpPushUriTargets": [], + "HttpPushUriTargetsBusy": false +........ + + - PATCH on "/redfish/v1/UpdateService" and works fine. +{ + "HttpPushUriTargets": ["bmc_recovery"], + "HttpPushUriTargetsBusy": true +} + + - Did Firmware update and verified end to end functionality + for both bmc active and backup images. + + - Successfully ran redfish validater with no new errors. + +Change-Id: I59f317ac001ebf56bbf30e7f43dbec5d69fa249a +Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com> +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + redfish-core/lib/update_service.hpp | 284 ++++++++++++++++++++++++++++++------ + 1 file changed, 241 insertions(+), 43 deletions(-) + +diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp +index ec9600e..9daf6ce 100644 +--- a/redfish-core/lib/update_service.hpp ++++ b/redfish-core/lib/update_service.hpp +@@ -30,6 +30,17 @@ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher; + static bool fwUpdateInProgress = false; + // Timer for software available + static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer; ++static constexpr const char *versionIntf = ++ "xyz.openbmc_project.Software.Version"; ++static constexpr const char *activationIntf = ++ "xyz.openbmc_project.Software.Activation"; ++static constexpr const char *reqActivationPropName = "RequestedActivation"; ++static constexpr const char *reqActivationsActive = ++ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"; ++static constexpr const char *reqActivationsStandBySpare = ++ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare"; ++static constexpr const char *activationsStandBySpare = ++ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare"; + + static void cleanUp() + { +@@ -37,27 +48,118 @@ static void cleanUp() + fwUpdateMatcher = nullptr; + } + static void activateImage(const std::string &objPath, +- const std::string &service) ++ const std::string &service, ++ const std::vector<std::string> &imgUriTargets) + { + BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; ++ ++ // If targets is empty, it will apply to the active. ++ if (imgUriTargets.size() == 0) ++ { ++ crow::connections::systemBus->async_method_call( ++ [](const boost::system::error_code error_code) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG << "RequestedActivation failed: ec = " ++ << error_code; ++ } ++ }, ++ service, objPath, "org.freedesktop.DBus.Properties", "Set", ++ activationIntf, reqActivationPropName, ++ std::variant<std::string>(reqActivationsActive)); ++ return; ++ } ++ ++ // TODO: Now we support only one target becuase software-manager ++ // code support one activation per object. It will be enhanced ++ // to multiple targets for single image in future. For now, ++ // consider first target alone. + crow::connections::systemBus->async_method_call( +- [](const boost::system::error_code error_code) { +- if (error_code) ++ [objPath, service, imgTarget{imgUriTargets[0]}]( ++ const boost::system::error_code ec, ++ const crow::openbmc_mapper::GetSubTreeType &subtree) { ++ if (ec || !subtree.size()) + { +- BMCWEB_LOG_DEBUG << "error_code = " << error_code; +- BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); ++ return; ++ } ++ ++ for (const auto &[invObjPath, invDict] : subtree) ++ { ++ std::size_t idPos = invObjPath.rfind("/"); ++ if ((idPos == std::string::npos) || ++ ((idPos + 1) >= invObjPath.size())) ++ { ++ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; ++ return; ++ } ++ std::string swId = invObjPath.substr(idPos + 1); ++ ++ if (swId != imgTarget) ++ { ++ continue; ++ } ++ ++ if (invDict.size() < 1) ++ { ++ continue; ++ } ++ BMCWEB_LOG_DEBUG << "Image target matched with object " ++ << invObjPath; ++ crow::connections::systemBus->async_method_call( ++ [objPath, ++ service](const boost::system::error_code error_code, ++ const std::variant<std::string> value) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "Error in querying activation value"; ++ // not all fwtypes are updateable, ++ // this is ok ++ return; ++ } ++ std::string activationValue = ++ std::get<std::string>(value); ++ BMCWEB_LOG_DEBUG << "Activation Value: " ++ << activationValue; ++ std::string reqActivation = reqActivationsActive; ++ if (activationValue == activationsStandBySpare) ++ { ++ reqActivation = reqActivationsStandBySpare; ++ } ++ BMCWEB_LOG_DEBUG ++ << "Setting RequestedActivation value as " ++ << reqActivation << " for " << service << " " ++ << objPath; ++ crow::connections::systemBus->async_method_call( ++ [](const boost::system::error_code error_code) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "RequestedActivation failed: ec = " ++ << error_code; ++ } ++ return; ++ }, ++ service, objPath, "org.freedesktop.DBus.Properties", ++ "Set", activationIntf, reqActivationPropName, ++ std::variant<std::string>(reqActivation)); ++ }, ++ invDict[0].first, ++ "/xyz/openbmc_project/software/" + imgTarget, ++ "org.freedesktop.DBus.Properties", "Get", activationIntf, ++ "Activation"); + } + }, +- service, objPath, "org.freedesktop.DBus.Properties", "Set", +- "xyz.openbmc_project.Software.Activation", "RequestedActivation", +- std::variant<std::string>( +- "xyz.openbmc_project.Software.Activation.RequestedActivations." +- "Active")); ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", ++ static_cast<int32_t>(0), std::array<const char *, 1>{versionIntf}); + } + + // Note that asyncResp can be either a valid pointer or nullptr. If nullptr + // then no asyncResp updates will occur + static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, ++ const std::vector<std::string> imgUriTargets, + sdbusplus::message::message &m) + { + std::vector<std::pair< +@@ -69,27 +171,24 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, + + m.read(objPath, interfacesProperties); + +- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; ++ BMCWEB_LOG_DEBUG << "Software Interface Added. objPath = " << objPath.str; + for (auto &interface : interfacesProperties) + { +- BMCWEB_LOG_DEBUG << "interface = " << interface.first; +- +- if (interface.first == "xyz.openbmc_project.Software.Activation") ++ if (interface.first == activationIntf) + { + // Found our interface, disable callbacks + fwUpdateMatcher = nullptr; +- + // Retrieve service and activate + crow::connections::systemBus->async_method_call( +- [objPath, asyncResp]( ++ [objPath, asyncResp, imgTargets{imgUriTargets}]( + const boost::system::error_code error_code, + const std::vector<std::pair< + std::string, std::vector<std::string>>> &objInfo) { + if (error_code) + { +- BMCWEB_LOG_DEBUG << "error_code = " << error_code; +- BMCWEB_LOG_DEBUG << "error msg = " +- << error_code.message(); ++ BMCWEB_LOG_DEBUG ++ << "GetSoftwareObject path failed: ec = " ++ << error_code; + if (asyncResp) + { + messages::internalError(asyncResp->res); +@@ -113,8 +212,7 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, + // xyz.openbmc_project.Software.Activation interface + // is added + fwAvailableTimer = nullptr; +- +- activateImage(objPath.str, objInfo[0].first); ++ activateImage(objPath.str, objInfo[0].first, imgTargets); + if (asyncResp) + { + redfish::messages::success(asyncResp->res); +@@ -124,17 +222,16 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, +- std::array<const char *, 1>{ +- "xyz.openbmc_project.Software.Activation"}); ++ std::array<const char *, 1>{activationIntf}); + } + } + } + + // Note that asyncResp can be either a valid pointer or nullptr. If nullptr + // then no asyncResp updates will occur +-static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, +- const crow::Request &req, +- int timeoutTimeSeconds = 5) ++static void monitorForSoftwareAvailable( ++ std::shared_ptr<AsyncResp> asyncResp, const crow::Request &req, ++ const std::vector<std::string> &imgUriTargets, int timeoutTimeSeconds = 5) + { + // Only allow one FW update at a time + if (fwUpdateInProgress != false) +@@ -145,7 +242,6 @@ static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, + } + return; + } +- + fwAvailableTimer = + std::make_unique<boost::asio::steady_timer>(*req.ioService); + +@@ -174,10 +270,10 @@ static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, + } + }); + +- auto callback = [asyncResp](sdbusplus::message::message &m) { +- BMCWEB_LOG_DEBUG << "Match fired"; +- softwareInterfaceAdded(asyncResp, m); +- }; ++ auto callback = ++ [asyncResp, imgTargets{imgUriTargets}](sdbusplus::message::message &m) { ++ softwareInterfaceAdded(asyncResp, imgTargets, m); ++ }; + + fwUpdateInProgress = true; + +@@ -286,9 +382,12 @@ class UpdateServiceActionsSimpleUpdate : public Node + std::string fwFile = imageURI.substr(separator + 1); + BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; + ++ // We will pass empty targets and its handled in activation. ++ std::vector<std::string> httpUriTargets; ++ + // Setup callback for when new software detected + // Give TFTP 2 minutes to complete +- monitorForSoftwareAvailable(nullptr, req, 120); ++ monitorForSoftwareAvailable(nullptr, req, httpUriTargets, 120); + + // TFTP can take up to 2 minutes depending on image size and + // connection speed. Return to caller as soon as the TFTP operation +@@ -322,7 +421,8 @@ class UpdateServiceActionsSimpleUpdate : public Node + class UpdateService : public Node + { + public: +- UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") ++ UpdateService(CrowApp &app) : ++ Node(app, "/redfish/v1/UpdateService/"), httpPushUriTargetBusy(false) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, +@@ -334,6 +434,9 @@ class UpdateService : public Node + } + + private: ++ std::vector<std::string> httpPushUriTargets; ++ bool httpPushUriTargetBusy; ++ + void doGet(crow::Response &res, const crow::Request &req, + const std::vector<std::string> ¶ms) override + { +@@ -346,6 +449,8 @@ class UpdateService : public Node + res.jsonValue["Description"] = "Service for Software Update"; + res.jsonValue["Name"] = "Update Service"; + res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; ++ res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets; ++ res.jsonValue["HttpPushUriTargetsBusy"] = httpPushUriTargetBusy; + // UpdateService cannot be disabled + res.jsonValue["ServiceEnabled"] = true; + res.jsonValue["FirmwareInventory"] = { +@@ -405,9 +510,14 @@ class UpdateService : public Node + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + std::optional<nlohmann::json> pushUriOptions; +- if (!json_util::readJson(req, res, "HttpPushUriOptions", +- pushUriOptions)) ++ std::optional<std::vector<std::string>> imgTargets; ++ std::optional<bool> imgTargetBusy; ++ ++ if (!json_util::readJson(req, res, "HttpPushUriOptions", pushUriOptions, ++ "HttpPushUriTargets", imgTargets, ++ "HttpPushUriTargetsBusy", imgTargetBusy)) + { ++ BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body"; + return; + } + +@@ -464,7 +574,6 @@ class UpdateService : public Node + messages::internalError(asyncResp->res); + return; + } +- messages::success(asyncResp->res); + }, + "xyz.openbmc_project.Settings", + "/xyz/openbmc_project/software/apply_time", +@@ -475,6 +584,98 @@ class UpdateService : public Node + } + } + } ++ ++ if (imgTargetBusy) ++ { ++ if ((httpPushUriTargetBusy) && (*imgTargetBusy)) ++ { ++ BMCWEB_LOG_DEBUG ++ << "Other client has reserved the HttpPushUriTargets " ++ "property for firmware updates."; ++ messages::resourceInUse(asyncResp->res); ++ return; ++ } ++ ++ if (imgTargets) ++ { ++ if (!(*imgTargetBusy)) ++ { ++ BMCWEB_LOG_DEBUG ++ << "UpdateService doPatch: httpPushUriTargetBusy " ++ "should be " ++ "true before setting httpPushUriTargets"; ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargetsBusy"); ++ return; ++ } ++ if ((*imgTargets).size() != 0) ++ { ++ // TODO: Now we support max one target becuase ++ // software-manager code support one activation per object. ++ // It will be enhanced to multiple targets for single image ++ // in future. For now, consider first target alone. ++ if ((*imgTargets).size() != 1) ++ { ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargets"); ++ return; ++ } ++ crow::connections::systemBus->async_method_call( ++ [this, asyncResp, uriTargets{*imgTargets}, ++ targetBusy{*imgTargetBusy}]( ++ const boost::system::error_code ec, ++ const std::vector<std::string> swInvPaths) { ++ if (ec) ++ { ++ return; ++ } ++ ++ bool swInvObjFound = false; ++ for (const std::string &path : swInvPaths) ++ { ++ std::size_t idPos = path.rfind("/"); ++ if ((idPos == std::string::npos) || ++ ((idPos + 1) >= path.size())) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_DEBUG ++ << "Can't parse firmware ID!!"; ++ return; ++ } ++ std::string swId = path.substr(idPos + 1); ++ ++ if (swId == uriTargets[0]) ++ { ++ swInvObjFound = true; ++ break; ++ } ++ } ++ if (!swInvObjFound) ++ { ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargets"); ++ return; ++ } ++ this->httpPushUriTargetBusy = targetBusy; ++ this->httpPushUriTargets = uriTargets; ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", ++ "/", static_cast<int32_t>(0), ++ std::array<const char *, 1>{versionIntf}); ++ } ++ else ++ { ++ httpPushUriTargetBusy = *imgTargetBusy; ++ httpPushUriTargets = *imgTargets; ++ } ++ } ++ else ++ { ++ httpPushUriTargetBusy = *imgTargetBusy; ++ } ++ } + } + + void doPost(crow::Response &res, const crow::Request &req, +@@ -485,7 +686,7 @@ class UpdateService : public Node + std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); + + // Setup callback for when new software detected +- monitorForSoftwareAvailable(asyncResp, req); ++ monitorForSoftwareAvailable(asyncResp, req, httpPushUriTargets); + + std::string filepath( + "/tmp/images/" + +@@ -574,8 +775,7 @@ class SoftwareInventoryCollection : public Node + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/software", static_cast<int32_t>(0), +- std::array<const char *, 1>{ +- "xyz.openbmc_project.Software.Version"}); ++ std::array<const char *, 1>{versionIntf}); + } + }; + +@@ -760,7 +960,7 @@ class SoftwareInventory : public Node + }, + obj.second[0].first, obj.first, + "org.freedesktop.DBus.Properties", "GetAll", +- "xyz.openbmc_project.Software.Version"); ++ versionIntf); + } + if (!found) + { +@@ -781,9 +981,7 @@ class SoftwareInventory : public Node + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", +- static_cast<int32_t>(0), +- std::array<const char *, 1>{ +- "xyz.openbmc_project.Software.Version"}); ++ static_cast<int32_t>(0), std::array<const char *, 1>{versionIntf}); + } + }; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket new file mode 100644 index 000000000..8782e4dd3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket @@ -0,0 +1,9 @@ +[Unit] +Description=BMC Webserver socket + +[Socket] +ListenStream=443 +ReusePort=true + +[Install] +WantedBy=sockets.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend new file mode 100644 index 000000000..54b4e1b6b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend @@ -0,0 +1,16 @@ +SRC_URI = "git://github.com/openbmc/bmcweb.git" +SRCREV = "363c23022eb3fb0cde577405e8a084a2e819b642" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +# add a user called bmcweb for the server to assume +# bmcweb is part of group shadow for non-root pam authentication +USERADD_PARAM_${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb" + +GROUPADD_PARAM_${PN} = "web; redfish " + +SRC_URI += "file://0001-Firmware-update-support-for-StandBySpare.patch" + +# Enable PFR support +EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DBMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE=ON', '', d)}" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/ipmitool_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/ipmitool_%.bbappend new file mode 100644 index 000000000..84e250b66 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/ipmitool_%.bbappend @@ -0,0 +1,6 @@ + +# Disable the shell to remove the usage of readline lib +# to fix the license conflict issue. More information: +# https://lists.ozlabs.org/pipermail/openbmc/2019-November/019678.html + +EXTRA_OECONF_append = " --disable-ipmishell" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend new file mode 100644 index 000000000..616fb9a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://dev_id.json \ + file://channel_access.json \ + file://channel_config.json \ + file://master_write_read_white_list.json \ + " + +FILES_${PN} += " \ + ${datadir}/ipmi-providers/channel_access.json \ + ${datadir}/ipmi-providers/channel_config.json \ + ${datadir}/ipmi-providers/master_write_read_white_list.json \ + " + +do_install_append() { + install -m 0644 -D ${WORKDIR}/channel_access.json \ + ${D}${datadir}/ipmi-providers/channel_access.json + install -m 0644 -D ${WORKDIR}/channel_config.json \ + ${D}${datadir}/ipmi-providers/channel_config.json + install -m 0644 -D ${WORKDIR}/master_write_read_white_list.json \ + ${D}${datadir}/ipmi-providers/master_write_read_white_list.json +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json new file mode 100644 index 000000000..299483121 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json @@ -0,0 +1,23 @@ +{ + "1" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "2" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + }, + "3" : { + "access_mode" : "always_available", + "user_auth_disabled" : false, + "per_msg_auth_disabled" : false, + "alerting_disabled" : false, + "priv_limit" : "priv-admin" + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json new file mode 100644 index 000000000..b02595e81 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json @@ -0,0 +1,178 @@ +{ + "0" : { + "name" : "Ipmb", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "1" : { + "name" : "eth1", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "lan-802.3", + "protocol_type" : "ipmb-1.0", + "session_supported" : "multi-session", + "is_ipmi" : true + } + }, + "2" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "3" : { + "name" : "eth0", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "lan-802.3", + "protocol_type" : "ipmb-1.0", + "session_supported" : "multi-session", + "is_ipmi" : true + } + }, + "4" : { + "name" : "RESERVED", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "5" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "6" : { + "name" : "SMLINK", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "7" : { + "name" : "ipmi_kcs4", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "system-interface", + "protocol_type" : "kcs", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "8" : { + "name" : "INTRABMC", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "oem", + "protocol_type" : "oem", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "9" : { + "name" : "SIPMB", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "10" : { + "name" : "PCIE", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "11" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "12" : { + "name" : "INTERNAL", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "ipmb", + "protocol_type" : "ipmb-1.0", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "13" : { + "name" : "RESERVED", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "reserved", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "14" : { + "name" : "SELF", + "is_valid" : false, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "unknown", + "protocol_type" : "na", + "session_supported" : "session-less", + "is_ipmi" : true + } + }, + "15" : { + "name" : "ipmi_kcs3", + "is_valid" : true, + "active_sessions" : 0, + "channel_info" : { + "medium_type" : "system-interface", + "protocol_type" : "kcs", + "session_supported" : "session-less", + "is_ipmi" : true + } + } +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json new file mode 100644 index 000000000..e561569d9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json @@ -0,0 +1,2 @@ +{"id": 35, "revision": 0, "addn_dev_support": 191, + "manuf_id": 343, "prod_id": 123, "aux": 0} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json new file mode 100644 index 000000000..6fc46f452 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json @@ -0,0 +1,76 @@ +{ + "filters": [ + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x01", + "slaveAddr": "0x4d", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x01", + "slaveAddr": "0x57", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x40", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x49", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x02", + "slaveAddr": "0x51", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x03", + "slaveAddr": "0x44", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x03", + "slaveAddr": "0x68", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x06", + "slaveAddr": "0x40", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + }, + { + "Description": "Allow full read - ignore first byte write value", + "busId": "0x07", + "slaveAddr": "0x51", + "slaveAddrMask": "0x00", + "command": "0x00", + "commandMask": "0xFF" + } + ] +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend new file mode 100644 index 000000000..2d892ad1a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +SRC_URI += " file://config.yaml" + +#override source file before it is used for final FRU file (merged from multiple sources) +do_install() { + cp ${WORKDIR}/config.yaml ${config_datadir}/ +} + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml new file mode 100644 index 000000000..e9b7a621e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml @@ -0,0 +1,31 @@ +# A YAML similar to this example would have to be generated, for eg with MRW +# inputs and system configuration, to depict IPMI Fru information. +# +# This file maps IPMI properties to phosphor dbus inventory properties +# +# This YAML could help generate C++ code. +# Format of the YAML: +# Fruid: +# Associated Fru paths +# d-bus Interfaces +# d-bus Properties +# IPMI Fru mapping +0: + /system/board/WFP_Baseboard: + entityID: 23 + entityInstance: 1 + interfaces: + xyz.openbmc_project.Inventory.Item: + name: + IPMIFruProperty: Product Name + IPMIFruSection: Product + xyz.openbmc_project.Inventory.Decorator.Asset: + Manufacturer: + IPMIFruProperty: Manufacturer + IPMIFruSection: Product + PartNumber: + IPMIFruProperty: Part Number + IPMIFruSection: Product + SerialNumber: + IPMIFruProperty: Serial Number + IPMIFruSection: Product diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format new file mode 100644 index 000000000..ea71ad6e1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format @@ -0,0 +1,99 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch new file mode 100644 index 000000000..7e3f92dbc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch @@ -0,0 +1,231 @@ +From 8e9fba263179ccc87be7212c7dbd87cd7a37ac30 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey <johnathanx.mantey@intel.com> +Date: Thu, 14 Nov 2019 11:24:19 -0800 +Subject: [PATCH] Modify Get Lan Configuration IP Address Source to use correct + DBus DHCPEnabled type + +The Get/Set Lan Configuration "IP Address Source" subcommand got +broken by phosphor-dbus-interfaces commit 12162be + +12162be changed the DBus DHCPEnabled type from boolean to enum +type. The Get LAN Configuration IP address Source IPMI command did not +get changed to an enum type prior to 12162be being merged. This commit +retroactively updates the boolean type to enum type. + +Tested: + +ipmitool raw 0xc 2 3 4 0 0 # returns correct state +ipmitool raw 0xc 1 3 4 1 # changes DCHP to Static +ipmitool raw 0xc 1 3 4 2 # returns Static to DHCP + +Assigned a static address via Redfish and tested using: +ipmitool raw 0xc 2 3 4 0 0 # returns correct state + +Returned the NIC to use DHCP via Redfish and tested using: +ipmitool raw 0xc 2 3 4 0 0 # returns correct state + +Change-Id: Ia66f7fcf3d5ad0a383b06658b18e8ce2b282e052 +Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com> +--- + transporthandler.cpp | 97 ++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 79 insertions(+), 18 deletions(-) + +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 16ce2b2..ccc2a97 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -109,6 +109,18 @@ constexpr auto INTF_NEIGHBOR_CREATE_STATIC = + constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN"; + constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create"; + ++static constexpr auto dhcpv4v6 = ++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"; ++static constexpr auto dhcpv6 = ++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6"; ++static constexpr auto dhcpv4 = ++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4"; ++static constexpr auto dhcpoff = ++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.none"; ++ ++static std::array<const char*, 4> dhcpEnumerations = {dhcpv4v6, dhcpv4, dhcpv6, ++ dhcpoff}; ++ + /** @brief Generic paramters for different address families */ + template <int family> + struct AddrFamily +@@ -456,25 +468,63 @@ auto channelCall(uint8_t channel, Args&&... args) + * + * @param[in] bus - The bus object used for lookups + * @param[in] params - The parameters for the channel +- * @return True if DHCP is enabled, false otherwise ++ * @return string containing an enumerated value ++ * constexpr's dhcpv4v6, dhcpv4, dhcpv6, and dhcpoff + */ +-bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) ++std::string getDHCPProperty(sdbusplus::bus::bus& bus, ++ const ChannelParams& params) + { +- return std::get<bool>(getDbusProperty( ++ return std::get<std::string>(getDbusProperty( + bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled")); + } + + /** @brief Sets the system value for DHCP on the given interface + * +- * @param[in] bus - The bus object used for lookups +- * @param[in] params - The parameters for the channel +- * @param[in] on - Whether or not to enable DHCP ++ * @param[in] bus - The bus object used for lookups ++ * @param[in] params - The parameters for the channel ++ * @param[in] setting - DHCP state to assign (none, v4, v6, both) + */ + void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, +- bool on) ++ const std::string& setting) + { ++ auto it = dhcpEnumerations.begin(); ++ while (it != dhcpEnumerations.end()) ++ { ++ if (*it == setting) ++ { ++ break; ++ } ++ it++; ++ } ++ if (it == dhcpEnumerations.end()) ++ { ++ log<level::ERR>("Invalid DHCP setting.", ++ entry("Requested DHCP mode=%s", setting.c_str())); ++ elog<InternalFailure>(); ++ } ++ ++ std::string dhcp = getDHCPProperty(bus, params); ++ std::string nextDhcp{}; ++ ++ if (((dhcp == dhcpv4) && (setting == dhcpv6)) || ++ ((dhcp == dhcpv6) && (setting == dhcpv4))) ++ { ++ // DHCP is enabled independently for IPv4 and IPv6. If IPv4 ++ // DHCP is enabled, and a request to add IPv6 is received, ++ // change the DHCPEnabled enum to "both" active. The same ++ // logic is applied if IPV6 is already enabled, and an IPv4 ++ // enable request is made. ++ nextDhcp = dhcpv4v6; ++ } ++ else ++ { ++ // "both" enabled -> ipv4 only ++ // "both" enabled -> ipv6 only ++ // "ip4v", "ipv6", or "both" enabled -> no DHCP ++ nextDhcp = setting; ++ } + setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET, +- "DHCPEnabled", on); ++ "DHCPEnabled", nextDhcp); + } + + /** @brief Converts a human readable MAC string into MAC bytes +@@ -1113,7 +1163,7 @@ void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params) + } + + // Clear out any settings on the lower physical interface +- setDHCPProperty(bus, params, false); ++ setDHCPProperty(bus, params, dhcpoff); + } + + /** @brief Creates a new VLAN on the specified interface +@@ -1401,7 +1451,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, + } + case LanParam::IP: + { +- if (channelCall<getDHCPProperty>(channel)) ++ std::string dhcpSetting = channelCall<getDHCPProperty>(channel); ++ if ((dhcpSetting == dhcpv4) || (dhcpSetting == dhcpv4v6)) + { + return responseCommandNotAvailable(); + } +@@ -1431,7 +1482,11 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, + { + case IPSrc::DHCP: + { +- channelCall<setDHCPProperty>(channel, true); ++ // The IPSrc IPMI command is only for IPv4 ++ // management. Modifying IPv6 state is done using ++ // a completely different Set LAN Configuration ++ // subcommand. ++ channelCall<setDHCPProperty>(channel, dhcpv4); + return responseSuccess(); + } + case IPSrc::Unspecified: +@@ -1439,7 +1494,7 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, + case IPSrc::BIOS: + case IPSrc::BMC: + { +- channelCall<setDHCPProperty>(channel, false); ++ channelCall<setDHCPProperty>(channel, dhcpoff); + return responseSuccess(); + } + } +@@ -1464,7 +1519,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, + } + case LanParam::SubnetMask: + { +- if (channelCall<getDHCPProperty>(channel)) ++ std::string dhcpSetting = channelCall<getDHCPProperty>(channel); ++ if ((dhcpSetting == dhcpv4) || (dhcpSetting == dhcpv4v6)) + { + return responseCommandNotAvailable(); + } +@@ -1481,7 +1537,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, + } + case LanParam::Gateway1: + { +- if (channelCall<getDHCPProperty>(channel)) ++ std::string dhcpSetting = channelCall<getDHCPProperty>(channel); ++ if ((dhcpSetting == dhcpv4) || (dhcpSetting == dhcpv4v6)) + { + return responseCommandNotAvailable(); + } +@@ -1606,7 +1663,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, + return responseReqDataLenInvalid(); + } + std::bitset<8> expected; +- if (channelCall<getDHCPProperty>(channel)) ++ std::string dhcp = channelCall<getDHCPProperty>(channel); ++ if ((dhcp == dhcpv4v6) || (dhcp == dhcpv6)) + { + expected[IPv6RouterControlFlag::Dynamic] = 1; + } +@@ -1756,7 +1814,8 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, + case LanParam::IPSrc: + { + auto src = IPSrc::Static; +- if (channelCall<getDHCPProperty>(channel)) ++ std::string dhcp = channelCall<getDHCPProperty>(channel); ++ if ((dhcp == dhcpv4) || (dhcp == dhcpv4v6)) + { + src = IPSrc::DHCP; + } +@@ -1877,7 +1936,8 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, + case LanParam::IPv6RouterControl: + { + std::bitset<8> control; +- if (channelCall<getDHCPProperty>(channel)) ++ std::string dhcp = channelCall<getDHCPProperty>(channel); ++ if ((dhcp == dhcpv4v6) || (dhcp == dhcpv6)) + { + control[IPv6RouterControlFlag::Dynamic] = 1; + } +@@ -1891,7 +1951,8 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, + case LanParam::IPv6StaticRouter1IP: + { + in6_addr gateway{}; +- if (!channelCall<getDHCPProperty>(channel)) ++ std::string dhcp = channelCall<getDHCPProperty>(channel); ++ if ((dhcp == dhcpv4) || (dhcp == dhcpoff)) + { + gateway = + channelCall<getGatewayProperty<AF_INET6>>(channel).value_or( +-- +2.24.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch new file mode 100644 index 000000000..ccf326a91 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch @@ -0,0 +1,41 @@ +From c1925ab965271875d4e9333be85cdfe8e1516948 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery <vernon.mauery@linux.intel.com> +Date: Fri, 14 Feb 2020 13:13:06 -0800 +Subject: [PATCH] Fix 'Get System GUID' to use settings UUID + +The upstream Get System GUID command looks first for a BMC interface +and then assumes that the UUID interface is next to that. But that is +not the case on Intel systems where the system GUID is found in the +settings daemon. + +Change-Id: I924bd05e0a546f2b30288c1faf72157296ab6579 +Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> +--- + apphandler.cpp | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/apphandler.cpp b/apphandler.cpp +index dcfda11..780afbc 100644 +--- a/apphandler.cpp ++++ b/apphandler.cpp +@@ -784,8 +784,6 @@ auto ipmiAppGetBtCapabilities() + + auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> + { +- static constexpr auto bmcInterface = +- "xyz.openbmc_project.Inventory.Item.Bmc"; + static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID"; + static constexpr auto uuidProperty = "UUID"; + +@@ -794,7 +792,7 @@ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> + { + // Get the Inventory object implementing BMC interface + auto busPtr = getSdBus(); +- auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface); ++ auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface); + + // Read UUID property value from bmcObject + // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch new file mode 100644 index 000000000..903ae96a7 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch @@ -0,0 +1,80 @@ +From ad93a6e17310d92ef07b8d367b23c93793562d0f Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@linux.intel.com> +Date: Wed, 23 Jan 2019 17:02:40 +0800 +Subject: [PATCH] Fix keep looping issue when entering OS + +Sometimes when entering OS, OS will keep continuously sending ipmi command +"READ EVENT MESSAGE BUFFER" to BMC. This issue is caused by incorrect KCS +status. If restart the host immediately while OS is still running, SMS_ATN +will be set, after that KCS come into an incorrect status, and then KCS +communction between BMC and OS crash. To make KCS go back to correct status +and fix the issue, clear SMS_ATN after every time power cycle happen. + +Unit Test: + After entered OS, force reset system, after enter OS again, OS can start +normally without keep sending READ EVENT MESSAGE BUFFER command. + After power on system, enter EFI SHELL, check cmdtool.efi can work +correctly through KCS channel. +--- + host-cmd-manager.cpp | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp +index f3aba7f..465eb81 100644 +--- a/host-cmd-manager.cpp ++++ b/host-cmd-manager.cpp +@@ -26,6 +26,8 @@ constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; + constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0"; + constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host"; + constexpr auto HOST_TRANS_PROP = "RequestedHostTransition"; ++constexpr const char* IPMI_PATH = "/xyz/openbmc_project/Ipmi/Channel/ipmi_kcs3"; ++constexpr const char* IPMI_INTERFACE = "xyz.openbmc_project.Ipmi.Channel.SMS"; + + // For throwing exceptions + using namespace phosphor::logging; +@@ -106,6 +108,20 @@ void Manager::clearQueue() + // `false` indicating Failure + std::get<CallBack>(command)(ipmiCmdData, false); + } ++ ++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "clearAttention"); ++ ++ try ++ { ++ auto reply = this->bus.call(method); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ log<level::ERR>("Error in clearing SMS attention"); ++ elog<InternalFailure>(); ++ } + } + + // Called for alerting the host +@@ -115,9 +131,6 @@ void Manager::checkQueueAndAlertHost() + { + log<level::DEBUG>("Asserting SMS Attention"); + +- std::string IPMI_PATH("/org/openbmc/HostIpmi/1"); +- std::string IPMI_INTERFACE("org.openbmc.HostIpmi"); +- + auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH); + + // Start the timer for this transaction +@@ -131,9 +144,8 @@ void Manager::checkQueueAndAlertHost() + return; + } + +- auto method = +- this->bus.new_method_call(host.c_str(), IPMI_PATH.c_str(), +- IPMI_INTERFACE.c_str(), "setAttention"); ++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH, ++ IPMI_INTERFACE, "setAttention"); + auto reply = this->bus.call(method); + + if (reply.is_method_error()) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch new file mode 100644 index 000000000..987e61448 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch @@ -0,0 +1,105 @@ +From f9f260391f099b4e67999f9d4ca05cbf9b422baf Mon Sep 17 00:00:00 2001 +From: "Jia, chunhui" <chunhui.jia@linux.intel.com> +Date: Tue, 19 Mar 2019 16:09:06 +0800 +Subject: [PATCH] add SetInProgress to get/set boot option cmd + +It is required by BIOS. BIOS will check setinprogress first. +If this flag is not supported, BIOS will bypass all boot +option flow. + +Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f +Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +--- + chassishandler.cpp | 28 +++++++++++++++++++++++++++- + chassishandler.hpp | 3 +++ + 2 files changed, 30 insertions(+), 1 deletion(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 305897b..ee23845 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -1399,6 +1399,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode) + return IPMI_CC_OK; + } + ++static constexpr uint8_t setComplete = 0x0; ++static constexpr uint8_t setInProgress = 0x1; ++static uint8_t transferStatus = setComplete; ++ + ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, +@@ -1413,11 +1417,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; + IpmiValue bootOption = ipmiDefault; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ *data_len = ++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS); ++ resp->version = SET_PARM_VERSION; ++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS); ++ resp->data[0] = transferStatus; ++ return IPMI_CC_OK; ++ } ++ + std::memset(resp, 0, sizeof(*resp)); + resp->version = SET_PARM_VERSION; + resp->parm = 5; + resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; +- + /* + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +@@ -1553,6 +1567,18 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // This IPMI command does not have any resposne data + *data_len = 0; + ++ if (reqptr->parameter == ++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS)) ++ { ++ if ((transferStatus == setInProgress) && ++ (reqptr->data[0] != setComplete)) ++ { ++ return IPMI_CC_FAIL_SET_IN_PROGRESS; ++ } ++ transferStatus = reqptr->data[0]; ++ return IPMI_CC_OK; ++ } ++ + /* 000101 + * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. + * This is the only parameter used by petitboot. +diff --git a/chassishandler.hpp b/chassishandler.hpp +index dcaf06c..353a929 100644 +--- a/chassishandler.hpp ++++ b/chassishandler.hpp +@@ -25,6 +25,7 @@ enum ipmi_chassis_return_codes + { + IPMI_OK = 0x0, + IPMI_CC_PARM_NOT_SUPPORTED = 0x80, ++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81, + }; + + // Generic completion codes, +@@ -46,6 +47,7 @@ enum ipmi_chassis_control_cmds : uint8_t + }; + enum class BootOptionParameter : size_t + { ++ SET_IN_PROGRESS = 0x0, + BOOT_INFO = 0x4, + BOOT_FLAGS = 0x5, + OPAL_NETWORK_SETTINGS = 0x61 +@@ -53,6 +55,7 @@ enum class BootOptionParameter : size_t + + enum class BootOptionResponseSize : size_t + { ++ SET_IN_PROGRESS = 3, + BOOT_FLAGS = 5, + OPAL_NETWORK_SETTINGS = 50 + }; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..bc8c72f13 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,356 @@ +From 1c8cb6b7c99ad85f470aa87095fcfb4de822ddb1 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 16 Oct 2019 14:24:20 +0800 +Subject: [PATCH 1/1] Move Set SOL config parameter to host-ipmid + +Move Set SOL config parameter command from net-ipmid to host-ipmid, +so that BIOS in Intel platform can enable or disable SOL through KCS. +Get SOL config parameter command will be moved later. + +Tested by: +With the related change in phospher-ipmi-net and phospher-dbus-interface, +Run commands: +ipmitool raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +All these commands have correct response and all dbus interface for +sol command change to same value in above commands. +After reboot BMC, "Progress" property in dbus interface change back +to 0 and other properties will not reset to default value. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 294 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 295 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index 5397115..c93f3b1 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -41,6 +41,7 @@ + 0x0A:0x48 //<Storage>:<Get SEL Time> + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> ++0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 61065ad..59e38ea 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1469,8 +1469,298 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, + } // namespace transport + } // namespace ipmi + ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; ++ + void register_netfn_transport_functions() __attribute__((constructor)); + ++static std::string ++ getSOLService(std::shared_ptr<sdbusplus::asio::connection> dbus, ++ const std::string& solPathWitheEthName) ++{ ++ static std::string solService{}; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = ++ ipmi::getService(*dbus, solInterface, solPathWitheEthName); ++ } ++ catch (const sdbusplus::exception::SdBusError& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return solService; ++ } ++ } ++ return solService; ++} ++ ++static int setSOLParameter(const std::string& property, ++ const ipmi::Value& value, const uint8_t& channelNum) ++{ ++ auto dbus = getSdBus(); ++ ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ ++ std::string solPathWitheEthName = std::string(solPath) + ethdevice; ++ ++ std::string service = getSOLService(dbus, solPathWitheEthName); ++ if (service.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get SOL service failed"); ++ return -1; ++ } ++ try ++ { ++ ipmi::setDbusProperty(*dbus, service, solPathWitheEthName, solInterface, ++ property, value); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int getSOLParameter(const std::string& property, ipmi::Value& value, ++ const uint8_t& channelNum) ++{ ++ auto dbus = getSdBus(); ++ ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ ++ std::string solPathWitheEthName = std::string(solPath) + ethdevice; ++ ++ std::string service = getSOLService(dbus, solPathWitheEthName); ++ if (service.empty()) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get SOL service failed"); ++ return -1; ++ } ++ try ++ { ++ value = ipmi::getDbusProperty(*dbus, service, solPathWitheEthName, ++ solInterface, property); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol parameter"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static const constexpr uint8_t encryptMask = 0x80; ++static const constexpr uint8_t encryptShift = 7; ++static const constexpr uint8_t authMask = 0x40; ++static const constexpr uint8_t authShift = 6; ++static const constexpr uint8_t privilegeMask = 0xf; ++ ++namespace ipmi ++{ ++constexpr Cc ccParmNotSupported = 0x80; ++constexpr Cc ccSetInProgressActive = 0x81; ++constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82; ++ ++static inline auto responseParmNotSupported() ++{ ++ return response(ccParmNotSupported); ++} ++static inline auto responseSetInProgressActive() ++{ ++ return response(ccSetInProgressActive); ++} ++static inline auto responseSystemInfoParameterSetReadOnly() ++{ ++ return response(ccSystemInfoParameterSetReadOnly); ++} ++ ++} // namespace ipmi ++ ++namespace sol ++{ ++enum class Parameter ++{ ++ progress, //!< Set In Progress. ++ enable, //!< SOL Enable. ++ authentication, //!< SOL Authentication. ++ accumulate, //!< Character Accumulate Interval & Send Threshold. ++ retry, //!< SOL Retry. ++ nvbitrate, //!< SOL non-volatile bit rate. ++ vbitrate, //!< SOL volatile bit rate. ++ channel, //!< SOL payload channel. ++ port, //!< SOL payload port. ++}; ++ ++enum class Privilege : uint8_t ++{ ++ highestPriv, ++ callbackPriv, ++ userPriv, ++ operatorPriv, ++ adminPriv, ++ oemPriv, ++}; ++ ++} // namespace sol ++ ++constexpr uint8_t progressMask = 0x03; ++constexpr uint8_t enableMask = 0x01; ++constexpr uint8_t retryMask = 0x07; ++ ++ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, ++ uint4_t reserved, uint8_t paramSelector, ++ uint8_t configParamData1, ++ std::optional<uint8_t> configParamData2) ++{ ++ ipmi::ChannelInfo chInfo; ++ uint8_t channelNum = ipmi::convertCurrentChannelNum( ++ static_cast<uint8_t>(chNum), ctx->channel); ++ if (reserved != 0 || ++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum)))) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ switch (static_cast<sol::Parameter>(paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ uint8_t progress = configParamData1 & progressMask; ++ ipmi::Value currentProgress = 0; ++ if (getSOLParameter("Progress", currentProgress, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ if ((std::get<uint8_t>(currentProgress) == 1) && (progress == 1)) ++ { ++ return ipmi::responseSetInProgressActive(); ++ } ++ ++ if (setSOLParameter("Progress", progress, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::enable: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ bool enable = configParamData1 & enableMask; ++ if (setSOLParameter("Enable", enable, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::authentication: ++ { ++ if (configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ uint8_t encrypt = (configParamData1 & encryptMask) >> encryptShift; ++ uint8_t auth = (configParamData1 & authMask) >> authShift; ++ uint8_t privilege = configParamData1 & privilegeMask; ++ // For security considering encryption and authentication must be ++ // true. ++ if (!encrypt || !auth) ++ { ++ return ipmi::responseSystemInfoParameterSetReadOnly(); ++ } ++ else if (privilege < ++ static_cast<uint8_t>(sol::Privilege::userPriv) || ++ privilege > static_cast<uint8_t>(sol::Privilege::oemPriv)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ if (setSOLParameter("Privilege", privilege, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ break; ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (!configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if (*configParamData2 == 0) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ if (setSOLParameter("AccumulateIntervalMS", configParamData1, ++ channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ if (setSOLParameter("Threshold", *configParamData2, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ break; ++ } ++ case sol::Parameter::retry: ++ { ++ if (!configParamData2) ++ { ++ return ipmi::responseReqDataLenInvalid(); ++ } ++ if ((setSOLParameter( ++ "RetryCount", ++ static_cast<uint8_t>(configParamData1 & retryMask), ++ channelNum) < 0) || ++ (setSOLParameter("RetryIntervalMS", *configParamData2, ++ channelNum) < 0)) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ break; ++ } ++ case sol::Parameter::port: ++ { ++ return ipmi::responseSystemInfoParameterSetReadOnly(); ++ } ++ case sol::Parameter::nvbitrate: ++ case sol::Parameter::vbitrate: ++ case sol::Parameter::channel: ++ default: ++ return ipmi::responseParmNotSupported(); ++ } ++ ++ return ipmi::responseSuccess(); ++} ++ + void register_netfn_transport_functions() + { + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, +@@ -1479,4 +1769,8 @@ void register_netfn_transport_functions() + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, + ipmi::transport::cmdGetLanConfigParameters, + ipmi::Privilege::Operator, ipmi::transport::getLan); ++ ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdSetSolConfigParameters, ++ ipmi::Privilege::Admin, setSOLConfParams); + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch new file mode 100644 index 000000000..61ac5fede --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch @@ -0,0 +1,259 @@ +From b5400c4bc756a800fbeb4cc53117956fb59dc57d Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Thu, 11 Jul 2019 00:32:58 +0800 +Subject: [PATCH 1/1] Move Get SOL config parameter to host-ipmid + +Move Get SOL config parameter command from net-ipmid to host-ipmid. + +Tested: +Run command ipmitool sol info 1 +Set in progress : set-complete +Enabled : true +Force Encryption : false +Force Authentication : false +Privilege Level : ADMINISTRATOR +Character Accumulate Level (ms) : 60 +Character Send Threshold : 96 +Retry Count : 6 +Retry Interval (ms) : 200 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : 115.2 +Payload Channel : 1 (0x01) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +Signed-off-by: James Feist <james.feist@linux.intel.com> +--- + host-ipmid-whitelist.conf | 1 + + transporthandler.cpp | 191 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 192 insertions(+) + +diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf +index c93f3b1..730437d 100644 +--- a/host-ipmid-whitelist.conf ++++ b/host-ipmid-whitelist.conf +@@ -42,6 +42,7 @@ + 0x0A:0x49 //<Storage>:<Set SEL Time> + 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> + 0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters> ++0x0C:0x22 //<Transport>:<Get SOL Configuration Parameters> + 0x2C:0x00 //<Group Extension>:<Group Extension Command> + 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities> + 0x2C:0x02 //<Group Extension>:<Get Power Reading> +diff --git a/transporthandler.cpp b/transporthandler.cpp +index 59e38ea..b64953f 100644 +--- a/transporthandler.cpp ++++ b/transporthandler.cpp +@@ -1559,6 +1559,28 @@ static int getSOLParameter(const std::string& property, ipmi::Value& value, + return 0; + } + ++constexpr const char* consoleInterface = "xyz.openbmc_project.console"; ++constexpr const char* consolePath = "/xyz/openbmc_project/console"; ++static int getSOLBaudRate(ipmi::Value& value) ++{ ++ auto dbus = getSdBus(); ++ ++ try ++ { ++ value = ++ ipmi::getDbusProperty(*dbus, "xyz.openbmc_project.console", ++ consolePath, consoleInterface, "baudrate"); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error getting sol baud rate"); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static const constexpr uint8_t encryptMask = 0x80; + static const constexpr uint8_t encryptShift = 7; + static const constexpr uint8_t authMask = 0x40; +@@ -1761,6 +1783,171 @@ ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, + return ipmi::responseSuccess(); + } + ++static const constexpr uint8_t retryCountMask = 0x07; ++static constexpr uint16_t ipmiStdPort = 623; ++static constexpr uint8_t solParameterRevision = 0x11; ++ipmi::RspType<uint8_t, std::optional<uint8_t>, std::optional<uint8_t>> ++ getSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, uint3_t reserved, ++ bool getParamRev, uint8_t paramSelector, ++ uint8_t setSelector, uint8_t blockSelector) ++{ ++ ipmi::ChannelInfo chInfo; ++ uint8_t channelNum = ipmi::convertCurrentChannelNum( ++ static_cast<uint8_t>(chNum), ctx->channel); ++ if (reserved != 0 || ++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))) || ++ (ipmi::EChannelSessSupported::none == ++ ipmi::getChannelSessionSupport(static_cast<uint8_t>(channelNum)))) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ipmi_ret_t compCode = ++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo); ++ if (compCode != IPMI_CC_OK || ++ chInfo.mediumType != ++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032)) ++ { ++ return ipmi::responseInvalidFieldRequest(); ++ } ++ ++ if (getParamRev) ++ { ++ return ipmi::responseSuccess(solParameterRevision, std::nullopt, ++ std::nullopt); ++ } ++ ++ ipmi::Value value; ++ switch (static_cast<sol::Parameter>(paramSelector)) ++ { ++ case sol::Parameter::progress: ++ { ++ if (getSOLParameter("Progress", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, std::get<uint8_t>(value), std::nullopt); ++ } ++ case sol::Parameter::enable: ++ { ++ if (getSOLParameter("Enable", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, ++ static_cast<uint8_t>(std::get<bool>(value)), std::nullopt); ++ } ++ case sol::Parameter::authentication: ++ { ++ uint8_t authentication = 0; ++ if (getSOLParameter("Privilege", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication = (std::get<uint8_t>(value) & 0x0f); ++ ++ if (getSOLParameter("ForceAuthentication", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 6); ++ ++ if (getSOLParameter("ForceEncryption", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ authentication |= ++ (static_cast<uint8_t>(std::get<bool>(value)) << 7); ++ return ipmi::responseSuccess(solParameterRevision, authentication, ++ std::nullopt); ++ } ++ case sol::Parameter::accumulate: ++ { ++ if (getSOLParameter("AccumulateIntervalMS", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ ipmi::Value value1; ++ if (getSOLParameter("Threshold", value1, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess(solParameterRevision, ++ std::get<uint8_t>(value), ++ std::get<uint8_t>(value1)); ++ } ++ case sol::Parameter::retry: ++ { ++ if (getSOLParameter("RetryCount", value, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ ++ ipmi::Value value1; ++ if (getSOLParameter("RetryIntervalMS", value1, channelNum) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ return ipmi::responseSuccess( ++ solParameterRevision, std::get<uint8_t>(value) & retryCountMask, ++ std::get<uint8_t>(value1)); ++ } ++ case sol::Parameter::channel: ++ { ++ return ipmi::responseSuccess(solParameterRevision, channelNum, ++ std::nullopt); ++ } ++ case sol::Parameter::port: ++ { ++ uint16_t port = htole16(ipmiStdPort); ++ auto buffer = reinterpret_cast<const uint8_t*>(&port); ++ return ipmi::responseSuccess(solParameterRevision, buffer[0], ++ buffer[1]); ++ } ++ case sol::Parameter::nvbitrate: ++ { ++ if (getSOLBaudRate(value) < 0) ++ { ++ return ipmi::responseUnspecifiedError(); ++ } ++ uint8_t bitRate = 0; ++ uint32_t* pBaudRate = std::get_if<uint32_t>(&value); ++ if (!pBaudRate) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Failed to get valid baud rate from D-Bus interface"); ++ } ++ switch (*pBaudRate) ++ { ++ case 9600: ++ bitRate = 0x06; ++ break; ++ case 19200: ++ bitRate = 0x07; ++ break; ++ case 38400: ++ bitRate = 0x08; ++ break; ++ case 57600: ++ bitRate = 0x09; ++ break; ++ case 115200: ++ bitRate = 0x0a; ++ break; ++ default: ++ break; ++ } ++ return ipmi::responseSuccess(solParameterRevision, bitRate, ++ std::nullopt); ++ } ++ default: ++ return ipmi::responseParmNotSupported(); ++ } ++} ++ + void register_netfn_transport_functions() + { + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, +@@ -1773,4 +1960,8 @@ void register_netfn_transport_functions() + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, + ipmi::transport::cmdSetSolConfigParameters, + ipmi::Privilege::Admin, setSOLConfParams); ++ ++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ++ ipmi::transport::cmdGetSolConfigParameters, ++ ipmi::Privilege::User, getSOLConfParams); + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch new file mode 100644 index 000000000..96e45cad3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch @@ -0,0 +1,291 @@ +From 92bdbcd90a445e49ba2f8e483d44ec41152d32b4 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" <jason.m.bills@linux.intel.com> +Date: Mon, 3 Jun 2019 17:01:47 -0700 +Subject: [PATCH] Update IPMI Chassis Control command + +This change updates the IPMI Chassis Control command to use the new +host state transitions. This allows each chassis control action +to more closely follow the behavior defined in the IPMI spec. + +ref: https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/22358 + +Tested: +Ran each IPMI chassis control command to confirm the expected +behavior: +ipmitool power on: system is powered-on +ipmitool power off: system is forced off +ipmitool power cycle: system is forced off then powered-on +ipmitool power reset: system is hard reset +ipmitool power soft: soft power-off requested from system software + +Change-Id: Ic9fba3ca4abd9a758eb88f1e6ee09f7ca64ff80a +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + chassishandler.cpp | 206 +++++++++++++---------------------------------------- + 1 file changed, 50 insertions(+), 156 deletions(-) + +diff --git a/chassishandler.cpp b/chassishandler.cpp +index 0326806..8bfab88 100644 +--- a/chassishandler.cpp ++++ b/chassishandler.cpp +@@ -31,6 +31,7 @@ + #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> + #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> + #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp> ++#include <xyz/openbmc_project/State/Chassis/server.hpp> + #include <xyz/openbmc_project/State/Host/server.hpp> + #include <xyz/openbmc_project/State/PowerOnHours/server.hpp> + +@@ -717,59 +718,63 @@ ipmi::RspType<> ipmiSetChassisCap(bool intrusion, bool fpLockout, + //------------------------------------------ + // Calls into Host State Manager Dbus object + //------------------------------------------ +-int initiate_state_transition(State::Host::Transition transition) ++int initiateHostStateTransition(State::Host::Transition transition) + { + // OpenBMC Host State Manager dbus framework +- constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0"; +- constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host"; +- constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties"; +- constexpr auto PROPERTY = "RequestedHostTransition"; ++ constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0"; ++ constexpr auto hostStateIntf = "xyz.openbmc_project.State.Host"; + +- // sd_bus error +- int rc = 0; +- char* busname = NULL; ++ auto service = ipmi::getService(*getSdBus(), hostStateIntf, hostStatePath); + +- // SD Bus error report mechanism. +- sd_bus_error bus_error = SD_BUS_ERROR_NULL; ++ // Convert to string equivalent of the passed in transition enum. ++ auto request = State::convertForMessage(transition); + +- // Gets a hook onto either a SYSTEM or SESSION bus +- sd_bus* bus_type = ipmid_get_sd_bus_connection(); +- rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname); +- if (rc < 0) ++ try ++ { ++ ipmi::setDbusProperty(*getSdBus(), service, hostStatePath, ++ hostStateIntf, "RequestedHostTransition", ++ request); ++ } ++ catch (std::exception& e) + { + log<level::ERR>( +- "Failed to get bus name", +- entry("ERRNO=0x%X, OBJPATH=%s", -rc, HOST_STATE_MANAGER_ROOT)); +- return rc; ++ "Failed to initiate transition", ++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str())); ++ return -1; + } ++ return 0; ++} ++ ++//------------------------------------------ ++// Calls into Chassis State Manager Dbus object ++//------------------------------------------ ++int initiateChassisStateTransition(State::Chassis::Transition transition) ++{ ++ // OpenBMC Chassis State Manager dbus framework ++ constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0"; ++ constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis"; ++ ++ auto service = ++ ipmi::getService(*getSdBus(), chassisStateIntf, chassisStatePath); + + // Convert to string equivalent of the passed in transition enum. + auto request = State::convertForMessage(transition); + +- rc = sd_bus_call_method(bus_type, // On the system bus +- busname, // Service to contact +- HOST_STATE_MANAGER_ROOT, // Object path +- DBUS_PROPERTY_IFACE, // Interface name +- "Set", // Method to be called +- &bus_error, // object to return error +- nullptr, // Response buffer if any +- "ssv", // Takes 3 arguments +- HOST_STATE_MANAGER_IFACE, PROPERTY, "s", +- request.c_str()); +- if (rc < 0) +- { +- log<level::ERR>("Failed to initiate transition", +- entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str())); ++ try ++ { ++ ipmi::setDbusProperty(*getSdBus(), service, chassisStatePath, ++ chassisStateIntf, "RequestedPowerTransition", ++ request); + } +- else ++ catch (std::exception& e) + { +- log<level::INFO>("Transition request initiated successfully"); ++ log<level::ERR>( ++ "Failed to initiate transition", ++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str())); ++ return -1; + } + +- sd_bus_error_free(&bus_error); +- free(busname); +- +- return rc; ++ return 0; + } + + //------------------------------------------ +@@ -1071,76 +1076,6 @@ ipmi::RspType<bool, // Power is on + diagButtonDisableAllow, sleepButtonDisableAllow); + } + +-//------------------------------------------------------------- +-// Send a command to SoftPowerOff application to stop any timer +-//------------------------------------------------------------- +-int stop_soft_off_timer() +-{ +- constexpr auto iface = "org.freedesktop.DBus.Properties"; +- constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal." +- "SoftPowerOff"; +- +- constexpr auto property = "ResponseReceived"; +- constexpr auto value = "xyz.openbmc_project.Ipmi.Internal." +- "SoftPowerOff.HostResponse.HostShutdown"; +- +- // Get the system bus where most system services are provided. +- auto bus = ipmid_get_sd_bus_connection(); +- +- // Get the service name +- // TODO openbmc/openbmc#1661 - Mapper refactor +- // +- // See openbmc/openbmc#1743 for some details but high level summary is that +- // for now the code will directly call the soft off interface due to a +- // race condition with mapper usage +- // +- // char *busname = nullptr; +- // auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname); +- // if (r < 0) +- //{ +- // fprintf(stderr, "Failed to get %s bus name: %s\n", +- // SOFTOFF_OBJPATH, -r); +- // return r; +- //} +- +- // No error object or reply expected. +- int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface, +- "Set", nullptr, nullptr, "ssv", soft_off_iface, +- property, "s", value); +- if (rc < 0) +- { +- log<level::ERR>("Failed to set property in SoftPowerOff object", +- entry("ERRNO=0x%X", -rc)); +- } +- +- // TODO openbmc/openbmc#1661 - Mapper refactor +- // free(busname); +- return rc; +-} +- +-//---------------------------------------------------------------------- +-// Create file to indicate there is no need for softoff notification to host +-//---------------------------------------------------------------------- +-void indicate_no_softoff_needed() +-{ +- fs::path path{HOST_INBAND_REQUEST_DIR}; +- if (!fs::is_directory(path)) +- { +- fs::create_directory(path); +- } +- +- // Add the host instance (default 0 for now) to the file name +- std::string file{HOST_INBAND_REQUEST_FILE}; +- auto size = std::snprintf(nullptr, 0, file.c_str(), 0); +- size++; // null +- std::unique_ptr<char[]> buf(new char[size]); +- std::snprintf(buf.get(), size, file.c_str(), 0); +- +- // Append file name to directory and create it +- path /= buf.get(); +- std::ofstream(path.c_str()); +-} +- + /** @brief Implementation of chassis control command + * + * @param - chassisControl command byte +@@ -1153,63 +1088,22 @@ ipmi::RspType<> ipmiChassisControl(uint8_t chassisControl) + switch (chassisControl) + { + case CMD_POWER_ON: +- rc = initiate_state_transition(State::Host::Transition::On); ++ rc = initiateHostStateTransition(State::Host::Transition::On); + break; + case CMD_POWER_OFF: +- // This path would be hit in 2 conditions. +- // 1: When user asks for power off using ipmi chassis command 0x04 +- // 2: Host asking for power off post shutting down. +- +- // If it's a host requested power off, then need to nudge Softoff +- // application that it needs to stop the watchdog timer if running. +- // If it is a user requested power off, then this is not really +- // needed. But then we need to differentiate between user and host +- // calling this same command +- +- // For now, we are going ahead with trying to nudge the soft off and +- // interpret the failure to do so as a non softoff case +- rc = stop_soft_off_timer(); +- +- // Only request the Off transition if the soft power off +- // application is not running +- if (rc < 0) +- { +- // First create a file to indicate to the soft off application +- // that it should not run. Not doing this will result in State +- // manager doing a default soft power off when asked for power +- // off. +- indicate_no_softoff_needed(); +- +- // Now request the shutdown +- rc = initiate_state_transition(State::Host::Transition::Off); +- } +- else +- { +- log<level::INFO>("Soft off is running, so let shutdown target " +- "stop the host"); +- } ++ rc = ++ initiateChassisStateTransition(State::Chassis::Transition::Off); + break; +- + case CMD_HARD_RESET: ++ rc = initiateHostStateTransition( ++ State::Host::Transition::ForceWarmReboot); ++ break; + case CMD_POWER_CYCLE: +- // SPEC has a section that says certain implementations can trigger +- // PowerOn if power is Off when a command to power cycle is +- // requested +- +- // First create a file to indicate to the soft off application +- // that it should not run since this is a direct user initiated +- // power reboot request (i.e. a reboot request that is not +- // originating via a soft power off SMS request) +- indicate_no_softoff_needed(); +- +- rc = initiate_state_transition(State::Host::Transition::Reboot); ++ rc = initiateHostStateTransition(State::Host::Transition::Reboot); + break; +- + case CMD_SOFT_OFF_VIA_OVER_TEMP: +- // Request Host State Manager to do a soft power off +- rc = initiate_state_transition(State::Host::Transition::Off); ++ rc = initiateHostStateTransition(State::Host::Transition::Off); + break; +- + case CMD_PULSE_DIAGNOSTIC_INTR: + rc = setNmiProperty(true); + break; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch new file mode 100644 index 000000000..aac0850ea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch @@ -0,0 +1,140 @@ +From d9c89943d7b0aa00ee99b7c11278ac272a47a790 Mon Sep 17 00:00:00 2001 +From: Ren Yu <yux.ren@intel.com> +Date: Tue, 28 May 2019 17:11:17 +0800 +Subject: [PATCH] Save the pre-timeout interrupt in dbus property + +Get the watchdog pre-timeout interrupt value from ipmi watchdog set command, +and store it into dbus property. + +Tested: +Config IPMI watchdog: BIOS FRB2 Power Cycle after 1 seconds: +ipmitool raw 0x06 0x24 0x01 0x13 0x0 0x2 0xa 0x00 +Start watchdog: +Ipmitool mc watchdog reset +Check the watchdog pre-timeout interrupt in below: +https://BMCIP/redfish/v1/Systems/system/LogServices/EventLog/Entries + +Signed-off-by: Ren Yu <yux.ren@intel.com> +--- + app/watchdog.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + app/watchdog_service.cpp | 6 ++++++ + app/watchdog_service.hpp | 9 +++++++++ + 3 files changed, 62 insertions(+) + +diff --git a/app/watchdog.cpp b/app/watchdog.cpp +index 2ffaae3..e9b7a9c 100644 +--- a/app/watchdog.cpp ++++ b/app/watchdog.cpp +@@ -81,6 +81,7 @@ ipmi::RspType<> ipmiAppResetWatchdogTimer() + + static constexpr uint8_t wd_dont_stop = 0x1 << 6; + static constexpr uint8_t wd_timeout_action_mask = 0x3; ++static constexpr uint8_t wdPreTimeoutInterruptMask = 0x3; + + static constexpr uint8_t wdTimerUseMask = 0x7; + static constexpr uint8_t wdTimerUseResTimer1 = 0x0; +@@ -130,6 +131,45 @@ WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action) + } + } + ++enum class IpmiPreTimeoutInterrupt : uint8_t ++{ ++ None = 0x0, ++ SMI = 0x1, ++ NMI = 0x2, ++ MI = 0x3, ++}; ++/** @brief Converts an IPMI Watchdog PreTimeoutInterrupt to DBUS defined action ++ * @param[in] ipmi_action The IPMI Watchdog PreTimeoutInterrupt ++ * @return The Watchdog PreTimeoutInterrupt that the ipmi_action maps to ++ */ ++WatchdogService::PreTimeoutInterruptAction ipmiPreTimeoutInterruptToWdAction( ++ IpmiPreTimeoutInterrupt ipmiPreTimeOutInterrupt) ++{ ++ switch (ipmiPreTimeOutInterrupt) ++ { ++ case IpmiPreTimeoutInterrupt::None: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::None; ++ } ++ case IpmiPreTimeoutInterrupt::SMI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::SMI; ++ } ++ case IpmiPreTimeoutInterrupt::NMI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::NMI; ++ } ++ case IpmiPreTimeoutInterrupt::MI: ++ { ++ return WatchdogService::PreTimeoutInterruptAction::MI; ++ } ++ default: ++ { ++ throw std::domain_error("IPMI PreTimeoutInterrupt is invalid"); ++ } ++ } ++} ++ + enum class IpmiTimerUse : uint8_t + { + Reserved = 0x0, +@@ -257,6 +297,13 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + // Mark as initialized so that future resets behave correctly + wd_service.setInitialized(true); + ++ // pretimeOutAction ++ const auto ipmiPreTimeoutInterrupt = ++ static_cast<IpmiPreTimeoutInterrupt>(wdPreTimeoutInterruptMask & ++ (static_cast<uint8_t>(preTimeoutInterrupt))); ++ wd_service.setPreTimeoutInterrupt( ++ ipmiPreTimeoutInterruptToWdAction(ipmiPreTimeoutInterrupt)); ++ + lastCallSuccessful = true; + return IPMI_CC_OK; + } +diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp +index 77663b4..0c4ea28 100644 +--- a/app/watchdog_service.cpp ++++ b/app/watchdog_service.cpp +@@ -203,3 +203,9 @@ void WatchdogService::setTimeRemaining(uint64_t timeRemaining) + { + setProperty("TimeRemaining", timeRemaining); + } ++ ++void WatchdogService::setPreTimeoutInterrupt( ++ PreTimeoutInterruptAction preTimeoutInterrupt) ++{ ++ setProperty("PreTimeoutInterrupt", convertForMessage(preTimeoutInterrupt)); ++} +\ No newline at end of file +diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp +index ed64a3c..b550f37 100644 +--- a/app/watchdog_service.hpp ++++ b/app/watchdog_service.hpp +@@ -15,6 +15,8 @@ class WatchdogService + + using Action = + sdbusplus::xyz::openbmc_project::State::server::Watchdog::Action; ++ using PreTimeoutInterruptAction = sdbusplus::xyz::openbmc_project::State:: ++ server::Watchdog::PreTimeoutInterruptAction; + using TimerUse = + sdbusplus::xyz::openbmc_project::State::server::Watchdog::TimerUse; + +@@ -99,6 +101,13 @@ class WatchdogService + */ + void setTimeRemaining(uint64_t timeRemaining); + ++ /** @brief Sets the value of the PreTimeoutInterrupt property on the host ++ * watchdog ++ * ++ * @param[in] PreTimeoutInterrupt - The new PreTimeoutInterrupt value ++ */ ++ void setPreTimeoutInterrupt(PreTimeoutInterruptAction preTimeoutInterrupt); ++ + private: + /** @brief sdbusplus handle */ + sdbusplus::bus::bus bus; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service new file mode 100644 index 000000000..1e45ee6c9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service @@ -0,0 +1,15 @@ +[Unit] +Description=Phosphor Inband IPMI + +[Service] +Restart=always +RestartSec=5 +StartLimitBurst=10 +ExecStart=/usr/bin/env ipmid +SyslogIdentifier=ipmid +RuntimeDirectory = ipmi +RuntimeDirectoryPreserve = yes +StateDirectory = ipmi + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp new file mode 100644 index 000000000..856a80fbc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp @@ -0,0 +1,147 @@ +/* Copyright 2019 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dcmihandler.hpp" + +#include <cstdint> +#include <ipmid/api-types.hpp> +#include <ipmid/api.hpp> +#include <ipmid/message.hpp> +#include <ipmid/message/types.hpp> +#include <ipmid/utils.hpp> +#include <vector> + +enum class oemLanParam : uint8_t +{ + intelHostnameConfig = 0xc7, +}; + +constexpr size_t IpmiHostnameLen = 16; +constexpr uint8_t CurrentRevision = 0x11; // Current rev per IPMI Spec 2.0 + +constexpr ipmi::Cc ccParamNotSupported = 0x80; +constexpr ipmi::Cc ccUnprintable = 0x90; + +namespace ipmi::transport +{ + +constexpr auto validHostnameChars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX" + "YZ0123456789-"; +constexpr int lanOemHostnameLength = 64; + +RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req) +{ + std::vector<uint8_t> dataBytes; + switch (static_cast<oemLanParam>(parameter)) + { + case oemLanParam::intelHostnameConfig: + { + static std::array<uint8_t, lanOemHostnameLength> blockData; + uint8_t block = 0; + uint8_t complete = 0; + if ((req.unpack(block, complete, dataBytes) != 0) || + (!req.fullyUnpacked())) + { + return responseReqDataLenInvalid(); + } + + size_t numDataBytes = req.size() - 4; + if ((numDataBytes > IpmiHostnameLen) || + (!complete && (numDataBytes < IpmiHostnameLen))) + { + return responseReqDataLenInvalid(); + } + + if (!((block > 0) && (block < 5)) || + ((complete != 0) && (complete != 1))) + { + return responseInvalidFieldRequest(); + } + + if (block == 1) + { + blockData.fill(0); + } + + std::copy(dataBytes.begin(), dataBytes.end(), + blockData.data() + ((block - 1) * IpmiHostnameLen)); + if (complete) + { + blockData[lanOemHostnameLength - 1] = 0; + // check hostname, and write it + std::string newHostname( + reinterpret_cast<char*>(blockData.data()), + lanOemHostnameLength); + size_t firstNull = newHostname.find_first_of('\0'); + if (newHostname.find_first_not_of(validHostnameChars) != + firstNull) + { + return response(ccUnprintable); + } + std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); + ipmi::setDbusProperty(*busp, ::dcmi::networkServiceName, + ::dcmi::networkConfigObj, + ::dcmi::networkConfigIntf, + ::dcmi::hostNameProp, newHostname); + } + return responseSuccess(); + } + default: + return response(ccParamNotSupported); + } + return response(ccParamNotSupported); +} + +RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter, + uint8_t set, uint8_t block) +{ + message::Payload message; + message.pack(CurrentRevision); + oemLanParam param = static_cast<oemLanParam>(parameter); + switch (param) + { + case oemLanParam::intelHostnameConfig: + { + if (set != 0) + { + return responseInvalidFieldRequest(); + } + if ((block < 1) || (block > 4)) + { + return responseInvalidFieldRequest(); + } + std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); + auto service = ipmi::getService(*busp, ::dcmi::networkConfigIntf, + ::dcmi::networkConfigObj); + auto value = ipmi::getDbusProperty( + *busp, service, ::dcmi::networkConfigObj, + ::dcmi::networkConfigIntf, ::dcmi::hostNameProp); + std::string hostname = std::get<std::string>(value); + std::array<char, IpmiHostnameLen> buf = {0}; + size_t head = (block - 1) * IpmiHostnameLen; + if (head < hostname.size()) + { + size_t numToCopy = hostname.size() - head; + numToCopy = std::min(IpmiHostnameLen, numToCopy); + hostname.copy(buf.data(), numToCopy, head); + } + message.pack(buf); + return responseSuccess(std::move(message)); + } + } + return response(ccParamNotSupported); +} +} // namespace ipmi::transport diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend new file mode 100644 index 000000000..fc724eb33 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend @@ -0,0 +1,44 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" +PROJECT_SRC_DIR := "${THISDIR}/${PN}" + +SRC_URI = "git://github.com/openbmc/phosphor-host-ipmid" +SRCREV = "3165569a562983cf3c43b0b10c23e7695a031b56" + +SRC_URI += "file://phosphor-ipmi-host.service \ + file://0010-fix-get-system-GUID-ipmi-command.patch \ + file://0053-Fix-keep-looping-issue-when-entering-OS.patch \ + file://0056-add-SetInProgress-to-get-set-boot-option-cmd.patch \ + file://0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch \ + file://0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch \ + file://0062-Update-IPMI-Chassis-Control-command.patch \ + file://0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch \ + file://0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch \ + " + +EXTRA_OECONF_append = " --disable-i2c-whitelist-check" +EXTRA_OECONF_append = " --enable-transport-oem=yes" +EXTRA_OECONF_append = " --disable-boot-flag-safe-mode-support" +EXTRA_OECONF_append = " --disable-ipmi-whitelist" + +RDEPENDS_${PN}_remove = "clear-once" + +# remove the softpoweroff service since we do not need it +SYSTEMD_SERVICE_${PN}_remove += " \ + xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service" + +SYSTEMD_LINK_${PN}_remove += " \ + ../xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service:obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \ + " +FILES_${PN}_remove = " \ + ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/ \ + ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \ + " + +do_compile_prepend(){ + cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S} +} + +do_install_append(){ + rm -f ${D}/${bindir}/phosphor-softpoweroff + rm -f ${S}/transporthandler_oem.cpp +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend new file mode 100644 index 000000000..69b730221 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend @@ -0,0 +1,2 @@ +SRC_URI = "git://github.com/openbmc/ipmbbridge.git" +SRCREV = "a86059348fe133725f4616f3e46ff0d555db4039" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules new file mode 100644 index 000000000..0a64b58db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules @@ -0,0 +1,2 @@ +KERNEL=="ipmi-kcs3", SYMLINK+="ipmi_kcs3" +KERNEL=="ipmi-kcs4", SYMLINK+="ipmi_kcs4" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend new file mode 100644 index 000000000..adb1cc551 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend @@ -0,0 +1,21 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}" + +# Default kcs device is ipmi-kcs3; this is SMS. +# Add SMM kcs device instance + +# Replace the '-' to '_', since Dbus object/interface names do not allow '-'. +KCS_DEVICE = "ipmi_kcs3" +SMM_DEVICE = "ipmi_kcs4" +SYSTEMD_SERVICE_${PN}_append = " ${PN}@${SMM_DEVICE}.service " + +SRC_URI = "git://github.com/openbmc/kcsbridge.git" +SRCREV = "46525ae48db23333493ac927c12ed13a0e663de5" + +SRC_URI += "file://99-ipmi-kcs.rules" + +do_install_append() { + install -d ${D}${base_libdir}/udev/rules.d + install -m 0644 ${WORKDIR}/99-ipmi-kcs.rules ${D}${base_libdir}/udev/rules.d/ +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch new file mode 100644 index 000000000..867b3aba6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch @@ -0,0 +1,40 @@ +From 0fd38eb0a155cb11ff5a5452087f68c46d12111b Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Thu, 28 Mar 2019 18:10:40 +0800 +Subject: [PATCH] Change Authentication Parameter + +Seprate D-bus interface Authentication to forceAuthentication, +forceEncryption, Privilege according to the related change in +sol-dbus-interface. + +Tested By: +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x03 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0xc2 +The parameters has been changed to the request data in above command. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + sol/sol_manager.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp +index de36723..0bd837e 100644 +--- a/sol/sol_manager.cpp ++++ b/sol/sol_manager.cpp +@@ -195,8 +195,12 @@ void Manager::updateSOLParameter() + + enable = std::get<bool>(properties["Enable"]); + ++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]); ++ ++ forceAuth = std::get<bool>(properties["ForceAuthentication"]); ++ + solMinPrivilege = static_cast<session::Privilege>( +- std::get<uint8_t>(properties["Authentication"])); ++ std::get<uint8_t>(properties["Privilege"])); + + accumulateInterval = + std::get<uint8_t>((properties["AccumulateIntervalMS"])) * +-- +2.16.2 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch new file mode 100644 index 000000000..0ad625a1f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch @@ -0,0 +1,39 @@ +From 6fc55bb689272d34ff6616cdd4b24367ea39c749 Mon Sep 17 00:00:00 2001 +From: Kuiying Wang <kuiying.wang@intel.com> +Date: Mon, 2 Jul 2018 15:51:52 +0800 +Subject: [PATCH] Modify dbus namespace of chassis control for guid.cpp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Switch chassis control service namespace for guid.cpp from “org” to “xyz”, +to compatible with new intel-chassis services + +Signed-off-by: Kuiying Wang <kuiying.wang@intel.com> +--- + command/guid.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: phosphor-net-ipmid.clean/command/guid.cpp +=================================================================== +--- phosphor-net-ipmid.clean.orig/command/guid.cpp ++++ phosphor-net-ipmid.clean/command/guid.cpp +@@ -21,7 +21,8 @@ namespace command + + std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr); + +-static constexpr auto guidObjPath = "/org/openbmc/control/chassis0"; ++static constexpr auto guidObjPath = ++ "/xyz/openbmc_project/Chassis/Control/Chassis0"; + static constexpr auto propInterface = "org.freedesktop.DBus.Properties"; + + Guid getSystemGUID() +@@ -31,7 +32,7 @@ Guid getSystemGUID() + Guid guid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; + +- constexpr auto chassisIntf = "org.openbmc.control.Chassis"; ++ constexpr auto chassisIntf = "xyz.openbmc_project.Chassis.Control.Chassis"; + + sd_bus_message* reply = nullptr; + sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch new file mode 100644 index 000000000..dc7f7357c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch @@ -0,0 +1,319 @@ +From 97c21a556702a0d65096b30c07ef23f15cb6a7d9 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Wed, 3 Jul 2019 07:39:47 +0800 +Subject: [PATCH] Add dbus interface for sol commands + +Add dbus interface for sol config parameters so that after move set/get +sol config parameter command from net-ipmid to host-ipmid, the command +can send config parameters to net-ipmid sol service through the dbus +interface. + +Tested by: +busctl introspect xyz.openbmc_project.Settings /xyz/openbmc_project +/network/host0/sol can show correct dbus properties of sol parameters. +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x00 0x01 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x01 0x00 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x83 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x03 0x5 0x03 +ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x04 0x5 0x03 +all these commands can change the dbus properties as the value in +above commands. +Before and after run these commands, ipmitool -I lanplus -H x -U x +-P x sol activate can start sol session correctly. +After reboot BMC, "Progress" property in dbus interface change back +to 0 and other properties will not reset to default value. + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + command/payload_cmds.cpp | 3 ++ + command/sol_cmds.cpp | 84 ------------------------------- + sol/sol_manager.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++++ + sol/sol_manager.hpp | 1 + + sol_module.cpp | 6 --- + 5 files changed, 129 insertions(+), 90 deletions(-) + +diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp +index c32a510..17167a7 100644 +--- a/command/payload_cmds.cpp ++++ b/command/payload_cmds.cpp +@@ -34,6 +34,9 @@ std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload, + return outPayload; + } + ++ std::get<sol::Manager&>(singletonPool) ++ .updateSOLParameter(ipmi::convertCurrentChannelNum( ++ ipmi::currentChNum, getInterfaceIndex())); + if (!std::get<sol::Manager&>(singletonPool).enable) + { + response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED; +diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp +index a8fa410..804b5ea 100644 +--- a/command/sol_cmds.cpp ++++ b/command/sol_cmds.cpp +@@ -65,90 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) + outPayload); + } + +-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler) +-{ +- std::vector<uint8_t> outPayload(sizeof(SetConfParamsResponse)); +- auto request = +- reinterpret_cast<const SetConfParamsRequest*>(inPayload.data()); +- auto response = reinterpret_cast<SetConfParamsResponse*>(outPayload.data()); +- response->completionCode = IPMI_CC_OK; +- +- switch (static_cast<Parameter>(request->paramSelector)) +- { +- case Parameter::PROGRESS: +- { +- uint8_t progress = request->value & progressMask; +- std::get<sol::Manager&>(singletonPool).progress = progress; +- break; +- } +- case Parameter::ENABLE: +- { +- bool enable = request->value & enableMask; +- std::get<sol::Manager&>(singletonPool).enable = enable; +- break; +- } +- case Parameter::AUTHENTICATION: +- { +- if (!request->auth.auth || !request->auth.encrypt) +- { +- response->completionCode = ipmiCCWriteReadParameter; +- } +- else if (request->auth.privilege < +- static_cast<uint8_t>(session::Privilege::USER) || +- request->auth.privilege > +- static_cast<uint8_t>(session::Privilege::OEM)) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- } +- else +- { +- std::get<sol::Manager&>(singletonPool).solMinPrivilege = +- static_cast<session::Privilege>(request->auth.privilege); +- } +- break; +- } +- case Parameter::ACCUMULATE: +- { +- using namespace std::chrono_literals; +- +- if (request->acc.threshold == 0) +- { +- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; +- break; +- } +- +- std::get<sol::Manager&>(singletonPool).accumulateInterval = +- request->acc.interval * sol::accIntervalFactor * 1ms; +- std::get<sol::Manager&>(singletonPool).sendThreshold = +- request->acc.threshold; +- break; +- } +- case Parameter::RETRY: +- { +- using namespace std::chrono_literals; +- +- std::get<sol::Manager&>(singletonPool).retryCount = +- request->retry.count; +- std::get<sol::Manager&>(singletonPool).retryInterval = +- request->retry.interval * sol::retryIntervalFactor * 1ms; +- break; +- } +- case Parameter::PORT: +- { +- response->completionCode = ipmiCCWriteReadParameter; +- break; +- } +- case Parameter::NVBITRATE: +- case Parameter::VBITRATE: +- case Parameter::CHANNEL: +- default: +- response->completionCode = ipmiCCParamNotSupported; +- } +- +- return outPayload; +-} +- + std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, + const message::Handler& handler) + { +diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp +index 2046fe4..eedd28a 100644 +--- a/sol/sol_manager.cpp ++++ b/sol/sol_manager.cpp +@@ -12,7 +12,13 @@ + #include <boost/asio/write.hpp> + #include <chrono> + #include <cmath> ++#include <ipmid/utils.hpp> + #include <phosphor-logging/log.hpp> ++#include <sdbusplus/message/types.hpp> ++ ++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; ++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; ++constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties"; + + namespace sol + { +@@ -93,6 +99,125 @@ void Manager::stopHostConsole() + } + } + ++std::string getService(sdbusplus::bus::bus& bus, const std::string& intf, ++ const std::string& path) ++{ ++ auto mapperCall = ++ bus.new_method_call("xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetObject"); ++ ++ mapperCall.append(path); ++ mapperCall.append(std::vector<std::string>({intf})); ++ ++ std::map<std::string, std::vector<std::string>> mapperResponse; ++ ++ try ++ { ++ auto mapperResponseMsg = bus.call(mapperCall); ++ mapperResponseMsg.read(mapperResponse); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ throw std::runtime_error("ERROR in mapper call"); ++ } ++ ++ if (mapperResponse.begin() == mapperResponse.end()) ++ { ++ throw std::runtime_error("ERROR in reading the mapper response"); ++ } ++ ++ return mapperResponse.begin()->first; ++} ++ ++ipmi::PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus, ++ const std::string& service, ++ const std::string& objPath, ++ const std::string& interface) ++{ ++ ipmi::PropertyMap properties; ++ ++ sdbusplus::message::message method = bus.new_method_call( ++ service.c_str(), objPath.c_str(), PROP_INTF, "GetAll"); ++ ++ method.append(interface); ++ ++ try ++ { ++ sdbusplus::message::message reply = bus.call(method); ++ reply.read(properties); ++ } ++ catch (sdbusplus::exception_t&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Failed to get all properties", ++ phosphor::logging::entry("PATH=%s", objPath.c_str()), ++ phosphor::logging::entry("INTERFACE=%s", interface.c_str())); ++ throw std::runtime_error("ERROR in reading proerties"); ++ } ++ ++ return properties; ++} ++ ++void Manager::updateSOLParameter(uint8_t channelNum) ++{ ++ std::variant<uint8_t, bool> value; ++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); ++ static std::string solService{}; ++ ipmi::PropertyMap properties; ++ std::string ethdevice = ipmi::getChannelName(channelNum); ++ std::string solPathWitheEthName = solPath + ethdevice; ++ if (solService.empty()) ++ { ++ try ++ { ++ solService = getService(dbus, solInterface, solPathWitheEthName); ++ } ++ catch (const std::runtime_error& e) ++ { ++ solService.clear(); ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error: get SOL service failed"); ++ return; ++ } ++ } ++ try ++ { ++ properties = getAllDbusProperties(dbus, solService, solPathWitheEthName, ++ solInterface); ++ } ++ catch (const std::runtime_error&) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error setting sol parameter"); ++ return; ++ } ++ ++ progress = std::get<uint8_t>(properties["Progress"]); ++ ++ enable = std::get<bool>(properties["Enable"]); ++ ++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]); ++ ++ forceAuth = std::get<bool>(properties["ForceAuthentication"]); ++ ++ solMinPrivilege = static_cast<session::Privilege>( ++ std::get<uint8_t>(properties["Privilege"])); ++ ++ accumulateInterval = ++ std::get<uint8_t>((properties["AccumulateIntervalMS"])) * ++ sol::accIntervalFactor * 1ms; ++ ++ sendThreshold = std::get<uint8_t>(properties["Threshold"]); ++ ++ retryCount = std::get<uint8_t>(properties["RetryCount"]); ++ ++ retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) * ++ sol::retryIntervalFactor * 1ms; ++ ++ return; ++} ++ + void Manager::startPayloadInstance(uint8_t payloadInstance, + session::SessionID sessionID) + { +diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp +index 5d96890..00da9fb 100644 +--- a/sol/sol_manager.hpp ++++ b/sol/sol_manager.hpp +@@ -248,6 +248,7 @@ class Manager + * @return 0 on success and errno on failure. + */ + int writeConsoleSocket(const std::vector<uint8_t>& input) const; ++ void updateSOLParameter(uint8_t channelNum); + + private: + SOLPayloadMap payloadMap; +diff --git a/sol_module.cpp b/sol_module.cpp +index 8200e74..2b1fb46 100644 +--- a/sol_module.cpp ++++ b/sol_module.cpp +@@ -42,12 +42,6 @@ void registerCommands() + &getPayloadInfo, + session::Privilege::USER, + false}, +- // Set SOL Configuration Parameters +- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x21}, +- &setConfParams, +- session::Privilege::ADMIN, +- false}, + // Get SOL Configuration Parameters + {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | + static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22}, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch new file mode 100644 index 000000000..da173704b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch @@ -0,0 +1,336 @@ +From a36f181163974b2da0a954fc97a89fb2cdbd7287 Mon Sep 17 00:00:00 2001 +From: Cheng C Yang <cheng.c.yang@intel.com> +Date: Tue, 30 Apr 2019 05:35:31 +0800 +Subject: [PATCH] Remove Get SOL Config Command from Netipmid + +Since Get SOL Config Parameter command already exists in host-ipmid, and +can be shared to net channel, remove this command from net-ipmid. + +Tested: +Run ipmitool -I lanplus -H xxx -U root -P 0penBmc sol info, the command +returns the same result as ipmitool sol info as below. +Info: SOL parameter 'Nonvolatile Bitrate (5)' not supported +Info: SOL parameter 'Volatile Bitrate (6)' not supported +Info: SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e +Set in progress : set-complete +Enabled : true +Force Encryption : true +Force Authentication : true +Privilege Level : USER +Character Accumulate Level (ms) : 100 +Character Send Threshold : 1 +Retry Count : 3 +Retry Interval (ms) : 100 +Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Non-Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting +Payload Channel : 14 (0x0e) +Payload Port : 623 + +Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com> +--- + command/sol_cmds.cpp | 91 ---------------------------- + command/sol_cmds.hpp | 168 --------------------------------------------------- + sol_module.cpp | 6 -- + 3 files changed, 265 deletions(-) + +diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp +index 804b5ea..8b2d041 100644 +--- a/command/sol_cmds.cpp ++++ b/command/sol_cmds.cpp +@@ -65,97 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID) + outPayload); + } + +-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler) +-{ +- std::vector<uint8_t> outPayload(sizeof(GetConfParamsResponse)); +- auto request = +- reinterpret_cast<const GetConfParamsRequest*>(inPayload.data()); +- auto response = reinterpret_cast<GetConfParamsResponse*>(outPayload.data()); +- response->completionCode = IPMI_CC_OK; +- response->paramRev = parameterRevision; +- +- if (request->getParamRev) +- { +- return outPayload; +- } +- +- switch (static_cast<Parameter>(request->paramSelector)) +- { +- case Parameter::PROGRESS: +- { +- outPayload.push_back( +- std::get<sol::Manager&>(singletonPool).progress); +- break; +- } +- case Parameter::ENABLE: +- { +- outPayload.push_back(std::get<sol::Manager&>(singletonPool).enable); +- break; +- } +- case Parameter::AUTHENTICATION: +- { +- Auth value{0}; +- +- value.encrypt = std::get<sol::Manager&>(singletonPool).forceEncrypt; +- value.auth = std::get<sol::Manager&>(singletonPool).forceAuth; +- value.privilege = static_cast<uint8_t>( +- std::get<sol::Manager&>(singletonPool).solMinPrivilege); +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::ACCUMULATE: +- { +- Accumulate value{0}; +- +- value.interval = std::get<sol::Manager&>(singletonPool) +- .accumulateInterval.count() / +- sol::accIntervalFactor; +- value.threshold = +- std::get<sol::Manager&>(singletonPool).sendThreshold; +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::RETRY: +- { +- Retry value{0}; +- +- value.count = std::get<sol::Manager&>(singletonPool).retryCount; +- value.interval = +- std::get<sol::Manager&>(singletonPool).retryInterval.count() / +- sol::retryIntervalFactor; +- auto buffer = reinterpret_cast<const uint8_t*>(&value); +- +- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::PORT: +- { +- auto port = endian::to_ipmi<uint16_t>(IPMI_STD_PORT); +- auto buffer = reinterpret_cast<const uint8_t*>(&port); +- +- std::copy_n(buffer, sizeof(port), std::back_inserter(outPayload)); +- break; +- } +- case Parameter::CHANNEL: +- { +- outPayload.push_back( +- std::get<sol::Manager&>(singletonPool).channel); +- break; +- } +- case Parameter::NVBITRATE: +- case Parameter::VBITRATE: +- default: +- response->completionCode = ipmiCCParamNotSupported; +- } +- +- return outPayload; +-} +- + } // namespace command + + } // namespace sol +diff --git a/command/sol_cmds.hpp b/command/sol_cmds.hpp +index 182b73e..10cbf25 100644 +--- a/command/sol_cmds.hpp ++++ b/command/sol_cmds.hpp +@@ -62,174 +62,6 @@ struct ActivatingRequest + */ + void activating(uint8_t payloadInstance, uint32_t sessionID); + +-/** @enum Parameter +- * +- * SOL parameters are volatile, they are initialized by the SOL manager. +- * They can be read using Get SOL configuration parameters command and updated +- * using Set SOL configuration parameters command. +- */ +-enum class Parameter +-{ +- PROGRESS, //!< Set In Progress. +- ENABLE, //!< SOL Enable. +- AUTHENTICATION, //!< SOL Authentication. +- ACCUMULATE, //!< Character Accumulate Interval & Send Threshold. +- RETRY, //!< SOL Retry. +- NVBITRATE, //!< SOL non-volatile bit rate. +- VBITRATE, //!< SOL volatile bit rate. +- CHANNEL, //!< SOL payload channel. +- PORT, //!< SOL payload port. +-}; +- +-constexpr uint8_t progressMask = 0x03; +-constexpr uint8_t enableMask = 0x01; +- +-/** @struct Auth +- * +- * SOL authentication parameter. +- */ +-struct Auth +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t privilege : 4; //!< SOL privilege level. +- uint8_t reserved : 2; //!< Reserved. +- uint8_t auth : 1; //!< Force SOL payload Authentication. +- uint8_t encrypt : 1; //!< Force SOL payload encryption. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t encrypt : 1; //!< Force SOL payload encryption. +- uint8_t auth : 1; //!< Force SOL payload Authentication. +- uint8_t reserved : 2; //!< Reserved. +- uint8_t privilege : 4; //!< SOL privilege level. +-#endif +-} __attribute__((packed)); +- +-/** @struct Accumulate +- * +- * Character accumulate interval & Character send threshold. +- */ +-struct Accumulate +-{ +- uint8_t interval; //!< Character accumulate interval. +- uint8_t threshold; //!< Character send threshold. +-} __attribute__((packed)); +- +-constexpr uint8_t retryCountMask = 0x07; +- +-/** @struct Retry +- * +- * SOL retry count and interval. +- */ +-struct Retry +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t count : 3; //!< SOL retry count. +- uint8_t reserved : 5; //!< Reserved. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t reserved : 5; //!< Reserved. +- uint8_t count : 3; //!< SOL retry count. +-#endif +- +- uint8_t interval; //!< SOL retry interval. +-} __attribute__((packed)); +- +-constexpr uint8_t ipmiCCParamNotSupported = 0x80; +-constexpr uint8_t ipmiCCInvalidSetInProgress = 0x81; +-constexpr uint8_t ipmiCCWriteReadParameter = 0x82; +-constexpr uint8_t ipmiCCReadWriteParameter = 0x83; +-constexpr uint8_t parameterRevision = 0x11; +- +-/** @struct SetConfParamsRequest +- * +- * IPMI payload for Set SOL configuration parameters command request. +- */ +-struct SetConfParamsRequest +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t channelNumber : 4; //!< Channel number. +- uint8_t reserved : 4; //!< Reserved. +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t reserved : 4; //!< Reserved. +- uint8_t channelNumber : 4; //!< Channel number. +-#endif +- +- uint8_t paramSelector; //!< Parameter selector. +- union +- { +- uint8_t value; //!< Represents one byte SOL parameters. +- struct Accumulate acc; //!< Character accumulate values. +- struct Retry retry; //!< Retry values. +- struct Auth auth; //!< Authentication parameters. +- }; +-} __attribute__((packed)); +- +-/** @struct SetConfParamsResponse +- * +- * IPMI payload for Set SOL configuration parameters command response. +- */ +-struct SetConfParamsResponse +-{ +- uint8_t completionCode; //!< Completion code. +-} __attribute__((packed)); +- +-/** @brief Set SOL configuration parameters command. +- * +- * @param[in] inPayload - Request data for the command. +- * @param[in] handler - Reference to the message handler. +- * +- * @return Response data for the command. +- */ +-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler); +- +-/** @struct GetConfParamsRequest +- * +- * IPMI payload for Get SOL configuration parameters command request. +- */ +-struct GetConfParamsRequest +-{ +-#if BYTE_ORDER == LITTLE_ENDIAN +- uint8_t channelNum : 4; //!< Channel number. +- uint8_t reserved : 3; //!< Reserved. +- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision +-#endif +- +-#if BYTE_ORDER == BIG_ENDIAN +- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision +- uint8_t reserved : 3; //!< Reserved. +- uint8_t channelNum : 4; //!< Channel number. +-#endif +- +- uint8_t paramSelector; //!< Parameter selector. +- uint8_t setSelector; //!< Set selector. +- uint8_t blockSelector; //!< Block selector. +-} __attribute__((packed)); +- +-/** @struct GetConfParamsResponse +- * +- * IPMI payload for Get SOL configuration parameters command response. +- */ +-struct GetConfParamsResponse +-{ +- uint8_t completionCode; //!< Completion code. +- uint8_t paramRev; //!< Parameter revision. +-} __attribute__((packed)); +- +-/** @brief Get SOL configuration parameters command. +- * +- * @param[in] inPayload - Request data for the command. +- * @param[in] handler - Reference to the message handler. +- * +- * @return Response data for the command. +- */ +-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload, +- const message::Handler& handler); +- + } // namespace command + + } // namespace sol +diff --git a/sol_module.cpp b/sol_module.cpp +index 2b1fb46..6da82c0 100644 +--- a/sol_module.cpp ++++ b/sol_module.cpp +@@ -42,12 +42,6 @@ void registerCommands() + &getPayloadInfo, + session::Privilege::USER, + false}, +- // Get SOL Configuration Parameters +- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) | +- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22}, +- &getConfParams, +- session::Privilege::USER, +- false}, + }; + + for (const auto& iter : commands) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend new file mode 100644 index 000000000..c82736781 --- /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 = "2555e2ec1c5bd6636eb67a1a2cdf6b8b567772c9" + +USERADD_PACKAGES = "${PN}" +# add a group called ipmi +GROUPADD_PARAM_${PN} = "ipmi " + +# Default rmcpp iface is eth0; channel 1 +# Add channel 2 instance (eth1) +RMCPP_EXTRA = "eth1" +SYSTEMD_SERVICE_${PN} += " \ + ${PN}@${RMCPP_EXTRA}.service \ + ${PN}@${RMCPP_EXTRA}.socket \ + " + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += " file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \ + file://0009-Add-dbus-interface-for-sol-commands.patch \ + file://0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch \ + " + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend new file mode 100644 index 000000000..72d991c7e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb new file mode 100644 index 000000000..36d65fd72 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb @@ -0,0 +1,19 @@ +SUMMARY = "Node Manager Proxy" +DESCRIPTION = "The Node Manager Proxy provides a simple interface for communicating \ +with Management Engine via IPMB" + +SRC_URI = "git://github.com/Intel-BMC/node-manager;protocol=ssh" +SRCREV = "de212d839bb515939bd089c66072e4fcf33b8653" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} = "node-manager-proxy.service" + +DEPENDS = "sdbusplus \ + phosphor-logging \ + boost" + +S = "${WORKDIR}/git/" +inherit cmake systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service new file mode 100644 index 000000000..51e59c614 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service @@ -0,0 +1,11 @@ +[Unit] +Description=turn off the ID LED when BMC is ready +Wants=multi-user.target +After=multi-user.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/id-led-off.sh + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh new file mode 100755 index 000000000..b609fc0ea --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh @@ -0,0 +1,12 @@ +#!/bin/sh +busctl set-property "xyz.openbmc_project.LED.GroupManager" \ +"/xyz/openbmc_project/led/groups/enclosure_identify" \ +"xyz.openbmc_project.Led.Group" "Asserted" b false + +busctl set-property "xyz.openbmc_project.LED.GroupManager" \ +"/xyz/openbmc_project/led/groups/enclosure_identify_blink" \ +"xyz.openbmc_project.Led.Group" "Asserted" b false + +busctl set-property "xyz.openbmc_project.LED.Controller.identify" \ +"/xyz/openbmc_project/led/physical/identify" \ +"xyz.openbmc_project.Led.Physical" "State" s "xyz.openbmc_project.Led.Physical.Action.Off" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb new file mode 100644 index 000000000..a1d20c2bc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb @@ -0,0 +1,24 @@ +SUMMARY = "Turn off the ID LED" +DESCRIPTION = "Script to turn off the ID LED after BMC is ready" + +S = "${WORKDIR}" +SRC_URI = "file://id-led-off.sh \ + file://id-led-off.service \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +RDEPENDS_${PN} += "bash" + +inherit systemd + +FILES_${PN} += "${systemd_system_unitdir}/id-led-off.service" + +do_install() { + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${WORKDIR}/id-led-off.service ${D}${systemd_system_unitdir} + install -d ${D}${bindir} + install -m 0755 ${S}/id-led-off.sh ${D}/${bindir}/id-led-off.sh +} + +SYSTEMD_SERVICE_${PN} += " id-led-off.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb new file mode 100644 index 000000000..dd48df0c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb @@ -0,0 +1,21 @@ +SUMMARY = "Phosphor LED Group Management for Intel" +PR = "r1" + +inherit native +inherit obmc-phosphor-utils + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +PROVIDES += "virtual/phosphor-led-manager-config-native" + +SRC_URI += "file://led.yaml" +S = "${WORKDIR}" + +# Overwrite the example led layout yaml file prior +# to building the phosphor-led-manager package +do_install() { + SRC=${S} + DEST=${D}${datadir}/phosphor-led-manager + install -D ${SRC}/led.yaml ${DEST}/led.yaml +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml new file mode 100644 index 000000000..533df68a4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml @@ -0,0 +1,48 @@ +bmc_booted: + +power_on: + +status_ok: + status_green: + Action: 'On' + status_amber: + Action: 'Off' + +status_degraded: + status_green: + Action: 'Blink' + DutyOn: 50 + Period: 1000 + status_amber: + Action: 'Off' + +status_non_critical: + status_green: + Action: 'Off' + status_amber: + Action: 'Blink' + DutyOn: 50 + Period: 1000 + +status_critical: + status_green: + Action: 'Off' + status_amber: + Action: 'On' + +enclosure_identify: + identify: + Action: 'On' + +enclosure_identify_blink: + identify: + Action: 'Blink' + +cpu0_fault: + cpu0fault: + Action: 'On' + +cpu1_fault: + cpu1fault: + Action: 'On' + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb new file mode 100644 index 000000000..620a2ab51 --- /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://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/multi-node-nl/multi-node-nl.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb new file mode 100644 index 000000000..c47a581f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb @@ -0,0 +1,27 @@ +SUMMARY = "Multi-node Non-legacy" +DESCRIPTION = "New systemd target for non-legacy nodes on multi-node platform" + +inherit systemd + +SYSTEMD_SERVICE_${PN} = "multi-node-nl.target" +SYSTEMD_SERVICE_${PN} += "nonLegacyNode.service" + +S = "${WORKDIR}" +SRC_URI = "file://multi-node-nl.target \ + file://nonLegacyNode.service \ + file://nonLegacyNode.sh \ + " + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +RDEPENDS_${PN} = "bash" + +do_install_append() { + install -d ${D}${bindir} + install -m 0755 ${S}/nonLegacyNode.sh ${D}/${bindir}/nonLegacyNode.sh + + install -d ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/multi-node-nl.target ${D}${base_libdir}/systemd/system + install -m 0644 ${S}/nonLegacyNode.service ${D}${base_libdir}/systemd/system +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target new file mode 100644 index 000000000..32b50532f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target @@ -0,0 +1,4 @@ +[Unit] +Description=Target for non-legacy node in multi-node system +Documentation=man:systemd.special(7) + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service new file mode 100644 index 000000000..8e3d07ba4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service @@ -0,0 +1,9 @@ +[Unit] +Description=Non Legacy node + +[Service] +ExecStart=/usr/bin/nonLegacyNode.sh +Type=exec + +[Install] +WantedBy=multi-node-nl.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh new file mode 100755 index 000000000..2a1a5ea3b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +PWM_FILE="/sys/class/hwmon/hwmon0/pwm" +FAN_SPEED=$((255 * 80 / 100)) + +set_fan_speed() { + local idx=0 + for ((idx=1; idx<=8; idx++)) + do + if [ -f $PWM_FILE$idx ]; then + echo $FAN_SPEED > $PWM_FILE$idx + fi + done +} + +$(set_fan_speed) + +export TERM=xterm +# Autologin root user to serial console (ttyS4) on boot +exec /sbin/agetty -a root -J -8 -L ttyS4 115200 $TERM diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb new file mode 100644 index 000000000..2a561dbe1 --- /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://github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.U_Boot.Environment.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb new file mode 100644 index 000000000..72acf3127 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb @@ -0,0 +1,26 @@ +SUMMARY = "MCTP Daemon" +DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)" + +LICENSE = "Apache-2.0 | GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh" +SRCREV = "df5eba0d1ea5a1e07d24eca95cc9ce5d25819c69" + +S = "${WORKDIR}/git/mctpd/" + +PV = "1.0+git${SRCPV}" + +inherit cmake systemd + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += " \ + libmctp \ + systemd \ + sdbusplus \ + phosphor-logging \ + boost \ + i2c-tools \ + " +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.mctpd.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend new file mode 100644 index 000000000..dc22b3c95 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI = "file://init"
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init new file mode 100755 index 000000000..e954d7757 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init @@ -0,0 +1,258 @@ +#!/bin/sh + +# Copyright 2017-2019 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# provide a couple of places in the RO root filesystem +# that can be made RW with an overlayfs + +log() { + [ -c /dev/kmsg ] && echo "init: $@" > /dev/kmsg + echo "init: $@" +} + +# start with /proc and /tmp mounted +[ -e /proc/mounts ] || mount -t proc proc /proc +# FIXME: add size limits to /tmp +grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp +grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys + +# fix up /srv to be RW +mkdir -p /tmp/srv +mount --bind /tmp/srv /srv + +if grep -q debug-init /proc/cmdline; then + exec > /tmp/init.log 2>&1 + set -x + env +else + # silent bob + exec >/dev/null 2>&1 +fi + +# list of things that need to be rw at boot +NV_OVERLAYS="/etc /var /home" + +# place to mount the overlay backing store +OVERLAY_MNT=/tmp/.overlay +OVERLAY_SIZE=16384 +# place to mount NV +RWFS_MNT=/tmp/.rwfs +# NV overlay storage +OVERLAY_SYNC=${RWFS_MNT}/.overlay + +if grep -q "$RWFS_MNT" /proc/mounts; then + # quit - we have already run + exit 0 +fi +mkdir -p "$OVERLAY_MNT" +# TODO: remount the overlay with a size limit? +# mount -t tmpfs -o rw,size=${OVERLAY_SIZE} oltmp ${OVERLAY_MNT} + +mtd_by_name() { + local name="$1" + local mtd="/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)" + echo "$mtd" +} + +mtdnum_by_name() { + local name="$1" + local mtdnum="$(grep "$name" /proc/mtd | cut -c 4)" + echo "$mtdnum" +} + +NV_MTD=rwfs +NV_MTD_DEV="$(mtd_by_name ${NV_MTD})" +NV_MTD_NUM="$(mtdnum_by_name ${NV_MTD})" + +nvrw() { + local p="$1" + # Clear the work dir doing overlay mount + rm -rf "${OVERLAY_MNT}${p}.work" + mkdir -p "${OVERLAY_MNT}${p}" "${OVERLAY_MNT}${p}.work" + local mname=$(echo "ol${p}" | sed 's,/,,g') + local opts="lowerdir=${p},upperdir=${OVERLAY_MNT}${p},workdir=${OVERLAY_MNT}${p}.work,sync" + mount -t overlay -o "$opts" "$mname" "$p" +} + +targeted_clean() { + log "restore-defaults: targeted_clean" + # Do not delete FRU info, ssh/ssl certs, or machine-id + ( + cd "${OVERLAY_SYNC}/etc" + find . ! -regex '.*\(/ssl\|/dropbear\|/machine-id\(_bkup\)\?\|/fru\).*' -exec rm -rf {} + + ) + # nothing should be in the workdir, but clear it just in case + rm -rf "${OVERLAY_SYNC}/etc.work" + + # clean everything out of /home + rm -rf "${OVERLAY_SYNC}/home" "${OVERLAY_SYNC}/home.work" + + # clean everything out of /var + rm -rf "${OVERLAY_SYNC}/var" "${OVERLAY_SYNC}/var.work" + + echo "Files remaining: $(find $OVERLAY_SYNC/)" + sync +} + +full_clean() { + log "restore-defaults: full_clean" + local OVL='' + for OVL in $NV_OVERLAYS; do + rm -rf "${OVERLAY_SYNC}${OVL}" "${OVERLAY_SYNC}${OVL}.work" + done + sync +} + +reformat_jffs2_partition() { + local mtd_name="$1" + local mnt="$2" + # unmount the partition to reformat it + umount -f "$mnt" + flash_eraseall "$(mtd_by_name ${mtd_name})" + # remount the JFFS2 + mount -t jffs2 -o sync mtd:"$mtd_name" "$mnt" + if [ $? -ne 0 ]; then + log "Failed to mount reformatted NV volume; system unstable" + fi +} + +clear_ubenv() { + log "Clearing U-Boot environment" + flash_erase /dev/mtd/u-boot-env 0 0 +} + +# mount NV filesystem +mkdir -p "$RWFS_MNT" +mount -t jffs2 -o sync mtd:"$NV_MTD" "$RWFS_MNT" +if [ $? -ne 0 ]; then + log "Failed to mount NV volume; attempting recovery" + reformat_jffs2_partition $NV_MTD $RWFS_MNT +fi + +# check for full factory reset: if so, format $NV_MTD_DEV +RESTORE_FLAG=$RWFS_MNT/.restore_op +restore_op=$(cat $RESTORE_FLAG) # read from NV +restore_op=${restore_op:-0} # set default value 0 +restore_op=$((restore_op & 3)) # mask off 2 bits +if [ $restore_op -eq 1 ]; then + targeted_clean +elif [ $restore_op -eq 2 ]; then + full_clean + clear_ubenv +elif [ $restore_op -eq 3 ]; then + log "restore-defaults: reformat" + reformat_jffs2_partition $NV_MTD $RWFS_MNT + clear_ubenv +fi +rm -f $RESTORE_FLAG + +# Restore the overlay saved in the sync +rsync -a --delete "${OVERLAY_SYNC}/" "${OVERLAY_MNT}" +log "Restored overlay from sync location" + +for FS in $NV_OVERLAYS; do + nvrw "$FS" +done + +# work around bug where /etc/machine-id will be mounted with a temporary file +# if rootfs is read-only and the file is empty +MACHINE_ID=/etc/machine-id +generate_machine_id() { + systemd-machine-id-setup + cp -pf "$MACHINE_ID" "${MACHINE_ID}_bkup" +} + +if [ ! -s "$MACHINE_ID" ]; then + # work around - Bug: Overlay fs fails for machine-id due to + # origin mismatch. Clean it up, from overlay fs before re-creating + # the same. + if [ -e "$OVERLAY_MNT$MACHINE_ID" ]; then + umount "/etc" + rm -f "$OVERLAY_MNT$MACHINE_ID" + nvrw "/etc" + # Restore the machine-id from backup, else generate it. + if [ -s "${MACHINE_ID}_bkup" ]; then + cp -pf "${MACHINE_ID}_bkup" "${MACHINE_ID}" + else + generate_machine_id + fi + log "Remounted /etc for machine-id origin mismatch" + else + generate_machine_id + fi +fi + +# mount persistent NV filesystem, where immortal settings live +SOFS_MNT=/var/sofs +if ! grep -q sofs /proc/mounts; then + mkdir -p $SOFS_MNT + SOFS_MTD=sofs + SOFS_MTD_NUM="$(mtdnum_by_name ${SOFS_MTD})" + + # mount a JFFS2 on the partition + mount -t jffs2 -o sync mtd:"$SOFS_MTD" "$SOFS_MNT" + if [ $? -ne 0 ]; then + log "Failed to mount SOFS volume; attempting recovery" + reformat_jffs2_partition $SOFS_MTD $SOFS_MNT + fi +fi + +log "Finished mounting nv and overlays" + + +# Detect the non-legacy node in cooper city and boot in to special mode. + +readonly COOPER_CITY=40 # Board id of cooper city + +is_nl_node() { + typeset -i nid1=$(gpioget $(gpiofind "FM_NODE_ID_1")) + typeset -i nid2=$(gpioget $(gpiofind "FM_NODE_ID_2")) + echo $((nid1|nid2)) +} + +read_board_id() { + local idx=0 + local result=0 + local value=0 + for ((idx=0; idx<6; idx++)) + do + typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N")) + value=$((value << idx)) + result=$((result | value)) + done + echo $result +} + +pfr_write() { + [ $# -ne 2 ] && return 1 + local PFR_BUS=4 + local PFR_ADDR=0x38 + local reg=$1 + local val=$2 + i2cset -y $PFR_BUS $PFR_ADDR $reg $val >&/dev/null +} + +board_id=$(read_board_id) +if [ $board_id -eq $COOPER_CITY ]; then + if [ $(is_nl_node) -ne 0 ]; then + systemctl set-default multi-node-nl.target + PFR_BMC_CHECKPOINT_REG=0xf + PFR_BMC_CHECKPOINT_COMPLETE=0x9 + pfr_write $PFR_BMC_CHECKPOINT_REG $PFR_BMC_CHECKPOINT_COMPLETE + fi +fi + +exec /lib/systemd/systemd diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb new file mode 100644 index 000000000..9db4eeb56 --- /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://github.com/Intel-BMC/provingground.git;protocol=ssh" + +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.RestrictionMode.Manager.service" + +DEPENDS = "boost sdbusplus phosphor-logging" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb new file mode 100644 index 000000000..64201acc1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb @@ -0,0 +1,24 @@ +SUMMARY = "Security Manager daemon to detect the security violation- ASD/ user management" +DESCRIPTION = "Daemon check for Remote debug enable and user account violation" + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/security-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" +inherit cmake systemd + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.SecurityManager.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + libgpiod \ + sdbusplus-native \ + phosphor-logging \ + boost \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend new file mode 100644 index 000000000..e80464274 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend @@ -0,0 +1,4 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git" +SRCREV = "151b7c1fc62971b7d319146e5ea129d44eadd9d7" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service new file mode 100644 index 000000000..b8c3554ae --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service @@ -0,0 +1,10 @@ +[Unit] +Description= BMC Self-Test + +[Service] +Restart=always +ExecStart=/usr/bin/env selftest +SyslogIdentifier=selftest + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb new file mode 100644 index 000000000..f655d22e4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb @@ -0,0 +1,38 @@ +SUMMARY = "BMC Self Test service" +DESCRIPTION = "BMC Self Test service for subsystem diagnosis failure info" + +SRC_URI = "git://github.com/Intel-BMC/intel-self-test;protocol=ssh" + +PV = "1.0+git${SRCPV}" +SRCREV = "d039998ad2c55aeae4191af30e15bbd3032508c1" + +S = "${WORKDIR}/git" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=fa818a259cbed7ce8bc2a22d35a464fc" + +inherit cmake +inherit obmc-phosphor-dbus-service +inherit obmc-phosphor-systemd +inherit pkgconfig pythonnative + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.selftest.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " + +EXTRA_OECMAKE = " -DENABLE_GTEST=OFF -DCMAKE_SKIP_RPATH=ON" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend new file mode 100644 index 000000000..d681a6266 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend @@ -0,0 +1,9 @@ +SRCREV = "883fb3a97b3ac47eab7d69e0841ff38ba5b9b2aa" +SRC_URI = "git://github.com/openbmc/dbus-sensors.git" + +DEPENDS_append = " libgpiod libmctp" + +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +EXTRA_OECMAKE += "-DDISABLE_NVME=OFF" +SYSTEMD_SERVICE_${PN} += " xyz.openbmc_project.nvmesensor.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb new file mode 100644 index 000000000..e49a410cb --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb @@ -0,0 +1,20 @@ +SUMMARY = "Settings" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" +PV = "0.1+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Settings.service" + +DEPENDS = "boost \ + nlohmann-json \ + sdbusplus" + +S = "${WORKDIR}/git/settings" +inherit cmake systemd + +EXTRA_OECMAKE = "-DYOCTO=1" + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb new file mode 100644 index 000000000..2690169ff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb @@ -0,0 +1,30 @@ +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://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" +EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "specialmodemgr.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + boost \ + libpam \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb new file mode 100644 index 000000000..b1ac1fbc1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb @@ -0,0 +1,28 @@ +SUMMARY = "Service configuration manager daemon to control service properties" +DESCRIPTION = "Daemon controls service properies like port, channels, state etc.." + +PV = "1.0+git${SRCPV}" + +S = "${WORKDIR}/git/srvcfg-manager" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +inherit cmake systemd +SYSTEMD_SERVICE_${PN} = "srvcfg-manager.service" + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + boost \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend new file mode 100644 index 000000000..aef2a020f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +DEPENDS += "gtest" 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..97896d72a --- /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 = "655837973feb51da3767f5f246ec198877900b0b" + +S = "${WORKDIR}/git" + +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327" + +inherit cmake pkgconfig systemd + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.State.Boot.PostCode.service" + +DEPENDS += " \ + autoconf-archive-native \ + systemd \ + boost \ + sdbusplus \ + sdbusplus-native \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + phosphor-logging \ + " +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-dbus-interfaces \ + phosphor-logging \ + " +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb new file mode 100644 index 000000000..cc84015f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb @@ -0,0 +1,19 @@ +SUMMARY = "Callback Manager" +DESCRIPTION = "D-Bus daemon that registers matches that trigger method calls" + +SRC_URI = "git://github.com/Intel-BMC/provingground;protocol=ssh" + +inherit cmake systemd +DEPENDS = "boost sdbusplus" + +PV = "0.1+git${SRCPV}" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +S = "${WORKDIR}/git/callback-manager" + +SYSTEMD_SERVICE_${PN} += "callback-manager.service" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENCE;md5=7becf906c8f8d03c237bad13bc3dac53" + +EXTRA_OECMAKE = "-DYOCTO=1" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch new file mode 100644 index 000000000..c19f33da2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch @@ -0,0 +1,1655 @@ +From b8a8e561d7dba48f3f0a0eb34662b2450dcad35d Mon Sep 17 00:00:00 2001 +From: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Date: Mon, 2 Jul 2018 19:23:25 -0700 +Subject: [PATCH] Added suport for multiple user manager services + +Support added for SSSD service implementation + +Signed-off-by: Alberto Salazar Perez <alberto.salazar.perez@intel.com> +Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com> +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + Makefile.am | 5 +- + mainapp.cpp | 89 ++++++- + user_mgr.cpp | 295 ++------------------- + user_mgr.hpp | 9 +- + user_service.cpp | 786 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + user_service.hpp | 233 +++++++++++++++++ + 6 files changed, 1144 insertions(+), 273 deletions(-) + create mode 100644 user_service.cpp + create mode 100644 user_service.hpp + +diff --git a/Makefile.am b/Makefile.am +index 7c7271e..58916b0 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1,11 +1,12 @@ + bin_PROGRAMS = phosphor-user-manager + +-noinst_HEADERS = user_mgr.hpp users.hpp ++noinst_HEADERS = user_mgr.hpp users.hpp user_service.hpp + + phosphor_user_manager_SOURCES = \ + mainapp.cpp \ + user_mgr.cpp \ +- users.cpp ++ users.cpp \ ++ user_service.cpp + + phosphor_user_manager_LDFLAGS = $(SDBUSPLUS_LIBS) \ + $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ +diff --git a/mainapp.cpp b/mainapp.cpp +index c9da030..03c406a 100644 +--- a/mainapp.cpp ++++ b/mainapp.cpp +@@ -14,18 +14,105 @@ + * limitations under the License. + */ + #include <string> ++#include <iostream> ++#include <getopt.h> + #include "user_mgr.hpp" ++#include "user_service.hpp" + #include "config.h" + + // D-Bus root for user manager + constexpr auto USER_MANAGER_ROOT = "/xyz/openbmc_project/user"; + ++void printUsage() ++{ ++ std::string usage = ++ R"(Usage: ++ phosphor-user-manager [OPTIONS] ++ ++Backend DBUS service for OpenBMC User Management. ++If no OPTIONS are specified, shadow file will be used. ++ ++Options: ++ -s, --service={shadow|sssd} ++ Specify the authentication service to use: ++ 'shadow' will use the /etc/shadow file. ++ 'sssd' will use the sssd service domains. ++ -h, --help Displays this help message. ++)"; ++ std::cerr << usage; ++} ++ ++void parseArgs(int argc, char** argv, ++ phosphor::user::UserService::ServiceType& srvc) ++{ ++ const std::string shortOpts{"s:h"}; ++ const struct option longOpts[] = {{"service", 1, nullptr, 's'}, ++ {"help", 0, nullptr, 'h'}, ++ {nullptr, 0, nullptr, 0}}; ++ ++ while (true) ++ { ++ const auto opt = ++ getopt_long(argc, argv, shortOpts.c_str(), longOpts, nullptr); ++ ++ if (opt == -1) ++ { ++ if (srvc == phosphor::user::UserService::ServiceType::none) ++ { ++ srvc = phosphor::user::UserService::ServiceType::shadow; ++ } ++ break; ++ } ++ ++ switch (opt) ++ { ++ case 's': ++ { ++ std::string srvcStr{optarg}; ++ if (!srvcStr.compare("shadow")) ++ { ++ srvc = phosphor::user::UserService::ServiceType::shadow; ++ } ++ else if (!srvcStr.compare("sssd")) ++ { ++ srvc = phosphor::user::UserService::ServiceType::sssd; ++ } ++ else ++ { ++ std::cerr << "Error. '" << srvcStr << "' is not a valid" ++ << " authentication service." << std::endl; ++ printUsage(); ++ exit(1); ++ } ++ } ++ break; ++ ++ case 'h': ++ { ++ printUsage(); ++ exit(0); ++ } ++ ++ default: ++ { ++ printUsage(); ++ exit(1); ++ } ++ } ++ } ++} ++ + int main(int argc, char** argv) + { ++ // Check command line options. Exit if error. ++ phosphor::user::UserService::ServiceType srvc = ++ phosphor::user::UserService::ServiceType::none; ++ parseArgs(argc, argv, srvc); ++ + auto bus = sdbusplus::bus::new_default(); + sdbusplus::server::manager::manager objManager(bus, USER_MANAGER_ROOT); + +- phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT); ++ phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT, srvc); + + // Claim the bus now + bus.request_name(USER_MANAGER_BUSNAME); +diff --git a/user_mgr.cpp b/user_mgr.cpp +index 2f22323..db6e7d5 100644 +--- a/user_mgr.cpp ++++ b/user_mgr.cpp +@@ -14,26 +14,20 @@ + // limitations under the License. + */ + +-#include <shadow.h> +-#include <unistd.h> +-#include <sys/types.h> +-#include <sys/wait.h> ++#include <cstdio> ++ + #include <fstream> + #include <grp.h> + #include <pwd.h> + #include <regex> +-#include <algorithm> +-#include <numeric> +-#include <boost/process/child.hpp> +-#include <boost/process/io.hpp> + #include <boost/algorithm/string/split.hpp> + #include <xyz/openbmc_project/Common/error.hpp> + #include <xyz/openbmc_project/User/Common/error.hpp> + #include <phosphor-logging/log.hpp> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/elog-errors.hpp> ++#include <stdexcept> + #include "shadowlock.hpp" +-#include "file.hpp" + #include "user_mgr.hpp" + #include "users.hpp" + #include "config.h" +@@ -43,12 +37,10 @@ namespace phosphor + namespace user + { + +-static constexpr const char *passwdFileName = "/etc/passwd"; + static constexpr size_t ipmiMaxUsers = 15; + static constexpr size_t ipmiMaxUserNameLen = 16; + static constexpr size_t systemMaxUserNameLen = 30; + static constexpr size_t maxSystemUsers = 30; +-static constexpr const char *grpSsh = "ssh"; + static constexpr uint8_t minPasswdLength = 8; + static constexpr int success = 0; + static constexpr int failure = -1; +@@ -94,79 +86,6 @@ using NoResource = + + using Argument = xyz::openbmc_project::Common::InvalidArgument; + +-template <typename... ArgTypes> +-static std::vector<std::string> executeCmd(const char *path, +- ArgTypes &&... tArgs) +-{ +- std::vector<std::string> stdOutput; +- boost::process::ipstream stdOutStream; +- boost::process::child execProg(path, const_cast<char *>(tArgs)..., +- boost::process::std_out > stdOutStream); +- std::string stdOutLine; +- +- while (stdOutStream && std::getline(stdOutStream, stdOutLine) && +- !stdOutLine.empty()) +- { +- stdOutput.emplace_back(stdOutLine); +- } +- +- execProg.wait(); +- +- int retCode = execProg.exit_code(); +- if (retCode) +- { +- log<level::ERR>("Command execution failed", entry("PATH=%d", path), +- entry("RETURN_CODE:%d", retCode)); +- elog<InternalFailure>(); +- } +- +- return stdOutput; +-} +- +-static std::string getCSVFromVector(std::vector<std::string> vec) +-{ +- switch (vec.size()) +- { +- case 0: +- { +- return ""; +- } +- break; +- +- case 1: +- { +- return std::string{vec[0]}; +- } +- break; +- +- default: +- { +- return std::accumulate( +- std::next(vec.begin()), vec.end(), vec[0], +- [](std::string a, std::string b) { return a + ',' + b; }); +- } +- } +-} +- +-static bool removeStringFromCSV(std::string &csvStr, const std::string &delStr) +-{ +- std::string::size_type delStrPos = csvStr.find(delStr); +- if (delStrPos != std::string::npos) +- { +- // need to also delete the comma char +- if (delStrPos == 0) +- { +- csvStr.erase(delStrPos, delStr.size() + 1); +- } +- else +- { +- csvStr.erase(delStrPos - 1, delStr.size() + 1); +- } +- return true; +- } +- return false; +-} +- + bool UserMgr::isUserExist(const std::string &userName) + { + if (userName.empty()) +@@ -293,39 +212,14 @@ void UserMgr::createUser(std::string userName, + { + throwForInvalidPrivilege(priv); + throwForInvalidGroups(groupNames); +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserExists(userName); + throwForUserNameConstraints(userName, groupNames); + throwForMaxGrpUserCount(groupNames); + +- std::string groups = getCSVFromVector(groupNames); +- bool sshRequested = removeStringFromCSV(groups, grpSsh); +- +- // treat privilege as a group - This is to avoid using different file to +- // store the same. +- if (!priv.empty()) +- { +- if (groups.size() != 0) +- { +- groups += ","; +- } +- groups += priv; +- } +- try +- { +- executeCmd("/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), +- "-m", "-N", "-s", +- (sshRequested ? "/bin/sh" : "/bin/nologin"), "-e", +- (enabled ? "" : "1970-01-02")); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("Unable to create new user"); +- elog<InternalFailure>(); +- } ++ // Tell the User Service to create a new user with the info provided. ++ userSrvc->createUser(userName, groupNames, priv, enabled); + +- // Add the users object before sending out the signal ++ // Add the users to the local list before sending out the signal + std::string userObj = std::string(usersObjPath) + "/" + userName; + std::sort(groupNames.begin(), groupNames.end()); + usersList.emplace( +@@ -339,19 +233,11 @@ void UserMgr::createUser(std::string userName, + + void UserMgr::deleteUser(std::string userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); +- try +- { +- executeCmd("/usr/sbin/userdel", userName.c_str(), "-r"); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("User delete failed", +- entry("USER_NAME=%s", userName.c_str())); +- elog<InternalFailure>(); +- } ++ ++ // Tell the User Service to delete user ++ userSrvc->deleteUser(userName); ++ // Then delete user from local list + + usersList.erase(userName); + +@@ -362,24 +248,13 @@ void UserMgr::deleteUser(std::string userName) + + void UserMgr::renameUser(std::string userName, std::string newUserName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); + throwForUserExists(newUserName); + throwForUserNameConstraints(newUserName, + usersList[userName].get()->userGroups()); +- try +- { +- std::string newHomeDir = "/home/" + newUserName; +- executeCmd("/usr/sbin/usermod", "-l", newUserName.c_str(), +- userName.c_str(), "-d", newHomeDir.c_str(), "-m"); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("User rename failed", +- entry("USER_NAME=%s", userName.c_str())); +- elog<InternalFailure>(); +- } ++ // Call The User Service to rename user on the system ++ userSrvc->renameUser(userName, newUserName); ++ // Update local list to reflect the name change + const auto &user = usersList[userName]; + std::string priv = user.get()->userPrivilege(); + std::vector<std::string> groupNames = user.get()->userGroups(); +@@ -403,8 +278,6 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName, + { + throwForInvalidPrivilege(priv); + throwForInvalidGroups(groupNames); +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); + const std::vector<std::string> &oldGroupNames = + usersList[userName].get()->userGroups(); +@@ -420,29 +293,8 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName, + throwForMaxGrpUserCount(groupNames); + } + +- std::string groups = getCSVFromVector(groupNames); +- bool sshRequested = removeStringFromCSV(groups, grpSsh); +- +- // treat privilege as a group - This is to avoid using different file to +- // store the same. +- if (!priv.empty()) +- { +- if (groups.size() != 0) +- { +- groups += ","; +- } +- groups += priv; +- } +- try +- { +- executeCmd("/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), +- "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("Unable to modify user privilege / groups"); +- elog<InternalFailure>(); +- } ++ // Call The User Service to update user groups and priv on the system ++ userSrvc->updateGroupsAndPriv(userName, groupNames, priv); + + log<level::INFO>("User groups / privilege updated successfully", + entry("USER_NAME=%s", userName.c_str())); +@@ -638,19 +490,9 @@ int UserMgr::setPamModuleArgValue(const std::string &moduleName, + + void UserMgr::userEnable(const std::string &userName, bool enabled) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); + throwForUserDoesNotExist(userName); +- try +- { +- executeCmd("/usr/sbin/usermod", userName.c_str(), "-e", +- (enabled ? "" : "1970-01-02")); +- } +- catch (const InternalFailure &e) +- { +- log<level::ERR>("Unable to modify user enabled state"); +- elog<InternalFailure>(); +- } ++ // Call The User Service to update user groups and priv on the system ++ userSrvc->updateUserStatus(userName, enabled); + + log<level::INFO>("User enabled/disabled state updated successfully", + entry("USER_NAME=%s", userName.c_str()), +@@ -728,54 +570,8 @@ bool UserMgr::userLockedForFailedAttempt(const std::string &userName, + + UserSSHLists UserMgr::getUserAndSshGrpList() + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- +- std::vector<std::string> userList; +- std::vector<std::string> sshUsersList; +- struct passwd pw, *pwp = nullptr; +- std::array<char, 1024> buffer{}; +- +- phosphor::user::File passwd(passwdFileName, "r"); +- if ((passwd)() == NULL) +- { +- log<level::ERR>("Error opening the passwd file"); +- elog<InternalFailure>(); +- } +- +- while (true) +- { +- auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(), +- &pwp); +- if ((r != 0) || (pwp == NULL)) +- { +- // Any error, break the loop. +- break; +- } +-#ifdef ENABLE_ROOT_USER_MGMT +- // Add all users whose UID >= 1000 and < 65534 +- // and special UID 0. +- if ((pwp->pw_uid == 0) || +- ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) +-#else +- // Add all users whose UID >=1000 and < 65534 +- if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)) +-#endif +- { +- std::string userName(pwp->pw_name); +- userList.emplace_back(userName); +- +- // ssh doesn't have separate group. Check login shell entry to +- // get all users list which are member of ssh group. +- std::string loginShell(pwp->pw_shell); +- if (loginShell == "/bin/sh") +- { +- sshUsersList.emplace_back(userName); +- } +- } +- } +- endpwent(); +- return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ // Call The User Service to get the User and SSUsers lists ++ return std::move(userSrvc->getUserAndSshGrpList()); + } + + size_t UserMgr::getIpmiUsersCount() +@@ -786,49 +582,14 @@ size_t UserMgr::getIpmiUsersCount() + + bool UserMgr::isUserEnabled(const std::string &userName) + { +- // All user management lock has to be based on /etc/shadow +- phosphor::user::shadow::Lock lock(); +- std::array<char, 4096> buffer{}; +- struct spwd spwd; +- struct spwd *resultPtr = nullptr; +- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), +- buffer.max_size(), &resultPtr); +- if (!status && (&spwd == resultPtr)) +- { +- if (resultPtr->sp_expire >= 0) +- { +- return false; // user locked out +- } +- return true; +- } +- return false; // assume user is disabled for any error. ++ // Call The User Service to verify if user is enabled ++ return userSrvc->isUserEnabled(userName); + } + + std::vector<std::string> UserMgr::getUsersInGroup(const std::string &groupName) + { +- std::vector<std::string> usersInGroup; +- // Should be more than enough to get the pwd structure. +- std::array<char, 4096> buffer{}; +- struct group grp; +- struct group *resultPtr = nullptr; +- +- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(), +- buffer.max_size(), &resultPtr); +- +- if (!status && (&grp == resultPtr)) +- { +- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) +- { +- usersInGroup.emplace_back(*(grp.gr_mem)); +- } +- } +- else +- { +- log<level::ERR>("Group not found", +- entry("GROUP=%s", groupName.c_str())); +- // Don't throw error, just return empty userList - fallback +- } +- return usersInGroup; ++ // Call The User Service to get the users that belong to a group ++ return std::move(userSrvc->getUsersInGroup(groupName)); + } + + DbusUserObj UserMgr::getPrivilegeMapperObject(void) +@@ -1057,11 +818,9 @@ void UserMgr::initUserObjects(void) + { + // All user management lock has to be based on /etc/shadow + phosphor::user::shadow::Lock lock(); +- std::vector<std::string> userNameList; +- std::vector<std::string> sshGrpUsersList; + UserSSHLists userSSHLists = getUserAndSshGrpList(); +- userNameList = std::move(userSSHLists.first); +- sshGrpUsersList = std::move(userSSHLists.second); ++ std::vector<std::string> userNameList = std::move(userSSHLists.first); ++ std::vector<std::string> sshGrpUsersList = std::move(userSSHLists.second); + + if (!userNameList.empty()) + { +@@ -1116,7 +875,8 @@ void UserMgr::initUserObjects(void) + } + } + +-UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) : ++UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path, ++ UserService::ServiceType srvc) : + Ifaces(bus, path, true), bus(bus), path(path) + { + UserMgrIface::allPrivileges(privMgr); +@@ -1225,6 +985,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) : + } + AccountPolicyIface::accountUnlockTimeout(value32); + } ++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr); + initUserObjects(); + + // emit the signal +diff --git a/user_mgr.hpp b/user_mgr.hpp +index b25e9f2..c24733b 100644 +--- a/user_mgr.hpp ++++ b/user_mgr.hpp +@@ -21,6 +21,7 @@ + #include <unordered_map> + #include <variant> + #include "users.hpp" ++#include "user_service.hpp" + + namespace phosphor + { +@@ -28,8 +29,6 @@ namespace user + { + + using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager; +-using UserSSHLists = +- std::pair<std::vector<std::string>, std::vector<std::string>>; + using AccountPolicyIface = + sdbusplus::xyz::openbmc_project::User::server::AccountPolicy; + +@@ -76,8 +75,10 @@ class UserMgr : public Ifaces + * + * @param[in] bus - sdbusplus handler + * @param[in] path - D-Bus path ++ * @param[in] srvc - User service to be used + */ +- UserMgr(sdbusplus::bus::bus &bus, const char *path); ++ UserMgr(sdbusplus::bus::bus &bus, const char *path, ++ UserService::ServiceType srvc); + + /** @brief create user method. + * This method creates a new user as requested +@@ -186,6 +187,8 @@ class UserMgr : public Ifaces + /** @brief object path */ + const std::string path; + ++ /** @brief user service to be used */ ++ std::unique_ptr<UserService> userSrvc; + /** @brief privilege manager container */ + std::vector<std::string> privMgr = {"priv-admin", "priv-operator", + "priv-user", "priv-callback"}; +diff --git a/user_service.cpp b/user_service.cpp +new file mode 100644 +index 0000000..c3c45bd +--- /dev/null ++++ b/user_service.cpp +@@ -0,0 +1,786 @@ ++/* ++// Copyright (c) 2018 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#include <grp.h> ++#include <pwd.h> ++#include <numeric> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++#include <boost/algorithm/string/split.hpp> ++#include "shadowlock.hpp" ++#include "file.hpp" ++#include "user_service.hpp" ++ ++/* anonymous namespace for User Service interface implementations. ++// Each class inside this namespace implements a special service ++// to be used for the User Manager class. This can be extended to use ++// other user management services and it should be as simple as ++// adding a new class which inherits from phosphor::user::UserServiceInterface ++*/ ++ ++namespace ++{ ++ ++std::string getCSVFromVector(std::vector<std::string> vec) ++{ ++ switch (vec.size()) ++ { ++ case 0: ++ { ++ return ""; ++ } ++ break; ++ ++ case 1: ++ { ++ return std::string{vec[0]}; ++ } ++ break; ++ ++ default: ++ { ++ return std::accumulate( ++ std::next(vec.begin()), vec.end(), vec[0], ++ [](std::string a, std::string b) { return a + ',' + b; }); ++ } ++ } ++} ++ ++bool removeStringFromCSV(std::string &csvStr, const std::string &delStr) ++{ ++ std::string::size_type delStrPos = csvStr.find(delStr); ++ if (delStrPos != std::string::npos) ++ { ++ // need to also delete the comma char ++ if (delStrPos == 0) ++ { ++ csvStr.erase(delStrPos, delStr.size() + 1); ++ } ++ else ++ { ++ csvStr.erase(delStrPos - 1, delStr.size() + 1); ++ } ++ return true; ++ } ++ return false; ++} ++ ++class ShadowService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ ShadowService() = default; ++ ++ ~ShadowService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::vector<std::string> userList; ++ std::vector<std::string> sshUsersList; ++ ++ struct passwd pw, *pwp = nullptr; ++ std::array<char, 1024> buffer{}; ++ ++ phosphor::user::File passwd(passwdFileName, "r"); ++ if ((passwd)() == NULL) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Error opening the passwd file"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ while (true) ++ { ++ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), ++ buffer.max_size(), &pwp); ++ if ((r != 0) || (pwp == NULL)) ++ { ++ // Any error, break the loop. ++ break; ++ } ++#ifdef ENABLE_ROOT_USER_MGMT ++ // Add all users whose UID >= 1000 and < 65534 ++ // and special UID 0. ++ if ((pwp->pw_uid == 0) || ++ ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))) ++#else ++ // Add all users whose UID >=1000 and < 65534 ++ if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)) ++#endif ++ { ++ std::string userName(pwp->pw_name); ++ userList.emplace_back(userName); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ std::string loginShell(pwp->pw_shell); ++ if (loginShell == "/bin/sh") ++ { ++ sshUsersList.emplace_back(userName); ++ } ++ } ++ } ++ endpwent(); ++ return std::make_pair(std::move(userList), std::move(sshUsersList)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const override ++ { ++ std::vector<std::string> usersInGroup; ++ // Should be more than enough to get the pwd structure. ++ std::array<char, 4096> buffer{}; ++ struct group grp; ++ struct group *grpPtr = &grp; ++ struct group *resultPtr; ++ ++ int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ ++ if (!status && (grpPtr == resultPtr)) ++ { ++ for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) ++ { ++ usersInGroup.emplace_back(*(grp.gr_mem)); ++ } ++ } ++ else ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Group not found", ++ phosphor::logging::entry("GROUP=%s", groupName.c_str())); ++ // Don't throw error, just return empty usersInGroup - fallback ++ } ++ return usersInGroup; ++ } ++ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups.append(","); ++ } ++ groups.append(priv); ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(), ++ "-m", "-N", "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ std::string newHomeDir = "/home/" + newUserName; ++ phosphor::user::executeCmd("/usr/sbin/usermod", "-l", ++ newUserName.c_str(), userName.c_str(), ++ "-d", newHomeDir.c_str(), "-m"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User rename failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void deleteUser(const std::string &userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/userdel", userName.c_str(), ++ "-r"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::INFO>( ++ "User delete failed", ++ phosphor::logging::entry("USER_NAME=%s", userName.c_str())); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same. ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(), ++ "-s", (sshRequested ? "/bin/sh" : "/bin/nologin")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user privilege / groups"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/usermod", userName.c_str(), ++ "-e", (enabled ? "" : "1970-01-02")); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to modify user enabled state"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string &userName) const override ++ { ++ // All user management lock has to be based on /etc/shadow ++ phosphor::user::shadow::Lock lock(); ++ std::array<char, 4096> buffer{}; ++ struct spwd spwd; ++ struct spwd *resultPtr = nullptr; ++ int status = getspnam_r(userName.c_str(), &spwd, buffer.data(), ++ buffer.max_size(), &resultPtr); ++ if (!status && (&spwd == resultPtr)) ++ { ++ if (resultPtr->sp_expire >= 0) ++ { ++ return false; // user locked out ++ } ++ return true; ++ } ++ return false; // assume user is disabled for any error. ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string &userName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::getUserGroups not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ return std::vector<std::string>(); ++ } ++ ++ void createGroup(const std::string &groupName) const override ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "ShadowService::createGroup not implemented!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ private: ++ static constexpr const char *passwdFileName = "/etc/passwd"; ++}; ++ ++class SSSDService : public phosphor::user::UserServiceInterface ++{ ++ public: ++ SSSDService(const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++ { ++ ++ createGroup(lockedGrp); ++ for (const auto &g : groups) ++ { ++ createGroup(g); ++ } ++ for (const auto &p : privs) ++ { ++ createGroup(p); ++ } ++ } ++ ++ ~SSSDService() = default; ++ ++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override ++ { ++ std::vector<std::string> users; ++ std::vector<std::string> sshGroup; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/bin/getent", "-s", ++ "sss", "passwd"); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get users information " ++ "from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ for (const auto &userLine : exeOutput) ++ { ++ std::vector<std::string> userInfo; ++ boost::algorithm::split(userInfo, userLine, ++ boost::algorithm::is_any_of(":")); ++ // At this point userInfo is a vector containing the passwd ++ // info for the user, so we know the correct positions: ++ // 0: User name. ++ // 1: Encrypted password. ++ // 2: User ID number (UID) ++ // 3: User's group ID number (GID) ++ // 4: Full name of the user (GECOS) ++ // 5: User home directory. ++ // 6: Login shell. ++ users.emplace_back(userInfo[0]); ++ ++ // ssh doesn't have separate group. Check login shell entry to ++ // get all users list which are member of ssh group. ++ if (userInfo[6] == "/bin/sh") ++ { ++ sshGroup.emplace_back(userInfo[0]); ++ } ++ } ++ ++ return std::make_pair(std::move(users), std::move(sshGroup)); ++ } ++ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const override ++ { ++ std::vector<std::string> userList; ++ std::vector<std::string> exeOutput; ++ ++ try ++ { ++ exeOutput = phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get group users from sssd service"); ++ // Don't throw error, just return empty usersInGroup - return ++ return userList; ++ } ++ // exeOutput should have 5 entries ++ // 0: Group ++ // 1: GID number ++ // 2: Member users ++ // 3: Is a member of ++ // 4: Member groups ++ exeOutput[2].erase( ++ exeOutput[2].begin(), ++ std::find(exeOutput[2].begin(), exeOutput[2].end(), ':')); ++ boost::algorithm::trim_left(exeOutput[2]); ++ boost::algorithm::split(userList, exeOutput[2], ++ boost::algorithm::is_any_of(",")); ++ return userList; ++ } ++ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const override ++ { ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_useradd", "-m", "-G", groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create new user in sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ // Sometimes the SSSD service needs some time to actually ++ // reflect the changes to the local DB to the NSS service, ++ // that is why we have this sleep here ... ++ std::this_thread::sleep_for(std::chrono::seconds(1)); ++ // update user status (locked/unlocked) ++ updateUserStatus(userName, enabled); ++ } ++ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const override ++ { ++ std::vector<std::string> exeOutput; ++ // Local Domain for sssd doesn't have a rename feature ++ // so we need to first create a new user and then delete ++ // the old one. ++ // The only issue with this is that the password for the ++ // user will have to be reseted since it is a new user being created. ++ ++ // Get original user groups ++ std::vector<std::string> groups = getUserGroups(userName); ++ // Check if it has a "ssh" group by looking for the shell login ++ try ++ { ++ exeOutput = phosphor::user::executeCmd( ++ "/usr/bin/getent", "-s", "sss", "passwd", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get information for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ if (exeOutput[0].find("/bin/sh")) ++ { ++ groups.emplace_back(phosphor::user::grpSsh); ++ } ++ // Call create user with the new user names and previous groups ++ // Priv is already part of the groups so that can be empty. ++ createUser(newUserName, groups, "", isUserEnabled(userName)); ++ ++ // Now delete original user ++ deleteUser(userName); ++ } ++ ++ void deleteUser(const std::string &userName) const override ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_userdel", "-r", ++ userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to delete user from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const override ++ { ++ // local domain sssd do not allow to update all list of groups, ++ // so we will remove all groups first (except for the user one) ++ // and then all all the ones that were passed ++ std::string oldGroups = getCSVFromVector(getUserGroups(userName)); ++ std::string groups = getCSVFromVector(groupNames); ++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh); ++ // treat privilege as a group - This is to avoid using different file to ++ // store the same ++ if (!priv.empty()) ++ { ++ if (groups.size() != 0) ++ { ++ groups += ","; ++ } ++ groups += priv; ++ } ++ try ++ { ++ phosphor::user::executeCmd( ++ "/usr/sbin/sss_usermod", "-r", oldGroups.c_str(), "-a", ++ groups.c_str(), "-s", ++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user groups and " ++ "priv from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const override ++ { ++ std::string enabledStr; ++ std::string lockedStr; ++ if (isUserEnabled(userName) == enabled) ++ { ++ return; ++ } ++ if (enabled) ++ { ++ enabledStr = "-r"; ++ lockedStr = "-U"; ++ } ++ else ++ { ++ enabledStr = "-a"; ++ lockedStr = "-L"; ++ } ++ try ++ { ++ // We will add a special locked group to identify the users ++ // that have been locked out of the system. ++ // TODO: sss_usermod is not locking user accounts for the ++ // LOCAL domain, need to find the correct PAM configuration ++ // to actually lockout users for SSSD. ++ // As a workaround we are using the pam module pam_listfile.so ++ // to lockout all users that belong to the locked group. ++ phosphor::user::executeCmd("/usr/sbin/sss_usermod", ++ enabledStr.c_str(), lockedGrp.c_str(), ++ lockedStr.c_str(), userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to update user status from sssd service"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ bool isUserEnabled(const std::string &userName) const override ++ { ++ std::vector<std::string> userGrps = getUserGroups(userName); ++ return std::find(userGrps.begin(), userGrps.end(), lockedGrp) == ++ userGrps.end(); ++ } ++ ++ std::vector<std::string> ++ getUserGroups(const std::string &userName) const override ++ { ++ std::vector<std::string> exeOutput; ++ try ++ { ++ exeOutput = ++ phosphor::user::executeCmd("/usr/bin/groups", userName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to get groups for user"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ std::vector<std::string> groups; ++ boost::algorithm::split(groups, exeOutput[0], ++ boost::algorithm::is_any_of(" ")); ++ // Delete group that equals user name if it exists ++ auto userNameGroup = std::find(groups.begin(), groups.end(), userName); ++ if (userNameGroup != groups.end()) ++ { ++ groups.erase(userNameGroup); ++ } ++ return groups; ++ } ++ ++ void createGroup(const std::string &groupName) const override ++ { ++ try ++ { ++ if (!groupExists(groupName)) ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupadd", ++ groupName.c_str()); ++ } ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Unable to create group"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ } ++ ++ private: ++ static const std::string lockedGrp; ++ ++ bool groupExists(const std::string &groupName) const ++ { ++ try ++ { ++ phosphor::user::executeCmd("/usr/sbin/sss_groupshow", ++ groupName.c_str()); ++ } ++ catch (const phosphor::user::InternalFailure &e) ++ { ++ return false; ++ } ++ return true; ++ } ++}; ++ ++const std::string SSSDService::lockedGrp = "sssd_locked"; ++} // anonymous namespace ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++UserService::UserService(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::updateServiceType(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ usrSrvcImpl.reset(); ++ setServiceImpl(srvcType, groups, privs); ++} ++ ++void UserService::setServiceImpl(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs) ++{ ++ switch (srvcType) ++ { ++ case ServiceType::shadow: ++ { ++ usrSrvcImpl = std::make_unique<ShadowService>(); ++ } ++ break; ++ ++ case ServiceType::sssd: ++ { ++ usrSrvcImpl = std::make_unique<SSSDService>(groups, privs); ++ } ++ break; ++ ++ case ServiceType::none: ++ default: ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Invalid service type initialization!"); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ break; ++ } ++} ++ ++UserService::~UserService() ++{ ++} ++ ++phosphor::user::UserSSHLists UserService::getUserAndSshGrpList() const ++{ ++ return usrSrvcImpl->getUserAndSshGrpList(); ++} ++ ++std::vector<std::string> ++ UserService::getUsersInGroup(const std::string &groupName) const ++{ ++ return usrSrvcImpl->getUsersInGroup(groupName); ++} ++ ++void UserService::createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const ++{ ++ usrSrvcImpl->createUser(userName, groupNames, priv, enabled); ++} ++ ++void UserService::renameUser(const std::string &userName, ++ const std::string &newUserName) const ++{ ++ usrSrvcImpl->renameUser(userName, newUserName); ++} ++ ++void UserService::deleteUser(const std::string &userName) const ++{ ++ usrSrvcImpl->deleteUser(userName); ++} ++ ++void UserService::updateGroupsAndPriv( ++ const std::string &userName, const std::vector<std::string> &groupNames, ++ const std::string &priv) const ++{ ++ usrSrvcImpl->updateGroupsAndPriv(userName, groupNames, priv); ++} ++ ++void UserService::updateUserStatus(const std::string &userName, ++ const bool &enabled) const ++{ ++ usrSrvcImpl->updateUserStatus(userName, enabled); ++} ++ ++bool UserService::isUserEnabled(const std::string &userName) const ++{ ++ return usrSrvcImpl->isUserEnabled(userName); ++} ++ ++std::vector<std::string> ++ UserService::getUserGroups(const std::string &userName) const ++{ ++ return usrSrvcImpl->getUserGroups(userName); ++} ++ ++} // namespace user ++} // namespace phosphor +diff --git a/user_service.hpp b/user_service.hpp +new file mode 100644 +index 0000000..97a049b +--- /dev/null ++++ b/user_service.hpp +@@ -0,0 +1,233 @@ ++/* ++// Copyright (c) 2018 Intel Corporation ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++*/ ++ ++#pragma once ++#include <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/User/Common/error.hpp> ++#include <phosphor-logging/log.hpp> ++#include <phosphor-logging/elog.hpp> ++#include <boost/process/child.hpp> ++#include <boost/process/io.hpp> ++ ++namespace phosphor ++{ ++namespace user ++{ ++ ++using UserSSHLists = ++ std::pair<std::vector<std::string>, std::vector<std::string>>; ++using InternalFailure = ++ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; ++using InsufficientPermission = ++ sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission; ++ ++const std::string grpSsh = "ssh"; ++ ++template <typename... ArgTypes> ++std::vector<std::string> executeCmd(const char *path, ArgTypes &&... tArgs) ++{ ++ std::vector<std::string> stdOutput; ++ boost::process::ipstream stdOutStream; ++ boost::process::child execProg(path, const_cast<char *>(tArgs)..., ++ boost::process::std_out > stdOutStream); ++ std::string stdOutLine; ++ ++ while (stdOutStream && std::getline(stdOutStream, stdOutLine) && ++ !stdOutLine.empty()) ++ { ++ stdOutput.emplace_back(stdOutLine); ++ } ++ ++ execProg.wait(); ++ ++ int retCode = execProg.exit_code(); ++ if (retCode) ++ { ++ phosphor::logging::log<phosphor::logging::level::ERR>( ++ "Command execution failed", ++ phosphor::logging::entry("PATH=%d", path), ++ phosphor::logging::entry("RETURN_CODE:%d", retCode)); ++ phosphor::logging::elog<phosphor::user::InternalFailure>(); ++ } ++ ++ return stdOutput; ++} ++ ++/** @class UserServiceInterface ++ * @brief Interface class for methods provided by the implemmentations ++ * of the user service. Provides the same methods as the UserService ++ * class. ++ */ ++class UserServiceInterface ++{ ++ public: ++ UserServiceInterface() = default; ++ virtual ~UserServiceInterface() = default; ++ virtual UserSSHLists getUserAndSshGrpList() const = 0; ++ virtual std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const = 0; ++ virtual void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, ++ const bool &enabled) const = 0; ++ virtual void renameUser(const std::string &userName, ++ const std::string &newUserName) const = 0; ++ virtual void deleteUser(const std::string &userName) const = 0; ++ virtual void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const = 0; ++ virtual void updateUserStatus(const std::string &userName, ++ const bool &enabled) const = 0; ++ virtual bool isUserEnabled(const std::string &userName) const = 0; ++ virtual std::vector<std::string> ++ getUserGroups(const std::string &userName) const = 0; ++ virtual void createGroup(const std::string &groupName) const = 0; ++}; ++ ++/** @class UserService ++ * @brief Responsible for managing the user service for the user manager. ++ * This service is the one responsible to actually change the user information ++ * of the application. It can support sevaral services, currently the ones ++ * supported are: ++ * ++ * 1) Shadow: Which uses the /etc/shadow file for updating the users ++ * 2) SSSD: Which uses the sssd service for a LOCAL domain only right now. ++ */ ++class UserService ++{ ++ public: ++ UserService() = delete; ++ UserService(const UserService &) = delete; ++ UserService &operator=(const UserService &) = delete; ++ UserService(UserService &&) = delete; ++ UserService &operator=(UserService &&) = delete; ++ ++ // Service Types implemented. None is used to validate. ++ enum class ServiceType ++ { ++ none, ++ shadow, ++ sssd ++ }; ++ ++ UserService(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ ~UserService(); ++ ++ /** @brief update the current Service type of the instance. ++ * This function is used to update in real time the service ++ * being used for the user management without restarting the ++ * whole service. ++ * ++ * @param[in] srvcType ++ * @param[in] groups ++ * @param[in] privs ++ */ ++ void updateServiceType(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ ++ /** @brief get user list and SSH group members list ++ * This method gets the list of users from the service. ++ * If the userlist reference is empty, all the users will be added ++ * and DBus notified about them. If the list is not empty, the function ++ * will only update list adding the missing ones to it. It will not remove ++ * any extra users on the list that are not part of the service! ++ * ++ */ ++ UserSSHLists getUserAndSshGrpList() const; ++ ++ /** @brief Get users in group. ++ * This method creates a new user as requested ++ * ++ * @param[in] groupName - Name of the group which has to be queried ++ */ ++ std::vector<std::string> ++ getUsersInGroup(const std::string &groupName) const; ++ ++ /** @brief create user method. ++ * This method creates a new user as requested ++ * ++ * @param[in] userName - Name of the user which has to be created ++ * @param[in] groupNames - Group names list, to which user has to be added. ++ * @param[in] priv - Privilege of the user. ++ * @param[in] enabled - State of the user enabled / disabled. ++ */ ++ void createUser(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv, const bool &enabled) const; ++ ++ /** @brief rename user method. ++ * This method renames the user as requested ++ * ++ * @param[in] userName - current name of the user ++ * @param[in] userName - user name to which it has to be renamed. ++ */ ++ void renameUser(const std::string &userName, ++ const std::string &newUserName) const; ++ ++ /** @brief delete user method. ++ * This method deletes the user as requested ++ * ++ * @param[in] userName - Name of the user which has to be deleted ++ */ ++ void deleteUser(const std::string &userName) const; ++ ++ /** @brief Updates user Groups and Privilege. ++ * ++ * @param[in] userName - Name of the user which has to be modified ++ * @param[in] groupNames - Group names list for user. ++ * @param[in] priv - Privilege of the user. ++ */ ++ void updateGroupsAndPriv(const std::string &userName, ++ const std::vector<std::string> &groupNames, ++ const std::string &priv) const; ++ ++ /** @brief Updates user status ++ * If enabled = false: User will be disabled ++ * If enabled = true : User will be enabled ++ * ++ * @param[in] userName - Name of the user ++ * @param[in] enabled - Status of the user: enabled / disabled? ++ */ ++ void updateUserStatus(const std::string &userName, ++ const bool &enabled) const; ++ ++ /** @brief Verify if user is enabled or not ++ * If enabled returns true ++ * If not enabled returns false ++ * ++ * @param[in] userName - Name of the user ++ */ ++ bool isUserEnabled(const std::string &userName) const; ++ ++ /** @brief Get the list of groups a user belongs to ++ * ++ * @param[in] userName - Name of the user ++ */ ++ std::vector<std::string> getUserGroups(const std::string &userName) const; ++ ++ private: ++ // User service implementation. ++ void setServiceImpl(const ServiceType &srvcType, ++ const std::vector<std::string> &groups, ++ const std::vector<std::string> &privs); ++ std::unique_ptr<UserServiceInterface> usrSrvcImpl; ++}; ++ ++} // namespace user ++} // namespace phosphor +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch new file mode 100644 index 000000000..12a2bda3e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch @@ -0,0 +1,73 @@ +From c0bf911cbc33659adddebde767029ffc23251c61 Mon Sep 17 00:00:00 2001 +From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +Date: Mon, 24 Feb 2020 13:37:12 +0530 +Subject: [PATCH] Use groupmems instead of getgrnam_r due to overlay + +With JFFS2 overlay, getgrnam_r during initial time returns the +old group details as per the lower dir, instead of the overlay one +but at the same time groupmems where returning proper values, which +reads the file everytime. Hence replacing getgrnam_r with groupmems + +Tested: +1. Verified that when added multiple user and then doing +BMC reset using ipmitool raw 6 2 doesn't reproduce the issue of +user with only ssh group. (on 38 version source + this fix) +2. Updated using redfish to version 39 + this fix, and made sure +issue doesn't happen. + +Note: For testing purpose added debug statements to dump ouput of +both getgrnam_r & groupmems and able to see proper list only +in groupmems when the issue is reproduced + +Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com> +--- + user_service.cpp | 26 +++++++++++--------------- + 1 file changed, 11 insertions(+), 15 deletions(-) + +diff --git a/user_service.cpp b/user_service.cpp +index c3c45bd..4fdf7a1 100644 +--- a/user_service.cpp ++++ b/user_service.cpp +@@ -143,28 +143,24 @@ class ShadowService : public phosphor::user::UserServiceInterface + getUsersInGroup(const std::string &groupName) const override + { + std::vector<std::string> usersInGroup; +- // Should be more than enough to get the pwd structure. +- std::array<char, 4096> buffer{}; +- struct group grp; +- struct group *grpPtr = &grp; +- struct group *resultPtr; +- +- int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(), +- buffer.max_size(), &resultPtr); +- +- if (!status && (grpPtr == resultPtr)) ++ std::vector<std::string> output; ++ try + { +- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem)) +- { +- usersInGroup.emplace_back(*(grp.gr_mem)); +- } ++ output = phosphor::user::executeCmd("/usr/sbin/groupmems", "-l", ++ "-g", groupName.c_str()); + } +- else ++ catch (const phosphor::user::InternalFailure &e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Group not found", + phosphor::logging::entry("GROUP=%s", groupName.c_str())); + // Don't throw error, just return empty usersInGroup - fallback ++ return usersInGroup; ++ } ++ if (!output.empty()) ++ { ++ boost::algorithm::split(usersInGroup, output[0], ++ boost::algorithm::is_any_of(" ")); + } + return usersInGroup; + } +-- +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..238511ed5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend @@ -0,0 +1,11 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +#SRC_URI = "git://github.com/openbmc/phosphor-user-manager;nobranch=1" +SRCREV = "d4d655006c6179d47008d9b374debcedcc03a1c4" + +EXTRA_OECONF += "${@bb.utils.contains_any("IMAGE_FEATURES", [ 'debug-tweaks', 'allow-root-login' ], '', '--disable-root_user_mgmt', d)}" + +SRC_URI += " \ + file://0005-Added-suport-for-multiple-user-manager-services.patch \ + file://0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb new file mode 100644 index 000000000..da60ca67e --- /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://github.com/Intel-BMC/provingground.git;protocol=ssh" +SRCREV = "bee56d62b209088454d166d1efae4825a2b175df" + +S = "${WORKDIR}/git/virtual-media/" +PV = "1.0+git${SRCPV}" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e" + +SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.VirtualMedia.service" + +DEPENDS = "udev boost nlohmann-json systemd sdbusplus" + +inherit cmake systemd + +EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON" + +FULL_OPTIMIZATION = "-Os -pipe -flto -fno-rtti" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb new file mode 100644 index 000000000..ebd795e83 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb @@ -0,0 +1,35 @@ + +SUMMARY = "FRB2 timer service" +DESCRIPTION = "The FRB2 timer service will monitor the mailbox register 0\ +and start a watchdog for FRB2 if the data is 1(BIOS will write this value)" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://frb2-watchdog.cpp \ + " +PV = "0.1" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +S = "${WORKDIR}" + +inherit cmake +inherit pkgconfig pythonnative + +DEPENDS += " \ + systemd \ + sdbusplus \ + sdbusplus-native \ + phosphor-logging \ + phosphor-dbus-interfaces \ + phosphor-dbus-interfaces-native \ + boost \ + " + +RDEPENDS_${PN} += " \ + libsystemd \ + sdbusplus \ + phosphor-logging \ + phosphor-dbus-interfaces \ + " diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format new file mode 100644 index 000000000..dd2770837 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format @@ -0,0 +1,98 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt new file mode 100644 index 000000000..bd5567d31 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required (VERSION 3.5 FATAL_ERROR) +project (frb2-watchdog CXX) +set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti") + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +# boost support +find_package (Boost REQUIRED) +# pkg_check_modules(Boost boost REQUIRED) +include_directories (${Boost_INCLUDE_DIRS}) +add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY) +add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED) +add_definitions (-DBOOST_ALL_NO_LIB) +add_definitions (-DBOOST_NO_RTTI) +add_definitions (-DBOOST_NO_TYPEID) +add_definitions (-DBOOST_ASIO_DISABLE_THREADS) + +# import libsystemd +find_package (PkgConfig REQUIRED) +pkg_check_modules (SYSTEMD libsystemd REQUIRED) +include_directories (${SYSTEMD_INCLUDE_DIRS}) +link_directories (${SYSTEMD_LIBRARY_DIRS}) + +# import sdbusplus +find_package (PkgConfig REQUIRED) +pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED) +include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS}) +link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS}) + +# import phosphor-logging +find_package (PkgConfig REQUIRED) +pkg_check_modules (LOGGING phosphor-logging REQUIRED) +include_directories (${LOGGING_INCLUDE_DIRS}) +link_directories (${LOGGING_LIBRARY_DIRS}) + +# import phosphor-dbus-interfaces +find_package (PkgConfig REQUIRED) +pkg_check_modules (DBUSINTERFACE phosphor-dbus-interfaces REQUIRED) +include_directories (${DBUSINTERFACE_INCLUDE_DIRS}) +link_directories (${DBUSINTERFACE_LIBRARY_DIRS}) + +add_executable (frb2-watchdog frb2-watchdog.cpp) + +target_link_libraries (${PROJECT_NAME} systemd) +target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}) +target_link_libraries (${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} + phosphor_logging) +install (TARGETS frb2-watchdog DESTINATION bin) diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json new file mode 100644 index 000000000..583c255a3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json @@ -0,0 +1,12 @@ +{ + "enum_char": ".", + "line_ending": "unix", + "bullet_char": "*", + "max_subargs_per_line": 99, + "command_case": "lower", + "tab_size": 4, + "line_width": 80, + "separate_fn_name_with_space": true, + "dangle_parens": true, + "separate_ctrl_name_with_space": true +}
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp new file mode 100644 index 000000000..5356e95db --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp @@ -0,0 +1,258 @@ +/* Copyright 2018 Intel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <boost/container/flat_set.hpp> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <optional> +#include <phosphor-logging/log.hpp> +#include <sdbusplus/asio/object_server.hpp> +#include <sdbusplus/bus.hpp> +#include <sdbusplus/bus/match.hpp> +#include <sdbusplus/message.hpp> +#include <sdbusplus/timer.hpp> +#include <vector> +#include <xyz/openbmc_project/State/Watchdog/server.hpp> + +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred); + +static int mailboxDevFd = -1; + +static boost::asio::io_service io; +static auto conn = std::make_shared<sdbusplus::asio::connection>(io); +boost::asio::ip::tcp::socket mailBoxDevSocket(io); +boost::asio::deadline_timer pollTimer(io); +boost::asio::posix::stream_descriptor inputDevice(io); + +// mailbox registre data[0:0] for FRB2 enable bit +boost::asio::streambuf readBuf(1); +std::string dataRead; + +// FRB2 watchdog timeout is 6 minutes +static constexpr unsigned int frb2TimerIntervalMs = 360 * 1000; + +// mailbox device polling time interval is 2 seconds +static constexpr unsigned int pollMs = 2000; + +static constexpr unsigned int frb2Started = 1; +static constexpr unsigned int frb2Stopped = 0; + +// FRB2 status +static uint8_t frb2Status = frb2Stopped; + +static constexpr const char *mailboxDevName = "/dev/aspeed-mbox"; + +static constexpr const char frb2Bus[] = "xyz.openbmc_project.FRB2"; +static constexpr const char frb2Obj[] = "/xyz/openbmc_project/FRB2"; +static constexpr const char frb2Intf[] = "xyz.openbmc_project.FRB2"; + +static constexpr char powerBus[] = "xyz.openbmc_project.Chassis.Control.Power"; +static constexpr char powerPath[] = + "/xyz/openbmc_project/Chassis/Control/Power0"; +static constexpr char powerIntf[] = "xyz.openbmc_project.Chassis.Control.Power"; + +static constexpr char wdBus[] = "xyz.openbmc_project.Watchdog"; +static constexpr char wdPath[] = "/xyz/openbmc_project/watchdog/host0"; +static constexpr char wdIntf[] = "xyz.openbmc_project.State.Watchdog"; +static constexpr char propIntf[] = "org.freedesktop.DBus.Properties"; + +typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator; + +// check if FRB2 bit is 0x1 +std::pair<iterator, bool> matchFRB2(iterator begin, iterator end) +{ + unsigned char ch = 0; + iterator i = begin; + + while (i != end) + { + ch = static_cast<unsigned char>(*i); + if (ch & 0x1) + { + return std::make_pair(i, true); + } + i++; + } + + return std::make_pair(i, false); +} + +static void startRead() +{ + boost::asio::async_read_until(inputDevice, readBuf, matchFRB2, + [&](const boost::system::error_code &ec, + std::size_t bytes_transferred) { + handleResponse(ec, bytes_transferred); + }); +} + +template <typename T> void setProperty(const std::string &key, const T &val) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "setProperty", phosphor::logging::entry("KEY=%s", key.c_str())); + + try + { + conn->async_method_call( + [](const boost::system::error_code &err) { + if (err) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "async_method_call error!", + phosphor::logging::entry( + "ERROR=%s", + boost::system::system_error(err).what())); + } + }, + wdBus, wdPath, propIntf, "Set", wdIntf, key, + sdbusplus::message::variant_ns::variant<T>(val)); + } + catch (sdbusplus::exception::SdBusError &e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Dbus error!", phosphor::logging::entry("ERROR=%s", e.what())); + } +} +void handleResponse(const boost::system::error_code &err, + std::size_t bytes_transferred) +{ + std::istream responseStream(&readBuf); + std::string response; + int n = 0; + uint64_t interval = frb2TimerIntervalMs; + + std::getline(responseStream, response); + responseStream.clear(); + + if (err == boost::system::errc::bad_file_descriptor) + { + + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "bad file descriptor"); + return; // we're being destroyed + } + + if (!err) + { + // FRB2 is set by BIOS + if (frb2Stopped == frb2Status) + { + // start FRB2 watchdog + frb2Status = frb2Started; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 enable, start FRB2 watchdog"); + setProperty( + "ExpireAction", + std::string( + "xyz.openbmc_project.State.Watchdog.Action.HardReset")); + setProperty("Interval", interval); + setProperty("TimeRemaining", interval); + setProperty("Initialized", true); + setProperty("Enabled", true); + } + } + else if (err == boost::asio::error::misc_errors::not_found) + { + // FRB2 is clear, stop FRB2 watchdog if it is started + if (frb2Started == frb2Status) + { + frb2Status = frb2Stopped; + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "FRB2 is unset, stop FRB2 watchdog"); + setProperty("Enabled", false); + } + } + else + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "handleResponse error!", + phosphor::logging::entry("ERROR=%s", + boost::system::system_error(err).what())); + } + + pollTimer.expires_from_now(boost::posix_time::milliseconds(pollMs)); + pollTimer.async_wait( + [](const boost::system::error_code &ec) { startRead(); }); +} + +int main(int argc, char **argv) +{ + phosphor::logging::log<phosphor::logging::level::DEBUG>( + "Monitor FRB2 signal"); + + sdbusplus::bus::match_t biosPostSignal( + static_cast<sdbusplus::bus::bus &>(*conn), + sdbusplus::bus::match::rules::type::signal() + + sdbusplus::bus::match::rules::member("PostCompleted") + + sdbusplus::bus::match::rules::path(powerPath) + + sdbusplus::bus::match::rules::interface(powerIntf), + [](sdbusplus::message::message &msg) { + uint8_t value = 0; + ssize_t rc = 0; + phosphor::logging::log<phosphor::logging::level::INFO>( + "BIOS post completed signal"); + // stop FRB2 and clean mailbox + value = 0; + rc = ::pwrite(mailboxDevFd, &value, 1, 0); + if (rc != 1) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox write error!"); + } + setProperty("Enabled", false); + frb2Status = frb2Stopped; + return; + }); + + conn->request_name(frb2Bus); + + auto server = sdbusplus::asio::object_server(conn); + + std::shared_ptr<sdbusplus::asio::dbus_interface> frb2Iface = + server.add_interface(frb2Obj, frb2Intf); + + frb2Iface->register_property("frb2Status", frb2Status); + + frb2Iface->initialize(); + + mailboxDevFd = ::open(mailboxDevName, O_RDWR | O_CLOEXEC); + if (mailboxDevFd < 0) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "mailbox device open fail!"); + return -1; + } + + inputDevice.assign(mailboxDevFd); + + startRead(); + + io.run(); + + ::close(mailboxDevFd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch new file mode 100644 index 000000000..360ba35f0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch @@ -0,0 +1,336 @@ +From 82f31d1e6096acd4f223f0b0fe0d814c27450022 Mon Sep 17 00:00:00 2001 +From: James Feist <james.feist@linux.intel.com> +Date: Mon, 17 Jun 2019 12:00:58 -0700 +Subject: [PATCH] Customize phosphor-watchdog for Intel platforms + +This patch adds various changes to phosphor-watchdog that are +required for compatibility with Intel platforms. + + 1. Add Redfish messages for watchdog timeout and pre-interrupt + 2. Use dbus properties for power control insted of service files + 3. Use host status to enable/disable watchdog + 4. Set preTimeoutInterruptOccurFlag + +Signed-off-by: James Feist <james.feist@linux.intel.com> +Signed-off-by: Ren Yu <yux.ren@intel.com> +Signed-off-by: Yong Li <yong.b.li@linux.intel.com> +Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com> +--- + watchdog.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + watchdog.hpp | 23 ++++++- + 2 files changed, 226 insertions(+), 10 deletions(-) + +diff --git a/watchdog.cpp b/watchdog.cpp +index 9090760..079d88e 100644 +--- a/watchdog.cpp ++++ b/watchdog.cpp +@@ -1,11 +1,14 @@ + #include "watchdog.hpp" + ++#include <systemd/sd-journal.h> ++ + #include <algorithm> + #include <chrono> + #include <phosphor-logging/elog.hpp> + #include <phosphor-logging/log.hpp> + #include <sdbusplus/exception.hpp> + #include <xyz/openbmc_project/Common/error.hpp> ++#include <xyz/openbmc_project/State/Host/server.hpp> + + namespace phosphor + { +@@ -18,10 +21,77 @@ using namespace phosphor::logging; + using sdbusplus::exception::SdBusError; + using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; + +-// systemd service to kick start a target. +-constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; +-constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1"; +-constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; ++const static constexpr char* currentHostState = "CurrentHostState"; ++const static constexpr char* hostStatusOff = ++ "xyz.openbmc_project.State.Host.HostState.Off"; ++ ++const static constexpr char* actionDescription = " due to Watchdog timeout"; ++const static constexpr char* hardResetDescription = "Hard Reset - System reset"; ++const static constexpr char* powerOffDescription = ++ "Power Down - System power down"; ++const static constexpr char* powerCycleDescription = ++ "Power Cycle - System power cycle"; ++const static constexpr char* timerExpiredDescription = "Timer expired"; ++ ++const static constexpr char* preInterruptActionNone = ++ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None"; ++ ++const static constexpr char* preInterruptDescriptionSMI = "SMI"; ++const static constexpr char* preInterruptDescriptionNMI = "NMI"; ++const static constexpr char* preInterruptDescriptionMI = "Messaging Interrupt"; ++ ++const static constexpr char* reservedDescription = "Reserved"; ++ ++const static constexpr char* timerUseDescriptionBIOSFRB2 = "BIOS FRB2"; ++const static constexpr char* timerUseDescriptionBIOSPOST = "BIOS/POST"; ++const static constexpr char* timerUseDescriptionOSLoad = "OSLoad"; ++const static constexpr char* timerUseDescriptionSMSOS = "SMS/OS"; ++const static constexpr char* timerUseDescriptionOEM = "OEM"; ++ ++namespace restart ++{ ++static constexpr const char* busName = ++ "xyz.openbmc_project.Control.Host.RestartCause"; ++static constexpr const char* path = ++ "/xyz/openbmc_project/control/host0/restart_cause"; ++static constexpr const char* interface = ++ "xyz.openbmc_project.Control.Host.RestartCause"; ++static constexpr const char* property = "RequestedRestartCause"; ++} // namespace restart ++ ++// chassis state manager service ++namespace chassis ++{ ++static constexpr const char* busName = "xyz.openbmc_project.State.Chassis"; ++static constexpr const char* path = "/xyz/openbmc_project/state/chassis0"; ++static constexpr const char* interface = "xyz.openbmc_project.State.Chassis"; ++static constexpr const char* request = "RequestedPowerTransition"; ++} // namespace chassis ++ ++namespace host ++{ ++static constexpr const char* busName = "xyz.openbmc_project.State.Host"; ++static constexpr const char* path = "/xyz/openbmc_project/state/host0"; ++static constexpr const char* interface = "xyz.openbmc_project.State.Host"; ++static constexpr const char* request = "RequestedHostTransition"; ++} // namespace host ++ ++void Watchdog::powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props) ++{ ++ const auto iter = props.find(currentHostState); ++ if (iter != props.end()) ++ { ++ const std::string* powerState = std::get_if<std::string>(&iter->second); ++ if (powerState && (*powerState == hostStatusOff)) ++ { ++ if (timerEnabled()) ++ { ++ enabled(false); ++ } ++ } ++ } ++} + + void Watchdog::resetTimeRemaining(bool enableWatchdog) + { +@@ -102,13 +172,102 @@ uint64_t Watchdog::interval(uint64_t value) + // Optional callback function on timer expiration + void Watchdog::timeOutHandler() + { ++ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt(); ++ std::string preInterruptActionMessageArgs{}; ++ + Action action = expireAction(); ++ std::string actionMessageArgs{}; ++ ++ expiredTimerUse(currentTimerUse()); ++ ++ TimerUse timeUser = expiredTimerUse(); ++ std::string timeUserMessage{}; ++ + if (!this->enabled()) + { + action = fallback->action; + } + +- expiredTimerUse(currentTimerUse()); ++ switch (timeUser) ++ { ++ case Watchdog::TimerUse::BIOSFRB2: ++ timeUserMessage = timerUseDescriptionBIOSFRB2; ++ break; ++ case Watchdog::TimerUse::BIOSPOST: ++ timeUserMessage = timerUseDescriptionBIOSPOST; ++ break; ++ case Watchdog::TimerUse::OSLoad: ++ timeUserMessage = timerUseDescriptionOSLoad; ++ break; ++ case Watchdog::TimerUse::SMSOS: ++ timeUserMessage = timerUseDescriptionSMSOS; ++ break; ++ case Watchdog::TimerUse::OEM: ++ timeUserMessage = timerUseDescriptionOEM; ++ break; ++ default: ++ timeUserMessage = reservedDescription; ++ break; ++ } ++ ++ switch (action) ++ { ++ case Watchdog::Action::HardReset: ++ actionMessageArgs = std::string(hardResetDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::PowerOff: ++ actionMessageArgs = std::string(powerOffDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::PowerCycle: ++ actionMessageArgs = std::string(powerCycleDescription) + ++ std::string(actionDescription); ++ break; ++ case Watchdog::Action::None: ++ actionMessageArgs = timerExpiredDescription; ++ break; ++ default: ++ actionMessageArgs = reservedDescription; ++ break; ++ } ++ ++ // Log into redfish event log ++ sd_journal_send("MESSAGE=IPMIWatchdog: Timed out ACTION=%s", ++ convertForMessage(action).c_str(), "PRIORITY=%i", LOG_INFO, ++ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=%s. timer use: %s", ++ actionMessageArgs.c_str(), timeUserMessage.c_str(), NULL); ++ ++ switch (preTimeoutInterruptAction) ++ { ++ case Watchdog::PreTimeoutInterruptAction::SMI: ++ preInterruptActionMessageArgs = preInterruptDescriptionSMI; ++ break; ++ case Watchdog::PreTimeoutInterruptAction::NMI: ++ preInterruptActionMessageArgs = preInterruptDescriptionNMI; ++ break; ++ case Watchdog::PreTimeoutInterruptAction::MI: ++ preInterruptActionMessageArgs = preInterruptDescriptionMI; ++ break; ++ default: ++ preInterruptActionMessageArgs = reservedDescription; ++ break; ++ } ++ ++ if (preInterruptActionNone != convertForMessage(preTimeoutInterruptAction)) ++ { ++ preTimeoutInterruptOccurFlag(true); ++ ++ sd_journal_send("MESSAGE=IPMIWatchdog: Pre Timed out Interrupt=%s", ++ convertForMessage(preTimeoutInterruptAction).c_str(), ++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", ++ "OpenBMC.0.1.IPMIWatchdog", ++ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to " ++ "Watchdog timeout. timer use: %s", ++ preInterruptActionMessageArgs.c_str(), ++ timeUserMessage.c_str(), NULL); ++ } + + auto target = actionTargetMap.find(action); + if (target == actionTargetMap.end()) +@@ -128,10 +287,23 @@ void Watchdog::timeOutHandler() + + try + { +- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, +- SYSTEMD_INTERFACE, "StartUnit"); +- method.append(target->second); +- method.append("replace"); ++ sdbusplus::message::message method; ++ if (action == Watchdog::Action::HardReset) ++ { ++ method = bus.new_method_call(host::busName, host::path, ++ "org.freedesktop.DBus.Properties", ++ "Set"); ++ method.append(host::interface, host::request, ++ std::variant<std::string>(target->second)); ++ } ++ else ++ { ++ method = bus.new_method_call(chassis::busName, chassis::path, ++ "org.freedesktop.DBus.Properties", ++ "Set"); ++ method.append(chassis::interface, chassis::request, ++ std::variant<std::string>(target->second)); ++ } + + bus.call_noreply(method); + } +@@ -142,6 +314,29 @@ void Watchdog::timeOutHandler() + entry("ERROR=%s", e.what())); + commit<InternalFailure>(); + } ++ ++ // set restart cause for watchdog HardReset & PowerCycle actions ++ if ((action == Watchdog::Action::HardReset) || ++ (action == Watchdog::Action::PowerCycle)) ++ { ++ try ++ { ++ auto method = bus.new_method_call( ++ restart::busName, restart::path, ++ "org.freedesktop.DBus.Properties", "Set"); ++ method.append( ++ restart::interface, restart::property, ++ std::variant<std::string>("xyz.openbmc_project.State.Host." ++ "RestartCause.WatchdogTimer")); ++ bus.call(method); ++ } ++ catch (sdbusplus::exception_t& e) ++ { ++ log<level::ERR>("Failed to set HostRestartCause property", ++ entry("ERROR=%s", e.what())); ++ commit<InternalFailure>(); ++ } ++ } + } + + tryFallbackOrDisable(); +diff --git a/watchdog.hpp b/watchdog.hpp +index 7de9bb3..b004b7a 100644 +--- a/watchdog.hpp ++++ b/watchdog.hpp +@@ -68,7 +68,18 @@ class Watchdog : public WatchdogInherits + WatchdogInherits(bus, objPath), + bus(bus), actionTargetMap(std::move(actionTargetMap)), + fallback(std::move(fallback)), minInterval(minInterval), +- timer(event, std::bind(&Watchdog::timeOutHandler, this)) ++ timer(event, std::bind(&Watchdog::timeOutHandler, this)), ++ powerStateChangedSignal( ++ bus, ++ sdbusplus::bus::match::rules::propertiesChanged( ++ "/xyz/openbmc_project/state/host0", ++ "xyz.openbmc_project.State.Host"), ++ [this](sdbusplus::message::message& msg) { ++ std::string objectName; ++ std::map<std::string, std::variant<std::string>> props; ++ msg.read(objectName, props); ++ powerStateChangedHandler(props); ++ }) + { + // We set the watchdog interval with the default value. + interval(interval()); +@@ -77,6 +88,12 @@ class Watchdog : public WatchdogInherits + tryFallbackOrDisable(); + } + ++ /** @brief Disable watchdog when power status change meet ++ * the specific requirement ++ */ ++ void powerStateChangedHandler( ++ const std::map<std::string, std::variant<std::string>>& props); ++ + /** @brief Resets the TimeRemaining to the configured Interval + * Optionally enables the watchdog. + * +@@ -165,6 +182,10 @@ class Watchdog : public WatchdogInherits + /** @brief Contained timer object */ + sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer; + ++ /** @brief Optional Callback handler when power status change meet ++ * the specific requirement */ ++ sdbusplus::bus::match_t powerStateChangedSignal; ++ + /** @brief Optional Callback handler on timer expirartion */ + void timeOutHandler(); + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service new file mode 100644 index 000000000..007e39d8a --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service @@ -0,0 +1,16 @@ +[Unit] +Description=Phosphor Watchdog + +[Service] +ExecStart=/usr/bin/env phosphor-watchdog --continue --service=xyz.openbmc_project.Watchdog \ + --path=/xyz/openbmc_project/watchdog/host0 \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=xyz.openbmc_project.State.Host.Transition.ForceWarmReboot \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=xyz.openbmc_project.State.Chassis.Transition.Off \ + --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=xyz.openbmc_project.State.Chassis.Transition.PowerCycle + +SyslogIdentifier=phosphor-watchdog +BusName =xyz.openbmc_project.Watchdog +Type=dbus + +[Install] +WantedBy=basic.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend new file mode 100644 index 000000000..f0b8e8f23 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend @@ -0,0 +1,9 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +SRCREV = "c35135d32f9cb84b62de7b72eee3a2e87b4b3d4d" +SRC_URI += "file://0001-Customize-phosphor-watchdog-for-Intel-platforms.patch \ + " + +# Remove the override to keep service running after DC cycle +SYSTEMD_OVERRIDE_${PN}_remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf" +SYSTEMD_SERVICE_${PN} = "phosphor-watchdog.service" diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb new file mode 100644 index 000000000..45c2c5364 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb @@ -0,0 +1,24 @@ +SUMMARY = "System watchdog" +DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \ + when unrecoverable events occurs" + +inherit allarch +inherit obmc-phosphor-systemd + +RDEPENDS_${PN} = "bash" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SYSTEMD_SERVICE_${PN} += "system-watchdog.service" +SYSTEMD_ENVIRONMENT_FILE_${PN} += "obmc/system-watchdog/system-watchdog.conf" + +SYSTEMD_SERVICE_${PN} += "watchdog-reset.service" +SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.service" +SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.timer" +SRC_URI += "file://watchdog-reset.sh" + +do_install_append(){ + install -d ${D}${bindir} + install -m 0755 ${WORKDIR}/watchdog-reset.sh ${D}${bindir} +} diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf new file mode 100644 index 000000000..defe830a1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf @@ -0,0 +1,3 @@ +TIMEOUT=60 +INTERVAL=10 +DEVICE=/dev/watchdog1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service new file mode 100644 index 000000000..1564fda20 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service @@ -0,0 +1,11 @@ +[Unit] +Description=BMC Hardware Watchdog Daemon + +[Service] +EnvironmentFile=/etc/default/obmc/system-watchdog/system-watchdog.conf +ExecStart=/sbin/watchdog -T ${{TIMEOUT}} -t ${{INTERVAL}} -F ${{DEVICE}} +KillSignal=SIGKILL + +[Install] +WantedBy=basic.target + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service new file mode 100644 index 000000000..801f4ed27 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service @@ -0,0 +1,10 @@ +[Unit] +Description=Reset BMC Hardware Watchdog Failure Count + +[Service] +ExecStart=busctl call xyz.openbmc_project.U_Boot.Environment.Manager \ + /xyz/openbmc_project/u_boot/environment/mgr \ + xyz.openbmc_project.U_Boot.Environment.Manager \ + Write ss bootfailures 0 +Type=oneshot + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer new file mode 100644 index 000000000..1abac4326 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer @@ -0,0 +1,8 @@ +[Unit] +Description=Starts the clear watchdog serivce after 30 minutes + +[Timer] +OnBootSec=30min + +[Install] +WantedBy=timers.target diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service new file mode 100644 index 000000000..6a5ffb4ba --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service @@ -0,0 +1,7 @@ +[Unit] +Description=Reset BMC Using Hardware Watchdog + +[Service] +ExecStart=/usr/bin/watchdog-reset.sh +Type=oneshot + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh new file mode 100644 index 000000000..b3afd73d3 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if /sbin/fw_printenv bootfailures -n | grep -q 3; then + exit 0 # passed boot limit, user started again on purpose +fi + +echo "Watchdog Failure Limit Reached, Failed Processes:" > /dev/kmsg +systemctl --failed --no-pager | grep failed > /dev/kmsg +echo "Log as follows:" > /dev/kmsg +journalctl -r -n 100 | while read line; do echo $line > /dev/kmsg; done + +systemctl stop system-watchdog.service +/sbin/watchdog -T 0 -F /dev/watchdog1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend new file mode 100644 index 000000000..e4e24c3d0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend @@ -0,0 +1,2 @@ +SRC_URI = "git://github.com/Intel-BMC/phosphor-webui;protocol=ssh;branch=intel2" +SRCREV = "d342b21139c40528a70a2e25c1a00fab7116441a" diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh new file mode 100644 index 000000000..176bfd7ca --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh @@ -0,0 +1 @@ +export LDB_MODULES_PATH=/usr/lib/ldb diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups new file mode 100644 index 000000000..7c189e231 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups @@ -0,0 +1 @@ +sssd_locked diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf new file mode 100644 index 000000000..d2ffe5ddc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf @@ -0,0 +1,2 @@ +enable-cache passwd no +enable-cache group no
\ No newline at end of file diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf new file mode 100644 index 000000000..7a2786bee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf @@ -0,0 +1,16 @@ +[sssd] +domains = LOCAL +services = nss, pam +config_file_version = 2 + +[nss] +enum_cache_timeout = 1 +filter_groups = root +filter_users = root + +[pam] + +[domain/LOCAL] +enumerate = true +id_provider = local +auth_provider = local diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service new file mode 100644 index 000000000..fe2bcf8b4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service @@ -0,0 +1,15 @@ +[Unit] +Description=System Security Services Daemon +# SSSD must be running before we permit user sessions +Before=systemd-user-sessions.service nss-user-lookup.target +Wants=nss-user-lookup.target + +[Service] +Environment=LDB_MODULES_PATH=/usr/lib/ldb DEBUG_LOGGER=-f +ExecStart=/usr/sbin/sssd $DEBUG_LOGGER +Type=simple +Restart=always +PIDFile=/var/run/sssd.pid + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend new file mode 100644 index 000000000..03965ce72 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend @@ -0,0 +1,26 @@ +inherit obmc-phosphor-systemd + +FILESEXTRAPATHS_append := "${THISDIR}/files:" +SRC_URI += "file://sssd.conf \ + file://nscd.conf \ + file://locked_groups \ + file://ldb.sh \ + " + +PACKAGECONFIG += " systemd " +SYSTEMD_AUTO_ENABLE = "enable" + +EXTRA_OECONF += " --enable-pammoddir=${base_libdir}/security" + +do_install_append() { + # sssd creates also the /var/run link. Need to remove it to avoid conflicts + # with the one created by base-files recipe. + rm -rf ${D}/var/run + install -m 600 ${WORKDIR}/locked_groups ${D}/${sysconfdir}/${BPN} + install -m 600 ${WORKDIR}/nscd.conf ${D}/${sysconfdir} + install -d ${D}${sysconfdir}/profile.d + install -m 0644 ${WORKDIR}/ldb.sh ${D}${sysconfdir}/profile.d +} + +FILES_${PN} += " /lib/security/pam_sss.so " + diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch b/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch new file mode 100644 index 000000000..80dfc2725 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch @@ -0,0 +1,28 @@ +From 318439af2e77731ae2c3df5e198c1d3e8392d556 Mon Sep 17 00:00:00 2001 +From: Simon Ebner <Simon.Ebner@advertima.com> +Date: Fri, 22 Mar 2019 15:27:35 +0100 +Subject: [PATCH 1/2] Fix Issue 62 + +Fixes a leaking pipe. See https://github.com/boostorg/process/issues/62 +--- + boost/process/detail/posix/executor.hpp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp +index 1390a58..8b86ed1 100644 +--- a/boost/process/detail/posix/executor.hpp ++++ b/boost/process/detail/posix/executor.hpp +@@ -282,7 +282,10 @@ class executor + set_error(std::error_code(err, std::system_category()), "Error read pipe"); + } + if (count == 0) ++ { ++ ::close(source); + return ; ++ } + + std::error_code ec(data[0], std::system_category()); + std::string msg(data[1], ' '); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend new file mode 100644 index 000000000..f85e30b1f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "file://0001-Fix-Issue-62.patch" diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default new file mode 100644 index 000000000..b9f8e0363 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default @@ -0,0 +1 @@ +EXTRA_ARGS="-r /dev/hwrng" diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init new file mode 100644 index 000000000..13f0ecd37 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init @@ -0,0 +1,42 @@ +#!/bin/sh +# +# This is an init script for openembedded +# Copy it to @SYSCONFDIR@/init.d/rng-tools and type +# > update-rc.d rng-tools defaults 60 +# + +rngd=@SBINDIR@/rngd +test -x "$rngd" || exit 1 + +[ -r @SYSCONFDIR@/default/rng-tools ] && . "@SYSCONFDIR@/default/rng-tools" + +case "$1" in + start) + echo -n "Starting random number generator daemon" + start-stop-daemon -S -q -x $rngd -- $EXTRA_ARGS + echo "." + ;; + stop) + echo -n "Stopping random number generator daemon" + start-stop-daemon -K -q -n rngd + echo "." + ;; + reload|force-reload) + echo -n "Signalling rng daemon restart" + start-stop-daemon -K -q -s 1 -x $rngd + start-stop-daemon -K -q -s 1 -x $rngd + ;; + restart) + echo -n "Stopping random number generator daemon" + start-stop-daemon -K -q -n rngd + echo "." + echo -n "Starting random number generator daemon" + start-stop-daemon -S -q -x $rngd -- $EXTRA_ARGS + echo "." + ;; + *) + echo "Usage: @SYSCONFDIR@/init.d/rng-tools {start|stop|reload|restart|force-reload}" + exit 1 +esac + +exit 0 diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service new file mode 100644 index 000000000..d76e9a0c4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service @@ -0,0 +1,10 @@ +[Unit] +Description=Hardware RNG Entropy Gatherer Daemon + +[Service] +EnvironmentFile=-@SYSCONFDIR@/default/rng-tools +ExecStart=@SBINDIR@/rngd -f $EXTRA_ARGS +Nice=15 + +[Install] +WantedBy=multi-user.target diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb new file mode 100644 index 000000000..b4e453f67 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb @@ -0,0 +1,52 @@ +SUMMARY = "Random number generator daemon" +DESCRIPTION = "Check and feed random data from hardware device to kernel" +AUTHOR = "Philipp Rumpf, Jeff Garzik <jgarzik@pobox.com>, \ + Henrique de Moraes Holschuh <hmh@debian.org>" +HOMEPAGE = "https://github.com/nhorman/rng-tools" +BUGTRACKER = "https://github.com/nhorman/rng-tools/issues" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263" +DEPENDS = "sysfsutils" + +SRC_URI = "\ + git://github.com/nhorman/rng-tools.git \ + file://init \ + file://default \ + file://rngd.service \ +" +SRCREV = "9fc873c5af0e392632e6b736938b811f7ca97251" + +S = "${WORKDIR}/git" + +inherit autotools update-rc.d systemd pkgconfig + +PACKAGECONFIG ??= "libgcrypt libjitterentropy" +PACKAGECONFIG_libc-musl = "libargp libjitterentropy" + +PACKAGECONFIG[libargp] = "--with-libargp,--without-libargp,argp-standalone," +PACKAGECONFIG[libgcrypt] = "--with-libgcrypt,--without-libgcrypt,libgcrypt," +PACKAGECONFIG[libjitterentropy] = "--enable-jitterentropy,--disable-jitterentropy,libjitterentropy" +PACKAGECONFIG[libp11] = "--with-pkcs11,--without-pkcs11,libp11 openssl" +PACKAGECONFIG[nistbeacon] = "--with-nistbeacon,--without-nistbeacon,curl libxml2 openssl" + +INITSCRIPT_NAME = "rng-tools" +INITSCRIPT_PARAMS = "start 03 2 3 4 5 . stop 30 0 6 1 ." + +SYSTEMD_SERVICE_${PN} = "rngd.service" + +# Refer autogen.sh in rng-tools +do_configure_prepend() { + cp ${S}/README.md ${S}/README +} + +do_install_append() { + install -Dm 0644 ${WORKDIR}/default ${D}${sysconfdir}/default/rng-tools + install -Dm 0755 ${WORKDIR}/init ${D}${sysconfdir}/init.d/rng-tools + install -Dm 0644 ${WORKDIR}/rngd.service \ + ${D}${systemd_system_unitdir}/rngd.service + sed -i \ + -e 's,@SYSCONFDIR@,${sysconfdir},g' \ + -e 's,@SBINDIR@,${sbindir},g' \ + ${D}${sysconfdir}/init.d/rng-tools \ + ${D}${systemd_system_unitdir}/rngd.service +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb new file mode 100644 index 000000000..51cda82e9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb @@ -0,0 +1,17 @@ +SUMMARY = "Beeper Test App" +DESCRIPTION = "Beeper Test Application for pwm-beeper" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM += "\ + file://beeper-test.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \ + " + +SRC_URI = "\ + file://CMakeLists.txt \ + file://beeper-test.cpp \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format new file mode 100644 index 000000000..ea71ad6e1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format @@ -0,0 +1,99 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +PointerAlignment: Left +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^[<"](gtest|gmock)' + Priority: 5 + - Regex: '^"config.h"' + Priority: -1 + - Regex: '^".*\.hpp"' + Priority: 1 + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*' + Priority: 3 + - Regex: '.*' + Priority: 4 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt new file mode 100644 index 000000000..81a0c7e81 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(beeper-test CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(beeper-test beeper-test.cpp) +install(TARGETS beeper-test DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp new file mode 100644 index 000000000..31dafdd88 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp @@ -0,0 +1,81 @@ +/* +// Copyright (c) 2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: pwm-beeper test application +// +*/ + +#include <fcntl.h> +#include <linux/input.h> +#include <stdio.h> +#include <unistd.h> + +#include <cstring> +#include <iostream> + +int main(int argc, char** argv) +{ + if (argc < 3) + { + std::cout << "usage: <input device> <sequence of 'tone in " + "Hz','duration in ms' pair>\n"; + std::cout << "example: beeper-test /dev/input/event0 " + "2100,100,0,150,2500,50,0,50,2200,100\n"; + return 1; + } + + int fd; + if ((fd = open(argv[1], O_RDWR | O_CLOEXEC)) < 0) + { + perror("Failed to open input device"); + return -1; + } + + struct input_event event; + event.type = EV_SND; + event.code = SND_TONE; + + char* pch = strtok(argv[2], ","); + while (pch != NULL) + { + event.value = atoi(pch); + + pch = strtok(NULL, ","); + if (!pch) + { + std::cerr << "Invalid tone,duration pair\n"; + close(fd); + return -1; + } + + int durationMs = atoi(pch); + + if (write(fd, &event, sizeof(struct input_event)) != + sizeof(struct input_event)) + { + perror("Failed to write a tone sound event"); + close(fd); + return -1; + } + + usleep(durationMs * 1000); + + pch = strtok(NULL, ","); + } + + close(fd); + + return 0; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb new file mode 100644 index 000000000..78240c0f4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb @@ -0,0 +1,17 @@ +SUMMARY = "Dimm Sensor" +DESCRIPTION = "Dimm Sensor Executable" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://DimmSensor.cpp \ + " + +LICENSE = "CLOSED" + +S = "${WORKDIR}" + +inherit cmake + +# linux-libc-headers guides this way to include custom uapi headers +CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi" +do_configure[depends] += "virtual/kernel:do_shared_workdir" diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt new file mode 100644 index 000000000..6262f8dee --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(dimmsensor CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(dimmsensor DimmSensor.cpp) +install (TARGETS dimmsensor DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp new file mode 100644 index 000000000..9cc13c2a5 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp @@ -0,0 +1,143 @@ +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <memory> +#include <vector> +#include <linux/aspeed_peci_ioctl.h> + +#define PECI_DIMM_TEMP_REG 0x150 +#define DIMM_DEFAULT_VALUE 0x55 + +class DimmConfig { + public: + uint8_t chanId, bus, device, function, dimmnum; +}; + +#define MAX_BUFFER_SIZE 32 + +// TODO get this from config +auto GetDimmConfig(uint8_t dimm) { + uint8_t chan = dimm / 2; + assert(chan < 6); + + auto ret = std::make_unique<DimmConfig>(); + + ret->chanId = chan; + ret->dimmnum = 2; + ret->bus = 2; + switch (chan) { + case 0: + ret->device = 10; + ret->function = 2; + break; + case 1: + ret->device = 10; + ret->function = 6; + break; + case 2: + ret->device = 11; + ret->function = 2; + break; + case 3: + ret->device = 12; + ret->function = 2; + break; + case 4: + ret->device = 12; + ret->function = 6; + break; + case 5: + ret->device = 13; + ret->function = 2; + break; + default: + assert(0); + break; + } + + return ret; +} + +// returns read vector on success, empty vector on failure +auto peci_config_local(uint8_t u8target, uint8_t u8bus, uint8_t u8device, + uint8_t u8fcn, uint16_t u16reg, uint8_t u8readlen) { + auto msg = std::make_unique<peci_xfer_msg>(); + uint32_t u32Address; + int fd; + std::vector<uint8_t> ret; + + u32Address = u16reg; + u32Address |= u8fcn << 12; + u32Address |= u8device << 15; + u32Address |= u8bus << 20; + + msg->client_addr = u8target; + msg->tx_len = RDPCICFGLOCAL_WRITE_LEN; + msg->rx_len = RDPCICFGLOCAL_READ_LEN_BASE + u8readlen; + + msg->tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; + msg->tx_buf[2] = u32Address & 0xFF; + msg->tx_buf[3] = (u32Address >> 8) & 0xFF; + msg->tx_buf[4] = (u32Address >> 16) & 0xFF; + + fd = open("/dev/peci", O_RDWR | O_CLOEXEC); + if (fd >= 0) { + int success = ioctl(fd, PECI_IOC_XFER, msg.get()); + if (success == 0) { + if (DEV_PECI_CC_SUCCESS == msg->rx_buf[0]) { + ret.resize(RDPCICFGLOCAL_READ_LEN_BASE + u8readlen - 1); + memcpy(ret.data(), &(msg->rx_buf[1]), ret.size()); + } + } + close(fd); + } + return ret; +} + +int main(int argc, char** argv) { + if (argc != 3) { + std::cout << argv[0] << " requires 2 arguments: CPUNum, DimmNum.\n"; + return -1; + } + uint8_t cpunum = atoi(argv[1]); + if (cpunum > 3) { + std::cout << cpunum << " greater than cpu max of 3.\n"; + return -1; + } + uint8_t dimmnum = atoi(argv[2]); + if (dimmnum > 11) { + std::cout << dimmnum << " greater than dimm max of 11.\n"; + return -1; + } + + auto dimm_config = GetDimmConfig(dimmnum); + + uint8_t dimmSelect = dimmnum % 2; // dimm 0 or 1 for each config + + auto val = peci_config_local(PECI_BASE_ADDR + cpunum, dimm_config->bus, + dimm_config->device, dimm_config->function, + PECI_DIMM_TEMP_REG + dimmSelect * 4, 4); + + if (!val.size()) { + std::cout << "Peci Error\n"; + return -1; + } + + // TODO dimm offsets needed? + + if (val[0] == 0) + std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum) + << " not populated.\n"; + else if(val[0] == DIMM_DEFAULT_VALUE) + std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum) + << " in illegal state.\n"; + else + std::cout << unsigned(val[0]) << " degrees C.\n"; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini new file mode 100644 index 000000000..38609ad5d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini @@ -0,0 +1,277 @@ +; +; Copyright 2015 Intel Corporation. +; +; The source code, information and material ("Material") contained herein is +; owned by Intel Corporation or its suppliers or licensors, and title to such +; Material remains with Intel Corporation or its suppliers or licensors. The +; Material contains proprietary information of Intel or its suppliers and +; licensors. The Material is protected by worldwide copyright laws and treaty +; provisions. No part of the Material may be used, copied, reproduced, +; modified, published, uploaded, posted, transmitted, distributed or disclosed +; in any way without Intel's prior express written permission. No license under +; any patent, copyright or other intellectual property rights in the Material +; is granted to or conferred upon you, either expressly, by implication, +; inducement, estoppel or otherwise. Any license under such intellectual +; property rights must be express and approved by Intel in writing. + +; +; This file is similar to the config.genimage2 file of previous BMC +; generations but it is not generated. It contains all of the information +; to generate the signed-image variant of the signtool config file. +; + +[GLOBAL] +Major = 0 +Minor = 72 +Output = update.bin +Alloc = 33792K ; 0x2100000 +BlockSize = 64K +Type = 0xffffffff ; generate top level composite image +Locate = 0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Factory ROM file generation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +RomOutput = rom-a-only.ima +RomAlloc = 33M +KeyRegion = Certificate +NewKeyRegion = ReplacementCertificate +SecVersion = 0 + + + +; RecoveryOnly items should be place first in the image + +[FRISBEE_ROM] +Major = 1 +Minor = 5 +Type = ROBL +File = frisbee.bin +Locate = 0x00000000 +Alloc = 240K +Compress = 0 +SecVersion = 1 +Unsigned = 1 + +[Certificate] +Locate = 0x3c000 +Type = CERT +Alloc = 8K +Fill = 0xff +Unsigned = 1 +ROMOnly = 1 +SecVersion = 0 + +;[FWPRODUCTID] +;Major = 1 +;Minor = 0 +;Type = FWID +;File = fwproductid.bin +;Locate = 0x0003f000 +;ROMOnly = 1 +;SecVersion = 0 + +[FRISBEE_UPD] +Major = 1 +Minor = 5 +Type = RWBL +File = frisbee.bin +Locate = 0x040000 +Alloc = 256K +Compress = 0 +SecVersion = 1 +IndivSign = 1 +SigOffset = 0x03e000 + +[U-Boot] +Major = 1 +Minor = 5 +Type = UBT\x00 +File = u-boot.bin +Alloc = 256K +Compress = 0 +SecVersion = 1 +IndivSign = 1 +SigOffset = 0x03e000 + +; Linux OS Image +[OSIMAGE] +Major = 1 +Minor = 1 +Type = LKNL +File = uImage +SecVersion = 1 + +[DTB] +Major = 1 +Minor = 1 +Type = DTB\x00 +File = uImage-aspeed-bmc-intel-ast2500.dtb +SecVersion = 0 + +; Root File System +[ROOT] +Major = 1 +Minor = 1 +Type = RtFS +File = image-rofs.squashfs-xz.u-boot +Load = 0x83000000 +SecVersion = 1 +; +; WWW File System in CRAMFS. +;[WWW] +;Major = 1 +;Minor = 1 +;Type = WWW\x00 +;File = webfs.bin +;BlockDev = 1 +;SecVersion = 1 + +; Replacement certificate for re-keying the BMC +; Will only be added to image if -rk is specified +[ReplacementCertificate] +Major = 1 +Minor = 1 +Type = CRT0 +Alloc = 4K +SecVersion = 0 +Compress = 0 +IndivSign = 1 +Unbound = 1 +Fill = 0xff +SigOffset = 0x800 + +; Manifest goes here +; This gets some special treatment (this needs to match the location +; that Frisbee thinks the manifest is at or it won't boot) +[Manifest] +Major = 0 +Minor = 0 +Type = MFST +Alloc = 4K +Locate = 0x1bff000 +Fill = 0xff +SecVersion = 0 + +; +; NV File System in JFFS2, but it is blank in the ROM version +; and filled in with defaults from the rootfs +[PARAMS] +Major = 1 +Minor = 1 +Type = CONF +Alloc = 4096K +Locate = 0x1c00000 +ROMOnly = 1 +BlockDev = 1 +SecVersion = 1 +Unsigned = 1 + +; notice that these sections have no file +; and are marked as ROMOnly. This forces them +; into the allocation so we don't get overlapping +; sections, but does not actually put anything into +; the rom at build time. + +[UBootEnv] +Major = 1 +Minor = 0 +Type = UENV +; File = ; no file makes this a placeholder +Locate = 0x2000000 +Alloc = 64K +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[FRUData] +Major = 1 +Minor = 0 +Type = FRU\x00 +Alloc = 64K +Locate = 0x2010000 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[SEL] +Major = 1 +Minor = 0 +Type = SEL\x00 +Alloc = 512K +Locate = 0x2020000 +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +; NV filesystem that survives reset mfg defaults. +; OEM Web customization goes here. +[PersistentNV] +Major = 1 +Minor = 0 +Type = PNV\x00 +Alloc = 2048K +Locate = 0x20a0000 +BlockDev = 1 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[RubixLog] +Major = 1 +Minor = 0 +Type = BTLG +Alloc = 4K +Locate = 0x23fe000 +BlockDev = 0 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +[BootPointer] +Major = 1 +Minor = 0 +Type = BPTR +Alloc = 4K +Locate = 0x23ff000 +BlockDev = 0 +ROMOnly = 1 +Unsigned = 1 +SecVersion = 0 + +; +; Example Section with all possible fields with their default +; values, unless the field is specified mandatory +; +;[EXAMPLE] +;Major = 0 ; Major number of module +;Minor = 0 ; Minor number of module +;Type = TYPE ; four bytes hopefully human readable, +; ; use c-style escapes if non-ascii, \x23\x10\x00\xf3 +; ; or use a number 0xf3001023 +;Alloc = X ; Maximum memory allocated; X = roundup +;File = name ; File containing the module +; ; If Alloc is specified, but no File, a blank +; ; header will be created (only useful for ROMOnly) +;Locate = addr ; Location in Flash; MANDATORY +;ROMOnly = 1 ; if ROMOnly is set and non-zero, this section +; ; will only be present in the ROM image, not the updater image +;RecoveryOnly = 1 ; if RecoveryOnly is set and non-zero, this section +; ; will only be present in the recovery image, not the active image +;BlockDev = 1 ; this will make the signed image code export this +; ; image as a mtd block device at runtime +;Unsigned = 1 ; Do not include this section in signatures (NV data) +;Compress = 1 ; compress image contents (useful for non-compressed items) +;SecVersion = X ; a 16-bit security revision to enforce no downgrades +;IndivSign = 1 ; section is individually signed; do not include in full signature +;Unbound = 1 ; by default, individually signed sections are part of the +; ; full signature too. This makes them independent +;SigOffset = X ; offset within individually-signed section to place signature +;Fill = xx ; fill with pattern xx instead of a file's contents +; +; Note: Numeric values can be represented either by decimal or a +; hexadecimal (Prefixed by 0x) +; Numeric values can either end with K or M to specify in +; KiloBytes or MegaBytes +; diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt new file mode 100644 index 000000000..0c98160b9 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(io-app C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +add_executable(io io-app.c) +install (TARGETS io DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c new file mode 100644 index 000000000..955674fa6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c @@ -0,0 +1,696 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Abstract: map io region to read or write to HW registers +// +*/ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <termios.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mman.h> + +static int quiet = 0; + +static int dump(unsigned long phys, void *addr, size_t len) +{ + const uint32_t *ubuf = addr; + unsigned int wd = 0, l, iv; + unsigned char *h, *a; + char line[256]; + static const char itoh[] = "0123456789abcdef"; + + /* 0 1 2 3 4 5 6 + * 0123456789012345678901234567890123456789012345678901234567890123456789 + * 00000000: 00000000 00000000 00000000 00000000 ................ + */ + while (wd < len) + { + memset(line, ' ', sizeof(line)); + sprintf(line, "%08lx: ", phys + (wd*sizeof(uint32_t))); + a = (unsigned char*)&line[47]; + h = (unsigned char*)&line[10]; + for (l=0; l<4 && (l+wd)<len; l++) + { + uint32_t v = *ubuf++; + for (iv=0; iv<sizeof(v); iv++) + { + uint8_t b = v >> (8*((sizeof(v)-1)-iv)); + *h++ = itoh[b>>4]; + *h++ = itoh[b&0xf]; + if (isprint(b)) + *a++ = (char)b; + else + *a++ = '.'; + } + *h++ = ' '; + } + *a++ = '\n'; + *a = 0; + wd += l; + fputs(line, stdout); + } + return wd; +} + + +struct mapping +{ + unsigned long phys; + void *virt; + size_t len; +}; + +static struct mapping *maps = NULL; +static int nr_maps = 0; + +static void unmap_all(void) +{ + int i; + for (i=0; i<nr_maps; i++) + { + if (maps[i].virt) + munmap(maps[i].virt, maps[i].len); + maps[i].virt = NULL; + } +} + +int add_a_map(unsigned long phys, void *virt, size_t len) +{ + void *new_maps; + new_maps = realloc(maps, (nr_maps + 1) * sizeof(struct mapping)); + if (!new_maps) + { + unmap_all(); + munmap(virt, len); + } + else + { + maps = new_maps; + maps[nr_maps].phys = phys; + maps[nr_maps].virt = virt; + maps[nr_maps].len = len; + nr_maps++; + return 0; + } + return -1; +} + +static void *map_fd(int fd, off_t offset, size_t len, int mode, int flags) +{ + void *mapped_at; + unsigned long phys = -1; + + if (offset != -1) + phys = offset; + else + offset = 0; + + mapped_at = mmap(NULL, len, mode, flags, fd, offset); + if (mapped_at != MAP_FAILED) + { + if (add_a_map(phys, mapped_at, len) != 0) + { + mapped_at = MAP_FAILED; + } + } + + return mapped_at; +} + +static void *map_file(const char *fname, size_t *len, int mode, int flags) +{ + int fd; + struct stat sb; + void *ptr; + int fmode; + + if (mode & PROT_WRITE) + fmode = O_RDWR; + else + fmode = O_RDONLY; + + fd = open(fname, fmode); + if (fd < 0) + return MAP_FAILED; + + if (*len == 0) + { + fstat(fd, &sb); + *len = sb.st_size; + } + ptr = map_fd(fd, -1, *len, mode, flags); + close(fd); + return ptr; +} + +static int load_maps(const char *cmap_str, size_t mlen) +{ + char *tmp_sa = NULL, *tmp_sl = NULL, *endptr = NULL; + const void *mapped = NULL; + int ret = 0; + const char *delim = "\r\n\t ,"; + unsigned long addr; + size_t len; + char *map_str = NULL, *paddr = NULL, *plen = NULL; + int fd; + + fd = open("/dev/mem", O_RDWR); + if (fd < 0) + { + return -1; + } + + len = strlen(cmap_str); + map_str = (char *)malloc(len + 1); + if (!map_str) + { + close(fd); + return -1; + } + strncpy(map_str, cmap_str, len); + map_str[len] = '\0'; + paddr = strtok_r(map_str, delim, &tmp_sa); + while (paddr) + { + /* find the next comma or newline */ + if (!strtok_r(paddr, ":", &tmp_sl)) + { + fprintf(stderr, "malformed map string '%s'\n", paddr); + goto _loop; + } + plen = strtok_r(NULL, ":", &tmp_sl); + if (!plen) + { + goto _loop; + } + addr = strtoul(paddr, &endptr, 16); + if (*endptr) + { + fprintf(stderr, "Failed to parse address from '%s'\n", paddr); + ret = -1; + break; + } + len = strtoul(plen, &endptr, 16); + if (*endptr) + { + fprintf(stderr, "Failed to parse len from '%s'\n", plen); + ret = -1; + break; + } + if (MAP_FAILED == (mapped = map_fd(fd, addr, len, PROT_READ|PROT_WRITE, MAP_SHARED))) + { + fprintf(stderr, "Failed to map %lx +%x\n", addr, len); + ret = -1; + break; + } + if (!quiet) + printf("added map: %p (%lx..%lx)\n", mapped, addr, addr+len); +_loop: + paddr = strtok_r(NULL, delim, &tmp_sa); + } + free(map_str); + close(fd); + return ret; +} + +int md(unsigned long addr, uint32_t unused, size_t len) +{ + int i, j; + + (void)unused; + for (i=0; i<nr_maps; i++) + { + if (-1 == maps[i].phys) + continue; + if (maps[i].phys <= addr && + (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len)) + { + uint32_t *buf, *pv; + + buf = (uint32_t *)malloc(len*sizeof(uint32_t)); + if (!buf) + return 1; + pv = (uint32_t *)(maps[i].virt + (addr - maps[i].phys)); + for (j=0; j<len; j++) + buf[j] = *pv++; + + dump(addr, buf, len); + free(buf); + return 0; + } + } + fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len); + return 1; +} + +int mw(unsigned long addr, uint32_t val, size_t len) +{ + int i, j; + + for (i=0; i<nr_maps; i++) + { + if (-1 == maps[i].phys) + continue; + if (maps[i].phys <= addr && + (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len)) + { + for (j=0; j<len; j++) + { + *((uint32_t*)(maps[i].virt + (addr - maps[i].phys))) = val; + } + return 0; + } + } + fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len); + return 1; +} + +char *readline(char *buf, size_t len, FILE *f) +{ + int raw = 0; + size_t br = 0; + struct termios tios, orig_tios; + + if (!quiet) + { + /* put terminal in raw mode to get unbuffered io */ + if (tcgetattr(fileno(f), &orig_tios) == 0) + { + tios = orig_tios; + tios.c_iflag |= IGNPAR; + tios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); + tios.c_oflag &= ~OPOST; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + tcsetattr(fileno(f), TCSADRAIN, &tios); + raw = 1; + } + } + if (!raw) + { + return fgets(buf, len, f); + } + /* read in bytes one at a time and echo them */ + while (br < (len-1)) + { + int c = fgetc(f); + switch (c) + { + case 3: /* ^C */ + br = 0; + c = '\n'; + break; + case 4: + br = 0; + c = -1; + break; + case '\b': + if (br > 0) + { + fputs("\b \b", stdout); + br--; + } + break; + case '\r': + case '\n': + fputs("\r\n", stdout); + buf[br++] = '\n'; + break; + case ' '...'~': + fputc(c, stdout); + buf[br++] = c; + break; + break; + default: + break; + } + if (c == -1) + { + if (br == 0) + buf = NULL; + break; + } + if (c == '\r' || c == '\n') + break; + } + if (buf) + buf[br] = 0; + + tcsetattr(fileno(f), TCSADRAIN, &orig_tios); + return buf; +} + +#define MAX_LINE_LEN 4096 +int io(void) +{ + const char delim1[] = "\r\n;"; + const char delim2[] = "\t "; + char line[MAX_LINE_LEN]; + char *command, *cmd, *paddr, *pval, *plen, *endptr; + char *tmp_s1, *tmp_s2; + unsigned long addr; + uint32_t val; + size_t len; + int (*fn)(unsigned long, uint32_t, size_t); + + if (!quiet) + fputs("> ", stdout); + while (readline(line, MAX_LINE_LEN, stdin) != NULL && *line) + { + /* read next line or next command (up to newline or ';') */ + command = strtok_r(line, delim1, &tmp_s1); + if (!command || strlen(command) == 0) + goto _command_loop; + while (NULL != command && strlen(command) > 0) + { + cmd = strtok_r(command, delim2, &tmp_s2); + if (!cmd) + goto _cmd_err; + if (cmd[0] == 'q' || cmd[0] == 'Q') + return 0; + paddr = strtok_r(NULL, delim2, &tmp_s2); + if (!paddr) + goto _cmd_err; + addr = strtoul(paddr, &endptr, 16); + if (*endptr) + goto _cmd_err; + fn = NULL; + if (strncmp(cmd, "mw", 3) == 0) + { + fn = mw; + pval = strtok_r(NULL, delim2, &tmp_s2); + if (!pval) + goto _cmd_err; + val = strtoul(pval, &endptr, 16); + if (*endptr) + goto _cmd_err; + len = 1; + } + else if (strncmp(cmd, "md", 3) == 0) + { + fn = md; + len = 0x40; + val = 0; + } + else + { + goto _cmd_err; + } + plen = strtok_r(NULL, delim2, &tmp_s2); + if (plen) + { + len = strtoul(plen, &endptr, 16); + if (*endptr) + goto _cmd_err; + } + + if (fn) + fn(addr, val, len); + + command = strtok_r(NULL, delim1, &tmp_s1); + } +_command_loop: + if (!quiet) + fputs("> ", stderr); + continue; +_cmd_err: + fprintf(stderr, "md addr [len]\nmw addr val [len]\n" + "q[uit] | ctrl-d | ctrl-c to exit\n"); + if (!quiet) + fputs("> ", stderr); + } + return 0; +} + +typedef enum +{ + CPU_NONE = 0, + CPU_PILOT3, + CPU_PILOT4, + CPU_AST2500, + CPU_AST2600, + CPU_MAX, +} CPU_TYPE; + +static CPU_TYPE probe_cpu(void) +{ + FILE *f; + char cpuinfo[128]; + static CPU_TYPE this_cpu = CPU_NONE; + + if (CPU_NONE == this_cpu) + { + f = fopen("/sys/firmware/devicetree/base/compatible", "r"); + if (f) { + int br = fread(cpuinfo, 1, sizeof(cpuinfo)-1, f); + if (br > 0) { + cpuinfo[br] = 0; + char *v = cpuinfo; + while (v < (cpuinfo + sizeof(cpuinfo)) && *v) { + if (strncmp("aspeed,ast2500", v, 15) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + } + v += 1 + strnlen(v, sizeof(cpuinfo) - (v - cpuinfo)); + } + } + fclose(f); + } + } + if (CPU_NONE == this_cpu) + { + const char delim[] = "\r\n\t :"; + char *tmp_s; + f = fopen("/proc/cpuinfo", "r"); + if (f != NULL) { + while (fgets(cpuinfo, sizeof(cpuinfo), f)) + { + strtok_r(cpuinfo, delim, &tmp_s); + if (strncmp("Hardware", cpuinfo, 9) == 0) + { + char *v = strtok_r(NULL, delim, &tmp_s); + if (v) + { + if (strncmp("AST2500", v, 8) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + break; + } + else if (strncmp("ASpeed SoC", v, 11) == 0) + { + if (!quiet) + fprintf(stderr, "Found ASpeed SoC\n"); + this_cpu = CPU_AST2500; + break; + } + else if (strncmp("ServerEngines PILOT3", v, 21) == 0) + { + if (!quiet) + fprintf(stderr, "Found PILOT3\n"); + this_cpu = CPU_PILOT3; + break; + } + } + } + else if (strncmp("CPU", cpuinfo, 4) == 0) + { + char *v = strtok_r(NULL, delim, &tmp_s); + if (!v || strncmp("part", v, 5) != 0) + { + continue; + } + v = strtok_r(NULL, delim, &tmp_s); + if (v) + { + if (strncmp("0xb76", v, 6) == 0) + { + if (!quiet) + fprintf(stderr, "AST2500\n"); + this_cpu = CPU_AST2500; + break; + } + else if (strncmp("0xc07", v, 6) == 0) + { + if (!quiet) + fprintf(stderr, "AST2600\n"); + this_cpu = CPU_AST2600; + break; + } + } + } + } + fclose(f); + } + } + return this_cpu; +} + +static const char *probe_cpu_for_map(void) +{ + switch (probe_cpu()) + { + case CPU_PILOT3: + return "0:2000000,10000000:8000,40000000:43b000"; + case CPU_AST2500: + return "0:4000000,1e600000:1a0000,20000000:4000000"; + case CPU_AST2600: + return "0:20000000,38000000:8000000,60000000:20000000"; + default: + return ""; + } +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: io [-c config] [-m map]\n" + " md [-c config] [-m map] <addr> [len]\n" + " mw [-c config] [-m map] <addr> <val> [len]\n\n" + "With: -c config load mappings from file config\n" + " -m map load mappings from string map\n" + " addr, val, len are all hex numbers\n\n" + "When invoked as io, this will start a shell that will\n" + "allow the user to type in md and mw commands much like\n" + "the U-Boot environment. By default, it will map in all\n" + "the addresses for the known processor type.\n\n" + "map string is of the format addr:len[,addr2:len2...]\n" + "config file is of the same format as map string\n" + "but with each mapping on separate lines instead of\n" + "comma separated values\n" + ); + exit(1); +} + +#define shift if (++i >= argc) usage() + +int main(int argc, const char *argv[]) +{ + char *exe_full; + char *exe; + char *endptr; + int i, first_arg = 1; + const char *cfg_file = NULL; + const char *map_str = NULL; + size_t flen = 0; + size_t len = 0; + unsigned long addr; + uint32_t val; + int ret = 0; + + i = 1; + while (i < argc) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'm': + shift; + map_str = argv[i]; + break; + case 'c': + shift; + cfg_file = argv[i]; + break; + default: + usage(); + } + } + else + { + first_arg = i; + break; + } + } + + exe_full = strdup(argv[0]); + if (exe_full != NULL ) + exe = basename(exe_full); + else + return ret; + + if (strncmp(exe, "io", 3) != 0 || !isatty(fileno(stdin))) + quiet = 1; + + if (!map_str) + { + if (!cfg_file) + map_str = probe_cpu_for_map(); + else + map_str = map_file(cfg_file, &flen, PROT_READ, MAP_PRIVATE); + } + else + { + flen = strlen(map_str); + } + if (load_maps(map_str, flen) < 0) + { + fprintf(stderr, "failed to map regions: check map string or config file\n"); + goto _cleanup; + } + + if (strncmp(exe, "md", 3) == 0) + { + len = 0x40; + addr = strtoul(argv[first_arg], &endptr, 16); + if ((first_arg + 1) < argc) + { + len = strtoul(argv[first_arg + 1], &endptr, 16); + } + ret = md(addr, 0, len); + goto _cleanup; + } + + if (strncmp(exe, "mw", 3) == 0) + { + len = 1; + addr = strtoul(argv[first_arg], &endptr, 16); + if ((first_arg + 1) < argc) + { + val = strtoul(argv[first_arg + 1], &endptr, 16); + } + else + { + usage(); + } + if ((first_arg + 2) < argc) + { + len = strtoul(argv[first_arg + 2], &endptr, 16); + } + ret = mw(addr, val, len); + goto _cleanup; + } + + io(); + +_cleanup: + unmap_all(); + free(exe_full); + return ret; +} diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb new file mode 100644 index 000000000..5ac0f0a75 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb @@ -0,0 +1,17 @@ +SUMMARY = "IO App" +DESCRIPTION = "IO application for accessing memory-mapped IO regions on the BMC" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM += "\ + file://io-app.c;beginline=2;endline=14;md5=639666a0bf40bb717b46b378297eeceb \ + " + +SRC_URI = "\ + file://CMakeLists.txt \ + file://io-app.c \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt new file mode 100644 index 000000000..1cde22b49 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR) +project(lpc-cmds C) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +add_executable(lpc_cmds lpc_cmds.c) +install (TARGETS lpc_cmds DESTINATION bin) + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c new file mode 100644 index 000000000..bc215f60b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c @@ -0,0 +1,528 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +*/ + +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include "lpc_drv.h" + +#define SIO_DEVICE_NAME "/dev/lpc-sio" +#define KCS_DEVICE_NAME "/dev/ipmi-kcs" +#define MAILBOX_DEVICE_NAME "/dev/aspeed-mbox" +#define SNOOP_DEVICE_NAME "/dev/aspeed-lpc-snoop" + +#define SNOOP_BUF_SIZE 4096 + +#define SUPPORT_KCS_ADDR_CMD 0 +#define SUPPORT_MAILBOX 1 +#define SUPPORT_SNOOP 1 + +/*********************************************************************************/ +static void ProcessKCSReq(int fd, unsigned char *pReq, int ReqLen, int NoPrint) +{ + int i; + unsigned char SendPkt[16]; + + if (!NoPrint) { + printf("\nKCS Request >>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + for (i = 0; i < ReqLen; i++) + printf("%02X ", pReq[i]); + printf("\n======================================\n"); + } + + SendPkt[0] = pReq[0] | 0x04; + SendPkt[1] = pReq[1]; + SendPkt[2] = 0xC1; /* Always Invalid Command */ + + if (!NoPrint) { + printf("\nKCS Response <<<<<<<<<<<<<<<<<<<<<<<<<\n"); + for (i = 0; i < 3; i++) + printf("%02X ", SendPkt[i]); + printf("\n======================================\n"); + } + + write(fd, SendPkt, 3); +} + +static void KCSIfcTask(int KCSIfcIdx, int NoPrint) +{ + int fd; + int RecvPktLen; + char KCSDev[16]; + struct kcs_ioctl_data IOData; + unsigned char RecvPkt[512]; + + snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx); + fd = open(KCSDev, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open KCS device: %s\n", KCSDev); + exit(1); + } + + IOData.cmd = KCS_FORCE_ABORT; + IOData.data = 0; + ioctl(fd, KCS_IOC_COMMAND, &IOData); + + while (1) { + RecvPktLen = read(fd, RecvPkt, sizeof(RecvPkt)); + if (RecvPktLen < 2) + continue; + + ProcessKCSReq(fd, RecvPkt, RecvPktLen, NoPrint); + } +} + +#if SUPPORT_KCS_ADDR_CMD +static void KCSIfcSetAddr(int KCSIfcIdx, unsigned int addr) +{ + int fd; + struct kcs_ioctl_data kcs_data; + char KCSDev[16]; + + snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx); + fd = open(KCSDev, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open KCS device: %s\n", KCSDev); + exit(1); + } + + kcs_data.cmd = KCS_SET_ADDR; + kcs_data.data = addr; + if (ioctl(fd, KCS_IOC_COMMAND, &kcs_data) == 0) + printf("Set KCS%d addr to 0x%X successfully!\n", KCSIfcIdx + 1, addr); + + close(fd); +} + +static void KCSIfcGetAddr(int KCSIfcIdx) +{ + int fd; + struct kcs_ioctl_data kcs_data; + char KCSDev[16]; + + snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx); + fd = open(KCSDev, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open KCS device: %s\n", KCSDev); + exit(1); + } + + kcs_data.cmd = KCS_GET_ADDR; + if (ioctl(fd, KCS_IOC_COMMAND, &kcs_data) == 0) + printf("KCS%d addr is : 0x%X!\n", KCSIfcIdx + 1, kcs_data.data); + + close(fd); +} +#endif + +/*********************************************************************************/ + +#if SUPPORT_SNOOP +static void ReadBiosPOSTCodes(unsigned int if_idx) +{ + char snoop_dev[32]; + int fd; + int i; + unsigned char buf[SNOOP_BUF_SIZE]; + int len; + + snprintf(snoop_dev, sizeof(snoop_dev), SNOOP_DEVICE_NAME"%d", if_idx); + fd = open(snoop_dev, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s !\n", snoop_dev); + return; + } + + len = read(fd, &buf, sizeof(buf)); + + if (len == 0 || errno == EAGAIN) { + printf("No BIOS POST Codes Found!\n"); + goto out; + } else if (len < 0) { + printf("Failed to read the POST Codes! (%s)\n", + strerror(errno)); + goto out; + } + + printf("BIOS POST Codes in Hex (%d entries):\n", len); + + for (i = 0; i < len; i++) + printf(" %d: %02X\n", i, buf[i]); + + printf("\n"); + +out: + close(fd); +} +#endif + +/*********************************************************************************/ + +static void SIOGetACPIState(unsigned short changed) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_ACPI_STATE; + sio_data.param = changed; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) { + if (changed) + printf("ACPI SLP state is %s!\n", + sio_data.param != 0 ? "Changed" : "Same"); + + if (sio_data.data == ACPI_STATE_S12) + printf("ACPI SLP state --> SLP_12\n"); + else if (sio_data.data == ACPI_STATE_S3I) + printf("ACPI SLP state --> SLP_3I\n"); + else if (sio_data.data == ACPI_STATE_S45) + printf("ACPI SLP state --> SLP_45\n"); + } + + close(fd); +} + +static void SIOGetPWRGDStatus(unsigned short changed) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_PWRGD_STATUS; + sio_data.param = changed; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) { + if (changed) + printf("PWRGD status : %s\n", + sio_data.param != 0 ? "Changed" : "Same"); + + printf("PWRGD status value :%u\n", sio_data.data); + } + + close(fd); +} + +static void SIOGetONCTLStatus(void) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_ONCTL_STATUS; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("ONCTL status value :%u\n", sio_data.data); + + close(fd); +} + +static void SIOSetONCTLGPIO(unsigned short enable, unsigned int value) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_SET_ONCTL_GPIO; + sio_data.param = enable; + sio_data.data = value; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("ONCTL GPIO mode setting is Done!\n"); + + close(fd); +} + +static void SIOGetPWRBTNOverride(unsigned short clear) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_PWRBTN_OVERRIDE; + sio_data.param = clear; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("PWRBTN Override status : %u\n", sio_data.data); + + close(fd); +} + +static void SIOGetPFailStatus() +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_GET_PFAIL_STATUS; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("PFail status : %u\n", sio_data.data); + + close(fd); +} + +static void SIOSetBMCSCIEvent(unsigned short set) +{ + int fd; + struct sio_ioctl_data sio_data; + + fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC); + if (fd < 0) { + printf("Error open %s\n", SIO_DEVICE_NAME); + exit(1); + } + + sio_data.sio_cmd = SIO_SET_BMC_SCI_EVENT; + sio_data.param = set; + + if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) + printf("BMC SCI event is %s\n", + sio_data.data ? "set" : "cleared"); + + close(fd); +} + +/*********************************************************************************/ + +#if SUPPORT_MAILBOX +static void MailBoxRead(int num) +{ + int fd; + int len; + uint8_t data; + + fd = open(MAILBOX_DEVICE_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + printf("Error open mailbox\n"); + exit(1); + } + + len = pread(fd, &data, 1, num); + if (len == 0 || errno == EAGAIN) { + printf("No mailbox message found!\n"); + goto out; + } else if (len < 0) { + printf("Error reading from mailbox%d! (%s)\n", num, + strerror(errno)); + goto out; + } + + printf("MailBox%d read value : 0x%02X\n", num, data); + +out: + close(fd); +} + +static void MailBoxWrite(int num, uint8_t value) +{ + int fd; + ssize_t rc; + + fd = open(MAILBOX_DEVICE_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + printf("Error open mailbox\n"); + exit(1); + } + + rc = pwrite(fd, &value, 1, num); + + if (rc == 1) + printf("MailBox%d write value : 0x%02X done!\n", num, value); + else + printf("Error writing to mailbox%d, rc: %d\n", num, rc); + + close(fd); +} +#endif + +/*********************************************************************************/ + +static void usage(void) +{ + printf("Usage:\n" + "\tlpc_cmds sio get_acpi_state\n" + "\tlpc_cmds sio get_acpi_changed\n" + "\tlpc_cmds sio get_pwrgd_status\n" + "\tlpc_cmds sio get_pwrgd_changed\n" + "\tlpc_cmds sio get_onctl_status\n" + "\tlpc_cmds sio set_onctl_gpio_disable\n" + "\tlpc_cmds sio set_onctl_gpio_high\n" + "\tlpc_cmds sio set_onctl_gpio_low\n" + "\tlpc_cmds sio get_pwrbtn_override_status\n" + "\tlpc_cmds sio get_pwrbtn_override_status_clear\n" + "\tlpc_cmds sio get_pfail_status\n" + "\tlpc_cmds sio set_bmc_sci_event\n" + "\tlpc_cmds sio clear_bmc_sci_event\n" + "\n" +#if SUPPORT_KCS_ADDR_CMD + "\tlpc_cmds kcs [1 ~ 4] (getaddr / setaddr / quiet)\n" +#else + "\tlpc_cmds kcs [1 ~ 4] (quiet)\n" +#endif +#if SUPPORT_MAILBOX + "\n" + "\tlpc_cmds mailbox read (0 ~ 15)\n" + "\tlpc_cmds mailbox write (0 ~ 15) (0x00 ~ 0xFF)\n" +#endif +#if SUPPORT_SNOOP + "\n" + "\tlpc_cmds snoop [0 ~ 1] read\n" +#endif + ); + + exit(-1); +} + +int main(int argc, char** argv) +{ + char *cmd; + + if (argc < 2) + usage(); + + cmd = argv[1]; + + if (strcmp(cmd, "sio") == 0) { + if (argc < 3) + usage(); + + if (strcmp(argv[2], "get_acpi_state") == 0) + SIOGetACPIState(0); + else if (strcmp(argv[2], "get_acpi_changed") == 0) + SIOGetACPIState(1); + else if (strcmp(argv[2], "get_pwrgd_status") == 0) + SIOGetPWRGDStatus(0); + else if (strcmp(argv[2], "get_pwrgd_changed") == 0) + SIOGetPWRGDStatus(1); + else if (strcmp(argv[2], "get_onctl_status") == 0) + SIOGetONCTLStatus(); + else if (strcmp(argv[2], "set_onctl_gpio_disable") == 0) + SIOSetONCTLGPIO(0, 0); + else if (strcmp(argv[2], "set_onctl_gpio_high") == 0) + SIOSetONCTLGPIO(1, 1); + else if (strcmp(argv[2], "set_onctl_gpio_low") == 0) + SIOSetONCTLGPIO(1, 0); + else if (strcmp(argv[2], "get_pwrbtn_override_status") == 0) + SIOGetPWRBTNOverride(0); + else if (strcmp(argv[2], "get_pwrbtn_override_status_clear") == 0) + SIOGetPWRBTNOverride(1); + else if (strcmp(argv[2], "get_pfail_status") == 0) + SIOGetPFailStatus(); + else if (strcmp(argv[2], "set_bmc_sci_event") == 0) + SIOSetBMCSCIEvent(1); + else if (strcmp(argv[2], "clear_bmc_sci_event") == 0) + SIOSetBMCSCIEvent(0); + } else if (strcmp(cmd, "kcs") == 0) { + int ifc; + + if (argc < 3) + usage(); + + ifc = atoi(argv[2]); + if (ifc < 1 || ifc > 4) /* ipmi-kcs1 ~ ipmi-kcs4 */ + usage(); + + if (argc == 3) + KCSIfcTask(ifc, 0); + else if (argc == 4 && strcmp(argv[3], "quiet") == 0) + KCSIfcTask(ifc, 1); +#if SUPPORT_KCS_ADDR_CMD + else if (argc == 4 && strcmp(argv[3], "getaddr") == 0) + KCSIfcGetAddr(ifc); + else if (argc == 5 && strcmp(argv[3], "setaddr") == 0) + KCSIfcSetAddr(ifc, strtoul(argv[4], NULL, 16)); +#endif +#if SUPPORT_MAILBOX + } else if (strcmp(cmd, "mailbox") == 0) { + if (argc < 4) + usage(); + + if (strcmp(argv[2], "read") == 0) { + MailBoxRead(atoi(argv[3])); + } else { + if (argc < 5) + usage(); + MailBoxWrite(atoi(argv[3]), strtoul(argv[4], NULL, 16)); + } +#endif +#if SUPPORT_SNOOP + } else if (strcmp(cmd, "snoop") == 0) { + int ifc; + + if (argc < 3) + usage(); + + ifc = atoi(argv[2]); + if (ifc < 0 || ifc > 1) /* snoop0 ~ snoop1 */ + usage(); + + if (strcmp(argv[3], "read") == 0) + ReadBiosPOSTCodes(ifc); + else + usage(); +#endif + } + + return 0; +} + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h new file mode 100644 index 000000000..793e8b49c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h @@ -0,0 +1,79 @@ +/* +// Copyright (c) 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +*/ + +#ifndef __LPC_DRV_H__ +#define __LPC_DRV_H__ + +#define LPC_DEV_MAJOR 250 +#define LPC_DEV_MINOR 0 + +/***********************************************************************************/ + +enum KCS_CMD { + KCS_SET_ADDR = 0, + KCS_GET_ADDR, + KCS_SMS_ATN, + KCS_FORCE_ABORT, +}; + +struct kcs_ioctl_data { + unsigned int cmd; + unsigned int data; +}; + +#define KCS_IOC_BASE 'K' +#define KCS_IOC_COMMAND _IOWR(KCS_IOC_BASE, 1, struct kcs_ioctl_data) + +/***********************************************************************************/ + +enum ACPI_SLP_STATE { + ACPI_STATE_S12 = 1, + ACPI_STATE_S3I, + ACPI_STATE_S45 +}; + +/* SWC & ACPI for SuperIO IOCTL */ +enum SIO_CMD { + SIO_GET_ACPI_STATE = 0, + SIO_GET_PWRGD_STATUS, + SIO_GET_ONCTL_STATUS, + SIO_SET_ONCTL_GPIO, + SIO_GET_PWRBTN_OVERRIDE, + SIO_GET_PFAIL_STATUS, /* Start from AC Loss */ + SIO_SET_BMC_SCI_EVENT, + + SIO_MAX_CMD +}; + +struct sio_ioctl_data { + unsigned short sio_cmd; + unsigned short param; + unsigned int data; +}; + +#define SIO_IOC_BASE 'P' +#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data) + +/***********************************************************************************/ + +#define MAX_MAILBOX_NUM 16 + +/***********************************************************************************/ + +#endif + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb new file mode 100644 index 000000000..38489263b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb @@ -0,0 +1,16 @@ +SUMMARY = "LPC tools" +DESCRIPTION = "command tool for LPC interface test on the BMC" + +inherit cmake + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658" + +SRC_URI = "\ + file://CMakeLists.txt \ + file://lpc_drv.h \ + file://lpc_cmds.c \ + " + +S = "${WORKDIR}" + diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py new file mode 100755 index 000000000..977fcd3a0 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py @@ -0,0 +1,144 @@ +#!/usr/bin/python + +import glob +import os +import sys +import time + +if len(sys.argv) == 1: + cpuno = 0 +else: + cpuno = int(sys.argv[1]) + +hwmon_path = '/sys/class/hwmon' +cputemp_name_match = '{}{}'.format('peci_cputemp.cpu', cpuno) +dimmtemp_name_match = '{}{}'.format('peci_dimmtemp.cpu', cpuno) + +dimmtemp_path = '' + +os.chdir(hwmon_path) + +for dirpath, dirnames, files in os.walk(hwmon_path): + for d in dirnames: + try: + with open('{}/{}'.format(d, 'name')) as f: + hwmon_name = f.read().strip() + if hwmon_name == cputemp_name_match: + cputemp_path = os.path.abspath(d) + cputemp_name = hwmon_name + elif hwmon_name == dimmtemp_name_match: + dimmtemp_path = os.path.abspath(d) + dimmtemp_name = hwmon_name + except: + continue + +if not cputemp_path: + print "Can't find the " + cputemp_name_match + quit() + +try: + while True: + os.system('clear') + os.chdir(cputemp_path) + + print '{}/{}: {}'.format(hwmon_path, cputemp_path, cputemp_name) + if dimmtemp_path: + print '{}/{}: {}'.format(hwmon_path, dimmtemp_path, dimmtemp_name) + + print + print 'Package temperature' + for input in glob.glob('temp[1-5]_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print '{:11s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000)) + + print + print 'Core temperature' + count = 0 + for input in glob.glob('temp[!1-5]_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + for input in glob.glob('temp??_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + print + + if dimmtemp_path: + os.chdir(dimmtemp_path) + print + print 'DIMM temperature' + count = 0 + for input in glob.glob('temp*_input'): + try: + with open(input) as f: + val = f.read().strip() + except IOError: + val = 0 + try: + with open(input.replace('input', 'label')) as l: + name = l.read().strip() + except IOError: + name = '' + print ('{:9s}:{:3d}.{:03d}'.format( + name, (int(val) / 1000), (int(val) % 1000))), + count += 1 + if count % 3 == 0: + print + else: + print ('\t'), + print + else: + os.chdir(hwmon_path) + for dirpath, dirnames, files in os.walk(hwmon_path): + for d in dirnames: + try: + with open('{}/{}'.format(d, 'name')) as f: + hwmon_name = f.read().strip() + if hwmon_name == dimmtemp_name_match: + dimmtemp_path = os.path.abspath(d) + dimmtemp_name = hwmon_name + except: + continue + + time.sleep(1) +except KeyboardInterrupt: + print " exiting..." diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb new file mode 100644 index 000000000..b3b4096a6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb @@ -0,0 +1,20 @@ +SUMMARY = "PECI hwmon test tool" +DESCRIPTION = "command line python tool for testing PECI hwmon" + +SRC_URI = "\ + file://peci-hwmon-test.py \ + " +LICENSE = "CLOSED" + +RDEPENDS_${PN} += "python" + +S = "${WORKDIR}" + +do_compile () { +} + +do_install () { + install -d ${D}/${bindir} + install -m 0755 ${WORKDIR}/peci-hwmon-test.py ${D}/${bindir} +} + diff --git a/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend new file mode 100755 index 000000000..0f84062d1 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend @@ -0,0 +1,3 @@ +# Enable downstream autobump +SRC_URI = "git://github.com/openbmc/x86-power-control.git;protocol=ssh" +SRCREV = "e7520ba18a5b5ba6c8eb7a9d543704f9699295a1" |