[][openwrt][common][bsp][Add support to reset boot count of dual image booting]

[Description]
Add built-in kernel driver to allow resetting boot count of A/B systems
Add init script which will be executed after init done.

[Release-log]
N/A

Change-Id: I9aeecccc6f7ffa34b69530041aeb0585eb6d6929
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8823085
diff --git a/21.02/files/package/base-files/files/etc/init.d/reset_boot_count b/21.02/files/package/base-files/files/etc/init.d/reset_boot_count
new file mode 100755
index 0000000..7b1640f
--- /dev/null
+++ b/21.02/files/package/base-files/files/etc/init.d/reset_boot_count
@@ -0,0 +1,12 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2024 All Rights Reserved.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+
+START=99
+boot() {
+	local enabled=$(cat /sys/module/boot_param/parameters/reset_boot_count 2>/dev/null)
+
+	if [ x"${enabled}" = xY ]; then
+		echo 1 > /proc/reset_boot_count
+	fi
+}
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/Makefile b/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/Makefile
index b725c38..f3f3692 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/Makefile
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MTK_ICE_DEBUG) += ice_debug/
 obj-y += infra_bus_prot/
+obj-y += reset-boot-count/
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/Makefile b/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/Makefile
new file mode 100644
index 0000000..a8c3756
--- /dev/null
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/Makefile
@@ -0,0 +1,2 @@
+

+obj-y      := reset-boot-count.o

diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/reset-boot-count.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/reset-boot-count.c
new file mode 100644
index 0000000..2b82d89
--- /dev/null
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/misc/mediatek/reset-boot-count/reset-boot-count.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: BSD-3-Clause

+/*

+ * Copyright (C) 2024 MediaTek Inc. All rights reserved.

+ *

+ * Helper for resetting boot count of A/B boot systems

+ *

+ * Author: Weijie Gao <weijie.gao@mediatek.com>

+ */

+

+#include <linux/kernel.h>

+#include <linux/module.h>

+#include <linux/delay.h>

+#include <linux/init.h>

+#include <linux/proc_fs.h>

+#include <linux/seq_file.h>

+#include <linux/arm-smccc.h>

+

+#define RBC "reset_boot_count"

+

+#define MTK_SIP_READ_NONRST_REG			0xC2000550

+#define MTK_SIP_WRITE_NONRST_REG		0xC2000551

+

+static struct proc_dir_entry *rbc_entry;

+

+static bool dual_boot_get_boot_count(u32 *retslot, u32 *retcnt)

+{

+	struct arm_smccc_res res = {0};

+	u32 val, slot;

+	s8 neg, pos;

+

+	arm_smccc_smc(MTK_SIP_READ_NONRST_REG, 0, 0, 0, 0, 0, 0, 0, &res);

+

+	val = (u32)res.a0;

+

+	/* slot: val[31..24] = -slot, val[23..16] = slot */

+	pos = (val >> 16) & 0xff;

+	neg = (val >> 24) & 0xff;

+

+	if (!(pos >= 0 && neg <= 0 && pos + neg == 0)) {

+		pr_debug("slot of boot count is invalid\n");

+		goto err;

+	}

+

+	slot = pos;

+

+	/* count: val[15..8] = -count, val[7..0] = count */

+	pos = val & 0xff;

+	neg = (val >> 8) & 0xff;

+

+	if (!(pos >= 0 && neg <= 0 && pos + neg == 0)) {

+		pr_debug("count of boot count is invalid\n");

+		goto err;

+	}

+

+	if (retslot)

+		*retslot = slot;

+

+	if (retcnt)

+		*retcnt = pos;

+

+	return true;

+

+err:

+	if (retslot)

+		*retslot = 0;

+

+	if (retcnt)

+		*retcnt = 0;

+

+	return false;

+}

+

+static void dual_boot_set_boot_count(u32 slot, u32 count)

+{

+	struct arm_smccc_res res = {0};

+	u32 val;

+	s32 neg;

+

+	if (slot > 127 || count > 127)

+		return;

+

+	neg = -count;

+	val = count | ((neg << 8) & 0xff00);

+

+	neg = -slot;

+	val = val | ((uint32_t)slot << 16) | ((neg << 24) & 0xff000000);

+

+	arm_smccc_smc(MTK_SIP_WRITE_NONRST_REG, 0, val, 0, 0, 0, 0, 0, &res);

+}

+

+static int rbc_display(struct seq_file *seq, void *v)

+{

+	return 0;

+}

+

+static int rbc_open(struct inode *inode, struct file *file)

+{

+	return single_open(file, rbc_display, inode->i_private);

+}

+

+static ssize_t rbc_write(struct file *file, const char __user *buffer,

+			 size_t count, loff_t *pos)

+{

+	u32 slot;

+

+	dual_boot_get_boot_count(&slot, NULL);

+	dual_boot_set_boot_count(slot, 0);

+

+	pr_info("Boot count reset\n");

+

+	return count;

+}

+

+static const struct file_operations rbc_fops =

+{

+	.open  = rbc_open,

+	.read = seq_read,

+	.write = rbc_write,

+	.llseek  = seq_lseek,

+	.release = single_release,

+};

+

+static int __init rbc_init(void)

+{

+	rbc_entry = proc_create(RBC, 0200, NULL, &rbc_fops);

+

+	if (!rbc_entry)

+		pr_err("failed to create proc entry " RBC);

+

+	return 0;

+}

+

+static void __exit rbc_exit(void)

+{

+	remove_proc_entry(RBC, NULL);

+}

+

+module_init(rbc_init);

+module_exit(rbc_exit);

+

+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");

+MODULE_DESCRIPTION("Kernel module for resetting boot count of A/B boot systems");

+MODULE_LICENSE("BSD");

diff --git a/21.02/files/target/linux/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch b/21.02/files/target/linux/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch
index 1eb437c..a160814 100644
--- a/21.02/files/target/linux/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch
+++ b/21.02/files/target/linux/mediatek/patches-5.4/999-2540-cmdline-boot-parameters.patch
@@ -27,7 +27,7 @@
 index 000000000..3dfe828bc
 --- /dev/null
 +++ b/kernel/boot_param.c
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,47 @@
 +/* SPDX-License-Identifier: BSD-3-Clause */
 +/*
 +* Copyright (C) 2022 MediaTek Inc. All rights reserved.
@@ -43,6 +43,9 @@
 +bool dual_boot;
 +module_param(dual_boot, bool, 0444);
 +
++static bool reset_boot_count;
++module_param(reset_boot_count, bool, 0444);
++
 +static bool no_split_rootfs_data;
 +module_param(no_split_rootfs_data, bool, 0444);
 +