[][openwrt][mt7988][tops][TOPS Alpha release]

[Description]
Add alpha version of TOPS(tunnel offload processor system) and tops-tool
package.

TOPS package supports tunnel protocol HW offload. The support offload
tunnel protocols for Alpha version are L2oGRE and L2TPv2.
Notice that, TOPS only guarantees that inner packets are TCP. It is still
unstable for UDP inner packet flow.

tops-tool package provides several debug features such as logger, coredump
for TOPS.

[Release-log]
N/A

Change-Id: Iab6e4a89bebbe42c967f28e0c9e9c0611673f354
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7852683
diff --git a/package-21.02/kernel/tops/src/hwspinlock.c b/package-21.02/kernel/tops/src/hwspinlock.c
new file mode 100644
index 0000000..1723cf4
--- /dev/null
+++ b/package-21.02/kernel/tops/src/hwspinlock.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "hwspinlock.h"
+
+#define SEMA_ID				(BIT(CORE_AP))
+
+static void __iomem *base;
+
+static inline u32 hwspinlock_read(u32 reg)
+{
+	return readl(base + reg);
+}
+
+static inline void hwspinlock_write(u32 reg, u32 val)
+{
+	writel(val, base + reg);
+}
+
+static inline u32 __mtk_tops_hwspinlock_get_reg(enum hwspinlock_group grp, u32 slot)
+{
+	if (unlikely(slot >= HWSPINLOCK_SLOT_MAX || grp >= __HWSPINLOCK_GROUP_MAX))
+		return 0;
+
+	if (grp == HWSPINLOCK_GROUP_TOP)
+		return HWSPINLOCK_TOP_BASE + slot * 4;
+	else
+		return HWSPINLOCK_CLUST_BASE + slot * 4;
+}
+
+/*
+ * try take TOPS HW spinlock
+ * return 1 on success
+ * return 0 on failure
+ */
+int mtk_tops_hwspin_try_lock(enum hwspinlock_group grp, u32 slot)
+{
+	u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
+
+	WARN_ON(!reg);
+
+	hwspinlock_write(reg, SEMA_ID);
+
+	return hwspinlock_read(reg) == SEMA_ID ? 1 : 0;
+}
+
+void mtk_tops_hwspin_lock(enum hwspinlock_group grp, u32 slot)
+{
+	u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
+
+	WARN_ON(!reg);
+
+	do {
+		hwspinlock_write(reg, SEMA_ID);
+	} while (hwspinlock_read(reg) != SEMA_ID);
+}
+
+void mtk_tops_hwspin_unlock(enum hwspinlock_group grp, u32 slot)
+{
+	u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
+
+	WARN_ON(!reg);
+
+	if (hwspinlock_read(reg) == SEMA_ID)
+		hwspinlock_write(reg, SEMA_ID);
+}
+
+int mtk_tops_hwspinlock_init(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
+	if (!res)
+		return -ENXIO;
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base)
+		return -ENOMEM;
+
+	return 0;
+}