From b854992ef2bf87123793976d0efec0f452c823af Mon Sep 17 00:00:00 2001 From: "Ycarus (Yannick Chabanois)" Date: Sat, 22 Jun 2019 20:21:54 +0200 Subject: [PATCH] Add working ext4 support for BPI-R2, but dirty for now --- root/package/boot/uboot-mediatek/Makefile | 58 + .../patches/0001-update-defconfig.patch | 39 + ...ding-saveenv-command-for-bananapi-r2.patch | 61 + ...dd-reset-controller-driver-for-Media.patch | 189 ++ ...ediaTek-bind-ethsys-reset-controller.patch | 109 ++ ...k-add-ethernet-driver-for-MediaTek-A.patch | 1517 +++++++++++++++++ ...ethernet-related-node-for-MT7623-SoC.patch | 76 + ...ethernet-related-node-for-MT7629-SoC.patch | 95 ++ ...d-ethernet-support-for-MT7623-boards.patch | 59 + ...d-ethernet-support-for-MT7629-boards.patch | 58 + ...ERS-ARM-MEDIATEK-update-file-entries.patch | 25 + ...-use-OF_SEPARATE-instead-of-OF_EMBED.patch | 40 + .../0013-test-add-test-for-lib-lmb.c.patch | 326 ++++ ...x-allocation-at-end-of-address-range.patch | 157 ++ ...ving-overlapping-regions-should-fail.patch | 208 +++ ...served-memory-for-memory-reservation.patch | 117 ++ ...b-extend-lmb-for-checks-at-load-time.patch | 312 ++++ ...-prevent-overwriting-reserved-memory.patch | 138 ++ ...common-function-lmb_init_and_reserve.patch | 35 + ...lmb-remove-unused-extern-declaration.patch | 26 + ...-prevent-overwriting-reserved-memory.patch | 172 ++ ...sp-detection-at-end-of-address-range.patch | 46 + ...d-strings-and-setenv-used-for-lstftp.patch | 27 + ...-increase-size-for-environment-4k-8k.patch | 22 + ...025-bootmenu-added-key-input-1-9-a-f.patch | 216 +++ .../boot/uboot-mediatek/uEnv-default.txt | 91 + root/target/linux/mediatek/image/Makefile | 22 + .../mediatek/image/gen_mediatek_sdcard_img.sh | 48 + root/target/linux/mediatek/image/mt7623.mk | 5 +- 29 files changed, 4292 insertions(+), 2 deletions(-) create mode 100644 root/package/boot/uboot-mediatek/Makefile create mode 100644 root/package/boot/uboot-mediatek/patches/0001-update-defconfig.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0002-adding-saveenv-command-for-bananapi-r2.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0003-reset-MedaiTek-add-reset-controller-driver-for-Media.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0004-clk-MediaTek-bind-ethsys-reset-controller.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0005-ethernet-MediaTek-add-ethernet-driver-for-MediaTek-A.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0006-arm-dts-add-ethernet-related-node-for-MT7623-SoC.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0007-arm-dts-add-ethernet-related-node-for-MT7629-SoC.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0008-arm-MediaTek-add-ethernet-support-for-MT7623-boards.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0009-arm-MediaTek-add-ethernet-support-for-MT7629-boards.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0010-MAINTAINERS-ARM-MEDIATEK-update-file-entries.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0011-configs-MediaTek-use-OF_SEPARATE-instead-of-OF_EMBED.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0013-test-add-test-for-lib-lmb.c.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0014-lmb-fix-allocation-at-end-of-address-range.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0015-lib-lmb-reserving-overlapping-regions-should-fail.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0016-fdt-parse-reserved-memory-for-memory-reservation.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0017-lib-lmb-extend-lmb-for-checks-at-load-time.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0018-fs-prevent-overwriting-reserved-memory.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0019-bootm-use-new-common-function-lmb_init_and_reserve.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0020-lmb-remove-unused-extern-declaration.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0021-tftp-prevent-overwriting-reserved-memory.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0022-arm-bootm-fix-sp-detection-at-end-of-address-range.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0023-defconfig-added-strings-and-setenv-used-for-lstftp.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0024-increase-size-for-environment-4k-8k.patch create mode 100644 root/package/boot/uboot-mediatek/patches/0025-bootmenu-added-key-input-1-9-a-f.patch create mode 100644 root/package/boot/uboot-mediatek/uEnv-default.txt create mode 100755 root/target/linux/mediatek/image/gen_mediatek_sdcard_img.sh diff --git a/root/package/boot/uboot-mediatek/Makefile b/root/package/boot/uboot-mediatek/Makefile new file mode 100644 index 00000000..c5a1213d --- /dev/null +++ b/root/package/boot/uboot-mediatek/Makefile @@ -0,0 +1,58 @@ +# +# Copyright (C) 2013-2019 OpenWrt.org +# Copyright (C) 2019 Alexey Loukianov +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_VERSION:=2019.01 + +PKG_HASH:=50bd7e5a466ab828914d080d5f6a432345b500e8fba1ad3b7b61e95e60d51c22 + +PKG_MAINTAINER:=Alexey Loukianov + +include $(INCLUDE_DIR)/u-boot.mk +include $(INCLUDE_DIR)/package.mk + +define U-Boot/Default + BUILD_TARGET:=mediatek + UBOOT_IMAGE:=u-boot.bin + UENV:=default + HIDDEN:=1 +endef + +define U-Boot/mt7623n_bpir2 + BUILD_SUBTARGET:=mt7623 + NAME:=Bannana PI R2 (mt7623) + BUILD_DEVICES:=7623n-bananapi-bpi-r2 +endef + +UBOOT_TARGETS := \ + mt7623n_bpir2 + +UBOOT_CONFIGURE_VARS += USE_PRIVATE_LIBGCC=yes + +UBOOT_MAKE_FLAGS = \ + HOSTCC="$(HOSTCC)" \ + HOSTCFLAGS="$(HOST_CFLAGS) $(HOST_CPPFLAGS) -std=gnu11" \ + HOSTLDFLAGS="$(HOST_LDFLAGS)" + +define Build/Prepare + $(call Build/Prepare/Default) + $(CP) uEnv-$(UENV).txt ${PKG_BUILD_DIR}/uEnv.txt +endef + +define Build/InstallDev + $(INSTALL_DIR) $(STAGING_DIR_IMAGE) + $(CP) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-uboot-mediatek.bin + $(CP) $(PKG_BUILD_DIR)/uEnv.txt $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-uEnv.txt +endef + +define Package/u-boot/install/default +endef + +$(eval $(call BuildPackage/U-Boot)) diff --git a/root/package/boot/uboot-mediatek/patches/0001-update-defconfig.patch b/root/package/boot/uboot-mediatek/patches/0001-update-defconfig.patch new file mode 100644 index 00000000..15023e0a --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0001-update-defconfig.patch @@ -0,0 +1,39 @@ +diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig +index ae4fb280..74252cd0 100644 +--- a/configs/mt7623n_bpir2_defconfig ++++ b/configs/mt7623n_bpir2_defconfig +@@ -3,6 +3,7 @@ CONFIG_SYS_THUMB_BUILD=y + CONFIG_ARCH_MEDIATEK=y + CONFIG_SYS_TEXT_BASE=0x81e00000 + CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_TARGET_MT7623=y + CONFIG_NR_DRAM_BANKS=1 + CONFIG_FIT=y + CONFIG_FIT_VERBOSE=y +@@ -11,7 +12,7 @@ CONFIG_SYS_CONSOLE_IS_IN_ENV=y + CONFIG_DEFAULT_FDT_FILE="mt7623n-bananapi-bpi-r2" + # CONFIG_DISPLAY_BOARDINFO is not set + CONFIG_HUSH_PARSER=y +-CONFIG_SYS_PROMPT="U-Boot> " ++CONFIG_SYS_PROMPT="BPI-R2> " + CONFIG_CMD_BOOTMENU=y + # CONFIG_CMD_ELF is not set + # CONFIG_CMD_XIMG is not set +@@ -51,3 +52,14 @@ CONFIG_MTK_TIMER=y + CONFIG_WDT_MTK=y + CONFIG_LZMA=y + # CONFIG_EFI_LOADER is not set ++ ++CONFIG_CMD_BOOTZ=y ++CONFIG_OF_LIBFDT_OVERLAY=y ++ ++CONFIG_USE_DEFAULT_ENV_FILE=y ++CONFIG_DEFAULT_ENV_FILE="uEnv.txt" ++ ++#enables savenenv-command ++CONFIG_ENV_IS_IN_MMC=y ++ ++CONFIG_CMD_ASKENV=y +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0002-adding-saveenv-command-for-bananapi-r2.patch b/root/package/boot/uboot-mediatek/patches/0002-adding-saveenv-command-for-bananapi-r2.patch new file mode 100644 index 00000000..59acf675 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0002-adding-saveenv-command-for-bananapi-r2.patch @@ -0,0 +1,61 @@ +From 2a59134ba1d841cf1a7845017656b74b74412aaf Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Mon, 3 Dec 2018 15:32:58 +0100 +Subject: adding saveenv-command for bananapi r2 + +bananapi r2 can be booted from sd-card and emmc +saving the environment have to choose the storage +from which the device has booted + +also the offset is set to 1MB-50Kb to make sure env is written +to block "user data area" between uboot and first partition + +https://www.fw-web.de/dokuwiki/lib/exe/fetch.php?cache=&media=bpi-r2:boot-structure.png + +v3: removed changes in defconfig (users choice) +v2: fixed bracket-style in if-else statement + +Signed-off-by: Frank Wunderlich + +diff --git a/board/mediatek/mt7623/mt7623_rfb.c b/board/mediatek/mt7623/mt7623_rfb.c +index 08468b50..4ec27649 100644 +--- a/board/mediatek/mt7623/mt7623_rfb.c ++++ b/board/mediatek/mt7623/mt7623_rfb.c +@@ -14,3 +14,22 @@ int board_init(void) + + return 0; + } ++ ++int mmc_get_boot_dev(void) ++{ ++ int g_mmc_devid = -1; ++ char *uflag = (char *)0x81DFFFF0; ++ if (strncmp(uflag,"eMMC",4)==0) { ++ g_mmc_devid = 0; ++ printf("Boot From Emmc(id:%d)\n\n", g_mmc_devid); ++ } else { ++ g_mmc_devid = 1; ++ printf("Boot From SD(id:%d)\n\n", g_mmc_devid); ++ } ++ return g_mmc_devid; ++} ++ ++int mmc_get_env_dev(void) ++{ ++ return mmc_get_boot_dev(); ++} +diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h +index ba763501..fb6ac073 100644 +--- a/include/configs/mt7623.h ++++ b/include/configs/mt7623.h +@@ -53,4 +53,7 @@ + #define CONFIG_EXTRA_ENV_SETTINGS \ + FDT_HIGH + ++#define CONFIG_SYS_MMC_ENV_DEV 0 ++#define CONFIG_ENV_OFFSET 0xF3800 ++ + #endif +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0003-reset-MedaiTek-add-reset-controller-driver-for-Media.patch b/root/package/boot/uboot-mediatek/patches/0003-reset-MedaiTek-add-reset-controller-driver-for-Media.patch new file mode 100644 index 00000000..ab8f2f42 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0003-reset-MedaiTek-add-reset-controller-driver-for-Media.patch @@ -0,0 +1,189 @@ +From e4033f535d7f6f86f354d36037565a319c02c324 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:51 +0800 +Subject: reset: MedaiTek: add reset controller driver for MediaTek SoCs + +This patch adds reset controller driver for MediaTek SoCs. + +Signed-off-by: Ryder Lee +Signed-off-by: Weijie Gao + +diff --git a/arch/arm/include/asm/arch-mediatek/reset.h b/arch/arm/include/asm/arch-mediatek/reset.h +new file mode 100644 +index 00000000..9704666d +--- /dev/null ++++ b/arch/arm/include/asm/arch-mediatek/reset.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ */ ++ ++#ifndef __MEDIATEK_RESET_H ++#define __MEDIATEK_RESET_H ++ ++#include ++ ++int mediatek_reset_bind(struct udevice *pdev, u32 regofs, u32 num_regs); ++ ++#endif /* __MEDIATEK_RESET_H */ +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index 9c5208b7..3a6d61f4 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -106,4 +106,11 @@ config RESET_SOCFPGA + help + Support for reset controller on SoCFPGA platform. + ++config RESET_MEDIATEK ++ bool "Reset controller driver for MediaTek SoCs" ++ depends on DM_RESET && ARCH_MEDIATEK && CLK ++ default y ++ help ++ Support for reset controller on MediaTek SoCs. ++ + endmenu +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +index f4520878..8a4dcab8 100644 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -17,3 +17,4 @@ obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o + obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o + obj-$(CONFIG_RESET_MESON) += reset-meson.o + obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o ++obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o +diff --git a/drivers/reset/reset-mediatek.c b/drivers/reset/reset-mediatek.c +new file mode 100644 +index 00000000..e3614e6e +--- /dev/null ++++ b/drivers/reset/reset-mediatek.c +@@ -0,0 +1,102 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ * ++ * Author: Ryder Lee ++ * Weijie Gao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct mediatek_reset_priv { ++ struct regmap *regmap; ++ u32 regofs; ++ u32 nr_resets; ++}; ++ ++static int mediatek_reset_request(struct reset_ctl *reset_ctl) ++{ ++ return 0; ++} ++ ++static int mediatek_reset_free(struct reset_ctl *reset_ctl) ++{ ++ return 0; ++} ++ ++static int mediatek_reset_assert(struct reset_ctl *reset_ctl) ++{ ++ struct mediatek_reset_priv *priv = dev_get_priv(reset_ctl->dev); ++ int id = reset_ctl->id; ++ ++ if (id >= priv->nr_resets) ++ return -EINVAL; ++ ++ return regmap_update_bits(priv->regmap, ++ priv->regofs + ((id / 32) << 2), BIT(id % 32), BIT(id % 32)); ++} ++ ++static int mediatek_reset_deassert(struct reset_ctl *reset_ctl) ++{ ++ struct mediatek_reset_priv *priv = dev_get_priv(reset_ctl->dev); ++ int id = reset_ctl->id; ++ ++ if (id >= priv->nr_resets) ++ return -EINVAL; ++ ++ return regmap_update_bits(priv->regmap, ++ priv->regofs + ((id / 32) << 2), BIT(id % 32), 0); ++} ++ ++struct reset_ops mediatek_reset_ops = { ++ .request = mediatek_reset_request, ++ .free = mediatek_reset_free, ++ .rst_assert = mediatek_reset_assert, ++ .rst_deassert = mediatek_reset_deassert, ++}; ++ ++static int mediatek_reset_probe(struct udevice *dev) ++{ ++ struct mediatek_reset_priv *priv = dev_get_priv(dev); ++ ++ if (!priv->regofs && !priv->nr_resets) ++ return -EINVAL; ++ ++ priv->regmap = syscon_node_to_regmap(dev_ofnode(dev)); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ return 0; ++} ++ ++int mediatek_reset_bind(struct udevice *pdev, u32 regofs, u32 num_regs) ++{ ++ struct udevice *rst_dev; ++ struct mediatek_reset_priv *priv; ++ int ret; ++ ++ ret = device_bind_driver_to_node(pdev, "mediatek_reset", "reset", ++ dev_ofnode(pdev), &rst_dev); ++ if (ret) ++ return ret; ++ ++ priv = malloc(sizeof(struct mediatek_reset_priv)); ++ priv->regofs = regofs; ++ priv->nr_resets = num_regs * 32; ++ rst_dev->priv = priv; ++ ++ return 0; ++} ++ ++U_BOOT_DRIVER(mediatek_reset) = { ++ .name = "mediatek_reset", ++ .id = UCLASS_RESET, ++ .probe = mediatek_reset_probe, ++ .ops = &mediatek_reset_ops, ++ .priv_auto_alloc_size = sizeof(struct mediatek_reset_priv), ++}; +diff --git a/include/dt-bindings/reset/mtk-reset.h b/include/dt-bindings/reset/mtk-reset.h +new file mode 100644 +index 00000000..5f0a74f2 +--- /dev/null ++++ b/include/dt-bindings/reset/mtk-reset.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ */ ++ ++#ifndef _DT_BINDINGS_MTK_RESET_H_ ++#define _DT_BINDINGS_MTK_RESET_H_ ++ ++/* ETHSYS */ ++#define ETHSYS_PPE_RST 31 ++#define ETHSYS_EPHY_RST 24 ++#define ETHSYS_GMAC_RST 23 ++#define ETHSYS_ESW_RST 16 ++#define ETHSYS_FE_RST 6 ++#define ETHSYS_MCM_RST 2 ++#define ETHSYS_SYS_RST 0 ++ ++#endif /* _DT_BINDINGS_MTK_RESET_H_ */ +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0004-clk-MediaTek-bind-ethsys-reset-controller.patch b/root/package/boot/uboot-mediatek/patches/0004-clk-MediaTek-bind-ethsys-reset-controller.patch new file mode 100644 index 00000000..d8096a40 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0004-clk-MediaTek-bind-ethsys-reset-controller.patch @@ -0,0 +1,109 @@ +From ab7ad2d077ef18d6d853c8838bc116fbbd0ac154 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:52 +0800 +Subject: clk: MediaTek: bind ethsys reset controller + +The ethsys contains not only the clock gating controller, but also the +reset controller for the whole ethernet subsystem and its components. + +This patch adds binding of the reset controller so that the ethernet node +can have references on it. + +Signed-off-by: Weijie Gao + +diff --git a/drivers/clk/mediatek/clk-mt7623.c b/drivers/clk/mediatek/clk-mt7623.c +index c6b09d8e..87ad4f79 100644 +--- a/drivers/clk/mediatek/clk-mt7623.c ++++ b/drivers/clk/mediatek/clk-mt7623.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + +@@ -782,6 +783,19 @@ static int mt7623_ethsys_probe(struct udevice *dev) + return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, eth_cgs); + } + ++static int mt7623_ethsys_bind(struct udevice *dev) ++{ ++ int ret = 0; ++ ++#if CONFIG_IS_ENABLED(RESET_MEDIATEK) ++ ret = mediatek_reset_bind(dev, ETHSYS_RST_CTRL_OFS, 1); ++ if (ret) ++ debug("Warning: failed to bind ethsys reset controller\n"); ++#endif ++ ++ return ret; ++} ++ + static const struct udevice_id mt7623_apmixed_compat[] = { + { .compatible = "mediatek,mt7623-apmixedsys" }, + { } +@@ -865,6 +879,7 @@ U_BOOT_DRIVER(mtk_clk_ethsys) = { + .id = UCLASS_CLK, + .of_match = mt7623_ethsys_compat, + .probe = mt7623_ethsys_probe, ++ .bind = mt7623_ethsys_bind, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, + }; +diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c +index 2601b6cf..6a9f6013 100644 +--- a/drivers/clk/mediatek/clk-mt7629.c ++++ b/drivers/clk/mediatek/clk-mt7629.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + +@@ -602,6 +603,19 @@ static int mt7629_ethsys_probe(struct udevice *dev) + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, eth_cgs); + } + ++static int mt7629_ethsys_bind(struct udevice *dev) ++{ ++ int ret = 0; ++ ++#if CONFIG_IS_ENABLED(RESET_MEDIATEK) ++ ret = mediatek_reset_bind(dev, ETHSYS_RST_CTRL_OFS, 1); ++ if (ret) ++ debug("Warning: failed to bind ethsys reset controller\n"); ++#endif ++ ++ return ret; ++} ++ + static int mt7629_sgmiisys_probe(struct udevice *dev) + { + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, sgmii_cgs); +@@ -695,6 +709,7 @@ U_BOOT_DRIVER(mtk_clk_ethsys) = { + .id = UCLASS_CLK, + .of_match = mt7629_ethsys_compat, + .probe = mt7629_ethsys_probe, ++ .bind = mt7629_ethsys_bind, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, + }; +diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h +index 74152ed9..7847388b 100644 +--- a/drivers/clk/mediatek/clk-mtk.h ++++ b/drivers/clk/mediatek/clk-mtk.h +@@ -23,6 +23,8 @@ + #define CLK_PARENT_TOPCKGEN BIT(5) + #define CLK_PARENT_MASK GENMASK(5, 4) + ++#define ETHSYS_RST_CTRL_OFS 0x34 ++ + /* struct mtk_pll_data - hardware-specific PLLs data */ + struct mtk_pll_data { + const int id; +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0005-ethernet-MediaTek-add-ethernet-driver-for-MediaTek-A.patch b/root/package/boot/uboot-mediatek/patches/0005-ethernet-MediaTek-add-ethernet-driver-for-MediaTek-A.patch new file mode 100644 index 00000000..7a940f1f --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0005-ethernet-MediaTek-add-ethernet-driver-for-MediaTek-A.patch @@ -0,0 +1,1517 @@ +From 9d80ec7dff8033a2a7309c0695c30d7299e44901 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:53 +0800 +Subject: ethernet: MediaTek: add ethernet driver for MediaTek ARM-based SoCs + +This patch adds ethernet support for Mediatek ARM-based SoCs, including +a minimum setup of the integrated switch. + +Cc: Joe Hershberger +Signed-off-by: Mark Lee +Signed-off-by: Weijie Gao +Tested-By: "Frank Wunderlich" + +diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig +index 7044c6ad..ff55e03d 100644 +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -513,4 +513,14 @@ config TSEC_ENET + This driver implements support for the (Enhanced) Three-Speed + Ethernet Controller found on Freescale SoCs. + ++config MEDIATEK_ETH ++ bool "MediaTek Ethernet GMAC Driver" ++ depends on DM_ETH ++ select PHYLIB ++ select DM_GPIO ++ select DM_RESET ++ help ++ This Driver support MediaTek Ethernet GMAC ++ Say Y to enable support for the MediaTek Ethernet GMAC. ++ + endif # NETDEVICES +diff --git a/drivers/net/Makefile b/drivers/net/Makefile +index 0dbfa033..ee7f3e71 100644 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -74,3 +74,4 @@ obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o + obj-$(CONFIG_FSL_PFE) += pfe_eth/ + obj-$(CONFIG_SNI_AVE) += sni_ave.o + obj-y += ti/ ++obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o +diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c +new file mode 100644 +index 00000000..cc094048 +--- /dev/null ++++ b/drivers/net/mtk_eth.c +@@ -0,0 +1,1175 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk_eth.h" ++ ++#define NUM_TX_DESC 24 ++#define NUM_RX_DESC 24 ++#define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN) ++#define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN) ++#define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE) ++ ++#define MT7530_NUM_PHYS 5 ++#define MT7530_DFL_SMI_ADDR 31 ++ ++#define MT7530_PHY_ADDR(base, addr) \ ++ (((base) + (addr)) & 0x1f) ++ ++#define GDMA_FWD_TO_CPU \ ++ (0x20000000 | \ ++ GDM_ICS_EN | \ ++ GDM_TCS_EN | \ ++ GDM_UCS_EN | \ ++ STRP_CRC | \ ++ (DP_PDMA << MYMAC_DP_S) | \ ++ (DP_PDMA << BC_DP_S) | \ ++ (DP_PDMA << MC_DP_S) | \ ++ (DP_PDMA << UN_DP_S)) ++ ++#define GDMA_FWD_DISCARD \ ++ (0x20000000 | \ ++ GDM_ICS_EN | \ ++ GDM_TCS_EN | \ ++ GDM_UCS_EN | \ ++ STRP_CRC | \ ++ (DP_DISCARD << MYMAC_DP_S) | \ ++ (DP_DISCARD << BC_DP_S) | \ ++ (DP_DISCARD << MC_DP_S) | \ ++ (DP_DISCARD << UN_DP_S)) ++ ++struct pdma_rxd_info1 { ++ u32 PDP0; ++}; ++ ++struct pdma_rxd_info2 { ++ u32 PLEN1 : 14; ++ u32 LS1 : 1; ++ u32 UN_USED : 1; ++ u32 PLEN0 : 14; ++ u32 LS0 : 1; ++ u32 DDONE : 1; ++}; ++ ++struct pdma_rxd_info3 { ++ u32 PDP1; ++}; ++ ++struct pdma_rxd_info4 { ++ u32 FOE_ENTRY : 14; ++ u32 CRSN : 5; ++ u32 SP : 3; ++ u32 L4F : 1; ++ u32 L4VLD : 1; ++ u32 TACK : 1; ++ u32 IP4F : 1; ++ u32 IP4 : 1; ++ u32 IP6 : 1; ++ u32 UN_USED : 4; ++}; ++ ++struct pdma_rxdesc { ++ struct pdma_rxd_info1 rxd_info1; ++ struct pdma_rxd_info2 rxd_info2; ++ struct pdma_rxd_info3 rxd_info3; ++ struct pdma_rxd_info4 rxd_info4; ++}; ++ ++struct pdma_txd_info1 { ++ u32 SDP0; ++}; ++ ++struct pdma_txd_info2 { ++ u32 SDL1 : 14; ++ u32 LS1 : 1; ++ u32 BURST : 1; ++ u32 SDL0 : 14; ++ u32 LS0 : 1; ++ u32 DDONE : 1; ++}; ++ ++struct pdma_txd_info3 { ++ u32 SDP1; ++}; ++ ++struct pdma_txd_info4 { ++ u32 VLAN_TAG : 16; ++ u32 INS : 1; ++ u32 RESV : 2; ++ u32 UDF : 6; ++ u32 FPORT : 3; ++ u32 TSO : 1; ++ u32 TUI_CO : 3; ++}; ++ ++struct pdma_txdesc { ++ struct pdma_txd_info1 txd_info1; ++ struct pdma_txd_info2 txd_info2; ++ struct pdma_txd_info3 txd_info3; ++ struct pdma_txd_info4 txd_info4; ++}; ++ ++enum mtk_switch { ++ SW_NONE, ++ SW_MT7530 ++}; ++ ++enum mtk_soc { ++ SOC_MT7623, ++ SOC_MT7629 ++}; ++ ++struct mtk_eth_priv { ++ char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); ++ ++ struct pdma_txdesc *tx_ring_noc; ++ struct pdma_rxdesc *rx_ring_noc; ++ ++ int rx_dma_owner_idx0; ++ int tx_cpu_owner_idx0; ++ ++ void __iomem *fe_base; ++ void __iomem *gmac_base; ++ void __iomem *ethsys_base; ++ ++ struct mii_dev *mdio_bus; ++ int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg); ++ int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val); ++ int (*mmd_read)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg); ++ int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, ++ u16 val); ++ ++ enum mtk_soc soc; ++ int gmac_id; ++ int force_mode; ++ int speed; ++ int duplex; ++ ++ struct phy_device *phydev; ++ int phy_interface; ++ int phy_addr; ++ ++ enum mtk_switch sw; ++ int (*switch_init)(struct mtk_eth_priv *priv); ++ u32 mt7530_smi_addr; ++ u32 mt7530_phy_base; ++ ++ struct gpio_desc rst_gpio; ++ int mcm; ++ ++ struct reset_ctl rst_fe; ++ struct reset_ctl rst_mcm; ++}; ++ ++static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val) ++{ ++ writel(val, priv->fe_base + PDMA_BASE + reg); ++} ++ ++static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, ++ u32 set) ++{ ++ clrsetbits_le32(priv->fe_base + PDMA_BASE + reg, clr, set); ++} ++ ++static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg, ++ u32 val) ++{ ++ u32 gdma_base; ++ ++ if (no == 1) ++ gdma_base = GDMA2_BASE; ++ else ++ gdma_base = GDMA1_BASE; ++ ++ writel(val, priv->fe_base + gdma_base + reg); ++} ++ ++static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg) ++{ ++ return readl(priv->gmac_base + reg); ++} ++ ++static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val) ++{ ++ writel(val, priv->gmac_base + reg); ++} ++ ++static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) ++{ ++ clrsetbits_le32(priv->gmac_base + reg, clr, set); ++} ++ ++static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, ++ u32 set) ++{ ++ clrsetbits_le32(priv->ethsys_base + reg, clr, set); ++} ++ ++/* Direct MDIO clause 22/45 access via SoC */ ++static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data, ++ u32 cmd, u32 st) ++{ ++ int ret; ++ u32 val; ++ ++ val = (st << MDIO_ST_S) | ++ ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | ++ (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | ++ (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); ++ ++ if (cmd == MDIO_CMD_WRITE) ++ val |= data & MDIO_RW_DATA_M; ++ ++ mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST); ++ ++ ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG, ++ PHY_ACS_ST, 0, 5000, 0); ++ if (ret) { ++ pr_warn("MDIO access timeout\n"); ++ return ret; ++ } ++ ++ if (cmd == MDIO_CMD_READ) { ++ val = mtk_gmac_read(priv, GMAC_PIAC_REG); ++ return val & MDIO_RW_DATA_M; ++ } ++ ++ return 0; ++} ++ ++/* Direct MDIO clause 22 read via SoC */ ++static int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg) ++{ ++ return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22); ++} ++ ++/* Direct MDIO clause 22 write via SoC */ ++static int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data) ++{ ++ return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22); ++} ++ ++/* Direct MDIO clause 45 read via SoC */ ++static int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg) ++{ ++ int ret; ++ ++ ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); ++ if (ret) ++ return ret; ++ ++ return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45, ++ MDIO_ST_C45); ++} ++ ++/* Direct MDIO clause 45 write via SoC */ ++static int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, ++ u16 reg, u16 val) ++{ ++ int ret; ++ ++ ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); ++ if (ret) ++ return ret; ++ ++ return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE, ++ MDIO_ST_C45); ++} ++ ++/* Indirect MDIO clause 45 read via MII registers */ ++static int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, ++ u16 reg) ++{ ++ int ret; ++ ++ ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_ADDR << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret) ++ return ret; ++ ++ ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_DATA << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ return priv->mii_read(priv, addr, MII_MMD_ADDR_DATA_REG); ++} ++ ++/* Indirect MDIO clause 45 write via MII registers */ ++static int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, ++ u16 reg, u16 val) ++{ ++ int ret; ++ ++ ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_ADDR << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret) ++ return ret; ++ ++ ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_DATA << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ return priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val); ++} ++ ++static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) ++{ ++ struct mtk_eth_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return priv->mii_read(priv, addr, reg); ++ else ++ return priv->mmd_read(priv, addr, devad, reg); ++} ++ ++static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, ++ u16 val) ++{ ++ struct mtk_eth_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return priv->mii_write(priv, addr, reg, val); ++ else ++ return priv->mmd_write(priv, addr, devad, reg, val); ++} ++ ++static int mtk_mdio_register(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ struct mii_dev *mdio_bus = mdio_alloc(); ++ int ret; ++ ++ if (!mdio_bus) ++ return -ENOMEM; ++ ++ /* Assign MDIO access APIs according to the switch/phy */ ++ switch (priv->sw) { ++ case SW_MT7530: ++ priv->mii_read = mtk_mii_read; ++ priv->mii_write = mtk_mii_write; ++ priv->mmd_read = mtk_mmd_ind_read; ++ priv->mmd_write = mtk_mmd_ind_write; ++ break; ++ default: ++ priv->mii_read = mtk_mii_read; ++ priv->mii_write = mtk_mii_write; ++ priv->mmd_read = mtk_mmd_read; ++ priv->mmd_write = mtk_mmd_write; ++ } ++ ++ mdio_bus->read = mtk_mdio_read; ++ mdio_bus->write = mtk_mdio_write; ++ snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name); ++ ++ mdio_bus->priv = (void *)priv; ++ ++ ret = mdio_register(mdio_bus); ++ ++ if (ret) ++ return ret; ++ ++ priv->mdio_bus = mdio_bus; ++ ++ return 0; ++} ++ ++/* ++ * MT7530 Internal Register Address Bits ++ * ------------------------------------------------------------------- ++ * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 | ++ * |----------------------------------------|---------------|--------| ++ * | Page Address | Reg Address | Unused | ++ * ------------------------------------------------------------------- ++ */ ++ ++static int mt7530_reg_read(struct mtk_eth_priv *priv, u32 reg, u32 *data) ++{ ++ int ret, low_word, high_word; ++ ++ /* Write page address */ ++ ret = mtk_mii_write(priv, priv->mt7530_smi_addr, 0x1f, reg >> 6); ++ if (ret) ++ return ret; ++ ++ /* Read low word */ ++ low_word = mtk_mii_read(priv, priv->mt7530_smi_addr, (reg >> 2) & 0xf); ++ if (low_word < 0) ++ return low_word; ++ ++ /* Read high word */ ++ high_word = mtk_mii_read(priv, priv->mt7530_smi_addr, 0x10); ++ if (high_word < 0) ++ return high_word; ++ ++ if (data) ++ *data = ((u32)high_word << 16) | (low_word & 0xffff); ++ ++ return 0; ++} ++ ++static int mt7530_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 data) ++{ ++ int ret; ++ ++ /* Write page address */ ++ ret = mtk_mii_write(priv, priv->mt7530_smi_addr, 0x1f, reg >> 6); ++ if (ret) ++ return ret; ++ ++ /* Write low word */ ++ ret = mtk_mii_write(priv, priv->mt7530_smi_addr, (reg >> 2) & 0xf, ++ data & 0xffff); ++ if (ret) ++ return ret; ++ ++ /* Write high word */ ++ return mtk_mii_write(priv, priv->mt7530_smi_addr, 0x10, data >> 16); ++} ++ ++static void mt7530_reg_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, ++ u32 set) ++{ ++ u32 val; ++ ++ mt7530_reg_read(priv, reg, &val); ++ val &= ~clr; ++ val |= set; ++ mt7530_reg_write(priv, reg, val); ++} ++ ++static void mt7530_core_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 val) ++{ ++ u8 phy_addr = MT7530_PHY_ADDR(priv->mt7530_phy_base, 0); ++ ++ mtk_mmd_ind_write(priv, phy_addr, 0x1f, reg, val); ++} ++ ++static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode) ++{ ++ u32 ncpo1, ssc_delta; ++ ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ ncpo1 = 0x0c80; ++ ssc_delta = 0x87; ++ break; ++ default: ++ printf("error: xMII mode %d not supported\n", mode); ++ return -EINVAL; ++ } ++ ++ /* Disable MT7530 core clock */ ++ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0); ++ ++ /* Disable MT7530 PLL */ ++ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1, ++ (2 << RG_GSWPLL_POSDIV_200M_S) | ++ (32 << RG_GSWPLL_FBKDIV_200M_S)); ++ ++ /* For MT7530 core clock = 500Mhz */ ++ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2, ++ (1 << RG_GSWPLL_POSDIV_500M_S) | ++ (25 << RG_GSWPLL_FBKDIV_500M_S)); ++ ++ /* Enable MT7530 PLL */ ++ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1, ++ (2 << RG_GSWPLL_POSDIV_200M_S) | ++ (32 << RG_GSWPLL_FBKDIV_200M_S) | ++ RG_GSWPLL_EN_PRE); ++ ++ udelay(20); ++ ++ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ ++ /* Setup the MT7530 TRGMII Tx Clock */ ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN | ++ RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN); ++ ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP2, ++ RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | ++ (1 << RG_SYSPLL_POSDIV_S)); ++ ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP7, ++ RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) | ++ RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); ++ ++ /* Enable MT7530 core clock */ ++ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, ++ REG_GSWCK_EN | REG_TRGMIICK_EN); ++ ++ return 0; ++} ++ ++static int mt7530_setup(struct mtk_eth_priv *priv) ++{ ++ u16 phy_addr, phy_val; ++ u32 val; ++ int i; ++ ++ /* Select 250MHz clk for RGMII mode */ ++ mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG, ++ ETHSYS_TRGMII_CLK_SEL362_5, 0); ++ ++ /* Global reset switch */ ++ if (priv->mcm) { ++ reset_assert(&priv->rst_mcm); ++ udelay(1000); ++ reset_deassert(&priv->rst_mcm); ++ mdelay(1000); ++ } else if (dm_gpio_is_valid(&priv->rst_gpio)) { ++ dm_gpio_set_value(&priv->rst_gpio, 0); ++ udelay(1000); ++ dm_gpio_set_value(&priv->rst_gpio, 1); ++ mdelay(1000); ++ } ++ ++ /* Modify HWTRAP first to allow direct access to internal PHYs */ ++ mt7530_reg_read(priv, HWTRAP_REG, &val); ++ val |= CHG_TRAP; ++ val &= ~C_MDIO_BPS; ++ mt7530_reg_write(priv, MHWTRAP_REG, val); ++ ++ /* Calculate the phy base address */ ++ val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3; ++ priv->mt7530_phy_base = (val | 0x7) + 1; ++ ++ /* Turn off PHYs */ ++ for (i = 0; i < MT7530_NUM_PHYS; i++) { ++ phy_addr = MT7530_PHY_ADDR(priv->mt7530_phy_base, i); ++ phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); ++ phy_val |= BMCR_PDOWN; ++ priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ /* Force MAC link down before reset */ ++ mt7530_reg_write(priv, PCMR_REG(5), FORCE_MODE); ++ mt7530_reg_write(priv, PCMR_REG(6), FORCE_MODE); ++ ++ /* MT7530 reset */ ++ mt7530_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST); ++ udelay(100); ++ ++ val = (1 << IPG_CFG_S) | ++ MAC_MODE | FORCE_MODE | ++ MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN | ++ (SPEED_1000M << FORCE_SPD_S) | ++ FORCE_DPX | FORCE_LINK; ++ ++ /* MT7530 Port6: Forced 1000M/FD, FC disabled */ ++ mt7530_reg_write(priv, PCMR_REG(6), val); ++ ++ /* MT7530 Port5: Forced link down */ ++ mt7530_reg_write(priv, PCMR_REG(5), FORCE_MODE); ++ ++ /* MT7530 Port6: Set to RGMII */ ++ mt7530_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII); ++ ++ /* Hardware Trap: Enable Port6, Disable Port5 */ ++ mt7530_reg_read(priv, HWTRAP_REG, &val); ++ val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS | ++ (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) | ++ (P5_INTF_MODE_RGMII << P5_INTF_MODE_S); ++ val &= ~(C_MDIO_BPS | P6_INTF_DIS); ++ mt7530_reg_write(priv, MHWTRAP_REG, val); ++ ++ /* Setup switch core pll */ ++ mt7530_pad_clk_setup(priv, priv->phy_interface); ++ ++ /* Lower Tx Driving for TRGMII path */ ++ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) ++ mt7530_reg_write(priv, MT7530_TRGMII_TD_ODT(i), ++ (8 << TD_DM_DRVP_S) | (8 << TD_DM_DRVN_S)); ++ ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mt7530_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16); ++ ++ /* Turn on PHYs */ ++ for (i = 0; i < MT7530_NUM_PHYS; i++) { ++ phy_addr = MT7530_PHY_ADDR(priv->mt7530_phy_base, i); ++ phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); ++ phy_val &= ~BMCR_PDOWN; ++ priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ /* Set port isolation */ ++ for (i = 0; i < 8; i++) { ++ /* Set port matrix mode */ ++ if (i != 6) ++ mt7530_reg_write(priv, PCR_REG(i), ++ (0x40 << PORT_MATRIX_S)); ++ else ++ mt7530_reg_write(priv, PCR_REG(i), ++ (0x3f << PORT_MATRIX_S)); ++ ++ /* Set port mode to user port */ ++ mt7530_reg_write(priv, PVC_REG(i), ++ (0x8100 << STAG_VPID_S) | ++ (VLAN_ATTR_USER << VLAN_ATTR_S)); ++ } ++ ++ return 0; ++} ++ ++static void mtk_phy_link_adjust(struct mtk_eth_priv *priv) ++{ ++ u16 lcl_adv = 0, rmt_adv = 0; ++ u8 flowctrl; ++ u32 mcr; ++ ++ mcr = (1 << IPG_CFG_S) | ++ (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | ++ MAC_MODE | FORCE_MODE | ++ MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN; ++ ++ switch (priv->phydev->speed) { ++ case SPEED_10: ++ mcr |= (SPEED_10M << FORCE_SPD_S); ++ break; ++ case SPEED_100: ++ mcr |= (SPEED_100M << FORCE_SPD_S); ++ break; ++ case SPEED_1000: ++ mcr |= (SPEED_1000M << FORCE_SPD_S); ++ break; ++ }; ++ ++ if (priv->phydev->link) ++ mcr |= FORCE_LINK; ++ ++ if (priv->phydev->duplex) { ++ mcr |= FORCE_DPX; ++ ++ if (priv->phydev->pause) ++ rmt_adv = LPA_PAUSE_CAP; ++ if (priv->phydev->asym_pause) ++ rmt_adv |= LPA_PAUSE_ASYM; ++ ++ if (priv->phydev->advertising & ADVERTISED_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_CAP; ++ if (priv->phydev->advertising & ADVERTISED_Asym_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_ASYM; ++ ++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); ++ ++ if (flowctrl & FLOW_CTRL_TX) ++ mcr |= FORCE_TX_FC; ++ if (flowctrl & FLOW_CTRL_RX) ++ mcr |= FORCE_RX_FC; ++ ++ debug("rx pause %s, tx pause %s\n", ++ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", ++ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); ++ } ++ ++ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); ++} ++ ++static int mtk_phy_start(struct mtk_eth_priv *priv) ++{ ++ struct phy_device *phydev = priv->phydev; ++ int ret; ++ ++ ret = phy_startup(phydev); ++ ++ if (ret) { ++ debug("Could not initialize PHY %s\n", phydev->dev->name); ++ return ret; ++ } ++ ++ if (!phydev->link) { ++ debug("%s: link down.\n", phydev->dev->name); ++ return 0; ++ } ++ ++ mtk_phy_link_adjust(priv); ++ ++ debug("Speed: %d, %s duplex%s\n", phydev->speed, ++ (phydev->duplex) ? "full" : "half", ++ (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); ++ ++ return 0; ++} ++ ++static int mtk_phy_probe(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ struct phy_device *phydev; ++ ++ phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev, ++ priv->phy_interface); ++ if (!phydev) ++ return -ENODEV; ++ ++ phydev->supported &= PHY_GBIT_FEATURES; ++ phydev->advertising = phydev->supported; ++ ++ priv->phydev = phydev; ++ phy_config(phydev); ++ ++ return 0; ++} ++ ++static void mtk_mac_init(struct mtk_eth_priv *priv) ++{ ++ int i, ge_mode = 0; ++ u32 mcr; ++ ++ switch (priv->phy_interface) { ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_SGMII: ++ ge_mode = GE_MODE_RGMII; ++ break; ++ case PHY_INTERFACE_MODE_MII: ++ case PHY_INTERFACE_MODE_GMII: ++ ge_mode = GE_MODE_MII; ++ break; ++ case PHY_INTERFACE_MODE_RMII: ++ ge_mode = GE_MODE_RMII; ++ break; ++ default: ++ break; ++ } ++ ++ /* set the gmac to the right mode */ ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, ++ SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id), ++ ge_mode << SYSCFG0_GE_MODE_S(priv->gmac_id)); ++ ++ if (priv->force_mode) { ++ mcr = (1 << IPG_CFG_S) | ++ (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | ++ MAC_MODE | FORCE_MODE | ++ MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN | ++ FORCE_LINK; ++ ++ switch (priv->speed) { ++ case SPEED_10: ++ mcr |= SPEED_10M << FORCE_SPD_S; ++ break; ++ case SPEED_100: ++ mcr |= SPEED_100M << FORCE_SPD_S; ++ break; ++ case SPEED_1000: ++ mcr |= SPEED_1000M << FORCE_SPD_S; ++ break; ++ } ++ ++ if (priv->duplex) ++ mcr |= FORCE_DPX; ++ ++ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); ++ } ++ ++ if (priv->soc == SOC_MT7623) { ++ /* Lower Tx Driving for TRGMII path */ ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i), ++ (8 << TD_DM_DRVP_S) | ++ (8 << TD_DM_DRVN_S)); ++ ++ mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0, ++ RX_RST | RXC_DQSISEL); ++ mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0); ++ } ++} ++ ++static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) ++{ ++ char *pkt_base = priv->pkt_pool; ++ int i; ++ ++ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0); ++ udelay(500); ++ ++ memset(priv->tx_ring_noc, 0, NUM_TX_DESC * sizeof(struct pdma_txdesc)); ++ memset(priv->rx_ring_noc, 0, NUM_RX_DESC * sizeof(struct pdma_rxdesc)); ++ memset(priv->pkt_pool, 0, TOTAL_PKT_BUF_SIZE); ++ ++ flush_dcache_range((u32)pkt_base, (u32)(pkt_base + TOTAL_PKT_BUF_SIZE)); ++ ++ priv->rx_dma_owner_idx0 = 0; ++ priv->tx_cpu_owner_idx0 = 0; ++ ++ for (i = 0; i < NUM_TX_DESC; i++) { ++ priv->tx_ring_noc[i].txd_info2.LS0 = 1; ++ priv->tx_ring_noc[i].txd_info2.DDONE = 1; ++ priv->tx_ring_noc[i].txd_info4.FPORT = priv->gmac_id + 1; ++ ++ priv->tx_ring_noc[i].txd_info1.SDP0 = virt_to_phys(pkt_base); ++ pkt_base += PKTSIZE_ALIGN; ++ } ++ ++ for (i = 0; i < NUM_RX_DESC; i++) { ++ priv->rx_ring_noc[i].rxd_info2.PLEN0 = PKTSIZE_ALIGN; ++ priv->rx_ring_noc[i].rxd_info1.PDP0 = virt_to_phys(pkt_base); ++ pkt_base += PKTSIZE_ALIGN; ++ } ++ ++ mtk_pdma_write(priv, TX_BASE_PTR_REG(0), ++ virt_to_phys(priv->tx_ring_noc)); ++ mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC); ++ mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); ++ ++ mtk_pdma_write(priv, RX_BASE_PTR_REG(0), ++ virt_to_phys(priv->rx_ring_noc)); ++ mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC); ++ mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1); ++ ++ mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0); ++} ++ ++static int mtk_eth_start(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ int ret; ++ ++ /* Reset FE */ ++ reset_assert(&priv->rst_fe); ++ udelay(1000); ++ reset_deassert(&priv->rst_fe); ++ mdelay(10); ++ ++ /* Packets forward to PDMA */ ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU); ++ ++ if (priv->gmac_id == 0) ++ mtk_gdma_write(priv, 1, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); ++ else ++ mtk_gdma_write(priv, 0, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); ++ ++ udelay(500); ++ ++ mtk_eth_fifo_init(priv); ++ ++ /* Start PHY */ ++ if (priv->sw == SW_NONE) { ++ ret = mtk_phy_start(priv); ++ if (ret) ++ return ret; ++ } ++ ++ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0, ++ TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN); ++ udelay(500); ++ ++ return 0; ++} ++ ++static void mtk_eth_stop(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ ++ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, ++ TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0); ++ udelay(500); ++ ++ wait_for_bit_le32(priv->fe_base + PDMA_BASE + PDMA_GLO_CFG_REG, ++ RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0); ++} ++ ++static int mtk_eth_write_hwaddr(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ unsigned char *mac = pdata->enetaddr; ++ u32 macaddr_lsb, macaddr_msb; ++ ++ macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1]; ++ macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) | ++ ((u32)mac[4] << 8) | (u32)mac[5]; ++ ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb); ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb); ++ ++ return 0; ++} ++ ++static int mtk_eth_send(struct udevice *dev, void *packet, int length) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 idx = priv->tx_cpu_owner_idx0; ++ void *pkt_base; ++ ++ if (!priv->tx_ring_noc[idx].txd_info2.DDONE) { ++ debug("mtk-eth: TX DMA descriptor ring is full\n"); ++ return -EPERM; ++ } ++ ++ pkt_base = (void *)phys_to_virt(priv->tx_ring_noc[idx].txd_info1.SDP0); ++ memcpy(pkt_base, packet, length); ++ flush_dcache_range((u32)pkt_base, (u32)pkt_base + ++ roundup(length, ARCH_DMA_MINALIGN)); ++ ++ priv->tx_ring_noc[idx].txd_info2.SDL0 = length; ++ priv->tx_ring_noc[idx].txd_info2.DDONE = 0; ++ ++ priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC; ++ mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); ++ ++ return 0; ++} ++ ++static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 idx = priv->rx_dma_owner_idx0; ++ uchar *pkt_base; ++ u32 length; ++ ++ if (!priv->rx_ring_noc[idx].rxd_info2.DDONE) { ++ debug("mtk-eth: RX DMA descriptor ring is empty\n"); ++ return -EAGAIN; ++ } ++ ++ length = priv->rx_ring_noc[idx].rxd_info2.PLEN0; ++ pkt_base = (void *)phys_to_virt(priv->rx_ring_noc[idx].rxd_info1.PDP0); ++ invalidate_dcache_range((u32)pkt_base, (u32)pkt_base + ++ roundup(length, ARCH_DMA_MINALIGN)); ++ ++ if (packetp) ++ *packetp = pkt_base; ++ ++ return length; ++} ++ ++static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 idx = priv->rx_dma_owner_idx0; ++ ++ priv->rx_ring_noc[idx].rxd_info2.DDONE = 0; ++ priv->rx_ring_noc[idx].rxd_info2.LS0 = 0; ++ priv->rx_ring_noc[idx].rxd_info2.PLEN0 = PKTSIZE_ALIGN; ++ ++ mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx); ++ priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC; ++ ++ return 0; ++} ++ ++static int mtk_eth_probe(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 iobase = pdata->iobase; ++ int ret; ++ ++ /* Frame Engine Register Base */ ++ priv->fe_base = (void *)iobase; ++ ++ /* GMAC Register Base */ ++ priv->gmac_base = (void *)(iobase + GMAC_BASE); ++ ++ /* MDIO register */ ++ ret = mtk_mdio_register(dev); ++ if (ret) ++ return ret; ++ ++ /* Prepare for tx/rx rings */ ++ priv->tx_ring_noc = (struct pdma_txdesc *) ++ noncached_alloc(sizeof(struct pdma_txdesc) * NUM_TX_DESC, ++ ARCH_DMA_MINALIGN); ++ priv->rx_ring_noc = (struct pdma_rxdesc *) ++ noncached_alloc(sizeof(struct pdma_rxdesc) * NUM_RX_DESC, ++ ARCH_DMA_MINALIGN); ++ ++ /* Set MAC mode */ ++ mtk_mac_init(priv); ++ ++ /* Probe phy if switch is not specified */ ++ if (priv->sw == SW_NONE) ++ return mtk_phy_probe(dev); ++ ++ /* Initialize switch */ ++ return priv->switch_init(priv); ++} ++ ++static int mtk_eth_remove(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ ++ /* MDIO unregister */ ++ mdio_unregister(priv->mdio_bus); ++ mdio_free(priv->mdio_bus); ++ ++ /* Stop possibly started DMA */ ++ mtk_eth_stop(dev); ++ ++ return 0; ++} ++ ++static int mtk_eth_ofdata_to_platdata(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_platdata(dev); ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ struct ofnode_phandle_args args; ++ struct regmap *regmap; ++ const char *str; ++ ofnode subnode; ++ int ret; ++ ++ priv->soc = dev_get_driver_data(dev); ++ ++ pdata->iobase = devfdt_get_addr(dev); ++ ++ /* get corresponding ethsys phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0, ++ &args); ++ if (ret) ++ return ret; ++ ++ regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ priv->ethsys_base = regmap_get_range(regmap, 0); ++ if (!priv->ethsys_base) { ++ dev_err(dev, "Unable to find ethsys\n"); ++ return -ENODEV; ++ } ++ ++ /* Reset controllers */ ++ ret = reset_get_by_name(dev, "fe", &priv->rst_fe); ++ if (ret) { ++ printf("error: Unable to get reset ctrl for frame engine\n"); ++ return ret; ++ } ++ ++ priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0); ++ ++ /* Interface mode is required */ ++ str = dev_read_string(dev, "phy-mode"); ++ if (str) { ++ pdata->phy_interface = phy_get_interface_by_name(str); ++ priv->phy_interface = pdata->phy_interface; ++ } else { ++ printf("error: phy-mode is not set\n"); ++ return -EINVAL; ++ } ++ ++ /* Force mode or autoneg */ ++ subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link"); ++ if (ofnode_valid(subnode)) { ++ priv->force_mode = 1; ++ priv->speed = ofnode_read_u32_default(subnode, "speed", 0); ++ priv->duplex = ofnode_read_bool(subnode, "full-duplex"); ++ ++ if (priv->speed != SPEED_10 && priv->speed != SPEED_100 && ++ priv->speed != SPEED_1000) { ++ printf("error: no valid speed set in fixed-link\n"); ++ return -EINVAL; ++ } ++ } ++ ++ /* check for switch first, otherwise phy will be used */ ++ priv->sw = SW_NONE; ++ priv->switch_init = NULL; ++ str = dev_read_string(dev, "mediatek,switch"); ++ ++ if (str) { ++ if (!strcmp(str, "mt7530")) { ++ priv->sw = SW_MT7530; ++ priv->switch_init = mt7530_setup; ++ priv->mt7530_smi_addr = MT7530_DFL_SMI_ADDR; ++ } else { ++ printf("error: unsupported switch\n"); ++ return -EINVAL; ++ } ++ ++ priv->mcm = dev_read_bool(dev, "mediatek,mcm"); ++ if (priv->mcm) { ++ ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm); ++ if (ret) { ++ printf("error: no reset ctrl for mcm\n"); ++ return ret; ++ } ++ } else { ++ gpio_request_by_name(dev, "reset-gpios", 0, ++ &priv->rst_gpio, GPIOD_IS_OUT); ++ } ++ } else { ++ subnode = ofnode_find_subnode(dev_ofnode(dev), "phy-handle"); ++ if (!ofnode_valid(subnode)) { ++ printf("error: phy-handle is not specified\n"); ++ return ret; ++ } ++ ++ priv->phy_addr = ofnode_read_s32_default(subnode, "reg", -1); ++ if (priv->phy_addr < 0) { ++ printf("error: phy address is not specified\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct udevice_id mtk_eth_ids[] = { ++ { .compatible = "mediatek,mt7629-eth", .data = SOC_MT7629 }, ++ { .compatible = "mediatek,mt7623-eth", .data = SOC_MT7623 }, ++ {} ++}; ++ ++static const struct eth_ops mtk_eth_ops = { ++ .start = mtk_eth_start, ++ .stop = mtk_eth_stop, ++ .send = mtk_eth_send, ++ .recv = mtk_eth_recv, ++ .free_pkt = mtk_eth_free_pkt, ++ .write_hwaddr = mtk_eth_write_hwaddr, ++}; ++ ++U_BOOT_DRIVER(mtk_eth) = { ++ .name = "mtk-eth", ++ .id = UCLASS_ETH, ++ .of_match = mtk_eth_ids, ++ .ofdata_to_platdata = mtk_eth_ofdata_to_platdata, ++ .platdata_auto_alloc_size = sizeof(struct eth_pdata), ++ .probe = mtk_eth_probe, ++ .remove = mtk_eth_remove, ++ .ops = &mtk_eth_ops, ++ .priv_auto_alloc_size = sizeof(struct mtk_eth_priv), ++ .flags = DM_FLAG_ALLOC_PRIV_DMA, ++}; +diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h +new file mode 100644 +index 00000000..fe89a037 +--- /dev/null ++++ b/drivers/net/mtk_eth.h +@@ -0,0 +1,286 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#ifndef _MTK_ETH_H_ ++#define _MTK_ETH_H_ ++ ++/* Frame Engine Register Bases */ ++#define PDMA_BASE 0x0800 ++#define GDMA1_BASE 0x0500 ++#define GDMA2_BASE 0x1500 ++#define GMAC_BASE 0x10000 ++ ++/* Ethernet subsystem registers */ ++ ++#define ETHSYS_SYSCFG0_REG 0x14 ++#define SYSCFG0_GE_MODE_S(n) (12 + ((n) * 2)) ++#define SYSCFG0_GE_MODE_M 0x3 ++ ++#define ETHSYS_CLKCFG0_REG 0x2c ++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) ++ ++/* SYSCFG0_GE_MODE: GE Modes */ ++#define GE_MODE_RGMII 0 ++#define GE_MODE_MII 1 ++#define GE_MODE_MII_PHY 2 ++#define GE_MODE_RMII 3 ++ ++/* Frame Engine Registers */ ++ ++/* PDMA */ ++#define TX_BASE_PTR_REG(n) (0x000 + (n) * 0x10) ++#define TX_MAX_CNT_REG(n) (0x004 + (n) * 0x10) ++#define TX_CTX_IDX_REG(n) (0x008 + (n) * 0x10) ++#define TX_DTX_IDX_REG(n) (0x00c + (n) * 0x10) ++ ++#define RX_BASE_PTR_REG(n) (0x100 + (n) * 0x10) ++#define RX_MAX_CNT_REG(n) (0x104 + (n) * 0x10) ++#define RX_CRX_IDX_REG(n) (0x108 + (n) * 0x10) ++#define RX_DRX_IDX_REG(n) (0x10c + (n) * 0x10) ++ ++#define PDMA_GLO_CFG_REG 0x204 ++#define TX_WB_DDONE BIT(6) ++#define RX_DMA_BUSY BIT(3) ++#define RX_DMA_EN BIT(2) ++#define TX_DMA_BUSY BIT(1) ++#define TX_DMA_EN BIT(0) ++ ++#define PDMA_RST_IDX_REG 0x208 ++#define RST_DRX_IDX0 BIT(16) ++#define RST_DTX_IDX0 BIT(0) ++ ++/* GDMA */ ++#define GDMA_IG_CTRL_REG 0x000 ++#define GDM_ICS_EN BIT(22) ++#define GDM_TCS_EN BIT(21) ++#define GDM_UCS_EN BIT(20) ++#define STRP_CRC BIT(16) ++#define MYMAC_DP_S 12 ++#define MYMAC_DP_M 0xf000 ++#define BC_DP_S 8 ++#define BC_DP_M 0xf00 ++#define MC_DP_S 4 ++#define MC_DP_M 0xf0 ++#define UN_DP_S 0 ++#define UN_DP_M 0x0f ++ ++#define GDMA_MAC_LSB_REG 0x008 ++ ++#define GDMA_MAC_MSB_REG 0x00c ++ ++/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */ ++#define DP_PDMA 0 ++#define DP_GDMA1 1 ++#define DP_GDMA2 2 ++#define DP_PPE 4 ++#define DP_QDMA 5 ++#define DP_DISCARD 7 ++ ++/* GMAC Registers */ ++ ++#define GMAC_PIAC_REG 0x0004 ++#define PHY_ACS_ST BIT(31) ++#define MDIO_REG_ADDR_S 25 ++#define MDIO_REG_ADDR_M 0x3e000000 ++#define MDIO_PHY_ADDR_S 20 ++#define MDIO_PHY_ADDR_M 0x1f00000 ++#define MDIO_CMD_S 18 ++#define MDIO_CMD_M 0xc0000 ++#define MDIO_ST_S 16 ++#define MDIO_ST_M 0x30000 ++#define MDIO_RW_DATA_S 0 ++#define MDIO_RW_DATA_M 0xffff ++ ++/* MDIO_CMD: MDIO commands */ ++#define MDIO_CMD_ADDR 0 ++#define MDIO_CMD_WRITE 1 ++#define MDIO_CMD_READ 2 ++#define MDIO_CMD_READ_C45 3 ++ ++/* MDIO_ST: MDIO start field */ ++#define MDIO_ST_C45 0 ++#define MDIO_ST_C22 1 ++ ++#define GMAC_PORT_MCR(p) (0x0100 + (p) * 0x100) ++#define MAC_RX_PKT_LEN_S 24 ++#define MAC_RX_PKT_LEN_M 0x3000000 ++#define IPG_CFG_S 18 ++#define IPG_CFG_M 0xc0000 ++#define MAC_MODE BIT(16) ++#define FORCE_MODE BIT(15) ++#define MAC_TX_EN BIT(14) ++#define MAC_RX_EN BIT(13) ++#define BKOFF_EN BIT(9) ++#define BACKPR_EN BIT(8) ++#define FORCE_RX_FC BIT(5) ++#define FORCE_TX_FC BIT(4) ++#define FORCE_SPD_S 2 ++#define FORCE_SPD_M 0x0c ++#define FORCE_DPX BIT(1) ++#define FORCE_LINK BIT(0) ++ ++/* MAC_RX_PKT_LEN: Max RX packet length */ ++#define MAC_RX_PKT_LEN_1518 0 ++#define MAC_RX_PKT_LEN_1536 1 ++#define MAC_RX_PKT_LEN_1552 2 ++#define MAC_RX_PKT_LEN_JUMBO 3 ++ ++/* FORCE_SPD: Forced link speed */ ++#define SPEED_10M 0 ++#define SPEED_100M 1 ++#define SPEED_1000M 2 ++ ++#define GMAC_TRGMII_RCK_CTRL 0x300 ++#define RX_RST BIT(31) ++#define RXC_DQSISEL BIT(30) ++ ++#define GMAC_TRGMII_TD_ODT(n) (0x354 + (n) * 8) ++#define TD_DM_DRVN_S 4 ++#define TD_DM_DRVN_M 0xf0 ++#define TD_DM_DRVP_S 0 ++#define TD_DM_DRVP_M 0x0f ++ ++/* MT7530 Registers */ ++ ++#define PCR_REG(p) (0x2004 + (p) * 0x100) ++#define PORT_MATRIX_S 16 ++#define PORT_MATRIX_M 0xff0000 ++ ++#define PVC_REG(p) (0x2010 + (p) * 0x100) ++#define STAG_VPID_S 16 ++#define STAG_VPID_M 0xffff0000 ++#define VLAN_ATTR_S 6 ++#define VLAN_ATTR_M 0xc0 ++ ++/* VLAN_ATTR: VLAN attributes */ ++#define VLAN_ATTR_USER 0 ++#define VLAN_ATTR_STACK 1 ++#define VLAN_ATTR_TRANSLATION 2 ++#define VLAN_ATTR_TRANSPARENT 3 ++ ++#define PCMR_REG(p) (0x3000 + (p) * 0x100) ++/* XXX: all fields are defined under GMAC_PORT_MCR */ ++ ++#define SYS_CTRL_REG 0x7000 ++#define SW_PHY_RST BIT(2) ++#define SW_SYS_RST BIT(1) ++#define SW_REG_RST BIT(0) ++ ++#define NUM_TRGMII_CTRL 5 ++ ++#define HWTRAP_REG 0x7800 ++#define MHWTRAP_REG 0x7804 ++#define CHG_TRAP BIT(16) ++#define LOOPDET_DIS BIT(14) ++#define P5_INTF_SEL_S 13 ++#define P5_INTF_SEL_M 0x2000 ++#define SMI_ADDR_S 11 ++#define SMI_ADDR_M 0x1800 ++#define XTAL_FSEL_S 9 ++#define XTAL_FSEL_M 0x600 ++#define P6_INTF_DIS BIT(8) ++#define P5_INTF_MODE_S 7 ++#define P5_INTF_MODE_M 0x80 ++#define P5_INTF_DIS BIT(6) ++#define C_MDIO_BPS BIT(5) ++#define CHIP_MODE_S 0 ++#define CHIP_MODE_M 0x0f ++ ++/* P5_INTF_SEL: Interface type of Port5 */ ++#define P5_INTF_SEL_GPHY 0 ++#define P5_INTF_SEL_GMAC5 1 ++ ++/* P5_INTF_MODE: Interface mode of Port5 */ ++#define P5_INTF_MODE_GMII_MII 0 ++#define P5_INTF_MODE_RGMII 1 ++ ++#define MT7530_P6ECR 0x7830 ++#define P6_INTF_MODE_M 0x3 ++#define P6_INTF_MODE_S 0 ++ ++/* P6_INTF_MODE: Interface mode of Port6 */ ++#define P6_INTF_MODE_RGMII 0 ++#define P6_INTF_MODE_TRGMII 1 ++ ++#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8) ++#define RD_TAP_S 0 ++#define RD_TAP_M 0x7f ++ ++#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8) ++/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */ ++ ++/* MT7530 GPHY MDIO Indirect Access Registers */ ++ ++#define MII_MMD_ACC_CTL_REG 0x0d ++#define MMD_CMD_S 14 ++#define MMD_CMD_M 0xc000 ++#define MMD_DEVAD_S 0 ++#define MMD_DEVAD_M 0x1f ++ ++/* MMD_CMD: MMD commands */ ++#define MMD_ADDR 0 ++#define MMD_DATA 1 ++#define MMD_DATA_RW_POST_INC 2 ++#define MMD_DATA_W_POST_INC 3 ++ ++#define MII_MMD_ADDR_DATA_REG 0x0e ++ ++/* MT7530 GPHY MDIO MMD Registers */ ++ ++#define CORE_PLL_GROUP2 0x401 ++#define RG_SYSPLL_EN_NORMAL BIT(15) ++#define RG_SYSPLL_VODEN BIT(14) ++#define RG_SYSPLL_POSDIV_S 5 ++#define RG_SYSPLL_POSDIV_M 0x60 ++ ++#define CORE_PLL_GROUP4 0x403 ++#define RG_SYSPLL_DDSFBK_EN BIT(12) ++#define RG_SYSPLL_BIAS_EN BIT(11) ++#define RG_SYSPLL_BIAS_LPF_EN BIT(10) ++ ++#define CORE_PLL_GROUP5 0x404 ++#define RG_LCDDS_PCW_NCPO1_S 0 ++#define RG_LCDDS_PCW_NCPO1_M 0xffff ++ ++#define CORE_PLL_GROUP6 0x405 ++#define RG_LCDDS_PCW_NCPO0_S 0 ++#define RG_LCDDS_PCW_NCPO0_M 0xffff ++ ++#define CORE_PLL_GROUP7 0x406 ++#define RG_LCDDS_PWDB BIT(15) ++#define RG_LCDDS_ISO_EN BIT(13) ++#define RG_LCCDS_C_S 4 ++#define RG_LCCDS_C_M 0x70 ++#define RG_LCDDS_PCW_NCPO_CHG BIT(3) ++ ++#define CORE_PLL_GROUP10 0x409 ++#define RG_LCDDS_SSC_DELTA_S 0 ++#define RG_LCDDS_SSC_DELTA_M 0xfff ++ ++#define CORE_PLL_GROUP11 0x40a ++#define RG_LCDDS_SSC_DELTA1_S 0 ++#define RG_LCDDS_SSC_DELTA1_M 0xfff ++ ++#define CORE_GSWPLL_GRP1 0x40d ++#define RG_GSWPLL_POSDIV_200M_S 12 ++#define RG_GSWPLL_POSDIV_200M_M 0x3000 ++#define RG_GSWPLL_EN_PRE BIT(11) ++#define RG_GSWPLL_FBKDIV_200M_S 0 ++#define RG_GSWPLL_FBKDIV_200M_M 0xff ++ ++#define CORE_GSWPLL_GRP2 0x40e ++#define RG_GSWPLL_POSDIV_500M_S 8 ++#define RG_GSWPLL_POSDIV_500M_M 0x300 ++#define RG_GSWPLL_FBKDIV_500M_S 0 ++#define RG_GSWPLL_FBKDIV_500M_M 0xff ++ ++#define CORE_TRGMII_GSW_CLK_CG 0x410 ++#define REG_GSWCK_EN BIT(0) ++#define REG_TRGMIICK_EN BIT(1) ++ ++#endif /* _MTK_ETH_H_ */ +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0006-arm-dts-add-ethernet-related-node-for-MT7623-SoC.patch b/root/package/boot/uboot-mediatek/patches/0006-arm-dts-add-ethernet-related-node-for-MT7623-SoC.patch new file mode 100644 index 00000000..505af94e --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0006-arm-dts-add-ethernet-related-node-for-MT7623-SoC.patch @@ -0,0 +1,76 @@ +From fbdf1c37235d4a5a50eaafff41cacff4fd3a6e9f Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:54 +0800 +Subject: arm: dts: add ethernet related node for MT7623 SoC + +This patch adds ethernet gmac node for MT7623 with MT7530 gigabit switch. + +Signed-off-by: Mark Lee + +diff --git a/arch/arm/dts/mt7623.dtsi b/arch/arm/dts/mt7623.dtsi +index f50f4ef1..448d1d73 100644 +--- a/arch/arm/dts/mt7623.dtsi ++++ b/arch/arm/dts/mt7623.dtsi +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include "skeleton.dtsi" + + / { +@@ -248,8 +249,26 @@ + }; + + ethsys: syscon@1b000000 { +- compatible = "mediatek,mt7623-ethsys"; ++ compatible = "mediatek,mt7623-ethsys", "syscon"; + reg = <0x1b000000 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ eth: ethernet@1b100000 { ++ compatible = "mediatek,mt7623-eth", "syscon"; ++ reg = <0x1b100000 0x20000>; ++ clocks = <&topckgen CLK_TOP_ETHIF_SEL>, ++ <ðsys CLK_ETHSYS_ESW>, ++ <ðsys CLK_ETHSYS_GP1>, ++ <ðsys CLK_ETHSYS_GP2>, ++ <&apmixedsys CLK_APMIXED_TRGPLL>; ++ clock-names = "ethif", "esw", "gp1", "gp2", "trgpll"; ++ power-domains = <&scpsys MT7623_POWER_DOMAIN_ETH>; ++ resets = <ðsys ETHSYS_FE_RST>, ++ <ðsys ETHSYS_MCM_RST>; ++ reset-names = "fe", "mcm"; ++ mediatek,ethsys = <ðsys>; ++ status = "disabled"; + }; + }; +diff --git a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts +index 84a77fde..51628bb6 100644 +--- a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts +@@ -67,6 +67,19 @@ + }; + }; + ++ð { ++ status = "okay"; ++ mediatek,gmac-id = <0>; ++ phy-mode = "rgmii"; ++ mediatek,switch = "mt7530"; ++ reset-gpios = <&gpio 33 GPIO_ACTIVE_HIGH>; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++}; ++ + &mmc0 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_default>; +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0007-arm-dts-add-ethernet-related-node-for-MT7629-SoC.patch b/root/package/boot/uboot-mediatek/patches/0007-arm-dts-add-ethernet-related-node-for-MT7629-SoC.patch new file mode 100644 index 00000000..7c314f50 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0007-arm-dts-add-ethernet-related-node-for-MT7629-SoC.patch @@ -0,0 +1,95 @@ +From 038e3dc3801007f5025a2e57bb4b715c48b9590d Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:55 +0800 +Subject: arm: dts: add ethernet related node for MT7629 SoC + +This patch adds ethernet gmac node for MT7629 with internal gigabit phy. + +Signed-off-by: Mark Lee + +diff --git a/arch/arm/dts/mt7629-rfb.dts b/arch/arm/dts/mt7629-rfb.dts +index a6d28a06..95d10aa6 100644 +--- a/arch/arm/dts/mt7629-rfb.dts ++++ b/arch/arm/dts/mt7629-rfb.dts +@@ -22,6 +22,17 @@ + }; + }; + ++ð { ++ status = "okay"; ++ mediatek,gmac-id = <1>; ++ phy-mode = "gmii"; ++ phy-handle = <&phy0>; ++ ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ }; ++}; ++ + &pinctrl { + qspi_pins: qspi-pins { + mux { +diff --git a/arch/arm/dts/mt7629.dtsi b/arch/arm/dts/mt7629.dtsi +index e6052bbd..c87115e0 100644 +--- a/arch/arm/dts/mt7629.dtsi ++++ b/arch/arm/dts/mt7629.dtsi +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include "skeleton.dtsi" + + / { +@@ -228,6 +229,48 @@ + compatible = "mediatek,mt7629-ethsys", "syscon"; + reg = <0x1b000000 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ eth: ethernet@1b100000 { ++ compatible = "mediatek,mt7629-eth", "syscon"; ++ reg = <0x1b100000 0x20000>; ++ clocks = <&topckgen CLK_TOP_ETH_SEL>, ++ <&topckgen CLK_TOP_F10M_REF_SEL>, ++ <ðsys CLK_ETH_ESW_EN>, ++ <ðsys CLK_ETH_GP0_EN>, ++ <ðsys CLK_ETH_GP1_EN>, ++ <ðsys CLK_ETH_GP2_EN>, ++ <ðsys CLK_ETH_FE_EN>, ++ <&sgmiisys0 CLK_SGMII_TX_EN>, ++ <&sgmiisys0 CLK_SGMII_RX_EN>, ++ <&sgmiisys0 CLK_SGMII_CDR_REF>, ++ <&sgmiisys0 CLK_SGMII_CDR_FB>, ++ <&sgmiisys1 CLK_SGMII_TX_EN>, ++ <&sgmiisys1 CLK_SGMII_RX_EN>, ++ <&sgmiisys1 CLK_SGMII_CDR_REF>, ++ <&sgmiisys1 CLK_SGMII_CDR_FB>, ++ <&apmixedsys CLK_APMIXED_SGMIPLL>, ++ <&apmixedsys CLK_APMIXED_ETH2PLL>; ++ clock-names = "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", ++ "fe", "sgmii_tx250m", "sgmii_rx250m", ++ "sgmii_cdr_ref", "sgmii_cdr_fb", ++ "sgmii2_tx250m", "sgmii2_rx250m", ++ "sgmii2_cdr_ref", "sgmii2_cdr_fb", ++ "sgmii_ck", "eth2pll"; ++ assigned-clocks = <&topckgen CLK_TOP_ETH_SEL>, ++ <&topckgen CLK_TOP_F10M_REF_SEL>; ++ assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>, ++ <&topckgen CLK_TOP_SGMIIPLL_D2>; ++ power-domains = <&scpsys MT7629_POWER_DOMAIN_ETHSYS>; ++ resets = <ðsys ETHSYS_FE_RST>; ++ reset-names = "fe"; ++ mediatek,ethsys = <ðsys>; ++ mediatek,sgmiisys = <&sgmiisys0>; ++ mediatek,infracfg = <&infracfg>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; + }; + + sgmiisys0: syscon@1b128000 { +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0008-arm-MediaTek-add-ethernet-support-for-MT7623-boards.patch b/root/package/boot/uboot-mediatek/patches/0008-arm-MediaTek-add-ethernet-support-for-MT7623-boards.patch new file mode 100644 index 00000000..1eabf49b --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0008-arm-MediaTek-add-ethernet-support-for-MT7623-boards.patch @@ -0,0 +1,59 @@ +From 8da1e0fd083f4c6a71f6735c06698e71250bcc07 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:56 +0800 +Subject: arm: MediaTek: add ethernet support for MT7623 boards + +Enable ethernet related configs to mt7623n_bpir2_defconfig. +Add default IP addresses. +Enable noncached memory region required by ethernet driver. + +Signed-off-by: Mark Lee + +diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig +index 74252cd0..bb67f328 100644 +--- a/configs/mt7623n_bpir2_defconfig ++++ b/configs/mt7623n_bpir2_defconfig +@@ -29,6 +29,7 @@ CONFIG_CMD_FAT=y + CONFIG_CMD_FS_GENERIC=y + CONFIG_OF_EMBED=y + CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2" ++CONFIG_NET_RANDOM_ETHADDR=y + CONFIG_REGMAP=y + CONFIG_SYSCON=y + # CONFIG_BLOCK_CACHE is not set +@@ -38,6 +39,11 @@ CONFIG_DM_MMC=y + # CONFIG_MMC_QUIRKS is not set + CONFIG_MMC_HS400_SUPPORT=y + CONFIG_MMC_MTK=y ++CONFIG_DM_RESET=y ++CONFIG_RESET_MEDIATEK=y ++CONFIG_PHY_FIXED=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y + CONFIG_PINCTRL=y + CONFIG_PINCONF=y + CONFIG_PINCTRL_MT7623=y +diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h +index fb6ac073..7d26debb 100644 +--- a/include/configs/mt7623.h ++++ b/include/configs/mt7623.h +@@ -24,6 +24,7 @@ + + /* Size of malloc() pool */ + #define CONFIG_SYS_MALLOC_LEN SZ_4M ++#define CONFIG_SYS_NONCACHED_MEMORY SZ_1M + + /* Environment */ + #define CONFIG_ENV_SIZE SZ_4K +@@ -56,4 +57,8 @@ + #define CONFIG_SYS_MMC_ENV_DEV 0 + #define CONFIG_ENV_OFFSET 0x100000 + ++/* Ethernet */ ++#define CONFIG_IPADDR 192.168.1.1 ++#define CONFIG_SERVERIP 192.168.1.2 ++ + #endif +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0009-arm-MediaTek-add-ethernet-support-for-MT7629-boards.patch b/root/package/boot/uboot-mediatek/patches/0009-arm-MediaTek-add-ethernet-support-for-MT7629-boards.patch new file mode 100644 index 00000000..1cc05c6c --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0009-arm-MediaTek-add-ethernet-support-for-MT7629-boards.patch @@ -0,0 +1,58 @@ +From 0fcb7ab842170e1ea7e9bf4d309af584b1e54388 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:57 +0800 +Subject: arm: MediaTek: add ethernet support for MT7629 boards + +Enable ethernet related configs to mt7629_rfb_defconfig. +Add default IP addresses. +Enable noncached memory region required by ethernet driver. + +Signed-off-by: Mark Lee + +diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig +index 1729d13c..fdd5f575 100644 +--- a/configs/mt7629_rfb_defconfig ++++ b/configs/mt7629_rfb_defconfig +@@ -32,6 +32,7 @@ CONFIG_CMD_PING=y + CONFIG_OF_EMBED=y + CONFIG_DEFAULT_DEVICE_TREE="mt7629-rfb" + CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-parents" ++CONFIG_NET_RANDOM_ETHADDR=y + CONFIG_SPL_DM_SEQ_ALIAS=y + CONFIG_REGMAP=y + CONFIG_SPL_REGMAP=y +@@ -51,6 +52,10 @@ CONFIG_SPI_FLASH_MACRONIX=y + CONFIG_SPI_FLASH_SPANSION=y + CONFIG_SPI_FLASH_STMICRO=y + CONFIG_SPI_FLASH_WINBOND=y ++CONFIG_DM_RESET=y ++CONFIG_RESET_MEDIATEK=y ++CONFIG_DM_ETH=y ++CONFIG_MEDIATEK_ETH=y + CONFIG_PINCTRL=y + CONFIG_PINCONF=y + CONFIG_PINCTRL_MT7629=y +diff --git a/include/configs/mt7629.h b/include/configs/mt7629.h +index a665a5eb..9910d8c8 100644 +--- a/include/configs/mt7629.h ++++ b/include/configs/mt7629.h +@@ -24,6 +24,7 @@ + + /* Size of malloc() pool */ + #define CONFIG_SYS_MALLOC_LEN SZ_4M ++#define CONFIG_SYS_NONCACHED_MEMORY SZ_1M + + /* Environment */ + #define CONFIG_ENV_SIZE SZ_4K +@@ -54,4 +55,8 @@ + /* DRAM */ + #define CONFIG_SYS_SDRAM_BASE 0x40000000 + ++/* Ethernet */ ++#define CONFIG_IPADDR 192.168.1.1 ++#define CONFIG_SERVERIP 192.168.1.2 ++ + #endif +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0010-MAINTAINERS-ARM-MEDIATEK-update-file-entries.patch b/root/package/boot/uboot-mediatek/patches/0010-MAINTAINERS-ARM-MEDIATEK-update-file-entries.patch new file mode 100644 index 00000000..101a4281 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0010-MAINTAINERS-ARM-MEDIATEK-update-file-entries.patch @@ -0,0 +1,25 @@ +From 31ca82655b5f623303e45508a820205b071df258 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:58 +0800 +Subject: MAINTAINERS: ARM MEDIATEK: update file entries + +This patch adds new file entries for MediaTek SoCs + +Signed-off-by: Weijie Gao + +diff --git a/MAINTAINERS b/MAINTAINERS +index f86fdf9c..e192db07 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -176,6 +176,8 @@ F: drivers/ram/mediatek/ + F: drivers/spi/mtk_qspi.c + F: drivers/timer/mtk_timer.c + F: drivers/watchdog/mtk_wdt.c ++F: drivers/net/mtk_eth.c ++F: drivers/reset/reset-mediatek.c + F: tools/mtk_image.c + F: tools/mtk_image.h + N: mediatek +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0011-configs-MediaTek-use-OF_SEPARATE-instead-of-OF_EMBED.patch b/root/package/boot/uboot-mediatek/patches/0011-configs-MediaTek-use-OF_SEPARATE-instead-of-OF_EMBED.patch new file mode 100644 index 00000000..31fdc83d --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0011-configs-MediaTek-use-OF_SEPARATE-instead-of-OF_EMBED.patch @@ -0,0 +1,40 @@ +From d4b93c443372d651bd6f8b78070c54338ee35b91 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Thu, 20 Dec 2018 16:12:59 +0800 +Subject: configs: MediaTek: use OF_SEPARATE instead of OF_EMBED + +This patch replace OF_EMBED with OF_SEPARATE of defconfig files of +MediaTek boards because now OF_EMBED is only used for debugging purpose. + +Signed-off-by: Weijie Gao +Reviewed-by: Simon Glass + +diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig +index bb67f328..a9f4506e 100644 +--- a/configs/mt7623n_bpir2_defconfig ++++ b/configs/mt7623n_bpir2_defconfig +@@ -27,7 +27,7 @@ CONFIG_CMD_READ=y + CONFIG_CMD_PING=y + CONFIG_CMD_FAT=y + CONFIG_CMD_FS_GENERIC=y +-CONFIG_OF_EMBED=y ++CONFIG_OF_SEPARATE=y + CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2" + CONFIG_NET_RANDOM_ETHADDR=y + CONFIG_REGMAP=y +diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig +index fdd5f575..1da9932d 100644 +--- a/configs/mt7629_rfb_defconfig ++++ b/configs/mt7629_rfb_defconfig +@@ -29,7 +29,7 @@ CONFIG_CMD_SF_TEST=y + # CONFIG_CMD_NFS is not set + CONFIG_CMD_PING=y + # CONFIG_PARTITIONS is not set +-CONFIG_OF_EMBED=y ++CONFIG_OF_SEPARATE=y + CONFIG_DEFAULT_DEVICE_TREE="mt7629-rfb" + CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-parents" + CONFIG_NET_RANDOM_ETHADDR=y +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0013-test-add-test-for-lib-lmb.c.patch b/root/package/boot/uboot-mediatek/patches/0013-test-add-test-for-lib-lmb.c.patch new file mode 100644 index 00000000..6e883e42 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0013-test-add-test-for-lib-lmb.c.patch @@ -0,0 +1,326 @@ +From d6755b9b0e59ea0193914e169f74df51d556fbb7 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:14 +0100 +Subject: test: add test for lib/lmb.c + +Add basic tests for the lmb memory allocation code used to reserve and +allocate memory during boot. + +Signed-off-by: Simon Goldschmidt +Reviewed-by: Simon Glass + +diff --git a/test/lib/Makefile b/test/lib/Makefile +index ea68fae5..5a636aac 100644 +--- a/test/lib/Makefile ++++ b/test/lib/Makefile +@@ -3,3 +3,4 @@ + # (C) Copyright 2018 + # Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + obj-y += hexdump.o ++obj-y += lmb.o +diff --git a/test/lib/lmb.c b/test/lib/lmb.c +new file mode 100644 +index 00000000..dd7ba14b +--- /dev/null ++++ b/test/lib/lmb.c +@@ -0,0 +1,297 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * (C) Copyright 2018 Simon Goldschmidt ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static int check_lmb(struct unit_test_state *uts, struct lmb *lmb, ++ phys_addr_t ram_base, phys_size_t ram_size, ++ unsigned long num_reserved, ++ phys_addr_t base1, phys_size_t size1, ++ phys_addr_t base2, phys_size_t size2, ++ phys_addr_t base3, phys_size_t size3) ++{ ++ ut_asserteq(lmb->memory.cnt, 1); ++ ut_asserteq(lmb->memory.region[0].base, ram_base); ++ ut_asserteq(lmb->memory.region[0].size, ram_size); ++ ++ ut_asserteq(lmb->reserved.cnt, num_reserved); ++ if (num_reserved > 0) { ++ ut_asserteq(lmb->reserved.region[0].base, base1); ++ ut_asserteq(lmb->reserved.region[0].size, size1); ++ } ++ if (num_reserved > 1) { ++ ut_asserteq(lmb->reserved.region[1].base, base2); ++ ut_asserteq(lmb->reserved.region[1].size, size2); ++ } ++ if (num_reserved > 2) { ++ ut_asserteq(lmb->reserved.region[2].base, base3); ++ ut_asserteq(lmb->reserved.region[2].size, size3); ++ } ++ return 0; ++} ++ ++#define ASSERT_LMB(lmb, ram_base, ram_size, num_reserved, base1, size1, \ ++ base2, size2, base3, size3) \ ++ ut_assert(!check_lmb(uts, lmb, ram_base, ram_size, \ ++ num_reserved, base1, size1, base2, size2, base3, \ ++ size3)) ++ ++/* ++ * Test helper function that reserves 64 KiB somewhere in the simulated RAM and ++ * then does some alloc + free tests. ++ */ ++static int test_multi_alloc(struct unit_test_state *uts, ++ const phys_addr_t ram, const phys_size_t ram_size, ++ const phys_addr_t alloc_64k_addr) ++{ ++ const phys_addr_t ram_end = ram + ram_size; ++ const phys_addr_t alloc_64k_end = alloc_64k_addr + 0x10000; ++ ++ struct lmb lmb; ++ long ret; ++ phys_addr_t a, a2, b, b2, c, d; ++ ++ /* check for overflow */ ++ ut_assert(ram_end == 0 || ram_end > ram); ++ ut_assert(alloc_64k_end > alloc_64k_addr); ++ /* check input addresses + size */ ++ ut_assert(alloc_64k_addr >= ram + 8); ++ ut_assert(alloc_64k_end <= ram_end - 8); ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ /* reserve 64KiB somewhere */ ++ ret = lmb_reserve(&lmb, alloc_64k_addr, 0x10000); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, ++ 0, 0, 0, 0); ++ ++ /* allocate somewhere, should be at the end of RAM */ ++ a = lmb_alloc(&lmb, 4, 1); ++ ut_asserteq(a, ram_end - 4); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, alloc_64k_addr, 0x10000, ++ ram_end - 4, 4, 0, 0); ++ /* alloc below end of reserved region -> below reserved region */ ++ b = lmb_alloc_base(&lmb, 4, 1, alloc_64k_end); ++ ut_asserteq(b, alloc_64k_addr - 4); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 4, 0x10000 + 4, ram_end - 4, 4, 0, 0); ++ ++ /* 2nd time */ ++ c = lmb_alloc(&lmb, 4, 1); ++ ut_asserteq(c, ram_end - 8); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 4, 0x10000 + 4, ram_end - 8, 8, 0, 0); ++ d = lmb_alloc_base(&lmb, 4, 1, alloc_64k_end); ++ ut_asserteq(d, alloc_64k_addr - 8); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 8, 0, 0); ++ ++ ret = lmb_free(&lmb, a, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 4, 0, 0); ++ /* allocate again to ensure we get the same address */ ++ a2 = lmb_alloc(&lmb, 4, 1); ++ ut_asserteq(a, a2); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 8, 0, 0); ++ ret = lmb_free(&lmb, a2, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 4, 0, 0); ++ ++ ret = lmb_free(&lmb, b, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 3, ++ alloc_64k_addr - 8, 4, alloc_64k_addr, 0x10000, ++ ram_end - 8, 4); ++ /* allocate again to ensure we get the same address */ ++ b2 = lmb_alloc_base(&lmb, 4, 1, alloc_64k_end); ++ ut_asserteq(b, b2); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 4, 0, 0); ++ ret = lmb_free(&lmb, b2, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 3, ++ alloc_64k_addr - 8, 4, alloc_64k_addr, 0x10000, ++ ram_end - 8, 4); ++ ++ ret = lmb_free(&lmb, c, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ++ alloc_64k_addr - 8, 4, alloc_64k_addr, 0x10000, 0, 0); ++ ret = lmb_free(&lmb, d, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, ++ 0, 0, 0, 0); ++ ++ return 0; ++} ++ ++static int test_multi_alloc_512mb(struct unit_test_state *uts, ++ const phys_addr_t ram) ++{ ++ return test_multi_alloc(uts, ram, 0x20000000, ram + 0x10000000); ++} ++ ++/* Create a memory region with one reserved region and allocate */ ++static int lib_test_lmb_simple(struct unit_test_state *uts) ++{ ++ /* simulate 512 MiB RAM beginning at 1GiB */ ++ return test_multi_alloc_512mb(uts, 0x40000000); ++} ++ ++DM_TEST(lib_test_lmb_simple, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); ++ ++/* Simulate 512 MiB RAM, allocate some blocks that fit/don't fit */ ++static int test_bigblock(struct unit_test_state *uts, const phys_addr_t ram) ++{ ++ const phys_size_t ram_size = 0x20000000; ++ const phys_size_t big_block_size = 0x10000000; ++ const phys_addr_t ram_end = ram + ram_size; ++ const phys_addr_t alloc_64k_addr = ram + 0x10000000; ++ struct lmb lmb; ++ long ret; ++ phys_addr_t a, b; ++ ++ /* check for overflow */ ++ ut_assert(ram_end == 0 || ram_end > ram); ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ /* reserve 64KiB in the middle of RAM */ ++ ret = lmb_reserve(&lmb, alloc_64k_addr, 0x10000); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, ++ 0, 0, 0, 0); ++ ++ /* allocate a big block, should be below reserved */ ++ a = lmb_alloc(&lmb, big_block_size, 1); ++ ut_asserteq(a, ram); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, a, ++ big_block_size + 0x10000, 0, 0, 0, 0); ++ /* allocate 2nd big block */ ++ /* This should fail, printing an error */ ++ b = lmb_alloc(&lmb, big_block_size, 1); ++ ut_asserteq(b, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, a, ++ big_block_size + 0x10000, 0, 0, 0, 0); ++ ++ ret = lmb_free(&lmb, a, big_block_size); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, ++ 0, 0, 0, 0); ++ ++ /* allocate too big block */ ++ /* This should fail, printing an error */ ++ a = lmb_alloc(&lmb, ram_size, 1); ++ ut_asserteq(a, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, ++ 0, 0, 0, 0); ++ ++ return 0; ++} ++ ++static int lib_test_lmb_big(struct unit_test_state *uts) ++{ ++ return test_bigblock(uts, 0x40000000); ++} ++ ++DM_TEST(lib_test_lmb_big, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); ++ ++/* Simulate 512 MiB RAM, allocate a block without previous reservation */ ++static int test_noreserved(struct unit_test_state *uts, const phys_addr_t ram) ++{ ++ const phys_size_t ram_size = 0x20000000; ++ const phys_addr_t ram_end = ram + ram_size; ++ struct lmb lmb; ++ long ret; ++ phys_addr_t a, b; ++ ++ /* check for overflow */ ++ ut_assert(ram_end == 0 || ram_end > ram); ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ /* allocate a block */ ++ a = lmb_alloc(&lmb, 4, 1); ++ ut_assert(a != 0); ++ /* and free it */ ++ ret = lmb_free(&lmb, a, 4); ++ ut_asserteq(ret, 0); ++ ++ /* allocate a block with base*/ ++ b = lmb_alloc_base(&lmb, 4, 1, ram_end); ++ ut_assert(a == b); ++ /* and free it */ ++ ret = lmb_free(&lmb, b, 4); ++ ut_asserteq(ret, 0); ++ ++ return 0; ++} ++ ++static int lib_test_lmb_noreserved(struct unit_test_state *uts) ++{ ++ return test_noreserved(uts, 0x40000000); ++} ++ ++DM_TEST(lib_test_lmb_noreserved, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); ++ ++/* ++ * Simulate a RAM that starts at 0 and allocate down to address 0, which must ++ * fail as '0' means failure for the lmb_alloc functions. ++ */ ++static int lib_test_lmb_at_0(struct unit_test_state *uts) ++{ ++ const phys_addr_t ram = 0; ++ const phys_size_t ram_size = 0x20000000; ++ struct lmb lmb; ++ long ret; ++ phys_addr_t a, b; ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ /* allocate nearly everything */ ++ a = lmb_alloc(&lmb, ram_size - 4, 1); ++ ut_asserteq(a, ram + 4); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, a, ram_size - 4, ++ 0, 0, 0, 0); ++ /* allocate the rest */ ++ /* This should fail as the allocated address would be 0 */ ++ b = lmb_alloc(&lmb, 4, 1); ++ ut_asserteq(b, 0); ++ /* check that this was an error by checking lmb */ ++ ASSERT_LMB(&lmb, ram, ram_size, 1, a, ram_size - 4, ++ 0, 0, 0, 0); ++ /* check that this was an error by freeing b */ ++ ret = lmb_free(&lmb, b, 4); ++ ut_asserteq(ret, -1); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, a, ram_size - 4, ++ 0, 0, 0, 0); ++ ++ ret = lmb_free(&lmb, a, ram_size - 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 0, 0, 0, 0, 0, 0, 0); ++ ++ return 0; ++} ++ ++DM_TEST(lib_test_lmb_at_0, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0014-lmb-fix-allocation-at-end-of-address-range.patch b/root/package/boot/uboot-mediatek/patches/0014-lmb-fix-allocation-at-end-of-address-range.patch new file mode 100644 index 00000000..d62fb4b4 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0014-lmb-fix-allocation-at-end-of-address-range.patch @@ -0,0 +1,157 @@ +From 8d8854693b9a288c6dbcf5382e74e6ce05839b33 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:15 +0100 +Subject: lmb: fix allocation at end of address range + +The lmb code fails if base + size of RAM overflows to zero. + +Fix this by calculating end as 'base + size - 1' instead of 'base + size' +where appropriate. + +Added tests to assert this is fixed. + +Signed-off-by: Simon Goldschmidt + +diff --git a/lib/lmb.c b/lib/lmb.c +index 17054173..6d3dcf4e 100644 +--- a/lib/lmb.c ++++ b/lib/lmb.c +@@ -43,7 +43,10 @@ void lmb_dump_all(struct lmb *lmb) + static long lmb_addrs_overlap(phys_addr_t base1, + phys_size_t size1, phys_addr_t base2, phys_size_t size2) + { +- return ((base1 < (base2+size2)) && (base2 < (base1+size1))); ++ const phys_addr_t base1_end = base1 + size1 - 1; ++ const phys_addr_t base2_end = base2 + size2 - 1; ++ ++ return ((base1 <= base2_end) && (base2 <= base1_end)); + } + + static long lmb_addrs_adjacent(phys_addr_t base1, phys_size_t size1, +@@ -89,18 +92,9 @@ static void lmb_coalesce_regions(struct lmb_region *rgn, + + void lmb_init(struct lmb *lmb) + { +- /* Create a dummy zero size LMB which will get coalesced away later. +- * This simplifies the lmb_add() code below... +- */ +- lmb->memory.region[0].base = 0; +- lmb->memory.region[0].size = 0; +- lmb->memory.cnt = 1; ++ lmb->memory.cnt = 0; + lmb->memory.size = 0; +- +- /* Ditto. */ +- lmb->reserved.region[0].base = 0; +- lmb->reserved.region[0].size = 0; +- lmb->reserved.cnt = 1; ++ lmb->reserved.cnt = 0; + lmb->reserved.size = 0; + } + +@@ -110,9 +104,10 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t + unsigned long coalesced = 0; + long adjacent, i; + +- if ((rgn->cnt == 1) && (rgn->region[0].size == 0)) { ++ if (rgn->cnt == 0) { + rgn->region[0].base = base; + rgn->region[0].size = size; ++ rgn->cnt = 1; + return 0; + } + +@@ -183,7 +178,7 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size) + { + struct lmb_region *rgn = &(lmb->reserved); + phys_addr_t rgnbegin, rgnend; +- phys_addr_t end = base + size; ++ phys_addr_t end = base + size - 1; + int i; + + rgnbegin = rgnend = 0; /* supress gcc warnings */ +@@ -191,7 +186,7 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size) + /* Find the region where (base, size) belongs to */ + for (i=0; i < rgn->cnt; i++) { + rgnbegin = rgn->region[i].base; +- rgnend = rgnbegin + rgn->region[i].size; ++ rgnend = rgnbegin + rgn->region[i].size - 1; + + if ((rgnbegin <= base) && (end <= rgnend)) + break; +@@ -209,7 +204,7 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size) + + /* Check to see if region is matching at the front */ + if (rgnbegin == base) { +- rgn->region[i].base = end; ++ rgn->region[i].base = end + 1; + rgn->region[i].size -= size; + return 0; + } +@@ -225,7 +220,7 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size) + * beginging of the hole and add the region after hole. + */ + rgn->region[i].size = base - rgn->region[i].base; +- return lmb_add_region(rgn, end, rgnend - end); ++ return lmb_add_region(rgn, end + 1, rgnend - end); + } + + long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size) +diff --git a/test/lib/lmb.c b/test/lib/lmb.c +index dd7ba14b..fb7ca45e 100644 +--- a/test/lib/lmb.c ++++ b/test/lib/lmb.c +@@ -146,8 +146,15 @@ static int test_multi_alloc_512mb(struct unit_test_state *uts, + /* Create a memory region with one reserved region and allocate */ + static int lib_test_lmb_simple(struct unit_test_state *uts) + { ++ int ret; ++ + /* simulate 512 MiB RAM beginning at 1GiB */ +- return test_multi_alloc_512mb(uts, 0x40000000); ++ ret = test_multi_alloc_512mb(uts, 0x40000000); ++ if (ret) ++ return ret; ++ ++ /* simulate 512 MiB RAM beginning at 1.5GiB */ ++ return test_multi_alloc_512mb(uts, 0xE0000000); + } + + DM_TEST(lib_test_lmb_simple, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +@@ -206,7 +213,15 @@ static int test_bigblock(struct unit_test_state *uts, const phys_addr_t ram) + + static int lib_test_lmb_big(struct unit_test_state *uts) + { +- return test_bigblock(uts, 0x40000000); ++ int ret; ++ ++ /* simulate 512 MiB RAM beginning at 1GiB */ ++ ret = test_bigblock(uts, 0x40000000); ++ if (ret) ++ return ret; ++ ++ /* simulate 512 MiB RAM beginning at 1.5GiB */ ++ return test_bigblock(uts, 0xE0000000); + } + + DM_TEST(lib_test_lmb_big, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +@@ -247,7 +262,15 @@ static int test_noreserved(struct unit_test_state *uts, const phys_addr_t ram) + + static int lib_test_lmb_noreserved(struct unit_test_state *uts) + { +- return test_noreserved(uts, 0x40000000); ++ int ret; ++ ++ /* simulate 512 MiB RAM beginning at 1GiB */ ++ ret = test_noreserved(uts, 0x40000000); ++ if (ret) ++ return ret; ++ ++ /* simulate 512 MiB RAM beginning at 1.5GiB */ ++ return test_noreserved(uts, 0xE0000000); + } + + DM_TEST(lib_test_lmb_noreserved, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0015-lib-lmb-reserving-overlapping-regions-should-fail.patch b/root/package/boot/uboot-mediatek/patches/0015-lib-lmb-reserving-overlapping-regions-should-fail.patch new file mode 100644 index 00000000..61a6c6c0 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0015-lib-lmb-reserving-overlapping-regions-should-fail.patch @@ -0,0 +1,208 @@ +From 0b66765ffcdc995177753b7e6607be477593041e Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:16 +0100 +Subject: lib: lmb: reserving overlapping regions should fail + +lmb_add_region handles overlapping regions wrong: instead of merging +or rejecting to add a new reserved region that overlaps an existing +one, it just adds the new region. + +Since internally the same function is used for lmb_alloc, change +lmb_add_region to reject overlapping regions. + +Also, to keep reserved memory correct after 'free', reserved entries +created by allocating memory must not set their size to a multiple +of alignment but to the original size. This ensures the reserved +region is completely removed when the caller calls 'lmb_free', as +this one takes the same size as passed to 'lmb_alloc' etc. + +Add test to assert this. + +Signed-off-by: Simon Goldschmidt + +diff --git a/lib/lmb.c b/lib/lmb.c +index 6d3dcf4e..cd297f82 100644 +--- a/lib/lmb.c ++++ b/lib/lmb.c +@@ -131,6 +131,9 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t + rgn->region[i].size += size; + coalesced++; + break; ++ } else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) { ++ /* regions overlap */ ++ return -1; + } + } + +@@ -269,11 +272,6 @@ static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size) + return addr & ~(size - 1); + } + +-static phys_addr_t lmb_align_up(phys_addr_t addr, ulong size) +-{ +- return (addr + (size - 1)) & ~(size - 1); +-} +- + phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr) + { + long i, j; +@@ -302,8 +300,7 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy + if (j < 0) { + /* This area isn't reserved, take it */ + if (lmb_add_region(&lmb->reserved, base, +- lmb_align_up(size, +- align)) < 0) ++ size) < 0) + return 0; + return base; + } +diff --git a/test/lib/lmb.c b/test/lib/lmb.c +index fb7ca45e..e6acb70e 100644 +--- a/test/lib/lmb.c ++++ b/test/lib/lmb.c +@@ -227,13 +227,16 @@ static int lib_test_lmb_big(struct unit_test_state *uts) + DM_TEST(lib_test_lmb_big, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + + /* Simulate 512 MiB RAM, allocate a block without previous reservation */ +-static int test_noreserved(struct unit_test_state *uts, const phys_addr_t ram) ++static int test_noreserved(struct unit_test_state *uts, const phys_addr_t ram, ++ const phys_addr_t alloc_size, const ulong align) + { + const phys_size_t ram_size = 0x20000000; + const phys_addr_t ram_end = ram + ram_size; + struct lmb lmb; + long ret; + phys_addr_t a, b; ++ const phys_addr_t alloc_size_aligned = (alloc_size + align - 1) & ++ ~(align - 1); + + /* check for overflow */ + ut_assert(ram_end == 0 || ram_end > ram); +@@ -242,20 +245,43 @@ static int test_noreserved(struct unit_test_state *uts, const phys_addr_t ram) + + ret = lmb_add(&lmb, ram, ram_size); + ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 0, 0, 0, 0, 0, 0, 0); + + /* allocate a block */ +- a = lmb_alloc(&lmb, 4, 1); ++ a = lmb_alloc(&lmb, alloc_size, align); + ut_assert(a != 0); +- /* and free it */ +- ret = lmb_free(&lmb, a, 4); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram + ram_size - alloc_size_aligned, ++ alloc_size, 0, 0, 0, 0); ++ /* allocate another block */ ++ b = lmb_alloc(&lmb, alloc_size, align); ++ ut_assert(b != 0); ++ if (alloc_size == alloc_size_aligned) { ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram + ram_size - ++ (alloc_size_aligned * 2), alloc_size * 2, 0, 0, 0, ++ 0); ++ } else { ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ram + ram_size - ++ (alloc_size_aligned * 2), alloc_size, ram + ram_size ++ - alloc_size_aligned, alloc_size, 0, 0); ++ } ++ /* and free them */ ++ ret = lmb_free(&lmb, b, alloc_size); + ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram + ram_size - alloc_size_aligned, ++ alloc_size, 0, 0, 0, 0); ++ ret = lmb_free(&lmb, a, alloc_size); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 0, 0, 0, 0, 0, 0, 0); + + /* allocate a block with base*/ +- b = lmb_alloc_base(&lmb, 4, 1, ram_end); ++ b = lmb_alloc_base(&lmb, alloc_size, align, ram_end); + ut_assert(a == b); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram + ram_size - alloc_size_aligned, ++ alloc_size, 0, 0, 0, 0); + /* and free it */ +- ret = lmb_free(&lmb, b, 4); ++ ret = lmb_free(&lmb, b, alloc_size); + ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 0, 0, 0, 0, 0, 0, 0); + + return 0; + } +@@ -265,16 +291,30 @@ static int lib_test_lmb_noreserved(struct unit_test_state *uts) + int ret; + + /* simulate 512 MiB RAM beginning at 1GiB */ +- ret = test_noreserved(uts, 0x40000000); ++ ret = test_noreserved(uts, 0x40000000, 4, 1); + if (ret) + return ret; + + /* simulate 512 MiB RAM beginning at 1.5GiB */ +- return test_noreserved(uts, 0xE0000000); ++ return test_noreserved(uts, 0xE0000000, 4, 1); + } + + DM_TEST(lib_test_lmb_noreserved, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + ++static int lib_test_lmb_unaligned_size(struct unit_test_state *uts) ++{ ++ int ret; ++ ++ /* simulate 512 MiB RAM beginning at 1GiB */ ++ ret = test_noreserved(uts, 0x40000000, 5, 8); ++ if (ret) ++ return ret; ++ ++ /* simulate 512 MiB RAM beginning at 1.5GiB */ ++ return test_noreserved(uts, 0xE0000000, 5, 8); ++} ++ ++DM_TEST(lib_test_lmb_unaligned_size, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + /* + * Simulate a RAM that starts at 0 and allocate down to address 0, which must + * fail as '0' means failure for the lmb_alloc functions. +@@ -318,3 +358,42 @@ static int lib_test_lmb_at_0(struct unit_test_state *uts) + } + + DM_TEST(lib_test_lmb_at_0, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); ++ ++/* Check that calling lmb_reserve with overlapping regions fails. */ ++static int lib_test_lmb_overlapping_reserve(struct unit_test_state *uts) ++{ ++ const phys_addr_t ram = 0x40000000; ++ const phys_size_t ram_size = 0x20000000; ++ struct lmb lmb; ++ long ret; ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ ret = lmb_reserve(&lmb, 0x40010000, 0x10000); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x10000, ++ 0, 0, 0, 0); ++ /* allocate overlapping region should fail */ ++ ret = lmb_reserve(&lmb, 0x40011000, 0x10000); ++ ut_asserteq(ret, -1); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x10000, ++ 0, 0, 0, 0); ++ /* allocate 3nd region */ ++ ret = lmb_reserve(&lmb, 0x40030000, 0x10000); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, 0x40010000, 0x10000, ++ 0x40030000, 0x10000, 0, 0); ++ /* allocate 2nd region */ ++ ret = lmb_reserve(&lmb, 0x40020000, 0x10000); ++ ut_assert(ret >= 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x30000, ++ 0, 0, 0, 0); ++ ++ return 0; ++} ++ ++DM_TEST(lib_test_lmb_overlapping_reserve, ++ DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0016-fdt-parse-reserved-memory-for-memory-reservation.patch b/root/package/boot/uboot-mediatek/patches/0016-fdt-parse-reserved-memory-for-memory-reservation.patch new file mode 100644 index 00000000..10593967 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0016-fdt-parse-reserved-memory-for-memory-reservation.patch @@ -0,0 +1,117 @@ +From 83dc6df2cff9e91e77890107c74d4858182e4b61 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:17 +0100 +Subject: fdt: parse "reserved-memory" for memory reservation + +boot_fdt_add_mem_rsv_regions() adds reserved memory sections to an lmb +struct. Currently, it only parses regions described by /memreserve/ +entries. + +Extend this to the more commonly used scheme of the "reserved-memory" +node. + +Signed-off-by: Simon Goldschmidt +Reviewed-by: Simon Glass + +diff --git a/common/image-fdt.c b/common/image-fdt.c +index 95748f0a..5c0d6db3 100644 +--- a/common/image-fdt.c ++++ b/common/image-fdt.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -67,30 +68,66 @@ static const image_header_t *image_get_fdt(ulong fdt_addr) + } + #endif + ++static void boot_fdt_reserve_region(struct lmb *lmb, uint64_t addr, ++ uint64_t size) ++{ ++ int ret; ++ ++ ret = lmb_reserve(lmb, addr, size); ++ if (!ret) { ++ debug(" reserving fdt memory region: addr=%llx size=%llx\n", ++ (unsigned long long)addr, (unsigned long long)size); ++ } else { ++ puts("ERROR: reserving fdt memory region failed "); ++ printf("(addr=%llx size=%llx)\n", ++ (unsigned long long)addr, (unsigned long long)size); ++ } ++} ++ + /** +- * boot_fdt_add_mem_rsv_regions - Mark the memreserve sections as unusable ++ * boot_fdt_add_mem_rsv_regions - Mark the memreserve and reserved-memory ++ * sections as unusable + * @lmb: pointer to lmb handle, will be used for memory mgmt + * @fdt_blob: pointer to fdt blob base address + * +- * Adds the memreserve regions in the dtb to the lmb block. Adding the +- * memreserve regions prevents u-boot from using them to store the initrd +- * or the fdt blob. ++ * Adds the and reserved-memorymemreserve regions in the dtb to the lmb block. ++ * Adding the memreserve regions prevents u-boot from using them to store the ++ * initrd or the fdt blob. + */ + void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob) + { + uint64_t addr, size; +- int i, total; ++ int i, total, ret; ++ int nodeoffset, subnode; ++ struct fdt_resource res; + + if (fdt_check_header(fdt_blob) != 0) + return; + ++ /* process memreserve sections */ + total = fdt_num_mem_rsv(fdt_blob); + for (i = 0; i < total; i++) { + if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0) + continue; +- printf(" reserving fdt memory region: addr=%llx size=%llx\n", +- (unsigned long long)addr, (unsigned long long)size); +- lmb_reserve(lmb, addr, size); ++ boot_fdt_reserve_region(lmb, addr, size); ++ } ++ ++ /* process reserved-memory */ ++ nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory"); ++ if (nodeoffset >= 0) { ++ subnode = fdt_first_subnode(fdt_blob, nodeoffset); ++ while (subnode >= 0) { ++ /* check if this subnode has a reg property */ ++ ret = fdt_get_resource(fdt_blob, subnode, "reg", 0, ++ &res); ++ if (!ret) { ++ addr = res.start; ++ size = res.end - res.start + 1; ++ boot_fdt_reserve_region(lmb, addr, size); ++ } ++ ++ subnode = fdt_next_subnode(fdt_blob, subnode); ++ } + } + } + +diff --git a/lib/Makefile b/lib/Makefile +index a6dd928a..358789ff 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -30,6 +30,7 @@ obj-y += crc7.o + obj-y += crc8.o + obj-y += crc16.o + obj-$(CONFIG_ERRNO_STR) += errno_str.o ++obj-$(CONFIG_OF_LIBFDT) += fdtdec.o + obj-$(CONFIG_FIT) += fdtdec_common.o + obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o + obj-$(CONFIG_GZIP_COMPRESSED) += gzip.o +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0017-lib-lmb-extend-lmb-for-checks-at-load-time.patch b/root/package/boot/uboot-mediatek/patches/0017-lib-lmb-extend-lmb-for-checks-at-load-time.patch new file mode 100644 index 00000000..ac9ac256 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0017-lib-lmb-extend-lmb-for-checks-at-load-time.patch @@ -0,0 +1,312 @@ +From 16448a9becefd10a64601a08bbcacea38075db70 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:18 +0100 +Subject: lib: lmb: extend lmb for checks at load time + +This adds two new functions, lmb_alloc_addr and +lmb_get_unreserved_size. + +lmb_alloc_addr behaves like lmb_alloc, but it tries to allocate a +pre-specified address range. Unlike lmb_reserve, this address range +must be inside one of the memory ranges that has been set up with +lmb_add. + +lmb_get_unreserved_size returns the number of bytes that can be +used up to the next reserved region or the end of valid ram. This +can be 0 if the address passed is reserved. + +Added test for these new functions. + +Signed-off-by: Simon Goldschmidt + +diff --git a/include/lmb.h b/include/lmb.h +index f04d0580..7d7e2a78 100644 +--- a/include/lmb.h ++++ b/include/lmb.h +@@ -38,6 +38,9 @@ extern phys_addr_t lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align + phys_addr_t max_addr); + extern phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, + phys_addr_t max_addr); ++extern phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, ++ phys_size_t size); ++extern phys_size_t lmb_get_unreserved_size(struct lmb *lmb, phys_addr_t addr); + extern int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr); + extern long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size); + +diff --git a/lib/lmb.c b/lib/lmb.c +index cd297f82..e380a0a7 100644 +--- a/lib/lmb.c ++++ b/lib/lmb.c +@@ -313,6 +313,59 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy + return 0; + } + ++/* ++ * Try to allocate a specific address range: must be in defined memory but not ++ * reserved ++ */ ++phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, phys_size_t size) ++{ ++ long j; ++ ++ /* Check if the requested address is in one of the memory regions */ ++ j = lmb_overlaps_region(&lmb->memory, base, size); ++ if (j >= 0) { ++ /* ++ * Check if the requested end address is in the same memory ++ * region we found. ++ */ ++ if (lmb_addrs_overlap(lmb->memory.region[j].base, ++ lmb->memory.region[j].size, base + size - ++ 1, 1)) { ++ /* ok, reserve the memory */ ++ if (lmb_reserve(lmb, base, size) >= 0) ++ return base; ++ } ++ } ++ return 0; ++} ++ ++/* Return number of bytes from a given address that are free */ ++phys_size_t lmb_get_unreserved_size(struct lmb *lmb, phys_addr_t addr) ++{ ++ int i; ++ long j; ++ ++ /* check if the requested address is in the memory regions */ ++ j = lmb_overlaps_region(&lmb->memory, addr, 1); ++ if (j >= 0) { ++ for (i = 0; i < lmb->reserved.cnt; i++) { ++ if (addr < lmb->reserved.region[i].base) { ++ /* first reserved range > requested address */ ++ return lmb->reserved.region[i].base - addr; ++ } ++ if (lmb->reserved.region[i].base + ++ lmb->reserved.region[i].size > addr) { ++ /* requested addr is in this reserved range */ ++ return 0; ++ } ++ } ++ /* if we come here: no reserved ranges above requested addr */ ++ return lmb->memory.region[lmb->memory.cnt - 1].base + ++ lmb->memory.region[lmb->memory.cnt - 1].size - addr; ++ } ++ return 0; ++} ++ + int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr) + { + int i; +diff --git a/test/lib/lmb.c b/test/lib/lmb.c +index e6acb70e..058d3c33 100644 +--- a/test/lib/lmb.c ++++ b/test/lib/lmb.c +@@ -397,3 +397,205 @@ static int lib_test_lmb_overlapping_reserve(struct unit_test_state *uts) + + DM_TEST(lib_test_lmb_overlapping_reserve, + DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); ++ ++/* ++ * Simulate 512 MiB RAM, reserve 3 blocks, allocate addresses in between. ++ * Expect addresses outside the memory range to fail. ++ */ ++static int test_alloc_addr(struct unit_test_state *uts, const phys_addr_t ram) ++{ ++ const phys_size_t ram_size = 0x20000000; ++ const phys_addr_t ram_end = ram + ram_size; ++ const phys_size_t alloc_addr_a = ram + 0x8000000; ++ const phys_size_t alloc_addr_b = ram + 0x8000000 * 2; ++ const phys_size_t alloc_addr_c = ram + 0x8000000 * 3; ++ struct lmb lmb; ++ long ret; ++ phys_addr_t a, b, c, d, e; ++ ++ /* check for overflow */ ++ ut_assert(ram_end == 0 || ram_end > ram); ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ /* reserve 3 blocks */ ++ ret = lmb_reserve(&lmb, alloc_addr_a, 0x10000); ++ ut_asserteq(ret, 0); ++ ret = lmb_reserve(&lmb, alloc_addr_b, 0x10000); ++ ut_asserteq(ret, 0); ++ ret = lmb_reserve(&lmb, alloc_addr_c, 0x10000); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 3, alloc_addr_a, 0x10000, ++ alloc_addr_b, 0x10000, alloc_addr_c, 0x10000); ++ ++ /* allocate blocks */ ++ a = lmb_alloc_addr(&lmb, ram, alloc_addr_a - ram); ++ ut_asserteq(a, ram); ++ ASSERT_LMB(&lmb, ram, ram_size, 3, ram, 0x8010000, ++ alloc_addr_b, 0x10000, alloc_addr_c, 0x10000); ++ b = lmb_alloc_addr(&lmb, alloc_addr_a + 0x10000, ++ alloc_addr_b - alloc_addr_a - 0x10000); ++ ut_asserteq(b, alloc_addr_a + 0x10000); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ram, 0x10010000, ++ alloc_addr_c, 0x10000, 0, 0); ++ c = lmb_alloc_addr(&lmb, alloc_addr_b + 0x10000, ++ alloc_addr_c - alloc_addr_b - 0x10000); ++ ut_asserteq(c, alloc_addr_b + 0x10000); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, 0x18010000, ++ 0, 0, 0, 0); ++ d = lmb_alloc_addr(&lmb, alloc_addr_c + 0x10000, ++ ram_end - alloc_addr_c - 0x10000); ++ ut_asserteq(d, alloc_addr_c + 0x10000); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, ram_size, ++ 0, 0, 0, 0); ++ ++ /* allocating anything else should fail */ ++ e = lmb_alloc(&lmb, 1, 1); ++ ut_asserteq(e, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, ram_size, ++ 0, 0, 0, 0); ++ ++ ret = lmb_free(&lmb, d, ram_end - alloc_addr_c - 0x10000); ++ ut_asserteq(ret, 0); ++ ++ /* allocate at 3 points in free range */ ++ ++ d = lmb_alloc_addr(&lmb, ram_end - 4, 4); ++ ut_asserteq(d, ram_end - 4); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ram, 0x18010000, ++ d, 4, 0, 0); ++ ret = lmb_free(&lmb, d, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, 0x18010000, ++ 0, 0, 0, 0); ++ ++ d = lmb_alloc_addr(&lmb, ram_end - 128, 4); ++ ut_asserteq(d, ram_end - 128); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, ram, 0x18010000, ++ d, 4, 0, 0); ++ ret = lmb_free(&lmb, d, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, 0x18010000, ++ 0, 0, 0, 0); ++ ++ d = lmb_alloc_addr(&lmb, alloc_addr_c + 0x10000, 4); ++ ut_asserteq(d, alloc_addr_c + 0x10000); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, 0x18010004, ++ 0, 0, 0, 0); ++ ret = lmb_free(&lmb, d, 4); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram, 0x18010000, ++ 0, 0, 0, 0); ++ ++ /* allocate at the bottom */ ++ ret = lmb_free(&lmb, a, alloc_addr_a - ram); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 1, ram + 0x8000000, 0x10010000, ++ 0, 0, 0, 0); ++ d = lmb_alloc_addr(&lmb, ram, 4); ++ ut_asserteq(d, ram); ++ ASSERT_LMB(&lmb, ram, ram_size, 2, d, 4, ++ ram + 0x8000000, 0x10010000, 0, 0); ++ ++ /* check that allocating outside memory fails */ ++ if (ram_end != 0) { ++ ret = lmb_alloc_addr(&lmb, ram_end, 1); ++ ut_asserteq(ret, 0); ++ } ++ if (ram != 0) { ++ ret = lmb_alloc_addr(&lmb, ram - 1, 1); ++ ut_asserteq(ret, 0); ++ } ++ ++ return 0; ++} ++ ++static int lib_test_lmb_alloc_addr(struct unit_test_state *uts) ++{ ++ int ret; ++ ++ /* simulate 512 MiB RAM beginning at 1GiB */ ++ ret = test_alloc_addr(uts, 0x40000000); ++ if (ret) ++ return ret; ++ ++ /* simulate 512 MiB RAM beginning at 1.5GiB */ ++ return test_alloc_addr(uts, 0xE0000000); ++} ++ ++DM_TEST(lib_test_lmb_alloc_addr, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); ++ ++/* Simulate 512 MiB RAM, reserve 3 blocks, check addresses in between */ ++static int test_get_unreserved_size(struct unit_test_state *uts, ++ const phys_addr_t ram) ++{ ++ const phys_size_t ram_size = 0x20000000; ++ const phys_addr_t ram_end = ram + ram_size; ++ const phys_size_t alloc_addr_a = ram + 0x8000000; ++ const phys_size_t alloc_addr_b = ram + 0x8000000 * 2; ++ const phys_size_t alloc_addr_c = ram + 0x8000000 * 3; ++ struct lmb lmb; ++ long ret; ++ phys_size_t s; ++ ++ /* check for overflow */ ++ ut_assert(ram_end == 0 || ram_end > ram); ++ ++ lmb_init(&lmb); ++ ++ ret = lmb_add(&lmb, ram, ram_size); ++ ut_asserteq(ret, 0); ++ ++ /* reserve 3 blocks */ ++ ret = lmb_reserve(&lmb, alloc_addr_a, 0x10000); ++ ut_asserteq(ret, 0); ++ ret = lmb_reserve(&lmb, alloc_addr_b, 0x10000); ++ ut_asserteq(ret, 0); ++ ret = lmb_reserve(&lmb, alloc_addr_c, 0x10000); ++ ut_asserteq(ret, 0); ++ ASSERT_LMB(&lmb, ram, ram_size, 3, alloc_addr_a, 0x10000, ++ alloc_addr_b, 0x10000, alloc_addr_c, 0x10000); ++ ++ /* check addresses in between blocks */ ++ s = lmb_get_unreserved_size(&lmb, ram); ++ ut_asserteq(s, alloc_addr_a - ram); ++ s = lmb_get_unreserved_size(&lmb, ram + 0x10000); ++ ut_asserteq(s, alloc_addr_a - ram - 0x10000); ++ s = lmb_get_unreserved_size(&lmb, alloc_addr_a - 4); ++ ut_asserteq(s, 4); ++ ++ s = lmb_get_unreserved_size(&lmb, alloc_addr_a + 0x10000); ++ ut_asserteq(s, alloc_addr_b - alloc_addr_a - 0x10000); ++ s = lmb_get_unreserved_size(&lmb, alloc_addr_a + 0x20000); ++ ut_asserteq(s, alloc_addr_b - alloc_addr_a - 0x20000); ++ s = lmb_get_unreserved_size(&lmb, alloc_addr_b - 4); ++ ut_asserteq(s, 4); ++ ++ s = lmb_get_unreserved_size(&lmb, alloc_addr_c + 0x10000); ++ ut_asserteq(s, ram_end - alloc_addr_c - 0x10000); ++ s = lmb_get_unreserved_size(&lmb, alloc_addr_c + 0x20000); ++ ut_asserteq(s, ram_end - alloc_addr_c - 0x20000); ++ s = lmb_get_unreserved_size(&lmb, ram_end - 4); ++ ut_asserteq(s, 4); ++ ++ return 0; ++} ++ ++static int lib_test_lmb_get_unreserved_size(struct unit_test_state *uts) ++{ ++ int ret; ++ ++ /* simulate 512 MiB RAM beginning at 1GiB */ ++ ret = test_get_unreserved_size(uts, 0x40000000); ++ if (ret) ++ return ret; ++ ++ /* simulate 512 MiB RAM beginning at 1.5GiB */ ++ return test_get_unreserved_size(uts, 0xE0000000); ++} ++ ++DM_TEST(lib_test_lmb_get_unreserved_size, ++ DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0018-fs-prevent-overwriting-reserved-memory.patch b/root/package/boot/uboot-mediatek/patches/0018-fs-prevent-overwriting-reserved-memory.patch new file mode 100644 index 00000000..c9df9302 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0018-fs-prevent-overwriting-reserved-memory.patch @@ -0,0 +1,138 @@ +From 94e5a755db2a72b8bdaceb634b732ed59816b5ac Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:19 +0100 +Subject: fs: prevent overwriting reserved memory + +This fixes CVE-2018-18440 ("insufficient boundary checks in filesystem +image load") by using lmb to check the load size of a file against +reserved memory addresses. + +Signed-off-by: Simon Goldschmidt +Reviewed-by: Simon Glass + +diff --git a/fs/fs.c b/fs/fs.c +index cb265174..7fd22101 100644 +--- a/fs/fs.c ++++ b/fs/fs.c +@@ -429,13 +429,57 @@ int fs_size(const char *filename, loff_t *size) + return ret; + } + +-int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, +- loff_t *actread) ++#ifdef CONFIG_LMB ++/* Check if a file may be read to the given address */ ++static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset, ++ loff_t len, struct fstype_info *info) ++{ ++ struct lmb lmb; ++ int ret; ++ loff_t size; ++ loff_t read_len; ++ ++ /* get the actual size of the file */ ++ ret = info->size(filename, &size); ++ if (ret) ++ return ret; ++ if (offset >= size) { ++ /* offset >= EOF, no bytes will be written */ ++ return 0; ++ } ++ read_len = size - offset; ++ ++ /* limit to 'len' if it is smaller */ ++ if (len && len < read_len) ++ read_len = len; ++ ++ lmb_init_and_reserve(&lmb, gd->bd->bi_dram[0].start, ++ gd->bd->bi_dram[0].size, (void *)gd->fdt_blob); ++ lmb_dump_all(&lmb); ++ ++ if (lmb_alloc_addr(&lmb, addr, read_len) == addr) ++ return 0; ++ ++ printf("** Reading file would overwrite reserved memory **\n"); ++ return -ENOSPC; ++} ++#endif ++ ++static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, ++ int do_lmb_check, loff_t *actread) + { + struct fstype_info *info = fs_get_info(fs_type); + void *buf; + int ret; + ++#ifdef CONFIG_LMB ++ if (do_lmb_check) { ++ ret = fs_read_lmb_check(filename, addr, offset, len, info); ++ if (ret) ++ return ret; ++ } ++#endif ++ + /* + * We don't actually know how many bytes are being read, since len==0 + * means read the whole file. +@@ -452,6 +496,12 @@ int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, + return ret; + } + ++int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, ++ loff_t *actread) ++{ ++ return _fs_read(filename, addr, offset, len, 0, actread); ++} ++ + int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, + loff_t *actwrite) + { +@@ -622,7 +672,7 @@ int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + pos = 0; + + time = get_timer(0); +- ret = fs_read(filename, addr, pos, bytes, &len_read); ++ ret = _fs_read(filename, addr, pos, bytes, 1, &len_read); + time = get_timer(time); + if (ret < 0) + return 1; +diff --git a/include/lmb.h b/include/lmb.h +index 7d7e2a78..62da85e7 100644 +--- a/include/lmb.h ++++ b/include/lmb.h +@@ -31,6 +31,8 @@ struct lmb { + extern struct lmb lmb; + + extern void lmb_init(struct lmb *lmb); ++extern void lmb_init_and_reserve(struct lmb *lmb, phys_addr_t base, ++ phys_size_t size, void *fdt_blob); + extern long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size); + extern long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size); + extern phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align); +diff --git a/lib/lmb.c b/lib/lmb.c +index e380a0a7..3407705f 100644 +--- a/lib/lmb.c ++++ b/lib/lmb.c +@@ -98,6 +98,19 @@ void lmb_init(struct lmb *lmb) + lmb->reserved.size = 0; + } + ++/* Initialize the struct, add memory and call arch/board reserve functions */ ++void lmb_init_and_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size, ++ void *fdt_blob) ++{ ++ lmb_init(lmb); ++ lmb_add(lmb, base, size); ++ arch_lmb_reserve(lmb); ++ board_lmb_reserve(lmb); ++ ++ if (IMAGE_ENABLE_OF_LIBFDT && fdt_blob) ++ boot_fdt_add_mem_rsv_regions(lmb, fdt_blob); ++} ++ + /* This routine called with relocation disabled. */ + static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t size) + { +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0019-bootm-use-new-common-function-lmb_init_and_reserve.patch b/root/package/boot/uboot-mediatek/patches/0019-bootm-use-new-common-function-lmb_init_and_reserve.patch new file mode 100644 index 00000000..8f8924e1 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0019-bootm-use-new-common-function-lmb_init_and_reserve.patch @@ -0,0 +1,35 @@ +From 2e3bdfbc449a5558ebbb55e36feee31f69fe32f7 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:20 +0100 +Subject: bootm: use new common function lmb_init_and_reserve + +This reduces duplicate code only. + +Signed-off-by: Simon Goldschmidt +Reviewed-by: Simon Glass + +diff --git a/common/bootm.c b/common/bootm.c +index 8bf84ebc..31e4f0f7 100644 +--- a/common/bootm.c ++++ b/common/bootm.c +@@ -56,15 +56,11 @@ static void boot_start_lmb(bootm_headers_t *images) + ulong mem_start; + phys_size_t mem_size; + +- lmb_init(&images->lmb); +- + mem_start = env_get_bootm_low(); + mem_size = env_get_bootm_size(); + +- lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size); +- +- arch_lmb_reserve(&images->lmb); +- board_lmb_reserve(&images->lmb); ++ lmb_init_and_reserve(&images->lmb, (phys_addr_t)mem_start, mem_size, ++ NULL); + } + #else + #define lmb_reserve(lmb, base, size) +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0020-lmb-remove-unused-extern-declaration.patch b/root/package/boot/uboot-mediatek/patches/0020-lmb-remove-unused-extern-declaration.patch new file mode 100644 index 00000000..2e82ddeb --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0020-lmb-remove-unused-extern-declaration.patch @@ -0,0 +1,26 @@ +From 8b554b62dcab25c0072c5b6880d0fcf079cc9d87 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:21 +0100 +Subject: lmb: remove unused extern declaration + +lmb.h includes an extern declaration of "struct lmb lmb;" which +is not used anywhere, so remove it. + +Signed-off-by: Simon Goldschmidt + +diff --git a/include/lmb.h b/include/lmb.h +index 62da85e7..1bb003e3 100644 +--- a/include/lmb.h ++++ b/include/lmb.h +@@ -28,8 +28,6 @@ struct lmb { + struct lmb_region reserved; + }; + +-extern struct lmb lmb; +- + extern void lmb_init(struct lmb *lmb); + extern void lmb_init_and_reserve(struct lmb *lmb, phys_addr_t base, + phys_size_t size, void *fdt_blob); +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0021-tftp-prevent-overwriting-reserved-memory.patch b/root/package/boot/uboot-mediatek/patches/0021-tftp-prevent-overwriting-reserved-memory.patch new file mode 100644 index 00000000..da53cc0e --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0021-tftp-prevent-overwriting-reserved-memory.patch @@ -0,0 +1,172 @@ +From 2e972e30c0b07736fedcc4fad53cfe49249495a5 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:22 +0100 +Subject: tftp: prevent overwriting reserved memory + +This fixes CVE-2018-18439 ("insufficient boundary checks in network +image boot") by using lmb to check for a valid range to store +received blocks. + +Signed-off-by: Simon Goldschmidt +Acked-by: Joe Hershberger + +diff --git a/net/tftp.c b/net/tftp.c +index 68ffd814..a9335b1b 100644 +--- a/net/tftp.c ++++ b/net/tftp.c +@@ -17,6 +17,8 @@ + #include + #endif + ++DECLARE_GLOBAL_DATA_PTR; ++ + /* Well known TFTP port # */ + #define WELL_KNOWN_PORT 69 + /* Millisecs to timeout for lost pkt */ +@@ -81,6 +83,10 @@ static ulong tftp_block_wrap; + /* memory offset due to wrapping */ + static ulong tftp_block_wrap_offset; + static int tftp_state; ++static ulong tftp_load_addr; ++#ifdef CONFIG_LMB ++static ulong tftp_load_size; ++#endif + #ifdef CONFIG_TFTP_TSIZE + /* The file size reported by the server */ + static int tftp_tsize; +@@ -164,10 +170,11 @@ static void mcast_cleanup(void) + + #endif /* CONFIG_MCAST_TFTP */ + +-static inline void store_block(int block, uchar *src, unsigned len) ++static inline int store_block(int block, uchar *src, unsigned int len) + { + ulong offset = block * tftp_block_size + tftp_block_wrap_offset; + ulong newsize = offset + len; ++ ulong store_addr = tftp_load_addr + offset; + #ifdef CONFIG_SYS_DIRECT_FLASH_TFTP + int i, rc = 0; + +@@ -175,24 +182,32 @@ static inline void store_block(int block, uchar *src, unsigned len) + /* start address in flash? */ + if (flash_info[i].flash_id == FLASH_UNKNOWN) + continue; +- if (load_addr + offset >= flash_info[i].start[0]) { ++ if (store_addr >= flash_info[i].start[0]) { + rc = 1; + break; + } + } + + if (rc) { /* Flash is destination for this packet */ +- rc = flash_write((char *)src, (ulong)(load_addr+offset), len); ++ rc = flash_write((char *)src, store_addr, len); + if (rc) { + flash_perror(rc); +- net_set_state(NETLOOP_FAIL); +- return; ++ return rc; + } + } else + #endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ + { +- void *ptr = map_sysmem(load_addr + offset, len); +- ++ void *ptr; ++ ++#ifdef CONFIG_LMB ++ if (store_addr < tftp_load_addr || ++ store_addr + len > tftp_load_addr + tftp_load_size) { ++ puts("\nTFTP error: "); ++ puts("trying to overwrite reserved memory...\n"); ++ return -1; ++ } ++#endif ++ ptr = map_sysmem(store_addr, len); + memcpy(ptr, src, len); + unmap_sysmem(ptr); + } +@@ -203,6 +218,8 @@ static inline void store_block(int block, uchar *src, unsigned len) + + if (net_boot_file_size < newsize) + net_boot_file_size = newsize; ++ ++ return 0; + } + + /* Clear our state ready for a new transfer */ +@@ -606,7 +623,11 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip, + timeout_count_max = tftp_timeout_count_max; + net_set_timeout_handler(timeout_ms, tftp_timeout_handler); + +- store_block(tftp_cur_block - 1, pkt + 2, len); ++ if (store_block(tftp_cur_block - 1, pkt + 2, len)) { ++ eth_halt(); ++ net_set_state(NETLOOP_FAIL); ++ break; ++ } + + /* + * Acknowledge the block just received, which will prompt +@@ -695,6 +716,25 @@ static void tftp_timeout_handler(void) + } + } + ++/* Initialize tftp_load_addr and tftp_load_size from load_addr and lmb */ ++static int tftp_init_load_addr(void) ++{ ++#ifdef CONFIG_LMB ++ struct lmb lmb; ++ phys_size_t max_size; ++ ++ lmb_init_and_reserve(&lmb, gd->bd->bi_dram[0].start, ++ gd->bd->bi_dram[0].size, (void *)gd->fdt_blob); ++ ++ max_size = lmb_get_unreserved_size(&lmb, load_addr); ++ if (!max_size) ++ return -1; ++ ++ tftp_load_size = max_size; ++#endif ++ tftp_load_addr = load_addr; ++ return 0; ++} + + void tftp_start(enum proto_t protocol) + { +@@ -791,7 +831,14 @@ void tftp_start(enum proto_t protocol) + } else + #endif + { +- printf("Load address: 0x%lx\n", load_addr); ++ if (tftp_init_load_addr()) { ++ eth_halt(); ++ net_set_state(NETLOOP_FAIL); ++ puts("\nTFTP error: "); ++ puts("trying to overwrite reserved memory...\n"); ++ return; ++ } ++ printf("Load address: 0x%lx\n", tftp_load_addr); + puts("Loading: *\b"); + tftp_state = STATE_SEND_RRQ; + #ifdef CONFIG_CMD_BOOTEFI +@@ -842,9 +889,15 @@ void tftp_start_server(void) + { + tftp_filename[0] = 0; + ++ if (tftp_init_load_addr()) { ++ eth_halt(); ++ net_set_state(NETLOOP_FAIL); ++ puts("\nTFTP error: trying to overwrite reserved memory...\n"); ++ return; ++ } + printf("Using %s device\n", eth_get_name()); + printf("Listening for TFTP transfer on %pI4\n", &net_ip); +- printf("Load address: 0x%lx\n", load_addr); ++ printf("Load address: 0x%lx\n", tftp_load_addr); + + puts("Loading: *\b"); + +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0022-arm-bootm-fix-sp-detection-at-end-of-address-range.patch b/root/package/boot/uboot-mediatek/patches/0022-arm-bootm-fix-sp-detection-at-end-of-address-range.patch new file mode 100644 index 00000000..7e7ffe50 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0022-arm-bootm-fix-sp-detection-at-end-of-address-range.patch @@ -0,0 +1,46 @@ +From 72bc6aa0bc7f034bd6966c872819f19af69f2b64 Mon Sep 17 00:00:00 2001 +From: Simon Goldschmidt +Date: Mon, 14 Jan 2019 22:38:23 +0100 +Subject: arm: bootm: fix sp detection at end of address range + +This fixes 'arch_lmb_reserve()' for ARM that tries to detect in which +DRAM bank 'sp' is in. + +This code failed if a bank was at the end of physical address range +(i.e. size + length overflowed to 0). + +To fix this, calculate 'bank_end' as 'size + length - 1' so that such +banks end at 0xffffffff, not 0. + +Fixes: 15751403b6 ("ARM: bootm: don't assume sp is in DRAM bank 0") +Reported-by: Frank Wunderlich +Signed-off-by: Simon Goldschmidt +Reviewed-by: Stephen Warren + +diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c +index c3c1d2fd..329f20c2 100644 +--- a/arch/arm/lib/bootm.c ++++ b/arch/arm/lib/bootm.c +@@ -64,13 +64,15 @@ void arch_lmb_reserve(struct lmb *lmb) + /* adjust sp by 4K to be safe */ + sp -= 4096; + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { +- if (sp < gd->bd->bi_dram[bank].start) ++ if (!gd->bd->bi_dram[bank].size || ++ sp < gd->bd->bi_dram[bank].start) + continue; ++ /* Watch out for RAM at end of address space! */ + bank_end = gd->bd->bi_dram[bank].start + +- gd->bd->bi_dram[bank].size; +- if (sp >= bank_end) ++ gd->bd->bi_dram[bank].size - 1; ++ if (sp > bank_end) + continue; +- lmb_reserve(lmb, sp, bank_end - sp); ++ lmb_reserve(lmb, sp, bank_end - sp + 1); + break; + } + } +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0023-defconfig-added-strings-and-setenv-used-for-lstftp.patch b/root/package/boot/uboot-mediatek/patches/0023-defconfig-added-strings-and-setenv-used-for-lstftp.patch new file mode 100644 index 00000000..48f34b9f --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0023-defconfig-added-strings-and-setenv-used-for-lstftp.patch @@ -0,0 +1,27 @@ +From 7b492a978a09fbc95340dbcdc1e14d604ac6ae76 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Wed, 23 Jan 2019 16:16:45 +0100 +Subject: [defconfig] added strings and setenv used for lstftp + + +diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig +index a9f4506e..bac45d11 100644 +--- a/configs/mt7623n_bpir2_defconfig ++++ b/configs/mt7623n_bpir2_defconfig +@@ -22,7 +22,6 @@ CONFIG_CMD_GPT=y + CONFIG_CMD_MMC=y + CONFIG_CMD_PART=y + CONFIG_CMD_READ=y +-# CONFIG_CMD_SETEXPR is not set + # CONFIG_CMD_NFS is not set + CONFIG_CMD_PING=y + CONFIG_CMD_FAT=y +@@ -69,3 +68,5 @@ CONFIG_DEFAULT_ENV_FILE="uEnv.txt" + CONFIG_ENV_IS_IN_MMC=y + + CONFIG_CMD_ASKENV=y ++CONFIG_CMD_STRINGS=y ++CONFIG_CMD_SETEXPR=y +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0024-increase-size-for-environment-4k-8k.patch b/root/package/boot/uboot-mediatek/patches/0024-increase-size-for-environment-4k-8k.patch new file mode 100644 index 00000000..a69cd7e3 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0024-increase-size-for-environment-4k-8k.patch @@ -0,0 +1,22 @@ +From 0164e641d4a64dcff5d5394b168d612b174d83bd Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Wed, 23 Jan 2019 16:30:39 +0100 +Subject: increase size for environment 4k => 8k + + +diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h +index 7d26debb..aa0314db 100644 +--- a/include/configs/mt7623.h ++++ b/include/configs/mt7623.h +@@ -27,7 +27,7 @@ + #define CONFIG_SYS_NONCACHED_MEMORY SZ_1M + + /* Environment */ +-#define CONFIG_ENV_SIZE SZ_4K ++#define CONFIG_ENV_SIZE SZ_8K + /* Allow to overwrite serial and ethaddr */ + #define CONFIG_ENV_OVERWRITE + +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/patches/0025-bootmenu-added-key-input-1-9-a-f.patch b/root/package/boot/uboot-mediatek/patches/0025-bootmenu-added-key-input-1-9-a-f.patch new file mode 100644 index 00000000..b7791007 --- /dev/null +++ b/root/package/boot/uboot-mediatek/patches/0025-bootmenu-added-key-input-1-9-a-f.patch @@ -0,0 +1,216 @@ +From 17843557032cc342117591939483d238e80bd169 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 28 Dec 2018 17:56:19 +0100 +Subject: [bootmenu] added key-input (1-9,a-f) + + +diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c +index 7f88c1ed..0935fd40 100644 +--- a/cmd/bootmenu.c ++++ b/cmd/bootmenu.c +@@ -39,7 +39,22 @@ struct bootmenu_data { + + enum bootmenu_key { + KEY_NONE = 0, +- KEY_UP, ++ KEY_1, ++ KEY_2, ++ KEY_3, ++ KEY_4, ++ KEY_5, ++ KEY_6, ++ KEY_7, ++ KEY_8, ++ KEY_9, ++ KEY_a, ++ KEY_b, ++ KEY_c, ++ KEY_d, ++ KEY_e, ++ KEY_f, ++ KEY_UP = 20, + KEY_DOWN, + KEY_SELECT, + }; +@@ -77,6 +92,23 @@ static void bootmenu_print_entry(void *data) + puts(ANSI_COLOR_RESET); + } + ++bool get_bootmenu_key(enum bootmenu_key *key, int c) ++{ ++ /* ANSI '1~9' - was pressed */ ++ if (c <= '9' && c >= '1' ) ++ { ++ *key = c-48; ++ return true; ++ }else ++ /* ANSI 'a~f' - was pressed */ ++ if (c <= 'f' && c >= 'a' ) ++ { ++ *key = c-87; ++ return true; ++ } ++ return false; ++} ++ + static void bootmenu_autoboot_loop(struct bootmenu_data *menu, + enum bootmenu_key *key, int *esc) + { +@@ -97,23 +129,23 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu, + + menu->delay = -1; + c = getc(); +- +- switch (c) { +- case '\e': +- *esc = 1; +- *key = KEY_NONE; +- break; +- case '\r': +- *key = KEY_SELECT; +- break; +- default: +- *key = KEY_NONE; +- break; ++ if (!get_bootmenu_key(key,c)) ++ { ++ switch (c) { ++ case '\e': ++ *esc = 1; ++ *key = KEY_NONE; ++ break; ++ case '\r': ++ *key = KEY_SELECT; ++ break; ++ default: ++ *key = KEY_NONE; ++ break; ++ } + } +- + break; + } +- + if (menu->delay < 0) + break; + +@@ -140,47 +172,49 @@ static void bootmenu_loop(struct bootmenu_data *menu, + + c = getc(); + +- switch (*esc) { +- case 0: +- /* First char of ANSI escape sequence '\e' */ +- if (c == '\e') { +- *esc = 1; +- *key = KEY_NONE; +- } +- break; +- case 1: +- /* Second char of ANSI '[' */ +- if (c == '[') { +- *esc = 2; +- *key = KEY_NONE; +- } else { +- *esc = 0; +- } +- break; +- case 2: +- case 3: +- /* Third char of ANSI (number '1') - optional */ +- if (*esc == 2 && c == '1') { +- *esc = 3; ++ if (!get_bootmenu_key(key,c)) ++ { ++ switch (*esc) { ++ case 0: ++ /* First char of ANSI escape sequence '\e' */ ++ if (c == '\e') { ++ *esc = 1; ++ *key = KEY_NONE; ++ } ++ break; ++ case 1: ++ /* Second char of ANSI '[' */ ++ if (c == '[') { ++ *esc = 2; + *key = KEY_NONE; ++ } else { ++ *esc = 0; ++ } + break; +- } ++ case 2: ++ case 3: ++ /* Third char of ANSI (number '1') - optional */ ++ if (*esc == 2 && c == '1') { ++ *esc = 3; ++ *key = KEY_NONE; ++ break; ++ } + +- *esc = 0; ++ *esc = 0; + +- /* ANSI 'A' - key up was pressed */ +- if (c == 'A') +- *key = KEY_UP; +- /* ANSI 'B' - key down was pressed */ +- else if (c == 'B') +- *key = KEY_DOWN; +- /* other key was pressed */ +- else +- *key = KEY_NONE; ++ /* ANSI 'A' - key up was pressed */ ++ if (c == 'A') ++ *key = KEY_UP; ++ /* ANSI 'B' - key down was pressed */ ++ else if (c == 'B') ++ *key = KEY_DOWN; ++ /* other key was pressed */ ++ else ++ *key = KEY_NONE; + +- break; ++ break; ++ } + } +- + /* enter key was pressed */ + if (c == '\r') + *key = KEY_SELECT; +@@ -203,6 +237,14 @@ static char *bootmenu_choice_entry(void *data) + bootmenu_loop(menu, &key, &esc); + } + ++ if (key < KEY_UP && key > KEY_NONE) ++ { ++ menu->active = key-1; ++ return NULL; ++ } ++ else ++ { ++ + switch (key) { + case KEY_UP: + if (menu->active > 0) +@@ -222,6 +264,7 @@ static char *bootmenu_choice_entry(void *data) + default: + break; + } ++ } + } + + /* never happens */ +@@ -466,7 +509,7 @@ void menu_display_statusline(struct menu *m) + printf(ANSI_CURSOR_POSITION, menu->count + 5, 1); + puts(ANSI_CLEAR_LINE); + printf(ANSI_CURSOR_POSITION, menu->count + 6, 1); +- puts(" Press UP/DOWN to move, ENTER to select"); ++ puts(" Press UP/DOWN to move or Press 1~9,a~f to choose, ENTER to select"); + puts(ANSI_CLEAR_LINE_TO_END); + printf(ANSI_CURSOR_POSITION, menu->count + 7, 1); + puts(ANSI_CLEAR_LINE); +-- +1.8.3.1 + diff --git a/root/package/boot/uboot-mediatek/uEnv-default.txt b/root/package/boot/uboot-mediatek/uEnv-default.txt new file mode 100644 index 00000000..b5e7af3c --- /dev/null +++ b/root/package/boot/uboot-mediatek/uEnv-default.txt @@ -0,0 +1,91 @@ +scriptaddr=0x83000000 +device=mmc +bootenv=uEnv.txt +kernel=uImage +loadaddr=0x80200000 +#default bootargs will be overidden by buildargs +bootargs=console=ttyS0,115200 root=/dev/mmcblk1p2 rw rootwait ip=dhcp + +console=earlyprintk console=ttyS0,115200 console=tty1 fbcon=map:0 +roottmpl=${rootdev} rootfstype=ext4 rootwait +prepsetroot=setenv setroot setenv root ${roottmpl} +bootopts=vmalloc=496M debug=7 initcall_debug=0 +graphic=video=1920x1080 drm.debug=0x7 + +buildargs=setenv bootargs "console=${console} root=${root} ${bootopts} ${graphic}" + +checkenv=test -e ${device} ${partition} ${bootenv} +importenv=env import -t ${scriptaddr} ${filesize} +loadbootenv=if fatload ${device} ${partition} ${scriptaddr} ${bootenv};then run importenv;else echo "fatload (${bootenv}) failed";fi +resetenv=env default -a;printenv; + +# Here we assume that SD card id mmcblk1 and eMMC is mmcblk0 in linux. Swap them if your DTS define them in reverse order. +usesd=setenv partition 1:1; setenv rootdev /dev/mmcblk0p2; setenv bootdev SD; setenv swaproot 'run useemmc'; +useemmc=setenv partition 0:1; setenv rootdev /dev/mmcblk1p2; setenv bootdev eMMC; setenv swaproot 'run usesd'; + +checkbootedfrom=if itest.l *81dffff0 == 434d4d65 ; then setenv bootedfrom eMMC; else setenv bootedfrom SD; fi; + +checkroot=fatinfo ${device} ${partition} +checksd=fatinfo ${device} 1:1 +checkmmc=fatinfo ${device} 0:1 + +reportbootedfrom=echo "Preloader/U-Boot loaded from ${bootedfrom}."; run validroot || echo "Both SD and eMMC pt#1 are not FAT, falling back to U-Boot shell." +reportvalidroot=run validroot || echo "Both SD and eMMC pt#1 are not FAT, falling back to U-Boot shell." +reportrootswapwarn=if test "${bootedfrom}" != "${bootdev}" ; then echo "Warning: Partition 1 on ${bootedfrom} is not FAT, failing back to ${bootdev}"; fi; true; +reportbootdev=echo "Booting from ${bootdev}." +reportboot=run reportbootedfrom reportvalidroot reportrootswapwarn reportbootdev + +detectroot=run useemmc; run checkbootedfrom; if test "${bootedfrom}" == "SD"; then run usesd; fi; run validateroot; +validateroot=setenv validroot false; run checkroot || run swaproot; run checkroot && setenv validroot true || run swaproot; + +newboot=run prepsetroot; run setroot;run buildargs;printenv bootargs;fatload ${device} ${partition} ${loadaddr} ${kernel}; bootm + +reloadenv=run detectroot; if run validroot; then if run checkenv; then run loadbootenv; run detectroot; else echo uEnv.txt file not found on ${bootdev}; fi; fi; +reloadmenu=run reloadenv; run reportboot; if run validroot; then if run checkenv; then run loadbootenv; else echo uEnv.txt file not found on ${bootdev}; fi; bootmenu; fi; + +lskernel=ls ${device} ${partition}; +lsdtb=ls ${device} ${partition} dtb +askkernel=askenv kernelinput "enter uImage-name:"; +askdtb=askenv dtbinput "enter dtb-name:"; + +#bootmenu +boot0=run lskernel;run askkernel;if printenv kernelinput ;then setenv kernel ${kernelinput};run lsdtb;run askdtb;if printenv dtbinput ;then setenv fdt ${dtbinput};fi; run newboot2; fi; +boot1=run newboot; + +bootmenu_default=2 +bootmenu_0=1. Enter kernel-name to boot from SD/EMMC.=run boot0 +bootmenu_1=2. Boot kernel from TFTP.=run bootnet +bootmenu_2=3. Boot from SD/EMMC.=run boot1 +bootmenu_3=4. Boot from eMMC.=run useemmc; run boot1 +bootmenu_4=5. Boot from SD.=run usesd; run boot1 + +#Netboot +ipaddr=192.168.0.11 +netmask=255.255.255.0 +serverip=192.168.0.10 + +bootfile=uImage +netbootargs=console=ttyS0,115200 root=/dev/mmcblk1p2 rw rootwait +#ip=dhcp sets ip on eth0 instead of wan + +lstftp=tftp ${loadaddr} ${serverip}:files.lst;setexpr listend ${loadaddr} + ${filesize};mw.b ${listend} 00 2;strings ${loadaddr}; +#md.b ${loadaddr} 60; + +bootnet=run lstftp;run askkernel;if printenv kernelinput ;then setenv bootfile "${kernelinput}"; fi;printenv; setenv bootargs ${netbootargs};tftp ${loadaddr} ${bootfile};bootm + +#separate fdt+dto +dtaddr=0x83f00000 +fdt_high=0xffffffff + +loadfdt=fatload ${device} ${partition} ${dtaddr} dtb/${fdt} +loadkernel=echo "loading kernel ${kernel}...";fatload ${device} ${partition} ${loadaddr} ${kernel} + +loaddto=echo "loaddto:${dto}";fdt addr ${dtaddr};fdt resize 8192; setexpr fdtovaddr ${dtaddr} + F000;fatload ${device} ${partition} ${fdtovaddr} dtb/${dto} && fdt apply ${fdtovaddr} +loaddtolist=for dto in ${dtolist} ; do run loaddto ; done + +bootall=if printenv fdt; then run loadfdt; if printenv dtolist;then run loaddtolist;fi; bootm ${loadaddr} - ${dtaddr} ;else bootm; fi +newboot2=run prepsetroot; run setroot;run buildargs; printenv bootargs; run loadkernel; run bootall; + +#automatic reload from sd/emmc +bootdelay=0 +bootcmd=setenv bootdelay 3; run reloadmenu; diff --git a/root/target/linux/mediatek/image/Makefile b/root/target/linux/mediatek/image/Makefile index 21111751..e45e8c78 100644 --- a/root/target/linux/mediatek/image/Makefile +++ b/root/target/linux/mediatek/image/Makefile @@ -8,6 +8,9 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/image.mk +FAT32_BLOCK_SIZE=1024 +FAT32_BLOCKS=$(shell echo $$((32*1024*1024/$(FAT32_BLOCK_SIZE)))) + # for arm KERNEL_LOADADDR := 0x80008000 @@ -16,6 +19,22 @@ ifeq ($(SUBTARGET),mt7622) KERNEL_LOADADDR = 0x41080000 endif +define Build/mediatek-sdcard + rm -f $@.boot + mkfs.fat $@.boot -C $(FAT32_BLOCKS) + + mcopy -i $@.boot $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-uEnv.txt ::uEnv.txt + mcopy -i $@.boot $(IMAGE_KERNEL) ::uImage + ./gen_mediatek_sdcard_img.sh $@ \ + $(STAGING_DIR_IMAGE)/bpi-r2-preloader.bin \ + $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-uboot-mediatek.bin \ + $@.boot \ + $(IMAGE_ROOTFS) \ + 32 \ + $(CONFIG_TARGET_ROOTFS_PARTSIZE) + rm -f $@.boot +endef + define Build/sysupgrade-emmc rm -f $@.recovery mkfs.fat -C $@.recovery 3070 @@ -30,6 +49,7 @@ define Build/sysupgrade-bpi-r2-sd dd bs="1024" if="$(STAGING_DIR_IMAGE)/mtk-bpi-r2-preloader-sd.bin" of="$@" seek="0" dd bs="1024" if="$(STAGING_DIR_IMAGE)/mtk-bpi-r2-uboot.bin" of="$@" seek="320" dd bs="1024" if="$(IMAGE_KERNEL)" of="$@" seek="2048" + #dd bs="1024" if="$(IMAGE_ROOTFS)" of="$@" seek="67584" dd bs="1024" if="$(IMAGE_ROOTFS)" of="$@" seek="67584" endef define Build/sysupgrade-bpi-r2-emmc @@ -48,9 +68,11 @@ define Device/Default IMAGES := sysupgrade.bin IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata ifeq ($(SUBTARGET),mt7623) + DEVICE_VARS := MEDIATEK_UBOOT KERNEL_NAME := zImage KERNEL := kernel-bin | append-dtb | uImage none KERNEL_INITRAMFS := kernel-bin | append-dtb | uImage none + FILESYSTEMS += ext4 endif ifeq ($(SUBTARGET),mt7622) KERNEL_NAME := Image diff --git a/root/target/linux/mediatek/image/gen_mediatek_sdcard_img.sh b/root/target/linux/mediatek/image/gen_mediatek_sdcard_img.sh new file mode 100755 index 00000000..f9a8dbde --- /dev/null +++ b/root/target/linux/mediatek/image/gen_mediatek_sdcard_img.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2013 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +set -e +[ $# -eq 7 ] || { + echo "SYNTAX: $0 " + exit 1 +} + +OUTPUT="$1" +PRELOADER="$2" +UBOOT="$3" +BOOTFS="$4" +ROOTFS="$5" +BOOTFSSIZE="$6" +ROOTFSSIZE="$7" + +head=4 +sect=63 + +set `ptgen -o $OUTPUT -h $head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M -t 83 -p ${ROOTFSSIZE}M -a 0` + +BOOT_OFFSET="$(($1 / 512))" +BOOT_SIZE="$(($2 / 512))" +ROOTFS_OFFSET="$(($3 / 512))" +ROOTFS_SIZE="$(($4 / 512))" + +PRELOADER_OFFSET=2 # 2KB +UBOOT_OFFSET=320 # 320KB + +SDMMC_BOOT="SDMMC_BOOT\x00\x00\x01\x00\x00\x00\x00\x02\x00\x00" +BRLYT="\ +BRLYT\x00\x00\x00\x01\x00\x00\x00\x00\x08\x00\x00\ +\x00\x08\x00\x00\x42\x42\x42\x42\x08\x00\x01\x00\x00\x08\x00\x00\ +\x00\x08\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + +echo -en "${SDMMC_BOOT}" | dd bs=1 of="${OUTPUT}" seek=0 conv=notrunc +echo -en "${BRLYT}" | dd bs=1 of="${OUTPUT}" seek=512 conv=notrunc + +dd bs=1024 if="${PRELOADER}" of="${OUTPUT}" seek="${PRELOADER_OFFSET}" conv=notrunc +dd bs=1024 if="${UBOOT}" of="${OUTPUT}" seek="${UBOOT_OFFSET}" conv=notrunc +dd bs=512 if="${BOOTFS}" of="${OUTPUT}" seek="${BOOT_OFFSET}" conv=notrunc +dd bs=512 if="${ROOTFS}" of="${OUTPUT}" seek="${ROOTFS_OFFSET}" conv=notrunc diff --git a/root/target/linux/mediatek/image/mt7623.mk b/root/target/linux/mediatek/image/mt7623.mk index 15bd579e..d361b9ec 100644 --- a/root/target/linux/mediatek/image/mt7623.mk +++ b/root/target/linux/mediatek/image/mt7623.mk @@ -13,12 +13,13 @@ define Device/7623n-bananapi-bpi-r2 DEVICE_TITLE := MTK7623n BananaPi R2 DEVICE_DTS := mt7623n-bananapi-bpi-r2 # DEVICE_PACKAGES := wmt uboot-mtk-bpi-r2 kmod-crypto-hw-mtk kmod-nat-hw-mtk - DEVICE_PACKAGES := wmt uboot-mtk-bpi-r2 kmod-crypto-hw-mtk kmod-mt6625l-wlan-gen2 + DEVICE_PACKAGES := wmt uboot-mtk-bpi-r2 kmod-crypto-hw-mtk kmod-mt6625l-wlan-gen2 kmod-usb-core kmod-ata-core kmod-usb3 kmod-usb2 kmod-usb-ohci mt7623n-preloader SUPPORTED_DEVICES := bananapi,bpi-r2 - IMAGES := sysupgrade.tar sysupgrade-sd.img.gz sysupgrade-emmc.img.gz + IMAGES := sysupgrade.tar sysupgrade-sd.img.gz sysupgrade-emmc.img.gz sdcard.img.gz IMAGE/sysupgrade.tar := sysupgrade-tar | append-metadata IMAGE/sysupgrade-sd.img.gz := sysupgrade-bpi-r2-sd | gzip | append-metadata IMAGE/sysupgrade-emmc.img.gz := sysupgrade-bpi-r2-emmc | gzip | append-metadata + IMAGE/sdcard.img.gz := mediatek-sdcard | gzip | append-metadata endef TARGET_DEVICES += 7623n-bananapi-bpi-r2