diff --git a/packages/lang/gcc-or1k-linux/package.mk b/packages/lang/gcc-or1k-linux/package.mk new file mode 100644 index 0000000000..fa0f7ca9df --- /dev/null +++ b/packages/lang/gcc-or1k-linux/package.mk @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="gcc-or1k-linux" +PKG_VERSION="2020.08-1" +PKG_SHA256="697ef122917022f400003931bc6da75fe07bb5234ef8186cbe027e560f04a168" +PKG_LICENSE="GPL" +PKG_SITE="https://toolchains.bootlin.com/releases_openrisc.html" +PKG_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/openrisc/tarballs/openrisc--musl--stable-${PKG_VERSION}.tar.bz2" +PKG_DEPENDS_HOST="ccache:host" +PKG_LONGDESC="OpenRISC 1000 GNU Linux Binary Toolchain" +PKG_TOOLCHAIN="manual" + +makeinstall_host() { + mkdir -p $TOOLCHAIN/lib/gcc-or1k-linux/ + cp -a * $TOOLCHAIN/lib/gcc-or1k-linux + + # wrap gcc and g++ with ccache like in gcc package.mk + PKG_GCC_PREFIX="$TOOLCHAIN/lib/gcc-or1k-linux/bin/or1k-linux-" + + rm -f "${PKG_GCC_PREFIX}gcc" +cat > "${PKG_GCC_PREFIX}gcc" << EOF +#!/bin/sh +$TOOLCHAIN/bin/ccache $TOOLCHAIN/lib/gcc-or1k-linux/bin/or1k-buildroot-linux-musl-gcc "\$@" +EOF + + chmod +x "${PKG_GCC_PREFIX}gcc" + + rm -f "${PKG_GCC_PREFIX}g++" +cat > "${PKG_GCC_PREFIX}g++" << EOF +#!/bin/sh +$TOOLCHAIN/bin/ccache $TOOLCHAIN/lib/gcc-or1k-linux/bin/or1k-buildroot-linux-musl-g++ "\$@" +EOF + + chmod +x "${PKG_GCC_PREFIX}g++" +} diff --git a/packages/linux/package.mk b/packages/linux/package.mk index 85f82bd0e9..7bc1a1f984 100644 --- a/packages/linux/package.mk +++ b/packages/linux/package.mk @@ -31,6 +31,10 @@ esac PKG_KERNEL_CFG_FILE=$(kernel_config_path) || die +if [ -n "$($ROOT/$SCRIPTS/uboot_helper $PROJECT $DEVICE $UBOOT_SYSTEM crust_config)" ]; then + PKG_PATCH_DIRS="$PKG_PATCH_DIRS crust" +fi + if [ -n "$KERNEL_TOOLCHAIN" ]; then PKG_DEPENDS_HOST="$PKG_DEPENDS_HOST gcc-arm-$KERNEL_TOOLCHAIN:host" PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET gcc-arm-$KERNEL_TOOLCHAIN:host" diff --git a/packages/tools/atf/package.mk b/packages/tools/atf/package.mk index d412e3ec3d..c0414c73b5 100644 --- a/packages/tools/atf/package.mk +++ b/packages/tools/atf/package.mk @@ -2,8 +2,8 @@ # Copyright (C) 2018-present Team LibreELEC PKG_NAME="atf" -PKG_VERSION="2.2" -PKG_SHA256="07e3c058ae2d95c7d516a46fc93565b797e912c3271ddbf29df523b1ab1ee911" +PKG_VERSION="2.4" +PKG_SHA256="4bfda9fdbe5022f2e88ad3344165f7d38a8ae4a0e2d91d44d9a1603425cc642d" PKG_ARCH="arm aarch64" PKG_LICENSE="BSD-3c" PKG_SITE="https://github.com/ARM-software/arm-trusted-firmware" diff --git a/packages/tools/crust/package.mk b/packages/tools/crust/package.mk new file mode 100644 index 0000000000..edef7066e9 --- /dev/null +++ b/packages/tools/crust/package.mk @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="crust" +PKG_VERSION="18f74f493690844a4392dc28d879abd4ba995513" +PKG_SHA256="7b8f004933054b6f394db532bf16fd9c3b42bd606f3e603f162f358436c4c3d8" +PKG_ARCH="arm aarch64" +PKG_LICENSE="BSD-3c" +PKG_SITE="https://github.com/crust-firmware/crust" +PKG_URL="https://github.com/crust-firmware/crust/archive/${PKG_VERSION}.tar.gz" +PKG_DEPENDS_TARGET="gcc-or1k-linux:host" +PKG_LONGDESC="Crust: Libre SCP firmware for Allwinner sunxi SoCs" +PKG_TOOLCHAIN="manual" + +pre_configure_target() { + export CROSS_COMPILE="$TOOLCHAIN/lib/gcc-or1k-linux/bin/or1k-linux-" +} + +make_target() { + CRUST_CONFIG=$($ROOT/$SCRIPTS/uboot_helper $PROJECT $DEVICE $UBOOT_SYSTEM crust_config) + + if [ -z "$CRUST_CONFIG" ]; then + echo "crust_config must be set to build an image" + echo "see './scripts/uboot_helper' for more information" + exit 1 + fi + + make distclean + if [ "${BUILD_WITH_DEBUG}" = "yes" ]; then + echo "CONFIG_DEBUG_LOG=y" >> configs/$CRUST_CONFIG + else + echo "CONFIG_SERIAL=n" >> configs/$CRUST_CONFIG + fi + # Boards with a PMIC need to disable CONFIG_PMIC_SHUTDOWN to get CIR wakeup from suspend + echo "CONFIG_PMIC_SHUTDOWN=n" >> configs/$CRUST_CONFIG + make $CRUST_CONFIG + make scp +} + +makeinstall_target() { + mkdir -p $INSTALL/usr/share/bootloader + cp -a build/scp/scp.bin $INSTALL/usr/share/bootloader +} diff --git a/packages/tools/u-boot/package.mk b/packages/tools/u-boot/package.mk index 3ce227381a..54c791a951 100644 --- a/packages/tools/u-boot/package.mk +++ b/packages/tools/u-boot/package.mk @@ -18,6 +18,9 @@ if [ -n "$UBOOT_FIRMWARE" ]; then PKG_DEPENDS_UNPACK+=" $UBOOT_FIRMWARE" fi +CRUST_CONFIG=$($ROOT/$SCRIPTS/uboot_helper $PROJECT $DEVICE $UBOOT_SYSTEM crust_config) +[ -n "$CRUST_CONFIG" ] && PKG_DEPENDS_TARGET+=" crust" + PKG_NEED_UNPACK="$PROJECT_DIR/$PROJECT/bootloader" [ -n "$DEVICE" ] && PKG_NEED_UNPACK+=" $PROJECT_DIR/$PROJECT/devices/$DEVICE/bootloader" @@ -29,8 +32,8 @@ case "$PROJECT" in PKG_PATCH_DIRS="rockchip" ;; *) - PKG_VERSION="v2020.10" - PKG_SHA256="0c022ca6796aa8c0689faae8b515eb62ac84519c31de3153257a9ee0f446618f" + PKG_VERSION="v2021.01-rc4" + PKG_SHA256="9e05a96f0cac4f8b6fdea5cdf10f0d814e6a0d7141243a6eb9862385c7ddeb14" PKG_URL="https://github.com/u-boot/u-boot/archive/$PKG_VERSION.tar.gz" ;; esac @@ -50,7 +53,8 @@ make_target() { echo "see './scripts/uboot_helper' for more information" else [ "${BUILD_WITH_DEBUG}" = "yes" ] && PKG_DEBUG=1 || PKG_DEBUG=0 - [ -n "$UBOOT_FIRMWARE" ] && find_file_path bootloader/firmware && . ${FOUND_PATH} + [ -n "$ATF_PLATFORM" ] && cp -av $(get_install_dir atf)/usr/share/bootloader/bl31.bin . + [ -n "$CRUST_CONFIG" ] && cp -av $(get_install_dir crust)/usr/share/bootloader/scp.bin . DEBUG=${PKG_DEBUG} CROSS_COMPILE="$TARGET_KERNEL_PREFIX" LDFLAGS="" ARCH=arm make mrproper DEBUG=${PKG_DEBUG} CROSS_COMPILE="$TARGET_KERNEL_PREFIX" LDFLAGS="" ARCH=arm make $($ROOT/$SCRIPTS/uboot_helper $PROJECT $DEVICE $UBOOT_SYSTEM config) DEBUG=${PKG_DEBUG} CROSS_COMPILE="$TARGET_KERNEL_PREFIX" LDFLAGS="" ARCH=arm _python_sysroot="$TOOLCHAIN" _python_prefix=/ _python_exec_prefix=/ make $UBOOT_TARGET HOSTCC="$HOST_CC" HOSTLDFLAGS="-L$TOOLCHAIN/lib" HOSTSTRIP="true" CONFIG_MKIMAGE_DTC_PATH="scripts/dtc/dtc" diff --git a/projects/Allwinner/bootloader/firmware b/projects/Allwinner/bootloader/firmware deleted file mode 100644 index 51142b4b91..0000000000 --- a/projects/Allwinner/bootloader/firmware +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) - -[ -n "$ATF_PLATFORM" ] && cp -av $(get_install_dir atf)/usr/share/bootloader/bl31.bin . diff --git a/projects/Allwinner/patches/linux/crust/0001-i2c-mv64xxx-Add-runtime-PM-support.patch b/projects/Allwinner/patches/linux/crust/0001-i2c-mv64xxx-Add-runtime-PM-support.patch new file mode 100644 index 0000000000..83b597f1d9 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0001-i2c-mv64xxx-Add-runtime-PM-support.patch @@ -0,0 +1,137 @@ +From 49d3e172a2e06e7670c508e1d960282d40e7237e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Wed, 12 Feb 2020 22:58:30 -0600 +Subject: [PATCH 01/31] i2c: mv64xxx: Add runtime PM support + +To save power, gate the clock when the bus is inactive, and during +system suspend. Also reset the controller during system suspend, since +it may be used by platform firmware, and we don't want to make any +assumptions about the hardware state at resume. + +On some platforms, specifically Allwinner A13/A20, gating the clock +implicitly resets the module as well. Since the module already needs to +be reset after some suspend/resume cycles, it is simple enough to reset +it during every runtime suspend/resume. + +Because the bus may be used by wakeup source IRQ threads, it needs to be +functional as soon as IRQs are enabled. Thus, its system PM hooks need +to run in the noirq phase. + +Signed-off-by: Samuel Holland +--- + drivers/i2c/busses/i2c-mv64xxx.c | 52 ++++++++++++++++++++++++++------ + 1 file changed, 42 insertions(+), 10 deletions(-) + +--- a/drivers/i2c/busses/i2c-mv64xxx.c ++++ b/drivers/i2c/busses/i2c-mv64xxx.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -713,6 +714,10 @@ mv64xxx_i2c_xfer(struct i2c_adapter *ada + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + int rc, ret = num; + ++ rc = pm_runtime_get_sync(&adap->dev); ++ if (rc < 0) ++ return rc; ++ + BUG_ON(drv_data->msgs != NULL); + drv_data->msgs = msgs; + drv_data->num_msgs = num; +@@ -728,6 +733,9 @@ mv64xxx_i2c_xfer(struct i2c_adapter *ada + drv_data->num_msgs = 0; + drv_data->msgs = NULL; + ++ pm_runtime_mark_last_busy(&adap->dev); ++ pm_runtime_put_autosuspend(&adap->dev); ++ + return ret; + } + +@@ -950,6 +958,11 @@ mv64xxx_i2c_probe(struct platform_device + goto exit_free_irq; + } + ++ pm_runtime_set_active(&pd->dev); ++ pm_runtime_set_autosuspend_delay(&pd->dev, 1000); ++ pm_runtime_use_autosuspend(&pd->dev); ++ pm_runtime_enable(&pd->dev); ++ + return 0; + + exit_free_irq: +@@ -968,40 +981,59 @@ mv64xxx_i2c_remove(struct platform_devic + { + struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(dev); + ++ pm_runtime_get_sync(&dev->dev); ++ + i2c_del_adapter(&drv_data->adapter); + free_irq(drv_data->irq, drv_data); + reset_control_assert(drv_data->rstc); + clk_disable_unprepare(drv_data->reg_clk); + clk_disable_unprepare(drv_data->clk); + ++ pm_runtime_put_noidle(&dev->dev); ++ pm_runtime_disable(&dev->dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused mv64xxx_i2c_runtime_suspend(struct device *dev) ++{ ++ struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); ++ ++ reset_control_assert(drv_data->rstc); ++ clk_disable_unprepare(drv_data->reg_clk); ++ clk_disable_unprepare(drv_data->clk); ++ + return 0; + } + +-#ifdef CONFIG_PM +-static int mv64xxx_i2c_resume(struct device *dev) ++static int __maybe_unused mv64xxx_i2c_runtime_resume(struct device *dev) + { + struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); + ++ if (!IS_ERR(drv_data->clk)) ++ clk_prepare_enable(drv_data->clk); ++ if (!IS_ERR(drv_data->reg_clk)) ++ clk_prepare_enable(drv_data->reg_clk); ++ reset_control_reset(drv_data->rstc); ++ + mv64xxx_i2c_hw_init(drv_data); + + return 0; + } + +-static const struct dev_pm_ops mv64xxx_i2c_pm = { +- .resume = mv64xxx_i2c_resume, ++static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { ++ SET_RUNTIME_PM_OPS(mv64xxx_i2c_runtime_suspend, ++ mv64xxx_i2c_runtime_resume, NULL) ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) + }; + +-#define mv64xxx_i2c_pm_ops (&mv64xxx_i2c_pm) +-#else +-#define mv64xxx_i2c_pm_ops NULL +-#endif +- + static struct platform_driver mv64xxx_i2c_driver = { + .probe = mv64xxx_i2c_probe, + .remove = mv64xxx_i2c_remove, + .driver = { + .name = MV64XXX_I2C_CTLR_NAME, +- .pm = mv64xxx_i2c_pm_ops, ++ .pm = &mv64xxx_i2c_pm_ops, + .of_match_table = mv64xxx_i2c_of_match_table, + }, + }; diff --git a/projects/Allwinner/patches/linux/crust/0002-clk-Implement-protected-clocks-for-all-OF-clock-prov.patch b/projects/Allwinner/patches/linux/crust/0002-clk-Implement-protected-clocks-for-all-OF-clock-prov.patch new file mode 100644 index 0000000000..f6d6dcc01e --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0002-clk-Implement-protected-clocks-for-all-OF-clock-prov.patch @@ -0,0 +1,198 @@ +From 87f8a2dea1cc62492a6eab63f50323127e508c3a Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 29 Dec 2019 20:23:28 -0600 +Subject: [PATCH 02/31] clk: Implement protected-clocks for all OF clock + providers + +This is a generic implementation of the "protected-clocks" property from +the common clock binding. It allows firmware to inform the OS about +clocks that must not be disabled while the OS is running. + +This implementation comes with some caveats: + +1) Clocks that have CLK_IS_CRITICAL in their init data are prepared/ +enabled before they are attached to the clock tree. protected-clocks are +only protected once the clock provider is added, which is generally +after all of the clocks it provides have been registered. This leaves a +window of opportunity where something could disable or modify the clock, +such as a driver running on another CPU, or the clock core itself. There +is a comment to this effect in __clk_core_init(): + + /* + * Enable CLK_IS_CRITICAL clocks so newly added critical clocks + * don't get accidentally disabled when walking the orphan tree and + * reparenting clocks + */ + +Similarly, these clocks will be enabled after they are first reparented, +unlike other CLK_IS_CRITICAL clocks. See the comment in +clk_core_reparent_orphans_nolock(): + + /* + * We need to use __clk_set_parent_before() and _after() to + * to properly migrate any prepare/enable count of the orphan + * clock. This is important for CLK_IS_CRITICAL clocks, which + * are enabled during init but might not have a parent yet. + */ + +Ideally we could detect protected clocks before they are reparented, but +there are two problems with that: + + a) From the clock core's perspective, hw->init is const. + + b) The clock core doesn't see the device_node until __clk_register is + called on the first clock. + +So the only "race-free" way to detect protected-clocks is to do it in +the middle of __clk_register, between when core->flags is initialized +and calling __clk_core_init(). That requires scanning the device tree +again for each clock, which is part of why I didn't do it that way. + +2) __clk_protect needs to be idempotent, for two reasons: + + a) Clocks with CLK_IS_CRITICAL in their init data are already + prepared/enabled, and we don't want to prepare/enable them again. + + b) of_clk_set_defaults() is called twice for (at least some) clock + controllers registered with CLK_OF_DECLARE. It is called first in + of_clk_add_provider()/of_clk_add_hw_provider() inside clk_init_cb, + and again afterward in of_clk_init(). The second call in + of_clk_init() may be unnecessary, but verifying that would require + auditing all users of CLK_OF_DECLARE to ensure they called one of + the of_clk_add{,_hw}_provider functions. + +Signed-off-by: Samuel Holland +--- + drivers/clk/clk-conf.c | 54 ++++++++++++++++++++++++++++++++++++++++++ + drivers/clk/clk.c | 31 ++++++++++++++++++++++++ + drivers/clk/clk.h | 2 ++ + 3 files changed, 87 insertions(+) + +--- a/drivers/clk/clk-conf.c ++++ b/drivers/clk/clk-conf.c +@@ -11,6 +11,54 @@ + #include + #include + ++#include "clk.h" ++ ++static int __set_clk_flags(struct device_node *node) ++{ ++ struct of_phandle_args clkspec; ++ struct property *prop; ++ int i, index = 0, rc; ++ const __be32 *cur; ++ struct clk *clk; ++ u32 nr_cells; ++ ++ rc = of_property_read_u32(node, "#clock-cells", &nr_cells); ++ if (rc < 0) { ++ pr_err("clk: missing #clock-cells property on %pOF\n", node); ++ return rc; ++ } ++ ++ clkspec.np = node; ++ clkspec.args_count = nr_cells; ++ ++ of_property_for_each_u32(node, "protected-clocks", prop, cur, clkspec.args[0]) { ++ /* read the remainder of the clock specifier */ ++ for (i = 1; i < nr_cells; ++i) { ++ cur = of_prop_next_u32(prop, cur, &clkspec.args[i]); ++ if (!cur) { ++ pr_err("clk: invalid value of protected-clocks" ++ " property at %pOF\n", node); ++ return -EINVAL; ++ } ++ } ++ clk = of_clk_get_from_provider(&clkspec); ++ if (IS_ERR(clk)) { ++ if (PTR_ERR(clk) != -EPROBE_DEFER) ++ pr_err("clk: couldn't get protected clock" ++ " %u for %pOF\n", index, node); ++ return PTR_ERR(clk); ++ } ++ ++ rc = __clk_protect(clk); ++ if (rc < 0) ++ pr_warn("clk: failed to protect %s: %d\n", ++ __clk_get_name(clk), rc); ++ clk_put(clk); ++ index++; ++ } ++ return 0; ++} ++ + static int __set_clk_parents(struct device_node *node, bool clk_supplier) + { + struct of_phandle_args clkspec; +@@ -135,6 +183,12 @@ int of_clk_set_defaults(struct device_no + if (!node) + return 0; + ++ if (clk_supplier) { ++ rc = __set_clk_flags(node); ++ if (rc < 0) ++ return rc; ++ } ++ + rc = __set_clk_parents(node, clk_supplier); + if (rc < 0) + return rc; +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -4188,6 +4188,37 @@ void devm_clk_hw_unregister(struct devic + EXPORT_SYMBOL_GPL(devm_clk_hw_unregister); + + /* ++ * clk-conf helpers ++ */ ++ ++int __clk_protect(struct clk *clk) ++{ ++ struct clk_core *core = clk->core; ++ int ret = 0; ++ ++ clk_prepare_lock(); ++ ++ /* ++ * If CLK_IS_CRITICAL was set in the clock's init data, then ++ * the clock was already prepared/enabled when it was added. ++ */ ++ if (core->flags & CLK_IS_CRITICAL) ++ goto out; ++ ++ core->flags |= CLK_IS_CRITICAL; ++ ret = clk_core_prepare(core); ++ if (ret) ++ goto out; ++ ++ ret = clk_core_enable_lock(core); ++ ++out: ++ clk_prepare_unlock(); ++ ++ return ret; ++} ++ ++/* + * clkdev helpers + */ + +--- a/drivers/clk/clk.h ++++ b/drivers/clk/clk.h +@@ -24,6 +24,7 @@ struct clk_hw *clk_find_hw(const char *d + #ifdef CONFIG_COMMON_CLK + struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, + const char *dev_id, const char *con_id); ++int __clk_protect(struct clk *clk); + void __clk_put(struct clk *clk); + #else + /* All these casts to avoid ifdefs in clkdev... */ +@@ -33,6 +34,7 @@ clk_hw_create_clk(struct device *dev, st + { + return (struct clk *)hw; + } ++static inline int __clk_protect(struct clk *clk) { return 0; } + static inline void __clk_put(struct clk *clk) { } + + #endif diff --git a/projects/Allwinner/patches/linux/crust/0003-Revert-clk-qcom-Support-protected-clocks-property.patch b/projects/Allwinner/patches/linux/crust/0003-Revert-clk-qcom-Support-protected-clocks-property.patch new file mode 100644 index 0000000000..159ae3c9f7 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0003-Revert-clk-qcom-Support-protected-clocks-property.patch @@ -0,0 +1,49 @@ +From fedd64540faff5a08239c062e03c64fb70d0aa4d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 12:39:31 -0600 +Subject: [PATCH 03/31] Revert "clk: qcom: Support 'protected-clocks' property" + +Now that protected-clocks is handled in the clk core, this +driver-specific implementation is redundant. + +This reverts commit b181b3b801da8893c8eb706e448dd5111b02de60. + +Signed-off-by: Samuel Holland +--- + drivers/clk/qcom/common.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +--- a/drivers/clk/qcom/common.c ++++ b/drivers/clk/qcom/common.c +@@ -194,22 +194,6 @@ int qcom_cc_register_sleep_clk(struct de + } + EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk); + +-/* Drop 'protected-clocks' from the list of clocks to register */ +-static void qcom_cc_drop_protected(struct device *dev, struct qcom_cc *cc) +-{ +- struct device_node *np = dev->of_node; +- struct property *prop; +- const __be32 *p; +- u32 i; +- +- of_property_for_each_u32(np, "protected-clocks", prop, p, i) { +- if (i >= cc->num_rclks) +- continue; +- +- cc->rclks[i] = NULL; +- } +-} +- + static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec, + void *data) + { +@@ -272,8 +256,6 @@ int qcom_cc_really_probe(struct platform + cc->rclks = rclks; + cc->num_rclks = num_clks; + +- qcom_cc_drop_protected(dev, cc); +- + for (i = 0; i < num_clk_hws; i++) { + ret = devm_clk_hw_register(dev, clk_hws[i]); + if (ret) diff --git a/projects/Allwinner/patches/linux/crust/0005-DO-NOT-MERGE-ARM-dts-sunxi-h3-h5-Protect-SCP-clocks.patch b/projects/Allwinner/patches/linux/crust/0005-DO-NOT-MERGE-ARM-dts-sunxi-h3-h5-Protect-SCP-clocks.patch new file mode 100644 index 0000000000..03b5922896 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0005-DO-NOT-MERGE-ARM-dts-sunxi-h3-h5-Protect-SCP-clocks.patch @@ -0,0 +1,29 @@ +From 0cd71d2659136cd9bead16348637d317d4bbfa66 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Wed, 1 Jan 2020 16:03:46 -0600 +Subject: [PATCH 05/31] [DO NOT MERGE] ARM: dts: sunxi: h3/h5: Protect SCP + clocks + +Signed-off-by: Samuel Holland +--- + arch/arm/boot/dts/sunxi-h3-h5.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi ++++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi +@@ -388,6 +388,7 @@ + reg = <0x01c20000 0x400>; + clocks = <&osc24M>, <&rtc 0>; + clock-names = "hosc", "losc"; ++ protected-clocks = ; + #clock-cells = <1>; + #reset-cells = <1>; + }; +@@ -852,6 +853,7 @@ + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>, + <&ccu CLK_PLL_PERIPH0>; + clock-names = "hosc", "losc", "iosc", "pll-periph"; ++ protected-clocks = ; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/projects/Allwinner/patches/linux/crust/0006-DO-NOT-MERGE-arm64-dts-allwinner-a64-Protect-SCP-clo.patch b/projects/Allwinner/patches/linux/crust/0006-DO-NOT-MERGE-arm64-dts-allwinner-a64-Protect-SCP-clo.patch new file mode 100644 index 0000000000..aa28404f93 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0006-DO-NOT-MERGE-arm64-dts-allwinner-a64-Protect-SCP-clo.patch @@ -0,0 +1,29 @@ +From bd91939780869b8c6b48e6eae07733660dceb56b Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 15:10:32 -0600 +Subject: [PATCH 06/31] [DO NOT MERGE] arm64: dts: allwinner: a64: Protect SCP + clocks + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +@@ -637,6 +637,7 @@ + reg = <0x01c20000 0x400>; + clocks = <&osc24M>, <&rtc 0>; + clock-names = "hosc", "losc"; ++ protected-clocks = ; + #clock-cells = <1>; + #reset-cells = <1>; + }; +@@ -1212,6 +1213,7 @@ + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>, + <&ccu CLK_PLL_PERIPH0>; + clock-names = "hosc", "losc", "iosc", "pll-periph"; ++ protected-clocks = ; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/projects/Allwinner/patches/linux/crust/0007-DO-NOT-MERGE-arm64-dts-allwinner-h6-Protect-SCP-cloc.patch b/projects/Allwinner/patches/linux/crust/0007-DO-NOT-MERGE-arm64-dts-allwinner-h6-Protect-SCP-cloc.patch new file mode 100644 index 0000000000..6f58990457 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0007-DO-NOT-MERGE-arm64-dts-allwinner-h6-Protect-SCP-cloc.patch @@ -0,0 +1,29 @@ +From 082b5969ad4a2705169c1c1612413ba7c98dc27f Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Wed, 1 Jan 2020 16:04:01 -0600 +Subject: [PATCH 07/31] [DO NOT MERGE] arm64: dts: allwinner: h6: Protect SCP + clocks + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -230,6 +230,7 @@ + reg = <0x03001000 0x1000>; + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>; + clock-names = "hosc", "losc", "iosc"; ++ protected-clocks = ; + #clock-cells = <1>; + #reset-cells = <1>; + }; +@@ -894,6 +895,7 @@ + clocks = <&osc24M>, <&rtc 0>, <&rtc 2>, + <&ccu CLK_PLL_PERIPH0>; + clock-names = "hosc", "losc", "iosc", "pll-periph"; ++ protected-clocks = ; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/projects/Allwinner/patches/linux/crust/0008-bus-sunxi-rsb-Always-check-register-address-validity.patch b/projects/Allwinner/patches/linux/crust/0008-bus-sunxi-rsb-Always-check-register-address-validity.patch new file mode 100644 index 0000000000..420b4a394b --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0008-bus-sunxi-rsb-Always-check-register-address-validity.patch @@ -0,0 +1,27 @@ +From fe3a4fd11558fac2ac10928d217b21ff2f67483f Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 21:56:59 -0600 +Subject: [PATCH 08/31] bus: sunxi-rsb: Always check register address validity + +The register address was already validated for read operations before +being truncated to a u8. Write operations have the same set of possible +addresses, and the address is being truncated from u32 to u8 here as +well, so the same check is needed. + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -414,6 +414,9 @@ static int regmap_sunxi_rsb_reg_write(vo + struct sunxi_rsb_ctx *ctx = context; + struct sunxi_rsb_device *rdev = ctx->rdev; + ++ if (reg > 0xff) ++ return -EINVAL; ++ + return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size); + } + diff --git a/projects/Allwinner/patches/linux/crust/0009-bus-sunxi-rsb-Use-devm_platform_ioremap_resource.patch b/projects/Allwinner/patches/linux/crust/0009-bus-sunxi-rsb-Use-devm_platform_ioremap_resource.patch new file mode 100644 index 0000000000..31a1e4584a --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0009-bus-sunxi-rsb-Use-devm_platform_ioremap_resource.patch @@ -0,0 +1,33 @@ +From febbd571f841fcf680f22148b0b5b24301fad5c1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 22:09:08 -0600 +Subject: [PATCH 09/31] bus: sunxi-rsb: Use devm_platform_ioremap_resource + +This simplifies the code and removes the need for a "struct resource". + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -627,7 +627,6 @@ static int sunxi_rsb_probe(struct platfo + { + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; +- struct resource *r; + struct sunxi_rsb *rsb; + unsigned long p_clk_freq; + u32 clk_delay, clk_freq = 3000000; +@@ -648,8 +647,8 @@ static int sunxi_rsb_probe(struct platfo + + rsb->dev = dev; + platform_set_drvdata(pdev, rsb); +- r = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- rsb->regs = devm_ioremap_resource(dev, r); ++ ++ rsb->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rsb->regs)) + return PTR_ERR(rsb->regs); + diff --git a/projects/Allwinner/patches/linux/crust/0010-bus-sunxi-rsb-Precompute-read-write-commands-and-mas.patch b/projects/Allwinner/patches/linux/crust/0010-bus-sunxi-rsb-Precompute-read-write-commands-and-mas.patch new file mode 100644 index 0000000000..72d22959bd --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0010-bus-sunxi-rsb-Precompute-read-write-commands-and-mas.patch @@ -0,0 +1,208 @@ +From 0a9087b56ec06abe2ff7f4c2c2732677cec8793e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 21:49:29 -0600 +Subject: [PATCH 10/31] bus: sunxi-rsb: Precompute read/write commands and mask + +Since we know the size of the transfer at context creation time, go +ahead and determine the commands used for reading and writing then, +instead of running through a switch statement for every read/write. +We can do the same thing for the read mask. + +The context pointer could be passed directly to sunxi_rsb_read/write +to avoid adding more parameters (which would be spilled for mutex_lock). +That would make the regmap read/write wrappers even more trivial, so I +inlined sunxi_rsb_read/write into them. + +I changed the error message to print the name of the device requesting +the regmap, not the RSB controller; I expect that to be more helpful +when tracking down the source of the error. + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 120 +++++++++++++++------------------------- + 1 file changed, 44 insertions(+), 76 deletions(-) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -311,41 +311,38 @@ static int _sunxi_rsb_run_xfer(struct su + return 0; + } + +-static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr, +- u32 *buf, size_t len) ++/* RSB regmap functions */ ++struct sunxi_rsb_ctx { ++ struct sunxi_rsb_device *rdev; ++ u32 mask; ++ u8 rd_cmd; ++ u8 wr_cmd; ++}; ++ ++static int regmap_sunxi_rsb_reg_read(void *context, unsigned int reg, ++ unsigned int *val) + { +- u32 cmd; ++ struct sunxi_rsb_ctx *ctx = context; ++ struct sunxi_rsb_device *rdev = ctx->rdev; ++ struct sunxi_rsb *rsb = rdev->rsb; + int ret; + +- if (!buf) ++ if (!val) + return -EINVAL; +- +- switch (len) { +- case 1: +- cmd = RSB_CMD_RD8; +- break; +- case 2: +- cmd = RSB_CMD_RD16; +- break; +- case 4: +- cmd = RSB_CMD_RD32; +- break; +- default: +- dev_err(rsb->dev, "Invalid access width: %zd\n", len); ++ if (reg > 0xff) + return -EINVAL; +- } + + mutex_lock(&rsb->lock); + +- writel(addr, rsb->regs + RSB_ADDR); +- writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR); +- writel(cmd, rsb->regs + RSB_CMD); ++ writel(reg, rsb->regs + RSB_ADDR); ++ writel(RSB_DAR_RTA(rdev->rtaddr), rsb->regs + RSB_DAR); ++ writel(ctx->rd_cmd, rsb->regs + RSB_CMD); + + ret = _sunxi_rsb_run_xfer(rsb); + if (ret) + goto unlock; + +- *buf = readl(rsb->regs + RSB_DATA) & GENMASK(len * 8 - 1, 0); ++ *val = readl(rsb->regs + RSB_DATA) & ctx->mask; + + unlock: + mutex_unlock(&rsb->lock); +@@ -353,36 +350,24 @@ unlock: + return ret; + } + +-static int sunxi_rsb_write(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr, +- const u32 *buf, size_t len) ++static int regmap_sunxi_rsb_reg_write(void *context, unsigned int reg, ++ unsigned int val) + { +- u32 cmd; ++ struct sunxi_rsb_ctx *ctx = context; ++ struct sunxi_rsb_device *rdev = ctx->rdev; ++ struct sunxi_rsb *rsb = rdev->rsb; + int ret; + +- if (!buf) +- return -EINVAL; +- +- switch (len) { +- case 1: +- cmd = RSB_CMD_WR8; +- break; +- case 2: +- cmd = RSB_CMD_WR16; +- break; +- case 4: +- cmd = RSB_CMD_WR32; +- break; +- default: +- dev_err(rsb->dev, "Invalid access width: %zd\n", len); ++ if (reg > 0xff) + return -EINVAL; +- } + + mutex_lock(&rsb->lock); + +- writel(addr, rsb->regs + RSB_ADDR); +- writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR); +- writel(*buf, rsb->regs + RSB_DATA); +- writel(cmd, rsb->regs + RSB_CMD); ++ writel(reg, rsb->regs + RSB_ADDR); ++ writel(RSB_DAR_RTA(rdev->rtaddr), rsb->regs + RSB_DAR); ++ writel(val, rsb->regs + RSB_DATA); ++ writel(ctx->wr_cmd, rsb->regs + RSB_CMD); ++ + ret = _sunxi_rsb_run_xfer(rsb); + + mutex_unlock(&rsb->lock); +@@ -390,36 +375,6 @@ static int sunxi_rsb_write(struct sunxi_ + return ret; + } + +-/* RSB regmap functions */ +-struct sunxi_rsb_ctx { +- struct sunxi_rsb_device *rdev; +- int size; +-}; +- +-static int regmap_sunxi_rsb_reg_read(void *context, unsigned int reg, +- unsigned int *val) +-{ +- struct sunxi_rsb_ctx *ctx = context; +- struct sunxi_rsb_device *rdev = ctx->rdev; +- +- if (reg > 0xff) +- return -EINVAL; +- +- return sunxi_rsb_read(rdev->rsb, rdev->rtaddr, reg, val, ctx->size); +-} +- +-static int regmap_sunxi_rsb_reg_write(void *context, unsigned int reg, +- unsigned int val) +-{ +- struct sunxi_rsb_ctx *ctx = context; +- struct sunxi_rsb_device *rdev = ctx->rdev; +- +- if (reg > 0xff) +- return -EINVAL; +- +- return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size); +-} +- + static void regmap_sunxi_rsb_free_ctx(void *context) + { + struct sunxi_rsb_ctx *ctx = context; +@@ -439,13 +394,24 @@ static struct sunxi_rsb_ctx *regmap_sunx + const struct regmap_config *config) + { + struct sunxi_rsb_ctx *ctx; ++ u8 rd_cmd, wr_cmd; + + switch (config->val_bits) { + case 8: ++ rd_cmd = RSB_CMD_RD8; ++ wr_cmd = RSB_CMD_WR8; ++ break; + case 16: ++ rd_cmd = RSB_CMD_RD16; ++ wr_cmd = RSB_CMD_WR16; ++ break; + case 32: ++ rd_cmd = RSB_CMD_RD32; ++ wr_cmd = RSB_CMD_WR32; + break; + default: ++ dev_err(&rdev->dev, "Invalid RSB access width: %d\n", ++ config->val_bits); + return ERR_PTR(-EINVAL); + } + +@@ -454,7 +420,9 @@ static struct sunxi_rsb_ctx *regmap_sunx + return ERR_PTR(-ENOMEM); + + ctx->rdev = rdev; +- ctx->size = config->val_bits / 8; ++ ctx->mask = GENMASK(config->val_bits - 1, 0); ++ ctx->rd_cmd = rd_cmd; ++ ctx->wr_cmd = wr_cmd; + + return ctx; + } diff --git a/projects/Allwinner/patches/linux/crust/0011-bus-sunxi-rsb-Move-OF-match-table.patch b/projects/Allwinner/patches/linux/crust/0011-bus-sunxi-rsb-Move-OF-match-table.patch new file mode 100644 index 0000000000..e8bc06de63 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0011-bus-sunxi-rsb-Move-OF-match-table.patch @@ -0,0 +1,43 @@ +From d58ad83eaf72e072d0e0205847ab4332dba24cd0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 17:12:42 -0600 +Subject: [PATCH 11/31] bus: sunxi-rsb: Move OF match table + +For some reason, this driver's OF match table was placed above the +probe/remove functions, far away from the platform_driver definition. +Adding device PM ops would move the table even farther away. Let's move +it to the usual place, right before the platform_driver. + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -585,12 +585,6 @@ static int of_rsb_register_devices(struc + return 0; + } + +-static const struct of_device_id sunxi_rsb_of_match_table[] = { +- { .compatible = "allwinner,sun8i-a23-rsb" }, +- {} +-}; +-MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table); +- + static int sunxi_rsb_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -717,6 +711,12 @@ static int sunxi_rsb_remove(struct platf + return 0; + } + ++static const struct of_device_id sunxi_rsb_of_match_table[] = { ++ { .compatible = "allwinner,sun8i-a23-rsb" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table); ++ + static struct platform_driver sunxi_rsb_driver = { + .probe = sunxi_rsb_probe, + .remove = sunxi_rsb_remove, diff --git a/projects/Allwinner/patches/linux/crust/0012-bus-sunxi-rsb-Split-out-controller-init-exit-functio.patch b/projects/Allwinner/patches/linux/crust/0012-bus-sunxi-rsb-Split-out-controller-init-exit-functio.patch new file mode 100644 index 0000000000..3fb4f0bf02 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0012-bus-sunxi-rsb-Split-out-controller-init-exit-functio.patch @@ -0,0 +1,216 @@ +From f8f487fcec9fc8ee7861b99dcf833bd82249ab21 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 22:36:04 -0600 +Subject: [PATCH 12/31] bus: sunxi-rsb: Split out controller init/exit + functions + +This separates the resource acquisition from the hardware initialization +phase, so the hardware initialization can be repeated after system +suspend/resume. The same is done for the exit/remove function, except +that there is no resource deallocation phase due to the use of devres. + +The call to reset_control_deassert() is replaced with a call to +reset_control_reset() to ensure the hardware is fully reinitialized, +regardless of the state firmware left it in. + +The requested RSB clock frequency is stored in `struct sunxi_rsb` so it +will be available when reinitializing the hardware. + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 129 +++++++++++++++++++++++----------------- + 1 file changed, 73 insertions(+), 56 deletions(-) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -126,6 +126,7 @@ struct sunxi_rsb { + struct completion complete; + struct mutex lock; + unsigned int status; ++ u32 clk_freq; + }; + + /* bus / slave device related functions */ +@@ -585,15 +586,75 @@ static int of_rsb_register_devices(struc + return 0; + } + ++static int sunxi_rsb_init_controller(struct sunxi_rsb *rsb) ++{ ++ struct device *dev = rsb->dev; ++ unsigned long p_clk_freq; ++ u32 clk_delay, reg; ++ int clk_div, ret; ++ ++ ret = clk_prepare_enable(rsb->clk); ++ if (ret) { ++ dev_err(dev, "failed to enable clk: %d\n", ret); ++ return ret; ++ } ++ ++ ret = reset_control_reset(rsb->rstc); ++ if (ret) { ++ dev_err(dev, "failed to deassert reset line: %d\n", ret); ++ goto err_clk_disable; ++ } ++ ++ /* reset the controller */ ++ writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL); ++ readl_poll_timeout(rsb->regs + RSB_CTRL, reg, ++ !(reg & RSB_CTRL_SOFT_RST), 1000, 100000); ++ ++ /* ++ * Clock frequency and delay calculation code is from ++ * Allwinner U-boot sources. ++ * ++ * From A83 user manual: ++ * bus clock frequency = parent clock frequency / (2 * (divider + 1)) ++ */ ++ p_clk_freq = clk_get_rate(rsb->clk); ++ clk_div = p_clk_freq / rsb->clk_freq / 2; ++ if (!clk_div) ++ clk_div = 1; ++ else if (clk_div > RSB_CCR_MAX_CLK_DIV + 1) ++ clk_div = RSB_CCR_MAX_CLK_DIV + 1; ++ ++ clk_delay = clk_div >> 1; ++ if (!clk_delay) ++ clk_delay = 1; ++ ++ dev_info(dev, "RSB running at %lu Hz\n", p_clk_freq / clk_div / 2); ++ writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1), ++ rsb->regs + RSB_CCR); ++ ++ return 0; ++ ++err_clk_disable: ++ clk_disable_unprepare(rsb->clk); ++ ++ return ret; ++} ++ ++static int sunxi_rsb_exit_controller(struct sunxi_rsb *rsb) ++{ ++ reset_control_assert(rsb->rstc); ++ clk_disable_unprepare(rsb->clk); ++ ++ return 0; ++} ++ + static int sunxi_rsb_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct sunxi_rsb *rsb; +- unsigned long p_clk_freq; +- u32 clk_delay, clk_freq = 3000000; +- int clk_div, irq, ret; +- u32 reg; ++ u32 clk_freq = 3000000; ++ int irq, ret; + + of_property_read_u32(np, "clock-frequency", &clk_freq); + if (clk_freq > RSB_MAX_FREQ) { +@@ -608,6 +669,7 @@ static int sunxi_rsb_probe(struct platfo + return -ENOMEM; + + rsb->dev = dev; ++ rsb->clk_freq = clk_freq; + platform_set_drvdata(pdev, rsb); + + rsb->regs = devm_platform_ioremap_resource(pdev, 0); +@@ -625,63 +687,27 @@ static int sunxi_rsb_probe(struct platfo + return ret; + } + +- ret = clk_prepare_enable(rsb->clk); +- if (ret) { +- dev_err(dev, "failed to enable clk: %d\n", ret); +- return ret; +- } +- +- p_clk_freq = clk_get_rate(rsb->clk); +- + rsb->rstc = devm_reset_control_get(dev, NULL); + if (IS_ERR(rsb->rstc)) { + ret = PTR_ERR(rsb->rstc); + dev_err(dev, "failed to retrieve reset controller: %d\n", ret); +- goto err_clk_disable; +- } +- +- ret = reset_control_deassert(rsb->rstc); +- if (ret) { +- dev_err(dev, "failed to deassert reset line: %d\n", ret); +- goto err_clk_disable; ++ return ret; + } + + init_completion(&rsb->complete); + mutex_init(&rsb->lock); + +- /* reset the controller */ +- writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL); +- readl_poll_timeout(rsb->regs + RSB_CTRL, reg, +- !(reg & RSB_CTRL_SOFT_RST), 1000, 100000); +- +- /* +- * Clock frequency and delay calculation code is from +- * Allwinner U-boot sources. +- * +- * From A83 user manual: +- * bus clock frequency = parent clock frequency / (2 * (divider + 1)) +- */ +- clk_div = p_clk_freq / clk_freq / 2; +- if (!clk_div) +- clk_div = 1; +- else if (clk_div > RSB_CCR_MAX_CLK_DIV + 1) +- clk_div = RSB_CCR_MAX_CLK_DIV + 1; +- +- clk_delay = clk_div >> 1; +- if (!clk_delay) +- clk_delay = 1; +- +- dev_info(dev, "RSB running at %lu Hz\n", p_clk_freq / clk_div / 2); +- writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1), +- rsb->regs + RSB_CCR); +- + ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb); + if (ret) { + dev_err(dev, "can't register interrupt handler irq %d: %d\n", + irq, ret); +- goto err_reset_assert; ++ return ret; + } + ++ ret = sunxi_rsb_init_controller(rsb); ++ if (ret) ++ return ret; ++ + /* initialize all devices on the bus into RSB mode */ + ret = sunxi_rsb_init_device_mode(rsb); + if (ret) +@@ -690,14 +716,6 @@ static int sunxi_rsb_probe(struct platfo + of_rsb_register_devices(rsb); + + return 0; +- +-err_reset_assert: +- reset_control_assert(rsb->rstc); +- +-err_clk_disable: +- clk_disable_unprepare(rsb->clk); +- +- return ret; + } + + static int sunxi_rsb_remove(struct platform_device *pdev) +@@ -705,8 +723,7 @@ static int sunxi_rsb_remove(struct platf + struct sunxi_rsb *rsb = platform_get_drvdata(pdev); + + device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices); +- reset_control_assert(rsb->rstc); +- clk_disable_unprepare(rsb->clk); ++ sunxi_rsb_exit_controller(rsb); + + return 0; + } diff --git a/projects/Allwinner/patches/linux/crust/0013-bus-sunxi-rsb-Implement-global-suspend-resume-callba.patch b/projects/Allwinner/patches/linux/crust/0013-bus-sunxi-rsb-Implement-global-suspend-resume-callba.patch new file mode 100644 index 0000000000..09b1a02eb8 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0013-bus-sunxi-rsb-Implement-global-suspend-resume-callba.patch @@ -0,0 +1,65 @@ +From 96302816684155abd59e0dbba7a999c0d269e736 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 22:50:02 -0600 +Subject: [PATCH 13/31] bus: sunxi-rsb: Implement global suspend/resume + callbacks + +Since system firmware is likely to use the RSB bus to communicate with a +PMIC while the system is suspended, we cannot make any assumptions about +the controller state after resuming. Thus it is important to completely +reinitialize the controller. + +The RSB bus needs to be ready as soon as IRQs are enabled, to handle +wakeup event IRQs coming from the PMIC. Thus it uses NOIRQ callbacks. + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -648,6 +649,24 @@ static int sunxi_rsb_exit_controller(str + return 0; + } + ++static int __maybe_unused sunxi_rsb_suspend(struct device *dev) ++{ ++ struct sunxi_rsb *rsb = dev_get_drvdata(dev); ++ ++ return sunxi_rsb_exit_controller(rsb); ++} ++ ++static int __maybe_unused sunxi_rsb_resume(struct device *dev) ++{ ++ struct sunxi_rsb *rsb = dev_get_drvdata(dev); ++ ++ return sunxi_rsb_init_controller(rsb); ++} ++ ++static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = { ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sunxi_rsb_suspend, sunxi_rsb_resume) ++}; ++ + static int sunxi_rsb_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -738,8 +757,9 @@ static struct platform_driver sunxi_rsb_ + .probe = sunxi_rsb_probe, + .remove = sunxi_rsb_remove, + .driver = { +- .name = RSB_CTRL_NAME, ++ .name = RSB_CTRL_NAME, + .of_match_table = sunxi_rsb_of_match_table, ++ .pm = &sunxi_rsb_dev_pm_ops, + }, + }; + diff --git a/projects/Allwinner/patches/linux/crust/0014-bus-sunxi-rsb-Implement-runtime-power-management.patch b/projects/Allwinner/patches/linux/crust/0014-bus-sunxi-rsb-Implement-runtime-power-management.patch new file mode 100644 index 0000000000..4ccebfa918 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0014-bus-sunxi-rsb-Implement-runtime-power-management.patch @@ -0,0 +1,122 @@ +From f226c7c38ef1b9ae026680c9c68fedd4fbd4ecd7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Wed, 1 Jan 2020 00:10:40 -0600 +Subject: [PATCH 14/31] bus: sunxi-rsb: Implement runtime power management + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -334,6 +335,7 @@ static int regmap_sunxi_rsb_reg_read(voi + if (reg > 0xff) + return -EINVAL; + ++ pm_runtime_get_sync(rsb->dev); + mutex_lock(&rsb->lock); + + writel(reg, rsb->regs + RSB_ADDR); +@@ -348,6 +350,8 @@ static int regmap_sunxi_rsb_reg_read(voi + + unlock: + mutex_unlock(&rsb->lock); ++ pm_runtime_mark_last_busy(rsb->dev); ++ pm_runtime_put_autosuspend(rsb->dev); + + return ret; + } +@@ -363,6 +367,7 @@ static int regmap_sunxi_rsb_reg_write(vo + if (reg > 0xff) + return -EINVAL; + ++ pm_runtime_get_sync(rsb->dev); + mutex_lock(&rsb->lock); + + writel(reg, rsb->regs + RSB_ADDR); +@@ -373,6 +378,8 @@ static int regmap_sunxi_rsb_reg_write(vo + ret = _sunxi_rsb_run_xfer(rsb); + + mutex_unlock(&rsb->lock); ++ pm_runtime_mark_last_busy(rsb->dev); ++ pm_runtime_put_autosuspend(rsb->dev); + + return ret; + } +@@ -649,10 +656,30 @@ static int sunxi_rsb_exit_controller(str + return 0; + } + ++static int __maybe_unused sunxi_rsb_runtime_suspend(struct device *dev) ++{ ++ struct sunxi_rsb *rsb = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(rsb->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused sunxi_rsb_runtime_resume(struct device *dev) ++{ ++ struct sunxi_rsb *rsb = dev_get_drvdata(dev); ++ ++ return clk_prepare_enable(rsb->clk); ++} ++ + static int __maybe_unused sunxi_rsb_suspend(struct device *dev) + { + struct sunxi_rsb *rsb = dev_get_drvdata(dev); + ++ /* Ensure the clock is running before asserting reset. */ ++ if (pm_runtime_status_suspended(dev)) ++ pm_runtime_resume(dev); ++ + return sunxi_rsb_exit_controller(rsb); + } + +@@ -664,6 +691,8 @@ static int __maybe_unused sunxi_rsb_resu + } + + static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = { ++ SET_RUNTIME_PM_OPS(sunxi_rsb_runtime_suspend, ++ sunxi_rsb_runtime_resume, NULL) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sunxi_rsb_suspend, sunxi_rsb_resume) + }; + +@@ -734,6 +763,12 @@ static int sunxi_rsb_probe(struct platfo + + of_rsb_register_devices(rsb); + ++ pm_suspend_ignore_children(dev, true); ++ pm_runtime_set_autosuspend_delay(dev, 1000); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ + return 0; + } + +@@ -741,9 +776,14 @@ static int sunxi_rsb_remove(struct platf + { + struct sunxi_rsb *rsb = platform_get_drvdata(pdev); + ++ pm_runtime_get_sync(&pdev->dev); ++ + device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices); + sunxi_rsb_exit_controller(rsb); + ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ + return 0; + } + diff --git a/projects/Allwinner/patches/linux/crust/0015-bus-sunxi-rsb-Make-interrupt-handling-more-robust.patch b/projects/Allwinner/patches/linux/crust/0015-bus-sunxi-rsb-Make-interrupt-handling-more-robust.patch new file mode 100644 index 0000000000..42cef50b4c --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0015-bus-sunxi-rsb-Make-interrupt-handling-more-robust.patch @@ -0,0 +1,69 @@ +From 3c8535aee4f58ffeae01dd4d6e32479e9fd68a7e Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Mon, 30 Dec 2019 22:58:21 -0600 +Subject: [PATCH 15/31] bus: sunxi-rsb: Make interrupt handling more robust + +The RSB controller has two registers for controlling interrupt inputs: +RSB_INTE, which has bits for each possible interrupt, and the global +interrupt enable bit in RSB_CTRL. + +Currently, we enable the bits in RSB_INTE before each transfer, but this +is unnecessary because we never disable them. Move the initialization of +RSB_INTE so it is done only once. + +We also set the global interrupt enable bit before each transfer. Unlike +other bits in RSB_CTRL, this bit is cleared by writing a zero. Thus, we +clear the bit in the post-timeout cleanup code, but that is not +documented, so note that in the comment. However, in the success/error +path (when an IRQ is received), we do not disable further interrupts. +Add a register write to do just that. + +Signed-off-by: Samuel Holland +--- + drivers/bus/sunxi-rsb.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -276,8 +276,6 @@ static int _sunxi_rsb_run_xfer(struct su + + reinit_completion(&rsb->complete); + +- writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER, +- rsb->regs + RSB_INTE); + writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB, + rsb->regs + RSB_CTRL); + +@@ -285,7 +283,7 @@ static int _sunxi_rsb_run_xfer(struct su + msecs_to_jiffies(100))) { + dev_dbg(rsb->dev, "RSB timeout\n"); + +- /* abort the transfer */ ++ /* abort the transfer and disable interrupts */ + writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL); + + /* clear any interrupt flags */ +@@ -460,7 +458,8 @@ static irqreturn_t sunxi_rsb_irq(int irq + status = readl(rsb->regs + RSB_INTS); + rsb->status = status; + +- /* Clear interrupts */ ++ /* Disable and clear interrupts */ ++ writel(0, rsb->regs + RSB_CTRL); + status &= (RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | + RSB_INTS_TRANS_OVER); + writel(status, rsb->regs + RSB_INTS); +@@ -640,6 +639,13 @@ static int sunxi_rsb_init_controller(str + writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1), + rsb->regs + RSB_CCR); + ++ /* ++ * Select the interrupts we care about. They will not actually fire ++ * until the RSB_CTRL_GLOBAL_INT_ENB bit is set. ++ */ ++ writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER, ++ rsb->regs + RSB_INTE); ++ + return 0; + + err_clk_disable: diff --git a/projects/Allwinner/patches/linux/crust/0016-irqchip-sun6i-r-Use-a-stacked-irqchip-driver.patch b/projects/Allwinner/patches/linux/crust/0016-irqchip-sun6i-r-Use-a-stacked-irqchip-driver.patch new file mode 100644 index 0000000000..869fdfdbc2 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0016-irqchip-sun6i-r-Use-a-stacked-irqchip-driver.patch @@ -0,0 +1,370 @@ +From ca108f8037f884821d5b70ea0f4cfd73a9ae4188 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 25 Aug 2019 05:35:08 -0500 +Subject: [PATCH 16/31] irqchip/sun6i-r: Use a stacked irqchip driver + +The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the +original sun4i interrupt controller than the sun7i/sun9i NMI controller. +It is used for two distinct purposes: + 1) To control the trigger, latch, and mask for the NMI input pin + 2) To provide the interrupt input for the ARISC coprocessor + +As this interrupt controller is not documented, information about it +comes from vendor-provided ARISC firmware and from experimentation. + +Like the original sun4i interrupt controller, it has: + - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04) + - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the + sun4i and sunxi-nmi drivers + - A MASK_REG at 0x50 + - A RESP_REG at 0x60 + +Differences from the sun4i interrupt controller appear to be: + - It is only known to have one register of each kind (max 32 inputs) + - There is no FIQ-related logic + - There is no interrupt priority logic + +In order to fulfill its two purposes, this hardware block combines two +types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this +chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0 +pending" output from this chip, if enabled, is then routed to a SPI IRQ +input on the GIC, as IRQ_TYPE_LEVEL_HIGH. In other words, bit 0 of +ENABLE_REG *does* affect the NMI IRQ seen at the GIC. + +The NMI is then followed by a contiguous block of (at least) 15 IRQ +inputs that are connected in parallel to both R_INTC and the GIC. Or +in other words, the other bits of ENABLE_REG *do not* affect the IRQs +seen at the GIC. + +Finally, the global "IRQ pending" output from R_INTC, after being masked +by MASK_REG and RESP_REG, is connected to the "external interrupt" input +of the ARISC CPU (an OR1200). This path is not relevant to Linux. + +Because of the 1:1 correspondence between R_INTC and GIC inputs, this is +a perfect scenario for using a stacked irqchip driver. We want to hook +into enabling/disabling IRQs to add more features to the GIC +(specifically to allow masking the NMI and setting its trigger type), +but we don't need to actually handle the IRQ in this driver. + +And since R_INTC is in the always-on power domain, and its output is +connected directly in to the power management coprocessor, a stacked +irqchip driver provides a simple way to add wakeup support to this set +of IRQs. That is a future patch; for now, just the NMI is moved over. + +This driver keeps the same DT binding as the existing driver. The +"interrupt" property of the R_INTC node is used to determine 1) the +offset between GIC and R_INTC hwirq numbers and 2) the type of trigger +between the R_INTC "IRQ 0 pending" output and the GIC NMI input. + +This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi: +Support sun6i-a31-r-intc compatible"). + +Signed-off-by: Samuel Holland +--- + arch/arm/mach-sunxi/Kconfig | 2 + + arch/arm64/Kconfig.platforms | 2 + + drivers/irqchip/Makefile | 1 + + drivers/irqchip/irq-sun6i-r.c | 212 ++++++++++++++++++++++++++++++++ + drivers/irqchip/irq-sunxi-nmi.c | 26 +--- + 5 files changed, 220 insertions(+), 23 deletions(-) + create mode 100644 drivers/irqchip/irq-sun6i-r.c + +--- a/arch/arm/mach-sunxi/Kconfig ++++ b/arch/arm/mach-sunxi/Kconfig +@@ -6,6 +6,8 @@ menuconfig ARCH_SUNXI + select CLKSRC_MMIO + select GENERIC_IRQ_CHIP + select GPIOLIB ++ select IRQ_DOMAIN_HIERARCHY ++ select IRQ_FASTEOI_HIERARCHY_HANDLERS + select PINCTRL + select PM_OPP + select SUN4I_TIMER +--- a/arch/arm64/Kconfig.platforms ++++ b/arch/arm64/Kconfig.platforms +@@ -17,6 +17,8 @@ config ARCH_SUNXI + bool "Allwinner sunxi 64-bit SoC Family" + select ARCH_HAS_RESET_CONTROLLER + select GENERIC_IRQ_CHIP ++ select IRQ_DOMAIN_HIERARCHY ++ select IRQ_FASTEOI_HIERARCHY_HANDLERS + select PINCTRL + select RESET_CONTROLLER + help +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -24,6 +24,7 @@ obj-$(CONFIG_OR1K_PIC) += irq-or1k-pic + obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o + obj-$(CONFIG_OMAP_IRQCHIP) += irq-omap-intc.o + obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o ++obj-$(CONFIG_ARCH_SUNXI) += irq-sun6i-r.o + obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o + obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o + obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o +--- /dev/null ++++ b/drivers/irqchip/irq-sun6i-r.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// ++// Allwinner A31 and newer SoCs R_INTC driver ++// ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define NMI_HWIRQ 0 ++#define NMI_HWIRQ_BIT BIT(NMI_HWIRQ) ++ ++#define SUN6I_R_INTC_NR_IRQS 16 ++ ++#define SUN6I_R_INTC_NMI_CTRL 0x0c ++#define SUN6I_R_INTC_PENDING 0x10 ++#define SUN6I_R_INTC_ENABLE 0x40 ++ ++static void __iomem *base; ++static irq_hw_number_t parent_offset; ++static u32 parent_type; ++ ++static struct irq_chip sun6i_r_intc_edge_chip; ++static struct irq_chip sun6i_r_intc_level_chip; ++ ++static void sun6i_r_intc_nmi_ack(void) ++{ ++ /* ++ * The NMI IRQ channel has a latch, separate from its trigger. ++ * This latch must be cleared to clear the output to the GIC. ++ */ ++ writel_relaxed(NMI_HWIRQ_BIT, base + SUN6I_R_INTC_PENDING); ++} ++ ++static void sun6i_r_intc_irq_mask(struct irq_data *data) ++{ ++ if (data->hwirq == NMI_HWIRQ) ++ sun6i_r_intc_nmi_ack(); ++ ++ irq_chip_mask_parent(data); ++} ++ ++static void sun6i_r_intc_irq_unmask(struct irq_data *data) ++{ ++ if (data->hwirq == NMI_HWIRQ) ++ sun6i_r_intc_nmi_ack(); ++ ++ irq_chip_unmask_parent(data); ++} ++ ++static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type) ++{ ++ /* ++ * Only the NMI IRQ is routed through this interrupt controller on its ++ * way to the GIC. Other IRQs are routed to the GIC in parallel and ++ * must have a trigger type appropriate for the GIC. ++ * ++ * The "External NMI" input to the GIC actually comes from bit 0 of ++ * this device's PENDING register. So the IRQ type of the NMI, as seen ++ * by the GIC, does not depend on the IRQ type of the NMI pin itself. ++ */ ++ if (data->hwirq == NMI_HWIRQ) { ++ struct irq_chip *chip; ++ u32 nmi_src_type; ++ ++ switch (type) { ++ case IRQ_TYPE_LEVEL_LOW: ++ chip = &sun6i_r_intc_level_chip; ++ nmi_src_type = 0; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ chip = &sun6i_r_intc_edge_chip; ++ nmi_src_type = 1; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ chip = &sun6i_r_intc_level_chip; ++ nmi_src_type = 2; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ chip = &sun6i_r_intc_edge_chip; ++ nmi_src_type = 3; ++ break; ++ default: ++ pr_err("%pOF: invalid trigger type %d for IRQ %d\n", ++ irq_domain_get_of_node(data->domain), type, ++ data->irq); ++ return -EBADR; ++ } ++ ++ irq_set_chip_handler_name_locked(data, chip, ++ handle_fasteoi_irq, NULL); ++ ++ writel_relaxed(nmi_src_type, base + SUN6I_R_INTC_NMI_CTRL); ++ ++ /* Send the R_INTC -> GIC trigger type to the GIC driver. */ ++ type = parent_type; ++ } ++ ++ return irq_chip_set_type_parent(data, type); ++} ++ ++static struct irq_chip sun6i_r_intc_edge_chip = { ++ .name = "sun6i-r-intc", ++ .irq_mask = sun6i_r_intc_irq_mask, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .irq_set_type = sun6i_r_intc_irq_set_type, ++ .irq_get_irqchip_state = irq_chip_get_parent_state, ++ .irq_set_irqchip_state = irq_chip_set_parent_state, ++ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, ++ .flags = IRQCHIP_SET_TYPE_MASKED, ++}; ++ ++static struct irq_chip sun6i_r_intc_level_chip = { ++ .name = "sun6i-r-intc", ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = sun6i_r_intc_irq_unmask, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .irq_set_type = sun6i_r_intc_irq_set_type, ++ .irq_get_irqchip_state = irq_chip_get_parent_state, ++ .irq_set_irqchip_state = irq_chip_set_parent_state, ++ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, ++ .flags = IRQCHIP_SET_TYPE_MASKED, ++}; ++ ++static int sun6i_r_intc_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, ++ unsigned int nr_irqs, void *arg) ++{ ++ struct irq_fwspec *fwspec = arg; ++ struct irq_fwspec gic_fwspec; ++ irq_hw_number_t hwirq; ++ unsigned int type; ++ int i, ret; ++ ++ ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); ++ if (ret) ++ return ret; ++ if (hwirq + nr_irqs > SUN6I_R_INTC_NR_IRQS) ++ return -EINVAL; ++ ++ /* Construct a GIC-compatible fwspec from this fwspec. */ ++ gic_fwspec = (struct irq_fwspec) { ++ .fwnode = domain->parent->fwnode, ++ .param_count = 3, ++ .param = { GIC_SPI, parent_offset + hwirq, type }, ++ }; ++ ++ for (i = 0; i < nr_irqs; ++i) ++ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, ++ &sun6i_r_intc_level_chip, NULL); ++ ++ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec); ++} ++ ++static const struct irq_domain_ops sun6i_r_intc_domain_ops = { ++ .translate = irq_domain_translate_twocell, ++ .alloc = sun6i_r_intc_domain_alloc, ++ .free = irq_domain_free_irqs_common, ++}; ++ ++static int __init sun6i_r_intc_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ struct irq_domain *domain, *parent_domain; ++ struct of_phandle_args parent_irq; ++ int ret; ++ ++ /* Extract the R_INTC -> GIC mapping from the OF node. */ ++ ret = of_irq_parse_one(node, 0, &parent_irq); ++ if (ret) ++ return ret; ++ if (parent_irq.args_count != 3 || parent_irq.args[0] != GIC_SPI) ++ return -EINVAL; ++ parent_offset = parent_irq.args[1]; ++ parent_type = parent_irq.args[2]; ++ ++ parent_domain = irq_find_host(parent); ++ if (!parent_domain) { ++ pr_err("%pOF: Failed to obtain parent domain\n", node); ++ return -ENXIO; ++ } ++ ++ base = of_io_request_and_map(node, 0, NULL); ++ if (IS_ERR(base)) { ++ pr_err("%pOF: Failed to map MMIO region\n", node); ++ return PTR_ERR(base); ++ } ++ ++ domain = irq_domain_add_hierarchy(parent_domain, 0, ++ SUN6I_R_INTC_NR_IRQS, node, ++ &sun6i_r_intc_domain_ops, NULL); ++ if (!domain) { ++ pr_err("%pOF: Failed to allocate domain\n", node); ++ iounmap(base); ++ return -ENOMEM; ++ } ++ ++ /* Clear and enable the NMI. */ ++ writel_relaxed(NMI_HWIRQ_BIT, base + SUN6I_R_INTC_PENDING); ++ writel_relaxed(NMI_HWIRQ_BIT, base + SUN6I_R_INTC_ENABLE); ++ ++ return 0; ++} ++IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init); +--- a/drivers/irqchip/irq-sunxi-nmi.c ++++ b/drivers/irqchip/irq-sunxi-nmi.c +@@ -27,18 +27,12 @@ + + #define SUNXI_NMI_IRQ_BIT BIT(0) + +-#define SUN6I_R_INTC_CTRL 0x0c +-#define SUN6I_R_INTC_PENDING 0x10 +-#define SUN6I_R_INTC_ENABLE 0x40 +- + /* + * For deprecated sun6i-a31-sc-nmi compatible. +- * Registers are offset by 0x0c. + */ +-#define SUN6I_R_INTC_NMI_OFFSET 0x0c +-#define SUN6I_NMI_CTRL (SUN6I_R_INTC_CTRL - SUN6I_R_INTC_NMI_OFFSET) +-#define SUN6I_NMI_PENDING (SUN6I_R_INTC_PENDING - SUN6I_R_INTC_NMI_OFFSET) +-#define SUN6I_NMI_ENABLE (SUN6I_R_INTC_ENABLE - SUN6I_R_INTC_NMI_OFFSET) ++#define SUN6I_NMI_CTRL 0x00 ++#define SUN6I_NMI_PENDING 0x04 ++#define SUN6I_NMI_ENABLE 0x34 + + #define SUN7I_NMI_CTRL 0x00 + #define SUN7I_NMI_PENDING 0x04 +@@ -61,12 +55,6 @@ struct sunxi_sc_nmi_reg_offs { + u32 enable; + }; + +-static const struct sunxi_sc_nmi_reg_offs sun6i_r_intc_reg_offs __initconst = { +- .ctrl = SUN6I_R_INTC_CTRL, +- .pend = SUN6I_R_INTC_PENDING, +- .enable = SUN6I_R_INTC_ENABLE, +-}; +- + static const struct sunxi_sc_nmi_reg_offs sun6i_reg_offs __initconst = { + .ctrl = SUN6I_NMI_CTRL, + .pend = SUN6I_NMI_PENDING, +@@ -232,14 +220,6 @@ fail_irqd_remove: + return ret; + } + +-static int __init sun6i_r_intc_irq_init(struct device_node *node, +- struct device_node *parent) +-{ +- return sunxi_sc_nmi_irq_init(node, &sun6i_r_intc_reg_offs); +-} +-IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", +- sun6i_r_intc_irq_init); +- + static int __init sun6i_sc_nmi_irq_init(struct device_node *node, + struct device_node *parent) + { diff --git a/projects/Allwinner/patches/linux/crust/0017-irqchip-sun6i-r-Add-wakeup-support.patch b/projects/Allwinner/patches/linux/crust/0017-irqchip-sun6i-r-Add-wakeup-support.patch new file mode 100644 index 0000000000..b92a97981b --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0017-irqchip-sun6i-r-Add-wakeup-support.patch @@ -0,0 +1,129 @@ +From c1f31a42b5d9be0000b1748e0c4bdaf22060abfc Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 12 Jan 2020 20:00:36 -0600 +Subject: [PATCH 17/31] irqchip/sun6i-r: Add wakeup support + +Maintain a mask of wake-enabled IRQs, and enable them in hardware +during the syscore phase of suspend. The restore the original mask +of enabled IRQs (just the NMI) during resume. + +This serves two purposes. First, it lets power management firmware +running on the ARISC coprocessor know which wakeup sources Linux wants +to have enabled. That way, it can avoid turning them off when it shuts +down the remainder of the clock tree. Second, it preconfigures the +coprocessor's interrupt controller, so the firmware's wakeup logic +is as simple as waiting for an interrupt to arrive. + +Signed-off-by: Samuel Holland +--- + drivers/irqchip/irq-sun6i-r.c | 51 +++++++++++++++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + +--- a/drivers/irqchip/irq-sun6i-r.c ++++ b/drivers/irqchip/irq-sun6i-r.c +@@ -3,12 +3,14 @@ + // Allwinner A31 and newer SoCs R_INTC driver + // + ++#include + #include + #include + #include + #include + #include + #include ++#include + + #include + +@@ -24,6 +26,9 @@ + static void __iomem *base; + static irq_hw_number_t parent_offset; + static u32 parent_type; ++#ifdef CONFIG_PM_SLEEP ++static atomic_t wake_mask; ++#endif + + static struct irq_chip sun6i_r_intc_edge_chip; + static struct irq_chip sun6i_r_intc_level_chip; +@@ -104,6 +109,20 @@ static int sun6i_r_intc_irq_set_type(str + return irq_chip_set_type_parent(data, type); + } + ++#ifdef CONFIG_PM_SLEEP ++static int sun6i_r_intc_irq_set_wake(struct irq_data *data, unsigned int on) ++{ ++ if (on) ++ atomic_or(BIT(data->hwirq), &wake_mask); ++ else ++ atomic_andnot(BIT(data->hwirq), &wake_mask); ++ ++ return 0; ++} ++#else ++#define sun6i_r_intc_irq_set_wake NULL ++#endif ++ + static struct irq_chip sun6i_r_intc_edge_chip = { + .name = "sun6i-r-intc", + .irq_mask = sun6i_r_intc_irq_mask, +@@ -113,6 +132,7 @@ static struct irq_chip sun6i_r_intc_edge + .irq_set_type = sun6i_r_intc_irq_set_type, + .irq_get_irqchip_state = irq_chip_get_parent_state, + .irq_set_irqchip_state = irq_chip_set_parent_state, ++ .irq_set_wake = sun6i_r_intc_irq_set_wake, + .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, + .flags = IRQCHIP_SET_TYPE_MASKED, + }; +@@ -126,6 +146,7 @@ static struct irq_chip sun6i_r_intc_leve + .irq_set_type = sun6i_r_intc_irq_set_type, + .irq_get_irqchip_state = irq_chip_get_parent_state, + .irq_set_irqchip_state = irq_chip_set_parent_state, ++ .irq_set_wake = sun6i_r_intc_irq_set_wake, + .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, + .flags = IRQCHIP_SET_TYPE_MASKED, + }; +@@ -166,6 +187,34 @@ static const struct irq_domain_ops sun6i + .free = irq_domain_free_irqs_common, + }; + ++#ifdef CONFIG_PM_SLEEP ++static int sun6i_r_intc_suspend(void) ++{ ++ /* All wake IRQs are enabled during system sleep. */ ++ writel_relaxed(atomic_read(&wake_mask), base + SUN6I_R_INTC_ENABLE); ++ ++ return 0; ++} ++ ++static void sun6i_r_intc_resume(void) ++{ ++ /* Only the NMI is relevant during normal operation. */ ++ writel_relaxed(NMI_HWIRQ_BIT, base + SUN6I_R_INTC_ENABLE); ++} ++ ++static struct syscore_ops sun6i_r_intc_syscore_ops = { ++ .suspend = sun6i_r_intc_suspend, ++ .resume = sun6i_r_intc_resume, ++}; ++ ++static void sun6i_r_intc_syscore_init(void) ++{ ++ register_syscore_ops(&sun6i_r_intc_syscore_ops); ++} ++#else ++static inline void sun6i_r_intc_syscore_init(void) {} ++#endif ++ + static int __init sun6i_r_intc_init(struct device_node *node, + struct device_node *parent) + { +@@ -207,6 +256,8 @@ static int __init sun6i_r_intc_init(stru + writel_relaxed(NMI_HWIRQ_BIT, base + SUN6I_R_INTC_PENDING); + writel_relaxed(NMI_HWIRQ_BIT, base + SUN6I_R_INTC_ENABLE); + ++ sun6i_r_intc_syscore_init(); ++ + return 0; + } + IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init); diff --git a/projects/Allwinner/patches/linux/crust/0018-dt-bindings-irq-Add-a-compatible-for-the-H3-R_INTC.patch b/projects/Allwinner/patches/linux/crust/0018-dt-bindings-irq-Add-a-compatible-for-the-H3-R_INTC.patch new file mode 100644 index 0000000000..a1d41598c3 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0018-dt-bindings-irq-Add-a-compatible-for-the-H3-R_INTC.patch @@ -0,0 +1,48 @@ +From 3d11a3e09d7ff58981243371c52c905b2bb24cde Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 12 Jan 2020 20:21:45 -0600 +Subject: [PATCH 18/31] dt-bindings: irq: Add a compatible for the H3 R_INTC + +The Allwinner H3 SoC contains an R_INTC that is, as far as we know, +compatible with the R_INTC present in other sun8i/sun50i SoCs starting +with the A31. Since the R_INTC hardware is undocumented, introduce a new +compatible for the R_INTC variant in this SoC, in case there turns out +to be some difference. + +Signed-off-by: Samuel Holland +--- + .../allwinner,sun7i-a20-sc-nmi.yaml | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml +@@ -23,22 +23,20 @@ properties: + compatible: + oneOf: + - const: allwinner,sun6i-a31-r-intc ++ - items: ++ - enum: ++ - allwinner,sun8i-a83t-r-intc ++ - allwinner,sun8i-h3-r-intc ++ - allwinner,sun50i-a64-r-intc ++ - allwinner,sun50i-h6-r-intc ++ - const: allwinner,sun6i-a31-r-intc + - const: allwinner,sun6i-a31-sc-nmi + deprecated: true + - const: allwinner,sun7i-a20-sc-nmi +- - items: +- - const: allwinner,sun8i-a83t-r-intc +- - const: allwinner,sun6i-a31-r-intc + - const: allwinner,sun9i-a80-nmi + - items: +- - const: allwinner,sun50i-a64-r-intc +- - const: allwinner,sun6i-a31-r-intc +- - items: + - const: allwinner,sun50i-a100-nmi + - const: allwinner,sun9i-a80-nmi +- - items: +- - const: allwinner,sun50i-h6-r-intc +- - const: allwinner,sun6i-a31-r-intc + + reg: + maxItems: 1 diff --git a/projects/Allwinner/patches/linux/crust/0019-ARM-dts-sunxi-h3-h5-Add-r_intc-node.patch b/projects/Allwinner/patches/linux/crust/0019-ARM-dts-sunxi-h3-h5-Add-r_intc-node.patch new file mode 100644 index 0000000000..887fc39996 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0019-ARM-dts-sunxi-h3-h5-Add-r_intc-node.patch @@ -0,0 +1,33 @@ +From acb925d41cbefdf633dd7b1a75179aef7dd2c131 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 12 Jan 2020 20:27:08 -0600 +Subject: [PATCH 19/31] ARM: dts: sunxi: h3/h5: Add r_intc node + +The H3 and H5 SoCs have an additional interrupt controller in the RTC +power domain that can be used to enable wakeup for certain IRQs. + +Add a node for it. + +Signed-off-by: Samuel Holland +--- + arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi ++++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi +@@ -847,6 +847,15 @@ + #clock-cells = <1>; + }; + ++ r_intc: interrupt-controller@1f00c00 { ++ compatible = "allwinner,sun8i-h3-r-intc", ++ "allwinner,sun6i-a31-r-intc"; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x01f00c00 0x400>; ++ interrupts = ; ++ }; ++ + r_ccu: clock@1f01400 { + compatible = "allwinner,sun8i-h3-r-ccu"; + reg = <0x01f01400 0x100>; diff --git a/projects/Allwinner/patches/linux/crust/0020-ARM-dts-sunxi-h3-h5-Move-wakeup-capable-IRQs-to-r_in.patch b/projects/Allwinner/patches/linux/crust/0020-ARM-dts-sunxi-h3-h5-Move-wakeup-capable-IRQs-to-r_in.patch new file mode 100644 index 0000000000..dcddcc10f2 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0020-ARM-dts-sunxi-h3-h5-Move-wakeup-capable-IRQs-to-r_in.patch @@ -0,0 +1,51 @@ +From 8882b2c4cca1e25bd6b6fb29c9ea072d8ef7f68f Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 25 Aug 2019 19:41:02 -0500 +Subject: [PATCH 20/31] ARM: dts: sunxi: h3/h5: Move wakeup-capable IRQs to + r_intc + +All IRQs that can be used to wake up the system must be routed through +r_intc, so they are visible to firmware while the system is suspended. + +For the H3/H5, r_intc IRQ numbers are offset by 32 from the GIC IRQ +numbers. + +Signed-off-by: Samuel Holland +--- + arch/arm/boot/dts/sunxi-h3-h5.dtsi | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi ++++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi +@@ -840,8 +840,9 @@ + rtc: rtc@1f00000 { + /* compatible is in per SoC .dtsi file */ + reg = <0x01f00000 0x400>; +- interrupts = , +- ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>, ++ <9 IRQ_TYPE_LEVEL_HIGH>; + clock-output-names = "osc32k", "osc32k-out", "iosc"; + clocks = <&osc32k>; + #clock-cells = <1>; +@@ -877,7 +878,8 @@ + clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>; + clock-names = "apb", "ir"; + resets = <&r_ccu RST_APB0_IR>; +- interrupts = ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x01f02000 0x400>; + status = "disabled"; + }; +@@ -898,7 +900,8 @@ + r_pio: pinctrl@1f02c00 { + compatible = "allwinner,sun8i-h3-r-pinctrl"; + reg = <0x01f02c00 0x400>; +- interrupts = ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&rtc 0>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; diff --git a/projects/Allwinner/patches/linux/crust/0022-arm64-dts-allwinner-a64-Move-wakeup-capable-IRQs-to-.patch b/projects/Allwinner/patches/linux/crust/0022-arm64-dts-allwinner-a64-Move-wakeup-capable-IRQs-to-.patch new file mode 100644 index 0000000000..d6040de8d7 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0022-arm64-dts-allwinner-a64-Move-wakeup-capable-IRQs-to-.patch @@ -0,0 +1,51 @@ +From 79d2176f5cf2902afd677a7fa8b5247e5710c132 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 12 Jan 2020 20:32:15 -0600 +Subject: [PATCH 22/31] arm64: dts: allwinner: a64: Move wakeup-capable IRQs to + r_intc + +All IRQs that can be used to wake up the system must be routed through +r_intc, so they are visible to firmware while the system is suspended. + +For the A64, r_intc IRQ numbers are offset by 32 from the GIC IRQ +numbers. + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +@@ -1191,8 +1191,9 @@ + compatible = "allwinner,sun50i-a64-rtc", + "allwinner,sun8i-h3-rtc"; + reg = <0x01f00000 0x400>; +- interrupts = , +- ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>, ++ <9 IRQ_TYPE_LEVEL_HIGH>; + clock-output-names = "osc32k", "osc32k-out", "iosc"; + clocks = <&osc32k>; + #clock-cells = <1>; +@@ -1243,7 +1244,8 @@ + clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>; + clock-names = "apb", "ir"; + resets = <&r_ccu RST_APB0_IR>; +- interrupts = ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&r_ir_rx_pin>; + status = "disabled"; +@@ -1263,7 +1265,8 @@ + r_pio: pinctrl@1f02c00 { + compatible = "allwinner,sun50i-a64-r-pinctrl"; + reg = <0x01f02c00 0x400>; +- interrupts = ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&osc32k>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; diff --git a/projects/Allwinner/patches/linux/crust/0023-arm64-dts-allwinner-h6-Fix-indentation-of-IR-node.patch b/projects/Allwinner/patches/linux/crust/0023-arm64-dts-allwinner-h6-Fix-indentation-of-IR-node.patch new file mode 100644 index 0000000000..4e096a9185 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0023-arm64-dts-allwinner-h6-Fix-indentation-of-IR-node.patch @@ -0,0 +1,44 @@ +From 537cf6daced84919286130c68735a248c62c186d Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 12 Jan 2020 20:33:18 -0600 +Subject: [PATCH 23/31] arm64: dts: allwinner: h6: Fix indentation of IR node + +This node was indented by two tabs when added instead of one. +Remove the extra tab. + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 22 ++++++++++---------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -941,17 +941,17 @@ + }; + + r_ir: ir@7040000 { +- compatible = "allwinner,sun50i-h6-ir", +- "allwinner,sun6i-a31-ir"; +- reg = <0x07040000 0x400>; +- interrupts = ; +- clocks = <&r_ccu CLK_R_APB1_IR>, +- <&r_ccu CLK_IR>; +- clock-names = "apb", "ir"; +- resets = <&r_ccu RST_R_APB1_IR>; +- pinctrl-names = "default"; +- pinctrl-0 = <&r_ir_rx_pin>; +- status = "disabled"; ++ compatible = "allwinner,sun50i-h6-ir", ++ "allwinner,sun6i-a31-ir"; ++ reg = <0x07040000 0x400>; ++ interrupts = ; ++ clocks = <&r_ccu CLK_R_APB1_IR>, ++ <&r_ccu CLK_IR>; ++ clock-names = "apb", "ir"; ++ resets = <&r_ccu RST_R_APB1_IR>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&r_ir_rx_pin>; ++ status = "disabled"; + }; + + r_i2c: i2c@7081400 { diff --git a/projects/Allwinner/patches/linux/crust/0024-arm64-dts-allwinner-h6-Move-wakeup-capable-IRQs-to-r.patch b/projects/Allwinner/patches/linux/crust/0024-arm64-dts-allwinner-h6-Move-wakeup-capable-IRQs-to-r.patch new file mode 100644 index 0000000000..25ce155229 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0024-arm64-dts-allwinner-h6-Move-wakeup-capable-IRQs-to-r.patch @@ -0,0 +1,53 @@ +From d05c22e9079675ba1834ddac322897b45026ff90 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 25 Aug 2019 05:35:23 -0500 +Subject: [PATCH 24/31] arm64: dts: allwinner: h6: Move wakeup-capable IRQs to + r_intc + +All IRQs that can be used to wake up the system must be routed through +r_intc, so they are visible to firmware while the system is suspended. + +For the H6, r_intc IRQ numbers are offset by 96 from the GIC IRQ +numbers. + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -883,8 +883,9 @@ + rtc: rtc@7000000 { + compatible = "allwinner,sun50i-h6-rtc"; + reg = <0x07000000 0x400>; +- interrupts = , +- ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, ++ <6 IRQ_TYPE_LEVEL_HIGH>; + clock-output-names = "osc32k", "osc32k-out", "iosc"; + #clock-cells = <1>; + }; +@@ -920,8 +921,9 @@ + r_pio: pinctrl@7022000 { + compatible = "allwinner,sun50i-h6-r-pinctrl"; + reg = <0x07022000 0x400>; +- interrupts = , +- ; ++ interrupt-parent = <&r_intc>; ++ interrupts = < 9 IRQ_TYPE_LEVEL_HIGH>, ++ <15 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>; + clock-names = "apb", "hosc", "losc"; + gpio-controller; +@@ -944,7 +946,8 @@ + compatible = "allwinner,sun50i-h6-ir", + "allwinner,sun6i-a31-ir"; + reg = <0x07040000 0x400>; +- interrupts = ; ++ interrupt-parent = <&r_intc>; ++ interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&r_ccu CLK_R_APB1_IR>, + <&r_ccu CLK_IR>; + clock-names = "apb", "ir"; diff --git a/projects/Allwinner/patches/linux/crust/0025-rtc-sun6i-Use-wake-IRQ-instead-of-device-PM-ops.patch b/projects/Allwinner/patches/linux/crust/0025-rtc-sun6i-Use-wake-IRQ-instead-of-device-PM-ops.patch new file mode 100644 index 0000000000..775a80f3b8 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0025-rtc-sun6i-Use-wake-IRQ-instead-of-device-PM-ops.patch @@ -0,0 +1,78 @@ +From 882c9a65a1e6bb9bf1ddee8b2512f57b72cb9860 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 25 Aug 2019 05:36:21 -0500 +Subject: [PATCH 25/31] rtc: sun6i: Use wake IRQ instead of device PM ops + +Since the RTC has a single IRQ, we can use the generic wake IRQ +implementation instead of defining our own device PM ops. This has the +same effect with quite a bit less code. + +Signed-off-by: Samuel Holland +--- + drivers/rtc/rtc-sun6i.c | 34 ++++++---------------------------- + 1 file changed, 6 insertions(+), 28 deletions(-) + +--- a/drivers/rtc/rtc-sun6i.c ++++ b/drivers/rtc/rtc-sun6i.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -639,33 +640,6 @@ static const struct rtc_class_ops sun6i_ + .alarm_irq_enable = sun6i_rtc_alarm_irq_enable + }; + +-#ifdef CONFIG_PM_SLEEP +-/* Enable IRQ wake on suspend, to wake up from RTC. */ +-static int sun6i_rtc_suspend(struct device *dev) +-{ +- struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); +- +- if (device_may_wakeup(dev)) +- enable_irq_wake(chip->irq); +- +- return 0; +-} +- +-/* Disable IRQ wake on resume. */ +-static int sun6i_rtc_resume(struct device *dev) +-{ +- struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); +- +- if (device_may_wakeup(dev)) +- disable_irq_wake(chip->irq); +- +- return 0; +-} +-#endif +- +-static SIMPLE_DEV_PM_OPS(sun6i_rtc_pm_ops, +- sun6i_rtc_suspend, sun6i_rtc_resume); +- + static int sun6i_rtc_probe(struct platform_device *pdev) + { + struct sun6i_rtc_dev *chip = sun6i_rtc; +@@ -716,6 +690,11 @@ static int sun6i_rtc_probe(struct platfo + clk_prepare_enable(chip->losc); + + device_init_wakeup(&pdev->dev, 1); ++ ret = dev_pm_set_wake_irq(&pdev->dev, chip->irq); ++ if (ret) { ++ dev_err(&pdev->dev, "Could not set wake IRQ\n"); ++ return ret; ++ } + + chip->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(chip->rtc)) +@@ -756,7 +735,6 @@ static struct platform_driver sun6i_rtc_ + .driver = { + .name = "sun6i-rtc", + .of_match_table = sun6i_rtc_dt_ids, +- .pm = &sun6i_rtc_pm_ops, + }, + }; + builtin_platform_driver(sun6i_rtc_driver); diff --git a/projects/Allwinner/patches/linux/crust/0026-dt-bindings-sram-Add-ARM-SCP-SRAM-compatible.patch b/projects/Allwinner/patches/linux/crust/0026-dt-bindings-sram-Add-ARM-SCP-SRAM-compatible.patch new file mode 100644 index 0000000000..38ec5e5d6d --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0026-dt-bindings-sram-Add-ARM-SCP-SRAM-compatible.patch @@ -0,0 +1,28 @@ +From fe9d1c2c4700b8a8a31ee7d431cd9993b26f8953 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sat, 18 Jul 2020 17:18:23 -0500 +Subject: [PATCH 26/31] dt-bindings: sram: Add ARM SCP SRAM compatible + +As of commit a90b15e0ad72 ("Documentation: bindings: decouple juno +specific details from generic binding"), the SCPI binding in +Documentation/devicetree/bindings/arm/arm,scpi.txt mandates that SRAM +sections used for SCPI shared memory are compatible with arm,scp-shmem. +However, this compatible is missing from the SRAM binding. + +Add the arm,scp-shmem compatible here to match the SCPI binding. + +Signed-off-by: Samuel Holland +--- + Documentation/devicetree/bindings/sram/sram.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/sram/sram.yaml ++++ b/Documentation/devicetree/bindings/sram/sram.yaml +@@ -76,6 +76,7 @@ patternProperties: + - amlogic,meson8b-smp-sram + - amlogic,meson-gxbb-scp-shmem + - amlogic,meson-axg-scp-shmem ++ - arm,scp-shmem + - renesas,smp-sram + - rockchip,rk3066-smp-sram + - samsung,exynos4210-sysram diff --git a/projects/Allwinner/patches/linux/crust/0027-firmware-arm_scpi-Support-unidirectional-mailbox-cha.patch b/projects/Allwinner/patches/linux/crust/0027-firmware-arm_scpi-Support-unidirectional-mailbox-cha.patch new file mode 100644 index 0000000000..20fed7af21 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0027-firmware-arm_scpi-Support-unidirectional-mailbox-cha.patch @@ -0,0 +1,123 @@ +From fef8b000f7e05397399b78891f26c53a2581863a Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Tue, 5 Mar 2019 22:02:41 -0600 +Subject: [PATCH 27/31] firmware: arm_scpi: Support unidirectional mailbox + channels + +Some mailbox controllers have only unidirectional channels, so we need a +pair of them for each SCPI channel. If a mbox-names property is present, +look for "rx" and "tx" mbox channels; otherwise, the existing behavior +is preserved, and a single mbox channel is used for each SCPI channel. + +Note that since the mailbox framework only supports a single phandle +with each name (mbox_request_channel_byname always returns the first +one), this new mode only supports a single SCPI channel. + +Signed-off-by: Samuel Holland +--- + drivers/firmware/arm_scpi.c | 58 +++++++++++++++++++++++++++++-------- + 1 file changed, 46 insertions(+), 12 deletions(-) + +--- a/drivers/firmware/arm_scpi.c ++++ b/drivers/firmware/arm_scpi.c +@@ -231,7 +231,8 @@ struct scpi_xfer { + + struct scpi_chan { + struct mbox_client cl; +- struct mbox_chan *chan; ++ struct mbox_chan *rx_chan; ++ struct mbox_chan *tx_chan; + void __iomem *tx_payload; + void __iomem *rx_payload; + struct list_head rx_pending; +@@ -505,7 +506,7 @@ static int scpi_send_message(u8 idx, voi + msg->rx_len = rx_len; + reinit_completion(&msg->done); + +- ret = mbox_send_message(scpi_chan->chan, msg); ++ ret = mbox_send_message(scpi_chan->tx_chan, msg); + if (ret < 0 || !rx_buf) + goto out; + +@@ -854,8 +855,13 @@ static void scpi_free_channels(void *dat + struct scpi_drvinfo *info = data; + int i; + +- for (i = 0; i < info->num_chans; i++) +- mbox_free_channel(info->channels[i].chan); ++ for (i = 0; i < info->num_chans; i++) { ++ struct scpi_chan *pchan = &info->channels[i]; ++ ++ if (pchan->tx_chan != pchan->rx_chan) ++ mbox_free_channel(pchan->tx_chan); ++ mbox_free_channel(pchan->rx_chan); ++ } + } + + static int scpi_remove(struct platform_device *pdev) +@@ -903,6 +909,7 @@ static int scpi_probe(struct platform_de + struct resource res; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; ++ bool use_mbox_names = false; + + scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL); + if (!scpi_info) +@@ -916,6 +923,14 @@ static int scpi_probe(struct platform_de + dev_err(dev, "no mboxes property in '%pOF'\n", np); + return -ENODEV; + } ++ if (of_get_property(dev->of_node, "mbox-names", NULL)) { ++ use_mbox_names = true; ++ if (count != 2) { ++ dev_err(dev, "need exactly 2 mboxes with mbox-names\n"); ++ return -ENODEV; ++ } ++ count /= 2; ++ } + + scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan), + GFP_KERNEL); +@@ -961,15 +976,34 @@ static int scpi_probe(struct platform_de + mutex_init(&pchan->xfers_lock); + + ret = scpi_alloc_xfer_list(dev, pchan); +- if (!ret) { +- pchan->chan = mbox_request_channel(cl, idx); +- if (!IS_ERR(pchan->chan)) +- continue; +- ret = PTR_ERR(pchan->chan); +- if (ret != -EPROBE_DEFER) +- dev_err(dev, "failed to get channel%d err %d\n", +- idx, ret); ++ if (ret) ++ return ret; ++ ++ if (use_mbox_names) { ++ pchan->rx_chan = mbox_request_channel_byname(cl, "rx"); ++ if (IS_ERR(pchan->rx_chan)) { ++ ret = PTR_ERR(pchan->rx_chan); ++ goto fail; ++ } ++ pchan->tx_chan = mbox_request_channel_byname(cl, "tx"); ++ if (IS_ERR(pchan->rx_chan)) { ++ ret = PTR_ERR(pchan->tx_chan); ++ goto fail; ++ } ++ } else { ++ pchan->rx_chan = mbox_request_channel(cl, idx); ++ if (IS_ERR(pchan->rx_chan)) { ++ ret = PTR_ERR(pchan->rx_chan); ++ goto fail; ++ } ++ pchan->tx_chan = pchan->rx_chan; + } ++ continue; ++ ++fail: ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to get channel%d err %d\n", ++ idx, ret); + return ret; + } + diff --git a/projects/Allwinner/patches/linux/crust/0029-ARM-dts-sunxi-h3-h5-Add-SCPI-protocol.patch b/projects/Allwinner/patches/linux/crust/0029-ARM-dts-sunxi-h3-h5-Add-SCPI-protocol.patch new file mode 100644 index 0000000000..0a1ecb226e --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0029-ARM-dts-sunxi-h3-h5-Add-SCPI-protocol.patch @@ -0,0 +1,72 @@ +From 13bd8de3e31b42b4a44310294a29c620f36936ba Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Wed, 1 Jan 2020 16:12:36 -0600 +Subject: [PATCH 29/31] ARM: dts: sunxi: h3/h5: Add SCPI protocol + +Signed-off-by: Samuel Holland +--- + arch/arm/boot/dts/sun8i-h3.dtsi | 13 +++++++++++++ + arch/arm/boot/dts/sunxi-h3-h5.dtsi | 7 +++++++ + arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 13 +++++++++++++ + 3 files changed, 33 insertions(+) + +--- a/arch/arm/boot/dts/sun8i-h3.dtsi ++++ b/arch/arm/boot/dts/sun8i-h3.dtsi +@@ -170,6 +170,19 @@ + #size-cells = <1>; + ranges; + ++ sram_a2: sram@40000 { ++ compatible = "mmio-sram"; ++ reg = <0x00040000 0xc000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x00040000 0xc000>; ++ ++ scpi_sram: scpi-sram@bc00 { ++ compatible = "arm,scp-shmem"; ++ reg = <0xbc00 0x200>; ++ }; ++ }; ++ + sram_c: sram@1d00000 { + compatible = "mmio-sram"; + reg = <0x01d00000 0x80000>; +--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi ++++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi +@@ -105,6 +105,13 @@ + status = "disabled"; + }; + ++ scpi_protocol: scpi { ++ compatible = "arm,scpi"; ++ mboxes = <&msgbox 2>, <&msgbox 3>; ++ mbox-names = "tx", "rx"; ++ shmem = <&scpi_sram>; ++ }; ++ + soc { + compatible = "simple-bus"; + #address-cells = <1>; +--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi +@@ -86,6 +86,19 @@ + #size-cells = <1>; + ranges; + ++ sram_a2: sram@40000 { ++ compatible = "mmio-sram"; ++ reg = <0x00040000 0x14000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x00040000 0x14000>; ++ ++ scpi_sram: scpi-sram@13c00 { ++ compatible = "arm,scp-shmem"; ++ reg = <0x13c00 0x200>; ++ }; ++ }; ++ + sram_c1: sram@18000 { + compatible = "mmio-sram"; + reg = <0x00018000 0x1c000>; diff --git a/projects/Allwinner/patches/linux/crust/0030-arm64-dts-allwinner-a64-Add-SCPI-protocol.patch b/projects/Allwinner/patches/linux/crust/0030-arm64-dts-allwinner-a64-Add-SCPI-protocol.patch new file mode 100644 index 0000000000..c83ac885ca --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0030-arm64-dts-allwinner-a64-Add-SCPI-protocol.patch @@ -0,0 +1,46 @@ +From f0550a4bd9eefe64469813d81a1549ba31182ad7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sat, 14 Dec 2019 20:52:53 -0600 +Subject: [PATCH 30/31] arm64: dts: allwinner: a64: Add SCPI protocol + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +@@ -130,6 +130,13 @@ + method = "smc"; + }; + ++ scpi_protocol: scpi { ++ compatible = "arm,scpi"; ++ mboxes = <&msgbox 2>, <&msgbox 3>; ++ mbox-names = "tx", "rx"; ++ shmem = <&scpi_sram>; ++ }; ++ + sound: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sun50i-a64-audio"; +@@ -339,6 +346,19 @@ + #size-cells = <1>; + ranges; + ++ sram_a2: sram@40000 { ++ compatible = "mmio-sram"; ++ reg = <0x00040000 0x14000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x00040000 0x14000>; ++ ++ scpi_sram: scpi-sram@13c00 { ++ compatible = "arm,scp-shmem"; ++ reg = <0x13c00 0x200>; ++ }; ++ }; ++ + sram_c: sram@18000 { + compatible = "mmio-sram"; + reg = <0x00018000 0x28000>; diff --git a/projects/Allwinner/patches/linux/crust/0031-arm64-dts-allwinner-h6-Add-SCPI-protocol.patch b/projects/Allwinner/patches/linux/crust/0031-arm64-dts-allwinner-h6-Add-SCPI-protocol.patch new file mode 100644 index 0000000000..08ea5eda64 --- /dev/null +++ b/projects/Allwinner/patches/linux/crust/0031-arm64-dts-allwinner-h6-Add-SCPI-protocol.patch @@ -0,0 +1,46 @@ +From d39c105f72223beb931088032b82114c6ad01cba Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sat, 14 Dec 2019 20:54:40 -0600 +Subject: [PATCH 31/31] arm64: dts: allwinner: h6: Add SCPI protocol + +Signed-off-by: Samuel Holland +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -88,6 +88,13 @@ + method = "smc"; + }; + ++ scpi_protocol: scpi { ++ compatible = "arm,scpi"; ++ mboxes = <&msgbox 2>, <&msgbox 3>; ++ mbox-names = "tx", "rx"; ++ shmem = <&scpi_sram>; ++ }; ++ + timer { + compatible = "arm,armv8-timer"; + arm,no-tick-in-suspend; +@@ -196,6 +203,19 @@ + #size-cells = <1>; + ranges; + ++ sram_a2: sram@100000 { ++ compatible = "mmio-sram"; ++ reg = <0x00100000 0x18000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x00100000 0x18000>; ++ ++ scpi_sram: scpi-sram@17c00 { ++ compatible = "arm,scp-shmem"; ++ reg = <0x17c00 0x200>; ++ }; ++ }; ++ + sram_c: sram@28000 { + compatible = "mmio-sram"; + reg = <0x00028000 0x1e000>; diff --git a/scripts/uboot_helper b/scripts/uboot_helper index 400cf76624..d5c1415a3f 100755 --- a/scripts/uboot_helper +++ b/scripts/uboot_helper @@ -24,7 +24,8 @@ devices = \ 'A64': { 'orangepi-win': { 'dtb': 'sun50i-a64-orangepi-win.dtb', - 'config': 'orangepi_win_defconfig' + 'config': 'orangepi_win_defconfig', + 'crust_config': 'orangepi_win_defconfig', }, 'pine64': { 'dtb': 'sun50i-a64-pine64.dtb', @@ -36,7 +37,8 @@ devices = \ }, 'pine64-plus': { 'dtb': 'sun50i-a64-pine64-plus.dtb', - 'config': 'pine64_plus_defconfig' + 'config': 'pine64_plus_defconfig', + 'crust_config': 'pine64_plus_defconfig', }, }, 'H2-plus': { @@ -64,29 +66,35 @@ devices = \ }, 'orangepi-2': { 'dtb': 'sun8i-h3-orangepi-2.dtb', - 'config': 'orangepi_2_defconfig' + 'config': 'orangepi_2_defconfig', + 'crust_config': 'orangepi_2_defconfig', }, 'orangepi-pc': { 'dtb': 'sun8i-h3-orangepi-pc.dtb', - 'config': 'orangepi_pc_defconfig' + 'config': 'orangepi_pc_defconfig', + 'crust_config': 'orangepi_pc_defconfig', }, 'orangepi-pc-plus': { 'dtb': 'sun8i-h3-orangepi-pc-plus.dtb', - 'config': 'orangepi_pc_plus_defconfig' + 'config': 'orangepi_pc_plus_defconfig', + 'crust_config': 'orangepi_pc_plus_defconfig', }, 'orangepi-plus2e': { 'dtb': 'sun8i-h3-orangepi-plus2e.dtb', - 'config': 'orangepi_plus2e_defconfig' + 'config': 'orangepi_plus2e_defconfig', + 'crust_config': 'orangepi_plus2e_defconfig', }, 'orangepi-plus': { 'dtb': 'sun8i-h3-orangepi-plus.dtb', - 'config': 'orangepi_plus_defconfig' + 'config': 'orangepi_plus_defconfig', + 'crust_config': 'orangepi_plus_defconfig', }, }, 'H5' : { 'orangepi-pc2': { 'dtb': 'sun50i-h5-orangepi-pc2.dtb', - 'config': 'orangepi_pc2_defconfig' + 'config': 'orangepi_pc2_defconfig', + 'crust_config': 'orangepi_pc2_defconfig', }, 'tritium-h5': { 'dtb': 'sun50i-h5-libretech-all-h3-cc.dtb', @@ -100,7 +108,8 @@ devices = \ }, 'orangepi-3': { 'dtb': 'sun50i-h6-orangepi-3.dtb', - 'config': 'orangepi_3_defconfig' + 'config': 'orangepi_3_defconfig', + 'crust_config': 'orangepi_3_defconfig', }, 'orangepi-lite2': { 'dtb': 'sun50i-h6-orangepi-lite2.dtb', @@ -112,7 +121,8 @@ devices = \ }, 'pine-h64': { 'dtb': 'sun50i-h6-pine-h64.dtb', - 'config': 'pine_h64_defconfig' + 'config': 'pine_h64_defconfig', + 'crust_config': 'pine_h64_defconfig', }, 'pine-h64-model-b': { 'dtb': 'sun50i-h6-pine-h64-model-b.dtb', @@ -380,7 +390,7 @@ if len(sys.argv) > 3 and sys.argv[3] not in devices[sys.argv[1]][sys.argv[2]]: if len(sys.argv) == 4: exit_error('Invalid option: must specify dtb or config', PROJECT=sys.argv[1], SOC=sys.argv[2]) -elif len(sys.argv) > 4 and sys.argv[4] not in ['dtb', 'config']: +elif len(sys.argv) > 4 and sys.argv[4] not in ['dtb', 'config', 'crust_config']: exit_error('Invalid option: %s' % sys.argv[4], PROJECT=sys.argv[1], SOC=sys.argv[2]) if len(sys.argv) > 5: @@ -389,7 +399,8 @@ if len(sys.argv) > 5: # Get dtb or u-boot config for a given project, soc, and board # ./scripts/uboot_helper project device board-name dtb|config if len(sys.argv) == 5: - print(devices[sys.argv[1]][sys.argv[2]][sys.argv[3]][sys.argv[4]]) + if sys.argv[4] in devices[sys.argv[1]][sys.argv[2]][sys.argv[3]]: + print(devices[sys.argv[1]][sys.argv[2]][sys.argv[3]][sys.argv[4]]) # List boards supported by a given project and soc # ./scripts/uboot_helper project device