[][Add initial mtk feed for OpenWRT v21.02]
[Description]
Add initial mtk feed for OpenWRT v21.02
[Release-log]
N/A
Change-Id: I8051c6ba87f1ccf26c02fdd88a17d66f63c0b101
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/4495320
diff --git a/feed/mii_mgr/Makefile b/feed/mii_mgr/Makefile
new file mode 100755
index 0000000..166e3f5
--- /dev/null
+++ b/feed/mii_mgr/Makefile
@@ -0,0 +1,36 @@
+#
+# hua.shao@mediatek.com
+#
+# MTK Property Software.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mii_mgr
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/mii_mgr
+ SECTION:=MTK Properties
+ CATEGORY:=MTK Properties
+ TITLE:=mii_mgr/mii_mgr_cl45
+ SUBMENU:=Applications
+endef
+
+define Package/mii_mgr/description
+ An mdio r/w phy regs program.
+endef
+
+define Package/mii_mgr/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mii_mgr $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mii_mgr $(1)/usr/sbin/mii_mgr_cl45
+endef
+
+
+$(eval $(call BuildPackage,mii_mgr))
+
diff --git a/feed/mii_mgr/src/Makefile b/feed/mii_mgr/src/Makefile
new file mode 100644
index 0000000..55d6a6f
--- /dev/null
+++ b/feed/mii_mgr/src/Makefile
@@ -0,0 +1,16 @@
+EXEC = mii_mgr
+
+CFLAGS += -Wall -Werror
+
+all: $(EXEC)
+
+mii_mgr: mii_mgr.o
+
+ $(CC) $(LDFLAGS) -o $@ $^
+
+romfs:
+ $(ROMFSINST) /bin/mii_mgr
+
+clean:
+ -rm -f $(EXEC) *.elf *.gdb *.o
+
diff --git a/feed/mii_mgr/src/mii_mgr.c b/feed/mii_mgr/src/mii_mgr.c
new file mode 100644
index 0000000..34cf8d5
--- /dev/null
+++ b/feed/mii_mgr/src/mii_mgr.c
@@ -0,0 +1,131 @@
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/ethtool.h>
+#include <linux/mdio.h>
+#include <linux/sockios.h>
+
+void show_usage(void)
+{
+ printf("mii_mgr -g -i [ifname] -p [phy number] -r [register number]\n");
+ printf(" Get: mii_mgr -g -p 3 -r 4\n\n");
+ printf("mii_mgr -s -p [phy number] -r [register number] -v [0xvalue]\n");
+ printf(" Set: mii_mgr -s -p 4 -r 1 -v 0xff11\n");
+ printf("#NOTE: Without -i , eth0 is default ifname!\n");
+ printf("----------------------------------------------------------------------------------------\n");
+ printf("Get: mii_mgr_cl45 -g -p [port number] -d [dev number] -r [register number]\n");
+ printf("Example: mii_mgr_cl45 -g -p 3 -d 0x5 -r 0x4\n\n");
+ printf("Set: mii_mgr_cl45 -s -p [port number] -d [dev number] -r [register number] -v [value]\n");
+ printf("Example: mii_mgr_cl45 -s -p 4 -d 0x6 -r 0x1 -v 0xff11\n\n");
+}
+
+static int __phy_op(char *ifname,uint16_t phy_id,uint16_t reg_num, uint16_t *val, int cmd)
+{
+ static int sd = -1;
+
+ struct ifreq ifr;
+ struct mii_ioctl_data* mii = (struct mii_ioctl_data *)(&ifr.ifr_data);
+ int err;
+
+ if (sd < 0)
+ sd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (sd < 0)
+ return sd;
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ mii->phy_id = phy_id;
+ mii->reg_num = reg_num;
+ mii->val_in = *val;
+ mii->val_out = 0;
+
+ err = ioctl(sd, cmd, &ifr);
+ if (err)
+ return -errno;
+
+ *val = mii->val_out;
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ char options[] = "gsi:p:d:r:v:?t";
+ int is_write = 0,is_cl45 = 0;
+ unsigned int port=0, dev=0,reg_num=0,val=0;
+ char ifname[IFNAMSIZ]="eth0";
+ uint16_t phy_id=0;
+
+
+ if (argc < 6) {
+ show_usage();
+ return 0;
+ }
+
+ while ((opt = getopt(argc, argv, options)) != -1) {
+ switch (opt) {
+ case 'g':
+ is_write=0;
+ break;
+ case 's':
+ is_write=1;
+ break;
+ case 'i':
+ strncpy(ifname,optarg, 5);
+ break;
+ case 'p':
+ port = strtoul(optarg, NULL, 16);
+ break;
+ case 'd':
+ dev = strtoul(optarg, NULL, 16);
+ is_cl45 = 1;
+ break;
+ case 'r':
+ reg_num = strtoul(optarg, NULL, 16);
+ break;
+
+ case 'v':
+ val = strtoul(optarg, NULL, 16);
+ break;
+ case '?':
+ show_usage();
+ break;
+ }
+ }
+
+ if(is_cl45)
+ phy_id = mdio_phy_id_c45(port, dev);
+ else
+ phy_id = port;
+
+ if(is_write) {
+ __phy_op(ifname,phy_id,reg_num,(uint16_t *)&val,SIOCSMIIREG);
+
+ if(is_cl45)
+ printf("Set: port%x dev%Xh_reg%Xh = 0x%04X\n",port, dev, reg_num, val);
+ else
+ printf("Set: phy[%x].reg[%x] = %04x\n",port, reg_num, val);
+ }
+ else {
+ __phy_op(ifname,phy_id,reg_num,(uint16_t *)&val,SIOCGMIIREG);
+
+ if(is_cl45)
+ printf("Get: port%x dev%Xh_reg%Xh = 0x%04X\n",port, dev, reg_num, val);
+ else
+ printf("Get: phy[%x].reg[%x] = %04x\n",port, reg_num, val);
+
+ }
+
+ return 0;
+}
diff --git a/feed/mt76-vendor/Makefile b/feed/mt76-vendor/Makefile
new file mode 100644
index 0000000..7436e0d
--- /dev/null
+++ b/feed/mt76-vendor/Makefile
@@ -0,0 +1,29 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mt76-vendor
+PKG_RELEASE=1
+
+PKG_LICENSE:=GPLv2
+PKG_LICENSE_FILES:=
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+CMAKE_SOURCE_DIR:=$(PKG_BUILD_DIR)
+CMAKE_BINARY_DIR:=$(PKG_BUILD_DIR)
+
+define Package/mt76-vendor
+ SECTION:=devel
+ CATEGORY:=Development
+ TITLE:=vendor cmd for mt76
+ DEPENDS:=+libnl-tiny
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny
+
+define Package/mt76-vendor/install
+ mkdir -p $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mt76-vendor $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,mt76-vendor))
diff --git a/feed/mt76-vendor/src/CMakeLists.txt b/feed/mt76-vendor/src/CMakeLists.txt
new file mode 100644
index 0000000..97059d0
--- /dev/null
+++ b/feed/mt76-vendor/src/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8)
+
+PROJECT(mt76-vendor C)
+ADD_DEFINITIONS(-Os -Wall --std=gnu99 -g3)
+
+ADD_EXECUTABLE(mt76-vendor main.c)
+TARGET_LINK_LIBRARIES(mt76-vendor nl-tiny)
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+
+INSTALL(TARGETS mt76-vendor
+ RUNTIME DESTINATION sbin
+)
diff --git a/feed/mt76-vendor/src/main.c b/feed/mt76-vendor/src/main.c
new file mode 100644
index 0000000..188a151
--- /dev/null
+++ b/feed/mt76-vendor/src/main.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 Mediatek Inc. */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <net/if.h>
+
+#include "mt76-vendor.h"
+
+struct unl unl;
+static const char *progname;
+struct csi_data *csi;
+int csi_idx;
+
+static struct nla_policy csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {
+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG] = { .type = NLA_NESTED },
+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR] = { .type = NLA_NESTED },
+ [MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM] = { .type = NLA_U16 },
+ [MTK_VENDOR_ATTR_CSI_CTRL_DATA] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy csi_data_policy[NUM_MTK_VENDOR_ATTRS_CSI_DATA] = {
+ [MTK_VENDOR_ATTR_CSI_DATA_VER] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_TS] = { .type = NLA_U64 },
+ [MTK_VENDOR_ATTR_CSI_DATA_RSSI] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_SNR] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_BW] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_TA] = { .type = NLA_NESTED },
+ [MTK_VENDOR_ATTR_CSI_DATA_I] = { .type = NLA_NESTED },
+ [MTK_VENDOR_ATTR_CSI_DATA_Q] = { .type = NLA_NESTED },
+ [MTK_VENDOR_ATTR_CSI_DATA_INFO] = { .type = NLA_U32 },
+ [MTK_VENDOR_ATTR_CSI_DATA_TX_ANT] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_RX_ANT] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_MODE] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_CSI_DATA_H_IDX] = { .type = NLA_U32 },
+};
+
+void usage(void)
+{
+ static const char *const commands[] = {
+ "set csi_ctrl=",
+ "dump <packet num> <filename>",
+ };
+ int i;
+
+ fprintf(stderr, "Usage:\n");
+ for (i = 0; i < ARRAY_SIZE(commands); i++)
+ printf(" %s wlanX %s\n", progname, commands[i]);
+
+ exit(1);
+}
+
+static int mt76_dump_cb(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_CSI_CTRL];
+ struct nlattr *tb_data[NUM_MTK_VENDOR_ATTRS_CSI_DATA];
+ struct nlattr *attr;
+ struct nlattr *cur;
+ int rem, idx;
+ struct csi_data *c = &csi[csi_idx];
+
+ attr = unl_find_attr(&unl, msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr) {
+ fprintf(stderr, "Testdata attribute not found\n");
+ return NL_SKIP;
+ }
+
+ nla_parse_nested(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX,
+ attr, csi_ctrl_policy);
+
+ if (!tb[MTK_VENDOR_ATTR_CSI_CTRL_DATA])
+ return NL_SKIP;
+
+ nla_parse_nested(tb_data, MTK_VENDOR_ATTR_CSI_DATA_MAX,
+ tb[MTK_VENDOR_ATTR_CSI_CTRL_DATA], csi_data_policy);
+
+ if (!(tb_data[MTK_VENDOR_ATTR_CSI_DATA_VER] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_TS] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_RSSI] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_SNR] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_BW] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_TA] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_I] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_Q] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_INFO] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_MODE] &&
+ tb_data[MTK_VENDOR_ATTR_CSI_DATA_H_IDX])) {
+ fprintf(stderr, "Attributes error for CSI data\n");
+ return NL_SKIP;
+ }
+
+ c->rssi = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_RSSI]);
+ c->snr = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_SNR]);
+ c->data_bw = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_BW]);
+ c->pri_ch_idx = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_CH_IDX]);
+ c->rx_mode = nla_get_u8(tb_data[MTK_VENDOR_ATTR_CSI_DATA_MODE]);
+
+ c->tx_idx = nla_get_u16(tb_data[MTK_VENDOR_ATTR_CSI_DATA_TX_ANT]);
+ c->rx_idx = nla_get_u16(tb_data[MTK_VENDOR_ATTR_CSI_DATA_RX_ANT]);
+
+ c->info = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_INFO]);
+ c->h_idx = nla_get_u32(tb_data[MTK_VENDOR_ATTR_CSI_DATA_H_IDX]);
+
+ c->ts = nla_get_u64(tb_data[MTK_VENDOR_ATTR_CSI_DATA_TS]);
+
+ idx = 0;
+ nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_TA], rem) {
+ c->ta[idx++] = nla_get_u8(cur);
+ }
+
+ idx = 0;
+ nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_I], rem) {
+ c->data_i[idx++] = nla_get_u16(cur);
+ }
+
+ idx = 0;
+ nla_for_each_nested(cur, tb_data[MTK_VENDOR_ATTR_CSI_DATA_Q], rem) {
+ c->data_q[idx++] = nla_get_u16(cur);
+ }
+
+ csi_idx++;
+
+ return NL_SKIP;
+}
+
+static int mt76_csi_to_json(const char *name)
+{
+#define MAX_BUF_SIZE 6000
+ FILE *f;
+ int i;
+
+ f = fopen(name, "a+");
+ if (!f) {
+ printf("open failure");
+ return 1;
+ }
+
+ fwrite("[", 1, 1, f);
+
+ for (i = 0; i < csi_idx; i++) {
+ char *pos, *buf = malloc(MAX_BUF_SIZE);
+ struct csi_data *c = &csi[i];
+ int j;
+
+ pos = buf;
+
+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
+
+ pos += snprintf(pos, MAX_BUF_SIZE, "%ld,", c->ts);
+ pos += snprintf(pos, MAX_BUF_SIZE, "\"%02x%02x%02x%02x%02x%02x\",", c->ta[0], c->ta[1], c->ta[2], c->ta[3], c->ta[4], c->ta[5]);
+
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rssi);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->snr);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->data_bw);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->pri_ch_idx);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%u,", c->rx_mode);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->tx_idx);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->rx_idx);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->h_idx);
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d,", c->info);
+
+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
+ for (j = 0; j < 256; j++) {
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_i[j]);
+ if (j != 255)
+ pos += snprintf(pos, MAX_BUF_SIZE, ",");
+ }
+ pos += snprintf(pos, MAX_BUF_SIZE, "%c,", ']');
+
+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", '[');
+ for (j = 0; j < 256; j++) {
+ pos += snprintf(pos, MAX_BUF_SIZE, "%d", c->data_q[j]);
+ if (j != 255)
+ pos += snprintf(pos, MAX_BUF_SIZE, ",");
+ }
+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
+
+ pos += snprintf(pos, MAX_BUF_SIZE, "%c", ']');
+ if (i != csi_idx - 1)
+ pos += snprintf(pos, MAX_BUF_SIZE, ",");
+
+ fwrite(buf, 1, pos - buf, f);
+ free(buf);
+ }
+
+ fwrite("]", 1, 1, f);
+
+ fclose(f);
+}
+
+static int mt76_dump(int idx, int argc, char **argv)
+{
+ int pkt_num, ret, i;
+ struct nl_msg *msg;
+ void *data;
+
+ if (argc < 2)
+ return 1;
+ pkt_num = strtol(argv[0], NULL, 10);
+
+#define CSI_DUMP_PER_NUM 3
+ csi_idx = 0;
+ csi = (struct csi_data *)calloc(pkt_num, sizeof(*csi));
+
+ for (i = 0; i < pkt_num / CSI_DUMP_PER_NUM; i++) {
+ if (unl_genl_init(&unl, "nl80211") < 0) {
+ fprintf(stderr, "Failed to connect to nl80211\n");
+ return 2;
+ }
+
+ msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, true);
+
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
+ return false;
+
+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
+
+ if (nla_put_u16(msg, MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM, CSI_DUMP_PER_NUM))
+ return false;
+
+ nla_nest_end(msg, data);
+
+ ret = unl_genl_request(&unl, msg, mt76_dump_cb, NULL);
+ if (ret)
+ fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
+
+ unl_free(&unl);
+ }
+
+ mt76_csi_to_json(argv[1]);
+ free(csi);
+
+ return ret;
+}
+
+static int mt76_csi_ctrl(struct nl_msg *msg, int argc, char **argv)
+{
+ int idx = MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE;
+ char *val, *s1, *s2, *cur;
+ void *data;
+
+ val = strchr(argv[0], '=');
+ if (val)
+ *(val++) = 0;
+
+ s1 = s2 = strdup(val);
+
+ data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_CFG | NLA_F_NESTED);
+
+ while ((cur = strsep(&s1, ",")) != NULL)
+ nla_put_u8(msg, idx++, strtoul(cur, NULL, 0));
+
+ nla_nest_end(msg, data);
+
+ free(s2);
+
+ if (argc == 2 &&
+ !strncmp(argv[1], "mac_addr", strlen("mac_addr"))) {
+ u8 a[ETH_ALEN];
+ int matches, i;
+
+ val = strchr(argv[1], '=');
+ if (val)
+ *(val++) = 0;
+
+ matches = sscanf(val, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ a, a+1, a+2, a+3, a+4, a+5);
+
+ if (matches != ETH_ALEN)
+ return -EINVAL;
+
+ data = nla_nest_start(msg, MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR | NLA_F_NESTED);
+ for (i = 0; i < ETH_ALEN; i++)
+ nla_put_u8(msg, i, a[i]);
+
+ nla_nest_end(msg, data);
+ }
+
+ return 0;
+}
+
+static int mt76_set(int idx, int argc, char **argv)
+{
+ struct nl_msg *msg;
+ void *data;
+ int ret;
+
+ if (argc < 1)
+ return 1;
+
+ msg = unl_genl_msg(&unl, NL80211_CMD_VENDOR, false);
+
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, idx) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, MTK_NL80211_VENDOR_ID) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL))
+ return false;
+
+ data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA | NLA_F_NESTED);
+
+ if (!strncmp(argv[0], "csi_ctrl", strlen("csi_ctrl")))
+ mt76_csi_ctrl(msg, argc, argv);
+
+ nla_nest_end(msg, data);
+
+ ret = unl_genl_request(&unl, msg, NULL, NULL);
+ if (ret)
+ fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ const char *cmd;
+ int ret = 0;
+ int idx;
+
+ progname = argv[0];
+ if (argc < 3)
+ usage();
+
+ idx = if_nametoindex(argv[1]);
+ if (!idx) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ return 2;
+ }
+
+ cmd = argv[2];
+ argv += 3;
+ argc -= 3;
+
+ if (!strcmp(cmd, "dump"))
+ ret = mt76_dump(idx, argc, argv);
+ else if (!strcmp(cmd, "set")) {
+ if (unl_genl_init(&unl, "nl80211") < 0) {
+ fprintf(stderr, "Failed to connect to nl80211\n");
+ return 2;
+ }
+
+ ret = mt76_set(idx, argc, argv);
+ unl_free(&unl);
+ }
+ else
+ usage();
+
+ return ret;
+}
diff --git a/feed/mt76-vendor/src/mt76-vendor.h b/feed/mt76-vendor/src/mt76-vendor.h
new file mode 100644
index 0000000..3407903
--- /dev/null
+++ b/feed/mt76-vendor/src/mt76-vendor.h
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
+#ifndef __MT76_TEST_H
+#define __MT76_TEST_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <linux/nl80211.h>
+#include <netlink/attr.h>
+#include <unl.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64, ktime_t;
+
+#define MTK_NL80211_VENDOR_ID 0x0ce7
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#endif
+
+struct nl_msg;
+struct nlattr;
+
+enum mtk_nl80211_vendor_subcmds {
+ MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0xc2,
+};
+
+enum mtk_vendor_attr_csi_ctrl {
+ MTK_VENDOR_ATTR_CSI_CTRL_UNSPEC,
+
+ MTK_VENDOR_ATTR_CSI_CTRL_CFG,
+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE,
+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE,
+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1,
+ MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2,
+ MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR,
+
+ MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM,
+
+ MTK_VENDOR_ATTR_CSI_CTRL_DATA,
+
+ /* keep last */
+ NUM_MTK_VENDOR_ATTRS_CSI_CTRL,
+ MTK_VENDOR_ATTR_CSI_CTRL_MAX =
+ NUM_MTK_VENDOR_ATTRS_CSI_CTRL - 1
+};
+
+enum mtk_vendor_attr_csi_data {
+ MTK_VENDOR_ATTR_CSI_DATA_UNSPEC,
+ MTK_VENDOR_ATTR_CSI_DATA_PAD,
+
+ MTK_VENDOR_ATTR_CSI_DATA_VER,
+ MTK_VENDOR_ATTR_CSI_DATA_TS,
+ MTK_VENDOR_ATTR_CSI_DATA_RSSI,
+ MTK_VENDOR_ATTR_CSI_DATA_SNR,
+ MTK_VENDOR_ATTR_CSI_DATA_BW,
+ MTK_VENDOR_ATTR_CSI_DATA_CH_IDX,
+ MTK_VENDOR_ATTR_CSI_DATA_TA,
+ MTK_VENDOR_ATTR_CSI_DATA_I,
+ MTK_VENDOR_ATTR_CSI_DATA_Q,
+ MTK_VENDOR_ATTR_CSI_DATA_INFO,
+ MTK_VENDOR_ATTR_CSI_DATA_RSVD1,
+ MTK_VENDOR_ATTR_CSI_DATA_RSVD2,
+ MTK_VENDOR_ATTR_CSI_DATA_RSVD3,
+ MTK_VENDOR_ATTR_CSI_DATA_RSVD4,
+ MTK_VENDOR_ATTR_CSI_DATA_TX_ANT,
+ MTK_VENDOR_ATTR_CSI_DATA_RX_ANT,
+ MTK_VENDOR_ATTR_CSI_DATA_MODE,
+ MTK_VENDOR_ATTR_CSI_DATA_H_IDX,
+
+ /* keep last */
+ NUM_MTK_VENDOR_ATTRS_CSI_DATA,
+ MTK_VENDOR_ATTR_CSI_DATA_MAX =
+ NUM_MTK_VENDOR_ATTRS_CSI_DATA - 1
+};
+
+#define CSI_MAX_COUNT 256
+#define ETH_ALEN 6
+
+struct csi_data {
+ s16 data_i[CSI_MAX_COUNT];
+ s16 data_q[CSI_MAX_COUNT];
+ s8 rssi;
+ u8 snr;
+ ktime_t ts;
+ u8 data_bw;
+ u8 pri_ch_idx;
+ u8 ta[ETH_ALEN];
+ u32 info;
+ u8 rx_mode;
+ u32 h_idx;
+ u16 tx_idx;
+ u16 rx_idx;
+};
+
+struct vendor_field {
+ const char *name;
+ const char *prefix;
+
+ bool (*parse)(const struct vendor_field *field, int idx, struct nl_msg *msg,
+ const char *val);
+ void (*print)(const struct vendor_field *field, struct nlattr *attr);
+
+ union {
+ struct {
+ const char * const *enum_str;
+ int enum_len;
+ };
+ struct {
+ bool (*parse2)(const struct vendor_field *field, int idx,
+ struct nl_msg *msg, const char *val);
+ void (*print2)(const struct vendor_field *field,
+ struct nlattr *attr);
+ };
+ struct {
+ void (*print_extra)(const struct vendor_field *field,
+ struct nlattr **tb);
+ const struct vendor_field *fields;
+ struct nla_policy *policy;
+ int len;
+ };
+ };
+};
+
+extern struct unl unl;
+extern const struct vendor_field msg_field;
+
+void usage(void);
+
+#endif
diff --git a/feed/mtk_factory_rw/Makefile b/feed/mtk_factory_rw/Makefile
new file mode 100644
index 0000000..ad5316f
--- /dev/null
+++ b/feed/mtk_factory_rw/Makefile
@@ -0,0 +1,43 @@
+#
+# MTK-factory read and write
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mtk_factory_rw
+PKG_VERSION:=1
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PKG_CONFIG_DEPENDS:=
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mtk_factory_rw
+ SECTION:=MTK Properties
+ CATEGORY:=MTK Properties
+ SUBMENU:=Misc
+ TITLE:=mtk factory read and write
+ VERSION:=$(PKG_RELEASE)-$(REVISION)
+endef
+
+define Package/mtk_factory_rw/description
+ mtk factory's data read and write
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Compile/Default
+endef
+
+Build/Compile = $(Build/Compile/Default)
+
+define Package/mtk_factory_rw/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) ./files/mtk_factory_rw.sh $(1)/sbin/mtk_factory_rw.sh
+endef
+
+$(eval $(call BuildPackage,mtk_factory_rw))
+
diff --git a/feed/mtk_factory_rw/files/mtk_factory_rw.sh b/feed/mtk_factory_rw/files/mtk_factory_rw.sh
new file mode 100755
index 0000000..7657260
--- /dev/null
+++ b/feed/mtk_factory_rw/files/mtk_factory_rw.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+usage()
+{
+ echo "This is a script to get or set mtk factory's data"
+ echo "-Typically, get or set the eth lan/wan mac_address-"
+ echo "Usage1: $0 <op> <side> [mac_address] "
+ echo " <op>: -r or -w (Read or Write action)"
+ echo " [mac_address]: MAC[1] MAC[2] MAC[3] MAC[4] MAC[5] MAC[6] (only for write action)"
+ echo "Usage2: $0 <op> <length> <offset> [data] "
+ echo " <length>: length bytes of input"
+ echo " <offset>: Skip offset bytes from the beginning of the input"
+ echo "Usage3: $0 -o <length> <get_from> <overwrite_to>"
+ echo "Example:"
+ echo "$0 -w lan 00 0c 43 68 55 56"
+ echo "$0 -r lan"
+ echo "$0 -w 8 0x22 11 22 33 44 55 66 77 88"
+ echo "$0 -r 8 0x22"
+ echo "$0 -o 12 0x24 0x7fff4"
+ exit 1
+}
+
+factory_name="Factory"
+factory_mtd=/dev/$(grep -i ''${factory_name}'' /proc/mtd | cut -c 1-4)
+
+#default:7622
+lan_mac_offset=0x2A
+wan_mac_offset=0x24
+
+case `cat /tmp/sysinfo/board_name` in
+ *7621*ax*)
+ # 256k - 12 byte
+ lan_mac_offset=0x3FFF4
+ wan_mac_offset=0x3FFFA
+ ;;
+ *7621*)
+ lan_mac_offset=0xe000
+ wan_mac_offset=0xe006
+ ;;
+ *7622*)
+ #512k -12 byte
+ lan_mac_offset=0x7FFF4
+ wan_mac_offset=0x7FFFA
+ ;;
+ *7623*)
+ lan_mac_offset=0x1F800
+ wan_mac_offset=0x1F806
+ ;;
+ *)
+ lan_mac_offset=0x2A
+ wan_mac_offset=0x24
+ ;;
+esac
+
+#1.Read the offset's data from the Factory
+#usage: Get_offset_data length offset
+Get_offset_data()
+{
+ local length=$1
+ local offset=$2
+
+ hexdump -v -n ${length} -s ${offset} -e ''`expr ${length} - 1`'/1 "%02x-" "%02x "' ${factory_mtd}
+}
+
+overwrite_data=
+
+Get_offset_overwrite_data()
+{
+ local length=$1
+ local offset=$2
+
+ overwrite_data=`hexdump -v -n ${length} -s ${offset} -e ''\`expr ${length} - 1\`'/1 "%02x " " %02x"' ${factory_mtd}`
+}
+
+#2.Write the offset's data from the Factory
+#usage: Set_offset_data length offset data
+Set_offset_data()
+{
+ local length=$1
+ local offset=$2
+ local index=`expr $# - ${length} + 1`
+ local data=""
+
+ for j in $(seq ${index} `expr ${length} + ${index} - 1`)
+ do
+ temp=`eval echo '$'{"$j"}`
+ data=${data}"\x${temp}"
+ done
+
+ dd if=${factory_mtd} of=/tmp/Factory.backup
+ printf "${data}" | dd conv=notrunc of=/tmp/Factory.backup bs=1 seek=$((${offset}))
+ mtd write /tmp/Factory.backup ${factory_name}
+ rm -rf /tmp/Factory.backup
+}
+
+#3.Read Factory lan/wan mac address
+GetMac()
+{
+ if [ "$1" == "lan" ]; then
+ #read lan mac
+ Get_offset_data 6 ${lan_mac_offset}
+ elif [ "$1" == "wan" ]; then
+ #read wan mac
+ Get_offset_data 6 ${wan_mac_offset}
+ else
+ usage
+ exit 1
+ fi
+}
+
+
+#4.write Factory lan/wan mac address
+SetMac()
+{
+ if [ "$#" != "9" ]; then
+ echo "Mac address must be 6 bytes!"
+ exit 1
+ fi
+
+ if [ "$1" == "lan" ]; then
+ #write lan mac
+ Set_offset_data 6 ${lan_mac_offset} $@
+
+ elif [ "$1" == "wan" ]; then
+ #write wan mac
+ Set_offset_data 6 ${wan_mac_offset} $@
+ else
+ usage
+ exit 1
+ fi
+}
+
+#usage:
+# 1. Set/Get the mac_address: mtk_factory -r/-w lan/wan /data
+# 2. Set/Get the offset data: mtk_factory -r/-w length offset /data
+# 3. Overwrite from offset1 to offset2 by length byte : mtk_factory -o length from to
+if [ "$1" == "-r" ]; then
+ if [ "$2" == "lan" -o "$2" == "wan" ]; then
+ GetMac $2
+ elif [ "$2" -eq "$2" ]; then
+ Get_offset_data $2 $3
+ else
+ echo "Unknown command!"
+ usage
+ exit 1
+ fi
+elif [ "$1" == "-w" ]; then
+ if [ "$2" == "lan" -o "$2" == "wan" ]; then
+ SetMac $2 $@
+ else
+ Set_offset_data $2 $3 $@
+ fi
+elif [ "$1" == "-o" ]; then
+ Get_offset_overwrite_data $2 $3
+ Set_offset_data $2 $4 ${overwrite_data}
+else
+ echo "Unknown command!"
+ usage
+ exit 1
+fi
diff --git a/feed/mtk_failsafe/Makefile b/feed/mtk_failsafe/Makefile
new file mode 100755
index 0000000..7cbd3ca
--- /dev/null
+++ b/feed/mtk_failsafe/Makefile
@@ -0,0 +1,43 @@
+#
+# MTK-factory read and write
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mtk_failsafe
+PKG_VERSION:=1
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PKG_CONFIG_DEPENDS:=
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mtk_failsafe
+ SECTION:=MTK Properties
+ CATEGORY:=MTK Properties
+ SUBMENU:=Misc
+ TITLE:=mtk failsafe script
+ VERSION:=$(PKG_RELEASE)-$(REVISION)
+endef
+
+define Package/mtk_failsafe/description
+ mtk init script for failsafe mode
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Compile/Default
+endef
+
+Build/Compile = $(Build/Compile/Default)
+
+define Package/mtk_failsafe/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) ./files/mtk_failsafe.sh $(1)/sbin/mtk_failsafe.sh
+endef
+
+$(eval $(call BuildPackage,mtk_failsafe))
+
diff --git a/feed/mtk_failsafe/files/mtk_failsafe.sh b/feed/mtk_failsafe/files/mtk_failsafe.sh
new file mode 100755
index 0000000..d9b9e60
--- /dev/null
+++ b/feed/mtk_failsafe/files/mtk_failsafe.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+mtk_common_init() {
+ echo "Running mtk failsafe script..."
+ echo "You can edit here : package/mtk/mtk_failsafe/file/mtk_failsafe.sh"
+ echo "mtk_common_init....."
+ mount_root
+ mount_root done
+ sync
+ echo 3 > /proc/sys/vm/drop_caches
+}
+
+mtk_wifi_init() {
+ echo "mtk_wifi_init....."
+ # once the bin is correct, unmark below
+ #insmod wifi_emi_loader
+ #rmmod wifi_emi_loader
+ #insmod mt_wifi
+ #ifconfig ra0 up
+ #ifconfig rax0 up
+}
+
+mtk_network_init() {
+ echo "mtk_network_init....."
+ # NOTE : LAN IP subnet should be 192.168.1.x
+ ifconfig eth0 0.0.0.0
+ brctl addbr br-lan
+ ifconfig br-lan 192.168.1.1 netmask 255.255.255.0 up
+ brctl addif br-lan eth0
+ #brctl addif br-lan ra0
+ #brctl addif br-lan rax0
+ ./etc/init.d/telnet start
+ #./usr/bin/ated
+}
+
+mtk_common_init
+mtk_wifi_init
+mtk_network_init
+
diff --git a/feed/mtkhnat_util/Makefile b/feed/mtkhnat_util/Makefile
new file mode 100755
index 0000000..8ef168a
--- /dev/null
+++ b/feed/mtkhnat_util/Makefile
@@ -0,0 +1,48 @@
+#
+# MTK-factory read and write
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mtkhnat_util
+PKG_VERSION:=1
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PKG_CONFIG_DEPENDS:=
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mtkhnat_util
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=mtk hnat utility
+ VERSION:=$(PKG_RELEASE)-$(REVISION)
+endef
+
+define Package/mtkhnat_util/description
+ mtk hnat util to init hnat module
+endef
+
+define Build/Prepare
+ mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Compile/Default
+endef
+
+Build/Compile = $(Build/Compile/Default)
+
+define Package/mtkhnat_util/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_DIR) $(1)/etc/config
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_DIR) $(1)/etc/uci-defaults
+
+ $(INSTALL_BIN) ./files/mtkhnat $(1)/sbin/
+ $(INSTALL_BIN) ./files/mtkhnat.config $(1)/etc/config/mtkhnat
+ $(INSTALL_BIN) ./files/mtkhnat.init $(1)/etc/init.d/mtkhnat
+ $(INSTALL_BIN) ./files/99-firewall $(1)/etc/uci-defaults
+endef
+
+$(eval $(call BuildPackage,mtkhnat_util))
diff --git a/feed/mtkhnat_util/files/99-firewall b/feed/mtkhnat_util/files/99-firewall
new file mode 100755
index 0000000..9c72762
--- /dev/null
+++ b/feed/mtkhnat_util/files/99-firewall
@@ -0,0 +1,6 @@
+echo "iptables -t mangle -A FORWARD -m dscp --dscp-class BE -j MARK --set-mark 0" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -m dscp --dscp-class CS2 -j MARK --set-mark 2" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -m dscp --dscp-class CS4 -j MARK --set-mark 4" >> /etc/firewall.user
+echo "iptables -t mangle -A FORWARD -m dscp --dscp-class CS6 -j MARK --set-mark 6" >> /etc/firewall.user
+
+exit 0
diff --git a/feed/mtkhnat_util/files/mtkhnat b/feed/mtkhnat_util/files/mtkhnat
new file mode 100755
index 0000000..ce3ef9a
--- /dev/null
+++ b/feed/mtkhnat_util/files/mtkhnat
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+config_load mtkhnat
+config_get enable global enable 0
+config_get hqos global hqos 0
+config_get txq_num global txq_num 16
+config_get scheduling global scheduling "wrr"
+config_get sch0_bw global sch0_bw 100000
+config_get sch1_bw global sch1_bw 100000
+
+#if enable=0, disable qdma_sch & qdma_txq
+[ "${enable}" -eq 1 ] || {
+ echo 0 ${scheduling} ${sch0_bw} > /sys/kernel/debug/hnat/qdma_sch0
+ echo 0 ${scheduling} ${sch1_bw} > /sys/kernel/debug/hnat/qdma_sch1
+ echo 1 0 0 0 0 0 4 > /sys/kernel/debug/hnat/qdma_txq0
+ for i in $(seq 1 $((txq_num - 1)))
+ do
+ echo 0 0 0 0 0 0 0 > /sys/kernel/debug/hnat/qdma_txq$i
+ done
+
+ rmmod mtkhnat
+ exit 0
+}
+
+insmod mtkhnat
+
+#if hqos=0, disable qdma_sch & qdma_txq
+[ "${hqos}" -eq 1 ] || {
+ echo 0 ${scheduling} ${sch0_bw} > /sys/kernel/debug/hnat/qdma_sch0
+ echo 0 ${scheduling} ${sch1_bw} > /sys/kernel/debug/hnat/qdma_sch1
+ echo 1 0 0 0 0 0 4 > /sys/kernel/debug/hnat/qdma_txq0
+ for i in $(seq 1 $((txq_num - 1)))
+ do
+ echo 0 0 0 0 0 0 0 > /sys/kernel/debug/hnat/qdma_txq$i
+ done
+
+ exit 0
+}
+
+# enable qdma_sch0 and qdma_sch1
+echo 1 ${scheduling} ${sch0_bw} > /sys/kernel/debug/hnat/qdma_sch0
+echo 1 ${scheduling} ${sch1_bw} > /sys/kernel/debug/hnat/qdma_sch1
+
+setup_queue() {
+ local queue_id queue_scheduler queue_minebl queue_maxebl
+ local queue_minrate queue_maxrate queue_resv minrate maxrate queue_weight
+
+ config_get queue_id $1 id 0
+ config_get queue_minrate $1 minrate 0
+ config_get queue_maxrate $1 maxrate 0
+ config_get queue_resv $1 resv 4
+ config_get queue_weight $1 weight 4
+
+ # check qid < txq max num or not for loop condition
+ [ "${queue_id}" -gt $((txq_num - 1)) ] && return 0
+
+ # start to set per queue config
+ queue_minebl=1
+ queue_maxebl=1
+ queue_scheduler=0
+
+ # if min rate = 0, set min enable = 0
+ # if max rate = 0, set max enable = 0
+ [ "${queue_minrate}" -eq 0 ] && queue_minebl=0
+ [ "${queue_maxrate}" -eq 0 ] && queue_maxebl=0
+
+ # calculate min rate according to sch0_bw
+ minrate=$((sch0_bw * $queue_minrate))
+ minrate=$((minrate / 100))
+
+ # calculate max rate according to sch0_bw
+ maxrate=$((sch0_bw * $queue_maxrate))
+ maxrate=$((maxrate / 100))
+
+ # set the queue of sch0 group(the lower half of total queues)
+ [ "${queue_id}" -le $(((txq_num / 2) - 1)) ] && \
+ echo 0 ${queue_minebl} ${minrate} ${queue_maxebl} ${maxrate} ${queue_weight} \
+ ${queue_resv} > /sys/kernel/debug/hnat/qdma_txq${queue_id}
+
+ # calculate min rate according to sch1_bw
+ minrate=$((sch1_bw * $queue_minrate))
+ minrate=$((minrate / 100))
+
+ # calculate max rate according to sch1_bw
+ maxrate=$((sch1_bw * $queue_maxrate))
+ maxrate=$((maxrate / 100))
+
+ # set the queue of sch1 group(the upper half of total queues)
+ [ "${queue_id}" -gt $(((txq_num / 2) - 1)) ] && \
+ echo 1 ${queue_minebl} ${minrate} ${queue_maxebl} ${maxrate} ${queue_weight} \
+ ${queue_resv} > /sys/kernel/debug/hnat/qdma_txq${queue_id}
+}
+
+config_foreach setup_queue queue
diff --git a/feed/mtkhnat_util/files/mtkhnat.config b/feed/mtkhnat_util/files/mtkhnat.config
new file mode 100755
index 0000000..f252a98
--- /dev/null
+++ b/feed/mtkhnat_util/files/mtkhnat.config
@@ -0,0 +1,921 @@
+####################################################################
+# hqos: 1:ON, 0:OFF #
+# txq_num: 16:default (only supports 64 queues for MT7622) #
+# scheduling: wrr: weighted round-robin, sp: strict priority #
+# sch0_bw: sch0 bandwidth (unit:Kbps) #
+# sch1_bw: sch1 bandwidth (unit:Kbps) #
+####################################################################
+config global global
+ option enable 1
+ option hqos 0
+ option txq_num 16
+ option scheduling 'wrr'
+ option sch0_bw 1000000
+ option sch1_bw 1000000
+
+####################################################################
+# id: queue id #
+# minrate: percentage of min rate limit #
+# maxrate: percentage of max rate limit #
+# weight: weight for queue schedule #
+# resv: buffer reserved for HW/SW path #
+####################################################################
+config queue
+ option id 0
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 1
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 2
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 3
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 4
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 5
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 6
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 7
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 8
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 9
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 10
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 11
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 12
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 13
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 14
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 15
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+####################################################################
+# Default setting supports 16 queues (id: 0~15) #
+# Only supports 64 queues for MT7622 #
+####################################################################
+config queue
+ option id 16
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 17
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 18
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 19
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 20
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 21
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 22
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 23
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 24
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 25
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 26
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 27
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 28
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 29
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 30
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 31
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 32
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 33
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 34
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 35
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 36
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 37
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 38
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 39
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 40
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 41
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 42
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 43
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 44
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 45
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 46
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 47
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 48
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 49
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 50
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 51
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 52
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 53
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 54
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 55
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 56
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 57
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 58
+ option minrate 30
+ option maxrate 100
+ option weight 2
+ option resv 4
+
+config queue
+ option id 59
+ option minrate 30
+ option maxrate 100
+ option weight 4
+ option resv 4
+
+config queue
+ option id 60
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 61
+ option minrate 30
+ option maxrate 100
+ option weight 6
+ option resv 4
+
+config queue
+ option id 62
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 63
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 64
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 65
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 66
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 67
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 68
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 69
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 70
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 71
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 72
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 73
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 74
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 75
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 76
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 77
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 78
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 79
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 80
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 81
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 82
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 83
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 84
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 85
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 86
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 87
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 88
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 89
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 90
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 91
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 92
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 93
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 94
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 95
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 96
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 97
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 98
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 99
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 100
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 101
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 102
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 103
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 104
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 105
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 106
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 107
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 108
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 109
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 110
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 111
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 112
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 113
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 114
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 115
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 116
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 117
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 118
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 119
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 120
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 121
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 122
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 123
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 124
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 125
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 126
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
+
+config queue
+ option id 127
+ option minrate 30
+ option maxrate 100
+ option weight 8
+ option resv 4
diff --git a/feed/mtkhnat_util/files/mtkhnat.init b/feed/mtkhnat_util/files/mtkhnat.init
new file mode 100755
index 0000000..528e62e
--- /dev/null
+++ b/feed/mtkhnat_util/files/mtkhnat.init
@@ -0,0 +1,17 @@
+#!/bin/sh /etc/rc.common
+
+START=19
+
+USE_PROCD=1
+NAME=mtkhnat
+PROG=/sbin/mtkhnat
+
+start_service() {
+ procd_open_instance
+ procd_set_param command "${PROG}"
+ procd_close_instance
+}
+
+service_triggers() {
+ procd_add_reload_trigger "mtkhnat"
+}
diff --git a/feed/regs/Makefile b/feed/regs/Makefile
new file mode 100755
index 0000000..d0f2444
--- /dev/null
+++ b/feed/regs/Makefile
@@ -0,0 +1,39 @@
+#
+# hua.shao@mediatek.com
+#
+# MTK Property Software.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=regs
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/regs
+ SECTION:=MTK Properties
+ CATEGORY:=MTK Properties
+ TITLE:=an program to read/write from/to a pci device from userspace.
+ SUBMENU:=Applications
+ DEPENDS:=+@KERNEL_DEVMEM
+endef
+
+define Package/regs/description
+ Simple program to read/write from/to a pci device from userspace.
+endef
+
+define Build/Configure
+endef
+
+define Package/regs/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/regs $(1)/usr/bin
+endef
+
+
+$(eval $(call BuildPackage,regs))
+
diff --git a/feed/regs/src/Makefile b/feed/regs/src/Makefile
new file mode 100644
index 0000000..bc3a12f
--- /dev/null
+++ b/feed/regs/src/Makefile
@@ -0,0 +1,13 @@
+EXEC = regs
+
+all: $(EXEC)
+
+$(EXEC): $(EXEC).c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $@.c $(LDLIBS)
+
+romfs:
+ $(ROMFSINST) /bin/$(EXEC)
+
+clean:
+ -rm -f $(EXEC) *.elf *.gdb *.o
+
diff --git a/feed/regs/src/regs.c b/feed/regs/src/regs.c
new file mode 100755
index 0000000..43397dd
--- /dev/null
+++ b/feed/regs/src/regs.c
@@ -0,0 +1,166 @@
+/*
+ * pcimem.c: Simple program to read/write from/to a pci device from userspace.
+ *
+ * Copyright (C) 2010, Bill Farrow (bfarrow@beyondelectronics.us)
+ *
+ * Based on the devmem2.c code
+ * Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#define PRINT_ERROR \
+ do { \
+ fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
+ __LINE__, __FILE__, errno, strerror(errno)); exit(1); \
+ } while(0)
+
+#define MAP_SIZE 4096UL
+#define MAP_MASK (MAP_SIZE - 1)
+
+void dump_page(uint32_t *vaddr, uint32_t *vbase, uint32_t *pbase)
+{
+ int i =0;
+ uint32_t *end = vaddr + (MAP_SIZE >> 6);
+ uint32_t *start = vaddr;
+
+ while(start < end) {
+ printf("%p:%08x %08x %08x %08x\n",
+ start - vbase + pbase, start[0], start[1] , start[2], start[3]);
+ start+=4;
+ }
+}
+
+void reg_mod_bits(uint32_t *virt_addr, int data, int start_bit, int data_len)
+{
+ int mask=0;
+ int value;
+ int i;
+
+ if ((start_bit < 0) || (start_bit > 31) ||
+ (data_len < 1) || (data_len > 32) ||
+ (start_bit + data_len > 32)) {
+ fprintf(stderr, "Startbit range[0~31], and DataLen range[1~32], and Startbit + DataLen <= 32\n");
+ return;
+ }
+
+ for (i = 0; i < data_len; i++)
+ mask |= 1 << (start_bit + i);
+
+ value = *((volatile uint32_t *) virt_addr);
+ value &= ~mask;
+ value |= (data << start_bit) & mask;;
+
+ *((uint32_t *) virt_addr) = value;
+
+ printf("Modify 0x%X[%d:%d]; ", data, start_bit + data_len - 1, start_bit);
+}
+
+void usage(void)
+{
+ fprintf(stderr, "\nUsage:\tregs [Type] [ Offset:Hex ] [ Data:Hex ] [StartBit:Dec] [DataLen:Dec]\n"
+ "\tType : access operation type : [m]odify, [w]wite, [d]ump\n"
+ "\tOffset : offset into memory region to act upon\n"
+ "\tData : data to be written\n"
+ "\tStartbit: Startbit of Addr that want to be modified. Range[0~31]\n"
+ "\tDataLen : Data length of Data. Range[1~32], and Startbit + DataLen <= 32\n\n"
+ "Example:\tRead/Write/Modify register \n"
+ "\tRead : regs d 0x1b100000 //dump 0x1b100000~0x1b1000f0 \n"
+ "\tWrite : regs w 0x1b100000 0x1234 //write 0x1b100000=0x1234\n"
+ "\tModify : regs m 0x1b100000 0x0 29 3 //modify 0x1b100000[29:31]=0\n");
+}
+
+int main(int argc, char **argv) {
+ int fd;
+ void *map_base = NULL;
+ void *virt_addr = NULL;
+ uint32_t read_result =0;
+ uint32_t writeval = 0;
+ uint32_t startbit = 0;
+ uint32_t datalen = 0;
+ char *filename = NULL;
+ off_t offset = 0;
+ int access_type = 0;
+
+ if(argc < 3) {
+ usage();
+ exit(1);
+ }
+
+ access_type = tolower(argv[1][0]);
+ if ((access_type == 'w' && argc < 4) || (access_type == 'm' && argc < 6)) {
+ usage();
+ exit(1);
+ }
+
+ filename = "/dev/mem";
+ if((fd = open(filename, O_RDWR | O_SYNC)) == -1)
+ PRINT_ERROR;
+
+ /* Map one page */
+ offset = strtoul(argv[2], NULL, 16);
+ map_base = mmap(0, 2*MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset & ~MAP_MASK);
+ if(map_base == (void *) -1)
+ PRINT_ERROR;
+
+ virt_addr = map_base + (offset & MAP_MASK);
+ read_result = *((volatile uint32_t *) virt_addr);
+ printf("Value at 0x%llX (%p): 0x%X\n",
+ (unsigned long long)offset, virt_addr, read_result);
+
+ switch(access_type) {
+ case 'm':
+ writeval = strtoul(argv[3], 0, 16);
+ startbit = strtoul(argv[4], 0, 10);
+ datalen = strtoul(argv[5], 0, 10);
+ reg_mod_bits((uint32_t *)virt_addr, writeval, startbit, datalen);
+ break;
+ case 'w':
+ writeval = strtoul(argv[3], 0, 16);
+ *((uint32_t *) virt_addr) = writeval;
+ printf("Written 0x%X; ", writeval);
+ break;
+ case 'd':
+ dump_page(virt_addr, map_base, (uint32_t *)(offset & ~MAP_MASK));
+ goto out;
+ default:
+ fprintf(stderr, "Illegal data type '%c'.\n", access_type);
+ goto out;
+ }
+
+ read_result = *((volatile uint32_t *) virt_addr);
+ printf("Readback 0x%X\n", read_result);
+
+out:
+ if(munmap(map_base, MAP_SIZE) == -1)
+ PRINT_ERROR;
+
+ close(fd);
+ return 0;
+}
diff --git a/feed/switch/Makefile b/feed/switch/Makefile
new file mode 100755
index 0000000..0eb3d7e
--- /dev/null
+++ b/feed/switch/Makefile
@@ -0,0 +1,48 @@
+#
+# hua.shao@mediatek.com
+#
+# MTK Property Software.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=switch
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/switch
+ SECTION:=MTK Properties
+ CATEGORY:=MTK Properties
+ DEPENDS:=+libnl-tiny
+ TITLE:=Command to config switch
+ SUBMENU:=Applications
+endef
+
+define Package/switch/description
+ An program to config switch.
+endef
+
+TARGET_CPPFLAGS := \
+ -D_GNU_SOURCE \
+ -I$(LINUX_DIR)/user_headers/include \
+ -I$(STAGING_DIR)/usr/include/libnl-tiny \
+ -I$(PKG_BUILD_DIR) \
+ $(TARGET_CPPFLAGS) \
+
+define Build/Compile
+ CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
+ $(MAKE) -C $(PKG_BUILD_DIR) \
+ $(TARGET_CONFIGURE_OPTS) \
+ LIBS="$(TARGET_LDFLAGS) -lnl-tiny -lm"
+endef
+
+define Package/switch/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_DIR) $(1)/lib/network
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/switch $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,switch))
diff --git a/feed/switch/src/Makefile b/feed/switch/src/Makefile
new file mode 100644
index 0000000..81ae127
--- /dev/null
+++ b/feed/switch/src/Makefile
@@ -0,0 +1,14 @@
+EXEC = switch
+
+SRC=switch_fun.c switch_753x.c switch_ioctl.c switch_netlink.c
+
+all: $(EXEC)
+
+switch: $(SRC)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(SRC) $(LDLIBS) $(LIBS)
+
+romfs:
+ $(ROMFSINST) /bin/switch
+
+clean:
+ -rm -f $(EXEC) *.elf *.gdb *.o
diff --git a/feed/switch/src/NOTICE b/feed/switch/src/NOTICE
new file mode 100644
index 0000000..c031eed
--- /dev/null
+++ b/feed/switch/src/NOTICE
@@ -0,0 +1,202 @@
+MediaTek (C) 2011
+
+The GNU General Public License (GPL)
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU
+General Public License is intended to guarantee your freedom to share and change free software--to make sure the
+software is free for all its users. This General Public License applies to most of the Free Software Foundation's
+software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is
+covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make
+sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you
+receive source code or can get it if you want it, that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to
+surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all
+the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them
+these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty
+for this free software. If the software is modified by someone else and passed on, we want its recipients to know that
+what they have is not the original, so that any problems introduced by others will not reflect on the original authors'
+reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors
+of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this,
+we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it
+may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or
+work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to
+say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into
+another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is
+addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its
+scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made by running the Program). Whether that is true
+depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided
+that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of
+warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other
+recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection
+in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and
+copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of
+these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any
+change.
+
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the
+Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this
+License.
+
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for
+such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright
+notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may
+redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if
+the Program itself is interactive but does not normally print such an announcement, your work based on the Program is
+not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the
+Program, and can be reasonably considered independent and separate works in themselves, then this License, and its
+terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same
+sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you;
+rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the
+Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the
+Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms
+of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than
+your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source
+code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange;
+or,
+
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This
+alternative is allowed only for noncommercial distribution and only if you received the program in object code or
+executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work,
+complete source code means all the source code for all modules it contains, plus any associated interface definition
+files, plus the scripts used to control compilation and installation of the executable. However, as a special exception,
+the source code distributed need not include anything that is normally distributed (in either source or binary form)
+with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless
+that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering
+equivalent access to copy the source code from the same place counts as distribution of the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your
+rights under this License. However, parties who have received copies, or rights, from you under this License will not
+have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you
+permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do
+not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you
+indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or
+modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a
+license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You
+may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not
+responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to
+patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the
+conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as
+to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence
+you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy
+both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the
+section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest
+validity of any such claims; this section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many people have made generous contributions to
+the wide range of software distributed through that system in reliance on consistent application of that system; it is
+up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee
+cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted
+interfaces, the original copyright holder who places the Program under this License may add an explicit geographical
+distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time.
+Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or
+concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which
+applies to it and "any later version", you have the option of following the terms and conditions either of that version
+or of any later version published by the Free Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are
+different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation,
+write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two
+goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of
+software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
+"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY
+WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT
+LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+
diff --git a/feed/switch/src/switch_753x.c b/feed/switch/src/switch_753x.c
new file mode 100644
index 0000000..d0e1fc2
--- /dev/null
+++ b/feed/switch/src/switch_753x.c
@@ -0,0 +1,682 @@
+/*
+ * switch_753x.c: set for 753x switch
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+
+#include "switch_netlink.h"
+#include "switch_ioctl.h"
+#include "switch_fun.h"
+
+struct mt753x_attr *attres;
+int chip_name;
+bool nl_init_flag;
+
+static void usage(char *cmd)
+{
+ printf("==================Usage===============================================================================================================================\n");
+
+ /* 1. basic operations */
+ printf("1) mt753x switch Basic operations=================================================================================================================>>>>\n");
+ printf(" 1.1) %s devs - list switch device id and model name \n", cmd);
+ printf(" 1.2) %s sysctl - show the ways to access kenerl driver: netlink or ioctl \n", cmd);
+ printf(" 1.3) %s reset - sw reset switch fsm and registers\n", cmd);
+ printf(" 1.4) %s reg r [offset] - read the reg with default switch \n", cmd);
+ printf(" 1.5) %s reg w [offset] [value] - write the reg with default switch \n", cmd);
+ printf(" 1.6) %s reg d [offset] - dump the reg with default switch\n", cmd);
+ printf(" 1.7) %s dev [devid] reg r [addr] - read the reg with the switch devid \n", cmd);
+ printf(" 1.8) %s dev [devid] reg w [addr] [value] - write the regs with the switch devid \n", cmd);
+ printf(" 1.9) %s dev [devid] reg d [addr] - dump the regs with the switch devid \n", cmd);
+ printf(" \n");
+
+ /* 2. phy operations */
+ printf("2) mt753x switch PHY operations===================================================================================================================>>>>\n");
+ printf(" 2.1) %s phy - dump all phy registers (clause 22)\n", cmd);
+ printf(" 2.2) %s phy [phy_addr] - dump phy register of specific port (clause 22)\n", cmd);
+ printf(" 2.3) %s phy cl22 r [port_num] [phy_reg] - read specific phy register of specific port by clause 22\n", cmd);
+ printf(" 2.4) %s phy cl22 w [port_num] [phy_reg] [value] - write specific phy register of specific port by clause 22\n", cmd);
+ printf(" 2.5) %s phy cl45 r [port_num] [dev_num] [phy_reg] - read specific phy register of specific port by clause 45\n", cmd);
+ printf(" 2.6) %s phy cl45 w [port_num] [dev_num] [phy_reg] [value] - write specific phy register of specific port by clause 45\n", cmd);
+ printf(" 2.7) %s phy fc [port_num] [enable 0|1] - set switch phy flow control, port is 0~4, enable is 1, disable is 0 \n", cmd);
+ printf(" 2.8) %s phy an [port_num] [enable 0|1] - set switch phy auto-negotiation, port is 0~4, enable is 1, disable is 0 \n", cmd);
+ printf(" 2.9) %s trreg r [port_num] [ch_addr] [node_addr] [data_addr] - read phy token-ring of specific port\n", cmd);
+ printf(" 2.10) %s trreg w [port_num] [ch_addr] [node_addr] [data_addr] - write phy token-ring of specific port\n", cmd);
+ printf(" [high_value] [low_value] \n");
+ printf(" 2.11) %s crossover [port_num] [mode auto|mdi|mdix] - switch auto or force mdi/mdix mode for crossover cable\n", cmd);
+ printf(" \n");
+
+ /* 3. mac operations */
+ printf("3) mt753x switch MAC operations====================================================================================================================>>>>\n");
+ printf(" 3.1) %s dump - dump switch mac table\n", cmd);
+ printf(" 3.2) %s clear - clear switch mac table\n", cmd);
+ printf(" 3.3) %s add [mac] [portmap] - add an entry (with portmap) to switch mac table\n", cmd);
+ printf(" 3.4) %s add [mac] [portmap] [vlan id] - add an entry (with portmap, vlan id) to switch mac table\n", cmd);
+ printf(" 3.5) %s add [mac] [portmap] [vlan id] [age] - add an entry (with portmap, vlan id, age out time) to switch mac table\n", cmd);
+ printf(" 3.6) %s del mac [mac] vid [vid] - delete an entry from switch mac table\n", cmd);
+ printf(" 3.7) %s del mac [mac] fid [fid] - delete an entry from switch mac table\n", cmd);
+ printf(" 3.8) %s search mac [mac] vid [vid] - search an entry with specific mac and vid\n", cmd);
+ printf(" 3.9) %s search mac [mac] fid [fid] - search an entry with specific mac and fid\n", cmd);
+ printf(" 3.10) %s filt [mac] - add a SA filtering entry (with portmap 1111111) to switch mac table\n", cmd);
+ printf(" 3.11) %s filt [mac] [portmap] - add a SA filtering entry (with portmap)to switch mac table\n", cmd);
+ printf(" 3.12) %s filt [mac] [portmap] [vlan id - add a SA filtering entry (with portmap, vlan id)to switch mac table\n", cmd);
+ printf(" 3.13) %s filt [mac] [portmap] [vlan id] [age] - add a SA filtering entry (with portmap, vlan id, age out time) to switch table\n", cmd);
+ printf(" 3.14) %s arl aging [active:0|1] [time:1~65536] - set switch arl aging timeout value \n", cmd);
+ printf(" 3.15) %s macctl fc [enable|disable] - set switch mac global flow control,enable is 1, disable is 0 \n", cmd);
+ printf(" \n");
+
+ /* 4. mib counter operations */
+ printf("4) mt753x switch mib counter operations============================================================================================================>>>>\n");
+ printf(" 4.1) %s esw_cnt get -get switch mib counters \n", cmd);
+ printf(" 4.2) %s esw_cnt clear -clear switch mib counters \n", cmd);
+ printf(" 4.3) %s output_queue_cnt get -get switch output queue counters \n", cmd);
+ printf(" 4.4) %s free_page get -get switch system free page counters \n", cmd);
+ printf(" \n");
+
+ /* 5. acl function operations */
+ printf("5) mt753x switch acl function operations============================================================================================================>>>>\n");
+ printf(" 5.1) %s acl enable [port] [port_enable:0|1] - set switch acl function enabled, port is 0~6,enable is 1, disable is 0 \n", cmd);
+ printf(" 5.2) %s acl etype add [ethtype] [portmap] - drop L2 ethertype packets \n", cmd);
+ printf(" 5.3) %s acl dmac add [mac] [portmap] - drop L2 dest-Mac packets \n", cmd);
+ printf(" 5.4) %s acl dip add [dip] [portmap] - drop dip packets \n", cmd);
+ printf(" 5.5) %s acl port add [sport] [portmap] - drop L4 UDP/TCP source port packets\n", cmd);
+ printf(" 5.6) %s acl L4 add [2byes] [portmap] - drop L4 packets with 2bytes payload\n", cmd);
+ printf(" 5.7) %s acl acltbl-add [tbl_idx:0~63/255] [vawd1] [vawd2] - set switch acl table new entry, max index-7530:63,7531:255 \n", cmd);
+ printf(" 5.8) %s acl masktbl-add [tbl_idx:0~31/127] [vawd1] [vawd2] - set switch acl mask table new entry, max index-7530:31,7531:127 \n", cmd);
+ printf(" 5.9) %s acl ruletbl-add [tbl_idx:0~31/127] [vawd1] [vawd2] - set switch acl rule table new entry, max index-7530:31,7531:127 \n", cmd);
+ printf(" 5.10) %s acl ratetbl-add [tbl_idx:0~31] [vawd1] [vawd2] - set switch acl rate table new entry \n", cmd);
+ printf(" 5.11) %s acl dip meter [dip] [portmap][meter:kbps] - rate limit dip packets \n", cmd);
+ printf(" 5.12) %s acl dip trtcm [dip] [portmap][CIR:kbps][CBS][PIR][PBS]- TrTCM dip packets \n", cmd);
+ printf(" 5.13) %s acl dip modup [dip] [portmap][usr_pri] - modify usr priority from ACL \n", cmd);
+ printf(" 5.14) %s acl dip pppoe [dip] [portmap] - pppoe header removal \n", cmd);
+ printf(" \n");
+
+ /* 6. dip table operations */
+ printf("6) mt753x switch dip table operations=================================================================================================================>>>>\n");
+ printf(" 6.1) %s dip dump - dump switch dip table\n", cmd);
+ printf(" 6.2) %s dip clear - clear switch dip table\n", cmd);
+ printf(" 6.3) %s dip add [dip] [portmap] - add a dip entry to switch table\n", cmd);
+ printf(" 6.4) %s dip del [dip] - del a dip entry to switch table\n", cmd);
+ printf(" \n");
+
+ /* 7. sip table operations */
+ printf("7) mt753x switch sip table operations=================================================================================================================>>>>\n");
+ printf(" 7.1) %s sip dump - dump switch sip table\n", cmd);
+ printf(" 7.2) %s sip clear - clear switch sip table\n", cmd);
+ printf(" 7.3) %s sip add [sip] [dip] [portmap] - add a sip entry to switch table\n", cmd);
+ printf(" 7.4) %s sip del [sip] [dip] - del a sip entry to switch table\n", cmd);
+ printf(" \n");
+
+ /* 8. vlan table operations */
+ printf("8) mt753x switch sip table operations====================================================================================================================>>>>\n");
+ printf(" 8.1) %s vlan dump (egtag) - dump switch vlan table (with per port eg_tag setting)\n", cmd);
+ printf(" 8.2) %s vlan set [fid:0~7] [vid] [portmap] - set vlan id and associated member at switch vlan table\n", cmd);
+ printf(" ([stag:0~4095] [eg_con:0|1] [egtagPortMap 0:untagged 2:tagged]) \n");
+ printf(" Full Example: %s vlan set 0 3 10000100 0 0 20000200\n", cmd);
+ printf(" 8.3) %s vlan vid [vlan idx] [active:0|1] [vid] [portMap] - set switch vlan vid elements \n", cmd);
+ printf(" [egtagPortMap] [ivl_en] [fid] [stag] \n");
+ printf(" 8.4) %s vlan pvid [port] [pvid] - set switch vlan pvid \n", cmd);
+ printf(" 8.5) %s vlan acc-frm [port] [acceptable_frame_type:0~3] - set switch vlan acceptable_frame type : admit all frames: 0, \n", cmd);
+ printf(" admit only vlan-taged frames: 1,admit only untagged or priority-tagged frames: 2, reserved:3 \n");
+ printf(" 8.6) %s vlan port-attr [port] [attr:0~3] - set switch vlan port attribute: user port: 0, statck port: 1, \n", cmd);
+ printf(" translation port: 2, transparent port:3 \n");
+ printf(" 8.7) %s vlan port-mode [port] [mode:0~3] - set switch vlan port mode : port matrix mode: 0, fallback mode: 1, \n", cmd);
+ printf(" check mode: 2, security mode:3 \n");
+ printf(" 8.8) %s vlan eg-tag-pvc [port] [eg_tag:0~7] - set switch vlan eg tag pvc : disable: 0, consistent: 1, reserved: 2, \n", cmd);
+ printf(" reserved:3,untagged:4,swap:5,tagged:6, stack:7 \n");
+ printf(" 8.9) %s vlan eg-tag-pcr [port] [eg_tag:0~3] - set switch vlan eg tag pcr : untagged: 0, swap: 1, tagged: 2, stack:3 \n", cmd);
+ printf(" \n");
+
+ /* 9. rate limit operations */
+ printf("9) mt753x switch rate limit operations=================================================================================================================>>>>\n");
+ printf(" 9.1) %s ratectl [in_ex_gress:0|1] [port] [rate] - set switch port ingress(1) or egress(0) rate \n", cmd);
+ printf(" 9.2) %s ingress-rate on [port] [Kbps] - set ingress rate limit on port n (n= 0~ switch max port) \n", cmd);
+ printf(" 9.3) %s egress-rate on [port] [Kbps] - set egress rate limit on port n (n= 0~ switch max port) \n", cmd);
+ printf(" 9.4) %s ingress-rate off [port] - disable ingress rate limit on port n (n= 0~ switch max port) \n", cmd);
+ printf(" 9.5) %s egress-rate off [port] - disable egress rate limit on port n (n= 0~ switch max port)\n", cmd);
+ printf(" \n");
+
+ /* 10. igmp operations */
+ printf("10) mt753x igmp operations===============================================================================================================================>>>>\n");
+ printf(" 10.1) %s igmpsnoop on [leaky_en] [wan_num] - turn on IGMP snoop and router port learning\n", cmd);
+ printf(" leaky_en: 1 or 0. default 0; wan_num: 0 or 4. default 4\n");
+ printf(" 10.2) %s igmpsnoop off - turn off IGMP snoop and router port learning\n", cmd);
+ printf(" 10.3) %s igmpsnoop enable [port#] - enable IGMP HW leave/join/Squery/Gquery\n", cmd);
+ printf(" 10.4) %s igmpsnoop disable [port#] - disable IGMP HW leave/join/Squery/Gquery\n", cmd);
+ printf(" \n");
+
+ /* 11. QoS operations */
+ printf("11) mt753x QoS operations================================================================================================================================>>>>\n");
+ printf(" 11.1) %s qos sch [port:0~6] [queue:0~7] [shaper:min|max] [type:rr:0|sp:1|wfq:2] - set switch qos sch type\n", cmd);
+ printf(" 11.2) %s qos base [port:0~6] [base] - set switch qos base(UPW); port-based:0, tag-based:1, \n", cmd);
+ printf(" dscp-based:2, acl-based:3, arl-based:4, stag-based:5 \n");
+ printf(" 11.3) %s qos port-weight [port:0~6] [q0] [q1][q2][q3] - set switch qos port queue weight; \n", cmd);
+ printf(" [q4][q5][q6][q7] [qn]: the weight of queue n, range: 1~16 \n");
+ printf(" 11.4) %s qos port-prio [port:0~6] [prio:0~7] - set switch port qos user priority; port is 0~6, priority is 0~7 \n", cmd);
+ printf(" 11.5) %s qos dscp-prio [dscp:0~63] [prio:0~7] - set switch qos dscp user priority; dscp is 0~63, priority is 0~7 \n", cmd);
+ printf(" 11.6) %s qos prio-qmap [port:0~6] [prio:0~7] [queue:0~7] - set switch qos priority queue map; priority is 0~7,queue is 0~7 \n", cmd);
+ printf(" \n");
+
+ /*12. port mirror operations*/
+ printf(" 12) mt753x port mirror operations========================================================================================================================>>>>\n");
+ printf(" 12.1) %s mirror monitor [port] - enable port mirror and indicate monitor port number\n", cmd);
+ printf(" 12.2) %s mirror target [port] - set port mirror target\n", cmd);
+ printf(" [direction| 0:off, 1:rx, 2:tx, 3:all] \n");
+ printf(" 12.3) %s mirror enable [mirror_en:0|1] [mirror_port: 0-6] - set switch mirror function enable(1) or disabled(0) for port 0~6 \n", cmd);
+ printf(" 12.4) %s mirror port-based [port] [port_tx_mir:0|1] - set switch mirror port: target tx/rx/acl/vlan/igmp\n", cmd);
+ printf(" [port_rx_mir:0|1] [acl_mir:0|1] \n");
+ printf(" [vlan_mis:0|1] [igmp_mir:0|1] \n");
+ printf(" \n");
+
+ /*13. stp function*/
+ printf(" 13) mt753x stp operations===============================================================================================================================>>>>\n");
+ printf(" 13.1) %s stp [port] [fid] [state] - set switch spanning tree state, port is 0~6, fid is 0~7, \n", cmd);
+ printf(" state is 0~3(Disable/Discarding:0,Blocking/Listening/Discarding:1,) \n");
+ printf(" Learning:2,Forwarding:3 \n");
+ printf(" \n");
+
+ /*14. collision pool operations*/
+ printf("14) mt753x collision pool operations========================================================================================================================>>>>\n");
+ printf(" 14.1) %s collision-pool enable [enable 0|1] - enable or disable collision pool\n", cmd);
+ printf(" 14.2) %s collision-pool mac dump - dump collision pool mac table\n", cmd);
+ printf(" 14.3) %s collision-pool dip dump - dump collision pool dip table\n", cmd);
+ printf(" 14.4) %s collision-pool sip dump - dump collision pool sip table\n", cmd);
+ printf(" \n");
+
+ /*15. pfc(priority flow control) operations*/
+ printf("15) mt753x pfc(priority flow control) operations==============================================================================================================>>>>\n");
+ printf(" 15.1) %s pfc enable [port] [enable 0|1] - enable or disable port's pfc \n", cmd);
+ printf(" 15.2) %s pfc rx_counter [port] - get port n pfc 8 up rx counter \n", cmd);
+ printf(" 15.3) %s pfc tx_counter [port] - get port n pfc 8 up rx counter \n", cmd);
+ printf(" \n");
+
+ /*15. pfc(priority flow control) operations*/
+ printf("16) mt753x EEE(802.3az) operations==============================================================================================================>>>>\n");
+ printf(" 16.1) %s eee enable [enable 0|1] ([portMap]) - enable or disable EEE (by portMap)\n", cmd);
+ printf(" 16.2) %s eee dump ([port]) - dump EEE capability (by port)\n", cmd);
+ printf(" \n");
+
+ exit_free();
+ exit(0);
+}
+
+static void parse_reg_cmd(int argc, char *argv[], int len)
+{
+ unsigned int val;
+ unsigned int off;
+ int i, j;
+
+ if (!strncmp(argv[len - 3], "reg", 4)) {
+ if (argv[len - 2][0] == 'r') {
+ off = strtoul(argv[len - 1], NULL, 16);
+ reg_read(off, &val);
+ printf(" Read reg=%x, value=%x\n", off, val);
+ } else if (argv[len - 2][0] == 'w') {
+ off = strtoul(argv[len - 1], NULL, 16);
+ if (argc != len + 1)
+ usage(argv[0]);
+ val = strtoul(argv[len], NULL, 16);
+ reg_write(off, val);
+ printf(" Write reg=%x, value=%x\n", off, val);
+ } else if (argv[len - 2][0] == 'd') {
+ off = strtoul(argv[len - 1], NULL, 16);
+ for (i = 0; i < 16; i++) {
+ printf("0x%08x: ", off + 0x10 * i);
+ for (j = 0; j < 4; j++) {
+ reg_read(off + i * 0x10 + j * 0x4, &val);
+ printf(" 0x%08x", val);
+ }
+ printf("\n");
+ }
+ } else
+ usage(argv[0]);
+ } else
+ usage(argv[0]);
+}
+
+static int get_chip_name()
+{
+ unsigned int temp;
+ /*judge 7530*/
+ reg_read((0x7ffc), &temp);
+ temp = temp >> 16;
+ if (temp == 0x7530)
+ return temp;
+ /*judge 7531*/
+ reg_read(0x781c, &temp);
+ temp = temp >> 16;
+ if (temp == 0x7531)
+ return temp;
+ return -1;
+}
+
+static int phy_operate(int argc, char *argv[])
+{
+ unsigned int port_num;
+ unsigned int dev_num;
+ unsigned int value;
+ unsigned int reg;
+ int ret = 0;
+ char op;
+
+ if (strncmp(argv[2], "cl22", 4) && strncmp(argv[2], "cl45", 4))
+ usage(argv[0]);
+
+ op = argv[3][0];
+
+ switch(op) {
+ case 'r':
+ reg = strtoul(argv[argc-1], NULL, 0);
+ if (argc == 6) {
+ port_num = strtoul(argv[argc-2], NULL, 0);
+ ret = mii_mgr_read(port_num, reg, &value);
+ if (ret < 0)
+ printf(" Phy read reg fail\n");
+ else
+ printf(" Phy read reg=0x%x, value=0x%x\n", reg, value);
+ } else if (argc == 7) {
+ dev_num = strtoul(argv[argc-2], NULL, 0);
+ port_num = strtoul(argv[argc-3], NULL, 0);
+ ret = mii_mgr_c45_read(port_num, dev_num, reg, &value);
+ if (ret < 0)
+ printf(" Phy read reg fail\n");
+ else
+ printf(" Phy read reg=0x%x, value=0x%x\n", reg, value);
+ } else
+ ret = phy_dump(32);
+ break;
+ case 'w':
+ reg = strtoul(argv[argc-2], NULL, 0);
+ value = strtoul(argv[argc-1], NULL, 0);
+ if (argc == 7) {
+ port_num = strtoul(argv[argc-3], NULL, 0);
+ ret = mii_mgr_write(port_num, reg, value);
+ }
+ else if (argc == 8) {
+ dev_num = strtoul(argv[argc-3], NULL, 0);
+ port_num = strtoul(argv[argc-4], NULL, 0);
+ ret = mii_mgr_c45_write(port_num, dev_num, reg, value);
+ }
+ else
+ usage(argv[0]);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int err;
+
+ attres = (struct mt753x_attr *)malloc(sizeof(struct mt753x_attr));
+ attres->dev_id = -1;
+ attres->port_num = -1;
+ attres->phy_dev = -1;
+ nl_init_flag = true;
+
+ err = mt753x_netlink_init(MT753X_DSA_GENL_NAME);
+ if (!err)
+ chip_name = get_chip_name();
+
+ /* dsa netlink family might not be enabled. Try gsw netlink family. */
+ if (err < 0 || chip_name < 0) {
+ err = mt753x_netlink_init(MT753X_GENL_NAME);
+ if (!err)
+ chip_name = get_chip_name();
+ }
+
+ if (err < 0 || chip_name < 0) {
+ nl_init_flag = false;
+
+ switch_ioctl_init();
+ chip_name = get_chip_name();
+ if (chip_name < 0) {
+ printf("no chip unsupport or chip id is invalid!\n");
+ exit_free();
+ exit(0);
+ }
+ }
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ if (!strcmp(argv[1], "dev")) {
+ attres->dev_id = strtoul(argv[2], NULL, 0);
+ argv += 2;
+ argc -= 2;
+ if (argc < 2)
+ usage(argv[0]);
+
+ }
+
+ if (argc == 2) {
+ if (!strcmp(argv[1], "devs")) {
+ attres->type = MT753X_ATTR_TYPE_MESG;
+ mt753x_list_swdev(attres, MT753X_CMD_REQUEST);
+ } else if (!strncmp(argv[1], "dump", 5)) {
+ table_dump();
+ } else if (!strncmp(argv[1], "clear", 6)) {
+ table_clear();
+ printf("done.\n");
+ } else if (!strncmp(argv[1], "reset", 5)) {
+ switch_reset(argc, argv);
+ } else if (!strncmp(argv[1], "phy", 4)) {
+ phy_dump(32); //dump all phy register
+ } else if (!strncmp(argv[1], "sysctl", 7)) {
+ if (nl_init_flag)
+ printf("netlink(%s)\n",MT753X_GENL_NAME);
+ else
+ printf("ioctl(%s)\n",ETH_DEVNAME);
+ } else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "arl", 4)) {
+ if (!strncmp(argv[2], "aging", 6))
+ doArlAging(argc, argv);
+ } else if (!strncmp(argv[1], "esw_cnt", 8)) {
+ if (!strncmp(argv[2], "get", 4))
+ read_mib_counters();
+ else if (!strncmp(argv[2], "clear", 6))
+ clear_mib_counters();
+ else
+ usage(argv[0]);
+ }else if (!strncmp(argv[1], "output_queue_cnt", 17)) {
+ if (!strncmp(argv[2], "get", 4))
+ read_output_queue_counters();
+ else
+ usage(argv[0]);
+ }else if (!strncmp(argv[1], "free_page", 10)) {
+ if (!strncmp(argv[2], "get", 4))
+ read_free_page_counters();
+ else
+ usage(argv[0]);
+ }
+ else if (!strncmp(argv[1], "ratectl", 8))
+ rate_control(argc, argv);
+ else if (!strncmp(argv[1], "add", 4))
+ table_add(argc, argv);
+ else if (!strncmp(argv[1], "filt", 5))
+ table_add(argc, argv);
+ else if (!strncmp(argv[1], "del", 4)) {
+ if (!strncmp(argv[4], "fid", 4))
+ table_del_fid(argc, argv);
+ else if (!strncmp(argv[4], "vid", 4))
+ table_del_vid(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "search", 7)) {
+ if (!strncmp(argv[4], "fid", 4))
+ table_search_mac_fid(argc, argv);
+ else if (!strncmp(argv[4], "vid", 4))
+ table_search_mac_vid(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "phy", 4)) {
+ if (argc == 3) {
+ int phy_addr = strtoul(argv[2], NULL, 0);
+ if (phy_addr < 0 || phy_addr > 31)
+ usage(argv[0]);
+ phy_dump(phy_addr);
+ } else if (argc == 5) {
+ if (!strncmp(argv[2], "fc", 2))
+ phy_set_fc(argc, argv);
+ else if (!strncmp(argv[2], "an", 2))
+ phy_set_an(argc, argv);
+ else
+ phy_dump(32);
+ } else
+ phy_operate(argc, argv);
+ } else if (!strncmp(argv[1], "trreg", 4)) {
+ if (rw_phy_token_ring(argc, argv) < 0)
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "macctl", 7)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "fc", 3))
+ global_set_mac_fc(argc, argv);
+ else if (!strncmp(argv[2], "pfc", 4))
+ set_mac_pfc(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "qos", 4)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "sch", 4))
+ qos_sch_select(argc, argv);
+ else if (!strncmp(argv[2], "base", 5))
+ qos_set_base(argc, argv);
+ else if (!strncmp(argv[2], "port-weight", 12))
+ qos_wfq_set_weight(argc, argv);
+ else if (!strncmp(argv[2], "port-prio", 10))
+ qos_set_portpri(argc, argv);
+ else if (!strncmp(argv[2], "dscp-prio", 10))
+ qos_set_dscppri(argc, argv);
+ else if (!strncmp(argv[2], "prio-qmap", 10))
+ qos_pri_mapping_queue(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "stp", 3)) {
+ if (argc < 3)
+ usage(argv[0]);
+ else
+ doStp(argc, argv);
+ } else if (!strncmp(argv[1], "sip", 5)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "dump", 5))
+ sip_dump();
+ else if (!strncmp(argv[2], "add", 4))
+ sip_add(argc, argv);
+ else if (!strncmp(argv[2], "del", 4))
+ sip_del(argc, argv);
+ else if (!strncmp(argv[2], "clear", 6))
+ sip_clear();
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "dip", 4)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "dump", 5))
+ dip_dump();
+ else if (!strncmp(argv[2], "add", 4))
+ dip_add(argc, argv);
+ else if (!strncmp(argv[2], "del", 4))
+ dip_del(argc, argv);
+ else if (!strncmp(argv[2], "clear", 6))
+ dip_clear();
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "mirror", 7)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "monitor", 8))
+ set_mirror_to(argc, argv);
+ else if (!strncmp(argv[2], "target", 7))
+ set_mirror_from(argc, argv);
+ else if (!strncmp(argv[2], "enable", 7))
+ doMirrorEn(argc, argv);
+ else if (!strncmp(argv[2], "port-based", 11))
+ doMirrorPortBased(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "acl", 4)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "dip", 4)) {
+ if (!strncmp(argv[3], "add", 4))
+ acl_dip_add(argc, argv);
+ else if (!strncmp(argv[3], "modup", 6))
+ acl_dip_modify(argc, argv);
+ else if (!strncmp(argv[3], "pppoe", 6))
+ acl_dip_pppoe(argc, argv);
+ else if (!strncmp(argv[3], "trtcm", 4))
+ acl_dip_trtcm(argc, argv);
+ else if (!strncmp(argv[3], "meter", 6))
+ acl_dip_meter(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "dmac", 6)) {
+ if (!strncmp(argv[3], "add", 4))
+ acl_mac_add(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "etype", 6)) {
+ if (!strncmp(argv[3], "add", 4))
+ acl_ethertype(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "port", 5)) {
+ if (!strncmp(argv[3], "add", 4))
+ acl_sp_add(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "L4", 5)) {
+ if (!strncmp(argv[3], "add", 4))
+ acl_l4_add(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "enable", 7))
+ acl_port_enable(argc, argv);
+ else if (!strncmp(argv[2], "acltbl-add", 11))
+ acl_table_add(argc, argv);
+ else if (!strncmp(argv[2], "masktbl-add", 12))
+ acl_mask_table_add(argc, argv);
+ else if (!strncmp(argv[2], "ruletbl-add", 12))
+ acl_rule_table_add(argc, argv);
+ else if (!strncmp(argv[2], "ratetbl-add", 12))
+ acl_rate_table_add(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "vlan", 5)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "dump", 5))
+ vlan_dump(argc, argv);
+ else if (!strncmp(argv[2], "set", 4))
+ vlan_set(argc, argv);
+ else if (!strncmp(argv[2], "clear", 6))
+ vlan_clear(argc, argv);
+ else if (!strncmp(argv[2], "vid", 4))
+ doVlanSetVid(argc, argv);
+ else if (!strncmp(argv[2], "pvid", 5))
+ doVlanSetPvid(argc, argv);
+ else if (!strncmp(argv[2], "acc-frm", 8))
+ doVlanSetAccFrm(argc, argv);
+ else if (!strncmp(argv[2], "port-attr", 10))
+ doVlanSetPortAttr(argc, argv);
+ else if (!strncmp(argv[2], "port-mode", 10))
+ doVlanSetPortMode(argc, argv);
+ else if (!strncmp(argv[2], "eg-tag-pcr", 11))
+ doVlanSetEgressTagPCR(argc, argv);
+ else if (!strncmp(argv[2], "eg-tag-pvc", 11))
+ doVlanSetEgressTagPVC(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "reg", 4)) {
+ parse_reg_cmd(argc, argv, 4);
+ } else if (!strncmp(argv[1], "ingress-rate", 6)) {
+ int port = 0, bw = 0;
+ if (argv[2][1] == 'n') {
+ port = strtoul(argv[3], NULL, 0);
+ bw = strtoul(argv[4], NULL, 0);
+ if (ingress_rate_set(1, port, bw) == 0)
+ printf("switch port=%d, bw=%d\n", port, bw);
+ }
+ else if (argv[2][1] == 'f') {
+ if (argc != 4)
+ usage(argv[0]);
+ port = strtoul(argv[3], NULL, 0);
+ if (ingress_rate_set(0, port, bw) == 0)
+ printf("switch port=%d ingress rate limit off\n", port);
+ } else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "egress-rate", 6)) {
+ int port = 0, bw = 0;
+ if (argv[2][1] == 'n') {
+ port = strtoul(argv[3], NULL, 0);
+ bw = strtoul(argv[4], NULL, 0);
+ if (egress_rate_set(1, port, bw) == 0)
+ printf("switch port=%d, bw=%d\n", port, bw);
+ } else if (argv[2][1] == 'f') {
+ if (argc != 4)
+ usage(argv[0]);
+ port = strtoul(argv[3], NULL, 0);
+ if (egress_rate_set(0, port, bw) == 0)
+ printf("switch port=%d egress rate limit off\n", port);
+ } else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "igmpsnoop", 10)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "on", 3))
+ igmp_on(argc, argv);
+ else if (!strncmp(argv[2], "off", 4))
+ igmp_off();
+ else if (!strncmp(argv[2], "enable", 7))
+ igmp_enable(argc, argv);
+ else if (!strncmp(argv[2], "disable", 8))
+ igmp_disable(argc, argv);
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "collision-pool", 15)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "enable", 7))
+ collision_pool_enable(argc, argv);
+ else if (!strncmp(argv[2], "mac", 4)){
+ if (!strncmp(argv[3], "dump", 5))
+ collision_pool_mac_dump();
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "dip", 4)){
+ if (!strncmp(argv[3], "dump", 5))
+ collision_pool_dip_dump();
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[2], "sip", 4)){
+ if (!strncmp(argv[3], "dump", 5))
+ collision_pool_sip_dump();
+ else
+ usage(argv[0]);
+ }
+ else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "pfc", 15)) {
+ if (argc < 4 || argc > 5)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "enable", 7))
+ set_mac_pfc(argc, argv);
+ else if (!strncmp(argv[2], "rx_counter", 11)){
+ pfc_get_rx_counter(argc, argv);
+ } else if (!strncmp(argv[2], "tx_counter", 11)){
+ pfc_get_tx_counter(argc, argv);
+ } else
+ usage(argv[0]);
+ } else if (!strncmp(argv[1], "crossover", 10)) {
+ if (argc < 4)
+ usage(argv[0]);
+ else
+ phy_crossover(argc, argv);
+ } else if (!strncmp(argv[1], "eee", 4)) {
+ if (argc < 3)
+ usage(argv[0]);
+ if (!strncmp(argv[2], "enable", 7) ||
+ !strncmp(argv[2], "disable", 8))
+ eee_enable(argc, argv);
+ else if (!strncmp(argv[2], "dump", 5))
+ eee_dump(argc, argv);
+ else
+ usage(argv[0]);
+ } else
+ usage(argv[0]);
+
+ exit_free();
+ return 0;
+}
diff --git a/feed/switch/src/switch_extend.h b/feed/switch/src/switch_extend.h
new file mode 100644
index 0000000..c352767
--- /dev/null
+++ b/feed/switch/src/switch_extend.h
@@ -0,0 +1,342 @@
+#define atoi(x) strtoul(x, NULL,10)
+
+#define EXTEND_SETVID_PARAM 1
+#define SQA_VERIFY 1
+#define ETHCMD_DBG 1
+#define ACTIVED (1<<0)
+#define SWITCH_MAX_PORT 7
+
+#define GENERAL_TABLE 0
+#define COLLISION_TABLE 1
+
+#define GSW_BASE 0x0
+#define GSW_ARL_BASE (GSW_BASE + 0x0000)
+#define GSW_BMU_BASE (GSW_BASE + 0x1000)
+#define GSW_PORT_BASE (GSW_BASE + 0x2000)
+#define GSW_MAC_BASE (GSW_BASE + 0x3000)
+#define GSW_MIB_BASE (GSW_BASE + 0x4000)
+#define GSW_CFG_BASE (GSW_BASE + 0x7000)
+
+#define GSW_PCR(n) (GSW_PORT_BASE + (n)*0x100 + 0x04)
+#define GSW_MFC (GSW_ARL_BASE + 0x10)
+#define GSW_UPW(n) (GSW_PORT_BASE + (n)*0x100 + 0x40)
+//#define GSW_PEM(n) (GSW_ARL_BASE + (n)*0x4 + 0x48)
+#define GSW_PEM(n) (GSW_PORT_BASE + (n)*0x4 + 0x44)
+
+#define GSW_MMSCR0_Q(n) (GSW_BMU_BASE + (n)*0x8)
+#define GSW_MMSCR1_Q(n) (GSW_BMU_BASE + (n)*0x8 + 0x04)
+
+#define GSW_PMCR(n) (GSW_MAC_BASE + (n)*0x100)
+#define GSW_PMSR(n) (GSW_MAC_BASE + (n)*0x100 + 0x08)
+#define GSW_PINT_EN(n) (GSW_MAC_BASE + (n)*0x100 + 0x10)
+#define GSW_SMACCR0 (GSW_MAC_BASE + 0xe4)
+#define GSW_SMACCR1 (GSW_MAC_BASE + 0xe8)
+#define GSW_CKGCR (GSW_MAC_BASE + 0xf0)
+
+#define GSW_ESR(n) (GSW_MIB_BASE + (n)*0x100 + 0x00)
+#define GSW_INTS(n) (GSW_MIB_BASE + (n)*0x100 + 0x04)
+#define GSW_TGPC(n) (GSW_MIB_BASE + (n)*0x100 + 0x10)
+#define GSW_TBOC(n) (GSW_MIB_BASE + (n)*0x100 + 0x14)
+#define GSW_TGOC(n) (GSW_MIB_BASE + (n)*0x100 + 0x18)
+#define GSW_TEPC(n) (GSW_MIB_BASE + (n)*0x100 + 0x1C)
+#define GSW_RGPC(n) (GSW_MIB_BASE + (n)*0x100 + 0x20)
+#define GSW_RBOC(n) (GSW_MIB_BASE + (n)*0x100 + 0x24)
+#define GSW_RGOC(n) (GSW_MIB_BASE + (n)*0x100 + 0x28)
+#define GSW_REPC1(n) (GSW_MIB_BASE + (n)*0x100 + 0x2C)
+#define GSW_REPC2(n) (GSW_MIB_BASE + (n)*0x100 + 0x30)
+#define GSW_MIBCNTEN (GSW_MIB_BASE + 0x800)
+#define GSW_AECNT1 (GSW_MIB_BASE + 0x804)
+#define GSW_AECNT2 (GSW_MIB_BASE + 0x808)
+
+#define GSW_CFG_PPSC (GSW_CFG_BASE + 0x0)
+#define GSW_CFG_PIAC (GSW_CFG_BASE + 0x4)
+#define GSW_CFG_GPC (GSW_CFG_BASE + 0x14)
+
+#define MAX_VID_VALUE (4095)
+#define MAX_VLAN_RULE (16)
+
+
+#define REG_MFC_ADDR (0x0010)
+#define REG_ISC_ADDR (0x0018)
+
+#define REG_CFC_ADDR (0x0004)
+#define REG_CFC_MIRROR_PORT_OFFT (16)
+#define REG_CFC_MIRROR_PORT_LENG (3)
+#define REG_CFC_MIRROR_PORT_RELMASK (0x00000007)
+#define REG_CFC_MIRROR_PORT_MASK (REG_CFC_MIRROR_PORT_RELMASK << REG_CFC_MIRROR_PORT_OFFT)
+#define REG_CFC_MIRROR_EN_OFFT (19)
+#define REG_CFC_MIRROR_EN_LENG (1)
+#define REG_CFC_MIRROR_EN_RELMASK (0x00000001)
+#define REG_CFC_MIRROR_EN_MASK (REG_CFC_MIRROR_EN_RELMASK << REG_CFC_MIRROR_EN_OFFT)
+
+#define REG_ATA1_ADDR (0x0074)
+#define REG_ATA2_ADDR (0x0078)
+
+#define REG_ATWD_ADDR (0x007C)
+#define REG_ATWD_STATUS_OFFT (2)
+#define REG_ATWD_STATUS_LENG (2)
+#define REG_ATWD_STATUS_RELMASK (0x00000003)
+#define REG_ATWD_STATUS_MASK (REG_ATWD_STATUS_RELMASK << REG_ATWD_STATUS_OFFT)
+#define REG_ATWD_PORT_OFFT (4)
+#define REG_ATWD_PORT_LENG (8)
+#define REG_ATWD_PORT_RELMASK (0x000000FF)
+#define REG_ATWD_PORT_MASK (REG_ATWD_PORT_RELMASK << REG_ATWD_PORT_OFFT)
+#define REG_ATWD_LEAKY_EN_OFFT (12)
+#define REG_ATWD_LEAKY_EN_LENG (1)
+#define REG_ATWD_LEAKY_EN_RELMASK (0x00000001)
+#define REG_ATWD_LEAKY_EN_MASK (REG_ATWD_LEAKY_EN_RELMASK << REG_ATWD_LEAKY_EN_OFFT)
+#define REG_ATWD_EG_TAG_OFFT (13)
+#define REG_ATWD_EG_TAG_LENG (3)
+#define REG_ATWD_EG_TAG_RELMASK (0x00000007)
+#define REG_ATWD_EG_TAG_MASK (REG_ATWD_EG_TAG_RELMASK << REG_ATWD_EG_TAG_OFFT)
+#define REG_ATWD_USR_PRI_OFFT (16)
+#define REG_ATWD_USR_PRI_LENG (3)
+#define REG_ATWD_USR_PRI_RELMASK (0x00000007)
+#define REG_ATWD_USR_PRI_MASK (REG_ATWD_USR_PRI_RELMASK << REG_ATWD_USR_PRI_OFFT)
+#define REG_ATWD_SA_MIR_EN_OFFT (19)
+#define REG_ATWD_SA_MIR_EN_LENG (1)
+#define REG_ATWD_SA_MIR_EN_RELMASK (0x00000001)
+#define REG_ATWD_SA_MIR_EN_MASK (REG_ATWD_SA_MIR_EN_RELMASK << REG_ATWD_SA_MIR_EN_OFFT)
+#define REG_ATWD_SA_PORT_FW_OFFT (20)
+#define REG_ATWD_SA_PORT_FW_LENG (3)
+#define REG_ATWD_SA_PORT_FW_RELMASK (0x00000007)
+#define REG_ATWD_SA_PORT_FW_MASK (REG_ATWD_SA_PORT_FW_RELMASK << REG_ATWD_SA_PORT_FW_OFFT)
+
+#define REG_ATC_ADDR (0x0080)
+#define REG_ATC_AC_CMD_OFFT (0)
+#define REG_ATC_AC_CMD_LENG (3)
+#define REG_ATC_AC_CMD_RELMASK (0x00000007)
+#define REG_ATC_AC_CMD_MASK (REG_ATC_AC_CMD_RELMASK << REG_ATC_AC_CMD_OFFT)
+#define REG_ATC_AC_SAT_OFFT (4)
+#define REG_ATC_AC_SAT_LENG (2)
+#define REG_ATC_AC_SAT_RELMASK (0x00000003)
+#define REG_ATC_AC_SAT_MASK (REG_ATC_AC_SAT_RELMASK << REG_ATC_AC_SAT_OFFT)
+#define REG_ATC_AC_MAT_OFFT (8)
+#define REG_ATC_AC_MAT_LENG (4)
+#define REG_ATC_AC_MAT_RELMASK (0x0000000F)
+#define REG_ATC_AC_MAT_MASK (REG_ATC_AC_MAT_RELMASK << REG_ATC_AC_MAT_OFFT)
+#define REG_AT_SRCH_HIT_OFFT (13)
+#define REG_AT_SRCH_HIT_RELMASK (0x00000001)
+#define REG_AT_SRCH_HIT_MASK (REG_AT_SRCH_HIT_RELMASK << REG_AT_SRCH_HIT_OFFT)
+#define REG_AT_SRCH_END_OFFT (14)
+#define REG_AT_SRCH_END_RELMASK (0x00000001)
+#define REG_AT_SRCH_END_MASK (REG_AT_SRCH_END_RELMASK << REG_AT_SRCH_END_OFFT)
+#define REG_ATC_BUSY_OFFT (15)
+#define REG_ATC_BUSY_LENG (1)
+#define REG_ATC_BUSY_RELMASK (0x00000001)
+#define REG_ATC_BUSY_MASK (REG_ATC_BUSY_RELMASK << REG_ATC_BUSY_OFFT)
+#define REG_AT_ADDR_OFFT (16)
+#define REG_AT_ADDR_LENG (12)
+#define REG_AT_ADDR_RELMASK (0x00000FFF)
+#define REG_AT_ADDR_MASK (REG_AT_ADDR_RELMASK << REG_AT_ADDR_OFFT)
+
+#define REG_TSRA1_ADDR (0x0084)
+#define REG_TSRA2_ADDR (0x0088)
+#define REG_ATRD_ADDR (0x008C)
+
+#define REG_VTCR_ADDR (0x0090)
+#define REG_VTCR_VID_OFFT (0)
+#define REG_VTCR_VID_LENG (12)
+#define REG_VTCR_VID_RELMASK (0x00000FFF)
+#define REG_VTCR_VID_MASK (REG_VTCR_VID_RELMASK << REG_VTCR_VID_OFFT)
+#define REG_VTCR_FUNC_OFFT (12)
+#define REG_VTCR_FUNC_LENG (4)
+#define REG_VTCR_FUNC_RELMASK (0x0000000F)
+#define REG_VTCR_FUNC_MASK (REG_VTCR_FUNC_RELMASK << REG_VTCR_FUNC_OFFT)
+#define REG_VTCR_IDX_INVLD_OFFT (16)
+#define REG_VTCR_IDX_INVLD_RELMASK (0x00000001)
+#define REG_VTCR_IDX_INVLD_MASK (REG_VTCR_IDX_INVLD_RELMASK << REG_VTCR_IDX_INVLD_OFFT)
+#define REG_VTCR_BUSY_OFFT (31)
+#define REG_VTCR_BUSY_RELMASK (0x00000001)
+#define REG_VTCR_BUSY_MASK (REG_VTCR_BUSY_RELMASK << REG_VTCR_BUSY_OFFT)
+
+#define REG_VAWD1_ADDR (0x0094)
+#define REG_VAWD2_ADDR (0x0098)
+#define REG_VLAN_ID_BASE (0x0100)
+
+#define REG_CPGC_ADDR (0xB0)
+#define REG_CPCG_COL_EN_OFFT (0)
+#define REG_CPCG_COL_EN_RELMASK (0x00000001)
+#define REG_CPCG_COL_EN_MASK (REG_CPCG_COL_EN_RELMASK << REG_CPCG_COL_EN_OFFT)
+#define REG_CPCG_COL_CLK_EN_OFFT (1)
+#define REG_CPCG_COL_CLK_EN_RELMASK (0x00000001)
+#define REG_CPCG_COL_CLK_EN_MASK (REG_CPCG_COL_CLK_EN_RELMASK << REG_CPCG_COL_CLK_EN_OFFT)
+#define REG_CPCG_COL_RST_N_OFFT (2)
+#define REG_CPCG_COL_RST_N_RELMASK (0x00000001)
+#define REG_CPCG_COL_RST_N_MASK (REG_CPCG_COL_RST_N_RELMASK << REG_CPCG_COL_RST_N_OFFT)
+
+#define REG_GFCCR0_ADDR (0x1FE0)
+#define REG_FC_EN_OFFT (31)
+#define REG_FC_EN_RELMASK (0x00000001)
+#define REG_FC_EN_MASK (REG_FC_EN_RELMASK << REG_FC_EN_OFFT)
+
+#define REG_PFC_CTRL_ADDR (0x30b0)
+#define PFC_RX_COUNTER_L(n) (0x3030 + (n)*0x100)
+#define PFC_RX_COUNTER_H(n) (0x3034 + (n)*0x100)
+#define PFC_TX_COUNTER_L(n) (0x3040 + (n)*0x100)
+#define PFC_TX_COUNTER_H(n) (0x3044 + (n)*0x100)
+#define PMSR_P(n) (0x3008 + (n)*0x100)
+
+
+#define REG_SSC_P0_ADDR (0x2000)
+
+#define REG_PCR_P0_ADDR (0x2004)
+#define REG_PCR_VLAN_MIS_OFFT (2)
+#define REG_PCR_VLAN_MIS_LENG (1)
+#define REG_PCR_VLAN_MIS_RELMASK (0x00000001)
+#define REG_PCR_VLAN_MIS_MASK (REG_PCR_VLAN_MIS_RELMASK << REG_PCR_VLAN_MIS_OFFT)
+#define REG_PCR_ACL_MIR_OFFT (7)
+#define REG_PCR_ACL_MIR_LENG (1)
+#define REG_PCR_ACL_MIR_RELMASK (0x00000001)
+#define REG_PCR_ACL_MIR_MASK (REG_PCR_ACL_MIR_RELMASK << REG_PCR_ACL_MIR_OFFT)
+#define REG_PORT_RX_MIR_OFFT (8)
+#define REG_PORT_RX_MIR_LENG (1)
+#define REG_PORT_RX_MIR_RELMASK (0x00000001)
+#define REG_PORT_RX_MIR_MASK (REG_PORT_RX_MIR_RELMASK << REG_PORT_RX_MIR_OFFT)
+#define REG_PORT_TX_MIR_OFFT (9)
+#define REG_PORT_TX_MIR_LENG (1)
+#define REG_PORT_TX_MIR_RELMASK (0x00000001)
+#define REG_PORT_TX_MIR_MASK (REG_PORT_TX_MIR_RELMASK << REG_PORT_TX_MIR_OFFT)
+#define REG_PORT_ACL_EN_OFFT (10)
+#define REG_PORT_ACL_EN_LENG (1)
+#define REG_PORT_ACL_EN_RELMASK (0x00000001)
+#define REG_PORT_ACL_EN_MASK (REG_PORT_ACL_EN_RELMASK << REG_PORT_ACL_EN_OFFT)
+#define REG_PCR_EG_TAG_OFFT (28)
+#define REG_PCR_EG_TAG_LENG (2)
+#define REG_PCR_EG_TAG_RELMASK (0x00000003)
+#define REG_PCR_EG_TAG_MASK (REG_PCR_EG_TAG_RELMASK << REG_PCR_EG_TAG_OFFT)
+
+#define REG_PIC_P0_ADDR (0x2008)
+#define REG_PIC_IGMP_MIR_OFFT (19)
+#define REG_PIC_IGMP_MIR_LENG (1)
+#define REG_PIC_IGMP_MIR_RELMASK (0x00000001)
+#define REG_PIC_IGMP_MIR_MASK (REG_PIC_IGMP_MIR_RELMASK << REG_PIC_IGMP_MIR_OFFT)
+
+#define REG_PSC_P0_ADDR (0x200C)
+
+#define REG_PVC_P0_ADDR (0x2010)
+#define REG_PVC_ACC_FRM_OFFT (0)
+#define REG_PVC_ACC_FRM_LENG (2)
+#define REG_PVC_ACC_FRM_RELMASK (0x00000003)
+#define REG_PVC_ACC_FRM_MASK (REG_PVC_ACC_FRM_RELMASK << REG_PVC_ACC_FRM_OFFT)
+#define REG_PVC_EG_TAG_OFFT (8)
+#define REG_PVC_EG_TAG_LENG (3)
+#define REG_PVC_EG_TAG_RELMASK (0x00000007)
+#define REG_PVC_EG_TAG_MASK (REG_PVC_EG_TAG_RELMASK << REG_PVC_EG_TAG_OFFT)
+
+#define REG_PPBV1_P0_ADDR (0x2014)
+#define REG_PPBV2_P0_ADDR (0x2018)
+#define REG_BSR_P0_ADDR (0x201C)
+#define REG_STAG01_P0_ADDR (0x2020)
+#define REG_STAG23_P0_ADDR (0x2024)
+#define REG_STAG45_P0_ADDR (0x2028)
+#define REG_STAG67_P0_ADDR (0x202C)
+
+#define REG_CMACCR_ADDR (0x30E0)
+#define REG_MTCC_LMT_OFFT (9)
+#define REG_MTCC_LMT_LENG (4)
+#define REG_MTCC_LMT_RELMASK (0x0000000F)
+#define REG_MTCC_LMT_MASK (REG_MTCC_LMT_RELMASK << REG_MTCC_LMT_OFFT)
+
+#define ETHCMD_ENABLE "enable"
+#define ETHCMD_DISABLE "disable"
+
+#define HELP_VLAN_PVID "vlan pvid <port> <pvid>"
+
+#if defined(EXTEND_SETVID_PARAM) || defined(SQA_VERIFY)
+#define HELP_VLAN_VID "vlan vid <index> <active:0|1> <vid> <portMap> <egtagPortMap>\n" \
+ " <ivl_en> <fid> <stag>\n"
+#else
+#define HELP_VLAN_VID "vlan vid <index> <active:0|1> <vid> <portMap> <tagPortMap>\n"
+#endif //SQA_VERIFY
+
+//#if defined(SQA_VERIFY)
+
+#define MT7530_UPW_REG_UPDATE 1
+
+#define HELP_QOS_TYPE "qos type <rr:0|sp:1|wfq:2>\n"
+#ifdef MT7530_UPW_REG_UPDATE
+#define HELP_QOS_BASE "qos base <port-based:0|tag-based:1|dscp-based:2|acl-based:3|arl-based:4|stag-based:5>\n"
+#else
+#define HELP_QOS_BASE "qos base <port-based:0|tag-based:1|dscp-based:2|acl-based:3|arl-based:4>\n"
+#endif
+#define HELP_QOS_PRIO_QMAP "qos prio-qmap <prio:0~7> <queue:0~7>\n"
+#define HELP_QOS_PRIO_TAGMAP "qos prio-tagmap <prio:0~7> <tag:0~7>\n"
+#define HELP_QOS_PRIO_DSCPMAP "qos prio-dscpmap <prio:0~7> <dscp:0~63>\n"
+//#define HELP_QOS_VPRI_QMAP "qos vprio-qmap <prio:0~7> <queue:0~7>\n"
+#define HELP_QOS_PORT_PRIO "qos port-prio <port> <prio:0~7>\n"
+#define HELP_QOS_PORT_WEIGHT "qos port-weight <port:0~7> <q0> <q1> <q2> <q3> <q4> <q5> <q6> <q7>\n" \
+ " <qn>: the weight of queue n, range: 1~16\n"
+#define HELP_QOS_DSCP_PRIO "qos dscp-prio <dscp:0~63> <prio:0~7> : for ingress\n"
+
+#define HELP_ARL_L2LEN_CHK "arl l2len-chk <active:0|1>\n"
+
+#define HELP_ARL_AGING "arl aging <active:0|1> <time:1~65536>\n"
+
+#define HELP_ARL_MAC_TBL_ADD "arl mactbl-add <MacAddr> <DestPortMap>\n"\
+ " ** optional : <leaky_en:0|1> <eg_tag:0~7> <usr_pri:0~7> <sa_mir_en:0|1> <sa_port_fw:0~7>\n"
+
+#define HELP_ARL_DIP_TBL_ADD "arl diptbl-add <DIP> <DestPortMap> <leaky_en:0|1> <eg_tag:0~7> <usr_pri:0~7> <status:0~3>\n"
+
+#define HELP_ARL_SIP_TBL_ADD "arl siptbl-add <DIP> <SIP> <DestPortMap> <status:0~3>\n"
+
+#define HELP_ACL_SETPORTEN "acl enable <port> <port_enable:0|1>\n"
+#define HELP_ACL_ACL_TBL_ADD "arl acltbl-add <tbl_idx:0~63/255> <vawd1> <vawd2>\n"
+#define HELP_ACL_MASK_TBL_ADD "arl masktbl-add <tbl_idx:0~31/127> <vawd1> <vawd2>\n"
+#define HELP_ACL_RULE_TBL_ADD "arl ruletbl-add <tbl_idx:0~31/127> <vawd1> <vawd2>\n"
+#define HELP_ACL_RATE_TBL_ADD "arl ratetbl-add <tbl_idx:0~31> <vawd1> <vawd2>\n"
+#define HELP_ACL_TRTCM_TBL_ADD "arl trTCMtbl-add <tbl_idx:0~31> <vawd1> <vawd2>\n"
+
+
+#define HELP_VLAN_PORT_MODE "vlan port-mode <port> <mode:0~3>\n" \
+ "<mode>: 0: port matrix mode\n" \
+ " 1: fallback mode\n" \
+ " 2: check mode\n" \
+ " 3: security mode\n"\
+
+#define HELP_VLAN_PORT_ATTR "vlan port-attr <port> <attr:0~3>\n" \
+ "<attr>: 0: user port\n" \
+ " 1: statck port\n" \
+ " 2: translation port\n" \
+ " 3: transparent port\n"
+
+#define HELP_VLAN_EGRESS_TAG_PVC "vlan eg-tag-pvc <port> <eg_tag:0~7>\n" \
+ "<eg_tag>: 0: disable\n" \
+ " 1: consistent\n" \
+ " 2: reserved\n" \
+ " 3: reserved\n" \
+ " 4: untagged\n" \
+ " 5: swap\n" \
+ " 6: tagged\n" \
+ " 7: stack\n"
+
+#define HELP_VLAN_EGRESS_TAG_PCR "vlan eg-tag-pcr <port> <eg_tag:0~3>\n" \
+ "<eg_tag>: 0: untagged\n" \
+ " 1: swap\n" \
+ " 2: tagged\n" \
+ " 3: stack\n"
+
+#define HELP_VLAN_ACC_FRM "vlan acc-frm <port> <acceptable_frame_type:0~3>\n" \
+ "<type>: 0: admit all frames\n" \
+ " 1: admit only vlan-taged frames\n" \
+ " 2: admit only untagged or priority-tagged frames\n" \
+ " 3: reserved\n"
+
+
+#define HELP_SWITCH_RESET "switch software reset\n"
+#define HELP_MACCTL_FC "macctl fc <enable:0|1>\n"
+#define HELP_MIRROR_EN "mirror enable <mirror_en:0|1> <mirror_port: 0-6>\n"
+#define HELP_MIRROR_PORTBASED "mirror port-based <port> <port_tx_mir:0|1> <port_rx_mir:0|1> <acl_mir:0|1> <vlan_mis:0|1> <igmp_mir:0|1>\n"
+
+#define HELP_PHY_AN_EN "phyctl an <port> <auto_negotiation_en:0|1>\n"
+#define HELP_PHY_FC_EN "phyctl fc <port> <full_duplex_pause_capable:0|1>\n"
+
+#define HELP_STP "stp <port> <fid> <state>\n" \
+ "<state>: 0: Disable/Discarding\n" \
+ " 1: Blocking/Listening/Discarding\n" \
+ " 2: Learning\n" \
+ " 3: Forwarding\n"
+#define HELP_COLLISION_POOL_EN "collision-pool enable [enable 0|1] \n"
+#define HELP_EEE_EN "eee [enable|disable] ([port|portMap]) \n"
+
+//#endif //SQA_VERIFY
diff --git a/feed/switch/src/switch_fun.c b/feed/switch/src/switch_fun.c
new file mode 100755
index 0000000..aefb927
--- /dev/null
+++ b/feed/switch/src/switch_fun.c
@@ -0,0 +1,3753 @@
+/*
+* switch_fun.c: switch function sets
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "switch_extend.h"
+#include "switch_netlink.h"
+#include "switch_ioctl.h"
+#include "switch_fun.h"
+
+#define leaky_bucket 0
+
+static int getnext(char *src, int separator, char *dest)
+{
+ char *c;
+ int len;
+
+ if ((src == NULL) || (dest == NULL))
+ return -1;
+
+ c = strchr(src, separator);
+ if (c == NULL)
+ return -1;
+
+ len = c - src;
+ strncpy(dest, src, len);
+ dest[len] = '\0';
+ return len + 1;
+}
+
+static int str_to_ip(unsigned int *ip, char *str)
+{
+ int i;
+ int len;
+ char *ptr = str;
+ char buf[128];
+ unsigned char c[4];
+
+ for (i = 0; i < 3; ++i) {
+ if ((len = getnext(ptr, '.', buf)) == -1)
+ return 1;
+ c[i] = atoi(buf);
+ ptr += len;
+ }
+ c[3] = atoi(ptr);
+ *ip = (c[0] << 24) + (c[1] << 16) + (c[2] << 8) + c[3];
+ return 0;
+}
+
+/*convert IP address from number to string */
+static void ip_to_str(char *str, unsigned int ip)
+{
+ unsigned char *ptr = (unsigned char *)&ip;
+ unsigned char c[4];
+
+ c[0] = *(ptr);
+ c[1] = *(ptr + 1);
+ c[2] = *(ptr + 2);
+ c[3] = *(ptr + 3);
+ /*sprintf(str, "%d.%d.%d.%d", c[0], c[1], c[2], c[3]);*/
+ sprintf(str, "%d.%d.%d.%d", c[3], c[2], c[1], c[0]);
+}
+
+int reg_read(unsigned int offset, unsigned int *value)
+{
+ int ret = -1;
+
+ if (nl_init_flag == true) {
+ ret = reg_read_netlink(attres, offset, value);
+ } else {
+ if (attres->dev_id == -1)
+ ret = reg_read_ioctl(offset, value);
+ }
+ if (ret < 0) {
+ printf("Read fail\n");
+ *value = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+int reg_write(unsigned int offset, unsigned int value)
+{
+ int ret = -1;
+
+ if (nl_init_flag == true) {
+ ret = reg_write_netlink(attres, offset, value);
+ } else {
+ if (attres->dev_id == -1)
+ ret = reg_write_ioctl(offset, value);
+ }
+ if (ret < 0) {
+ printf("Write fail\n");
+ exit_free();
+ exit(0);
+ }
+ return 0;
+}
+
+int mii_mgr_read(unsigned int port_num, unsigned int reg, unsigned int *value)
+{
+ int ret;
+
+ if (port_num > 31) {
+ printf("Invalid Port or PHY addr \n");
+ return -1;
+ }
+
+ if (nl_init_flag == true)
+ ret = phy_cl22_read_netlink(attres, port_num, reg, value);
+ else
+ ret = mii_mgr_cl22_read_ioctl(port_num, reg, value);
+
+ if (ret < 0) {
+ printf("Phy read fail\n");
+ exit_free();
+ exit(0);
+ }
+
+ return 0;
+}
+
+int mii_mgr_write(unsigned int port_num, unsigned int reg, unsigned int value)
+{
+ int ret;
+
+ if (port_num > 31) {
+ printf("Invalid Port or PHY addr \n");
+ return -1;
+ }
+
+ if (nl_init_flag == true)
+ ret = phy_cl22_write_netlink(attres, port_num, reg, value);
+ else
+ ret = mii_mgr_cl22_write_ioctl(port_num, reg, value);
+
+ if (ret < 0) {
+ printf("Phy write fail\n");
+ exit_free();
+ exit(0);
+ }
+
+ return 0;
+}
+
+int mii_mgr_c45_read(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int *value)
+{
+ int ret;
+
+ if (port_num > 31) {
+ printf("Invalid Port or PHY addr \n");
+ return -1;
+ }
+
+ if (nl_init_flag == true)
+ ret = phy_cl45_read_netlink(attres, port_num, dev, reg, value);
+ else
+ ret = mii_mgr_cl45_read_ioctl(port_num, dev, reg, value);
+
+ if (ret < 0) {
+ printf("Phy read fail\n");
+ exit_free();
+ exit(0);
+ }
+
+ return 0;
+}
+
+int mii_mgr_c45_write(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int value)
+{
+ int ret;
+
+ if (port_num > 31) {
+ printf("Invalid Port or PHY addr \n");
+ return -1;
+ }
+
+ if (nl_init_flag == true)
+ ret = phy_cl45_write_netlink(attres, port_num, dev, reg, value);
+ else
+ ret = mii_mgr_cl45_write_ioctl(port_num, dev, reg, value);
+
+ if (ret < 0) {
+ printf("Phy write fail\n");
+ exit_free();
+ exit(0);
+ }
+
+ return 0;
+}
+
+
+int phy_dump(int phy_addr)
+{
+ int ret;
+
+ if (nl_init_flag == true)
+ ret = phy_dump_netlink(attres, phy_addr);
+ else
+ ret = phy_dump_ioctl(phy_addr);
+
+ if (ret < 0) {
+ printf("Phy dump fail\n");
+ exit_free();
+ exit(0);
+ }
+
+ return 0;
+}
+
+void phy_crossover(int argc, char *argv[])
+{
+ unsigned int port_num = strtoul(argv[2], NULL, 10);
+ unsigned int value;
+ int ret;
+
+ if (port_num > 4) {
+ printf("invaild value, port_name:0~4\n");
+ return;
+ }
+
+ if (nl_init_flag == true)
+ ret = phy_cl45_read_netlink(attres, port_num, 0x1E, MT7530_T10_TEST_CONTROL, &value);
+ else
+ ret = mii_mgr_cl45_read_ioctl(port_num, 0x1E, MT7530_T10_TEST_CONTROL, &value);
+ if (ret < 0) {
+ printf("phy_cl45 read fail\n");
+ exit_free();
+ exit(0);
+ }
+
+ printf("mii_mgr_cl45:");
+ printf("Read: port#=%d, device=0x%x, reg=0x%x, value=0x%x\n", port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+
+ if (!strncmp(argv[3], "auto", 5))
+ {
+ value &= (~(0x3 << 3));
+ } else if (!strncmp(argv[3], "mdi", 4)) {
+ value &= (~(0x3 << 3));
+ value |= (0x2 << 3);
+ } else if (!strncmp(argv[3], "mdix", 5)) {
+ value |= (0x3 << 3);
+ } else {
+ printf("invaild parameter\n");
+ return;
+ }
+ printf("Write: port#=%d, device=0x%x, reg=0x%x. value=0x%x\n", port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+
+ if (nl_init_flag == true)
+ ret = phy_cl45_write_netlink(attres, port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+ else
+ ret = mii_mgr_cl45_write_ioctl(port_num, 0x1E, MT7530_T10_TEST_CONTROL, value);
+
+ if (ret < 0) {
+ printf("phy_cl45 write fail\n");
+ exit_free();
+ exit(0);
+ }
+}
+
+int rw_phy_token_ring(int argc, char *argv[])
+{
+ int ch_addr, node_addr, data_addr;
+ unsigned int tr_reg_control;
+ unsigned int val_l = 0;
+ unsigned int val_h = 0;
+ unsigned int port_num;
+
+ if (argc < 4)
+ return -1;
+
+ if (argv[2][0] == 'r') {
+ if (argc != 7)
+ return -1;
+ mii_mgr_write(0, 0x1f, 0x52b5); // r31 = 0x52b5
+ port_num = strtoul(argv[3], NULL, 0);
+ if (port_num > MAX_PORT) {
+ printf("Illegal port index and port:0~6\n");
+ return -1;
+ }
+ ch_addr = strtoul(argv[4], NULL, 0);
+ node_addr = strtoul(argv[5], NULL, 0);
+ data_addr = strtoul(argv[6], NULL, 0);
+ printf("port = %x, ch_addr = %x, node_addr=%x, data_addr=%x\n", port_num, ch_addr, node_addr, data_addr);
+ tr_reg_control = (1 << 15) | (1 << 13) | (ch_addr << 11) | (node_addr << 7) | (data_addr << 1);
+ mii_mgr_write(port_num, 16, tr_reg_control); // r16 = tr_reg_control
+ mii_mgr_read(port_num, 17, &val_l);
+ mii_mgr_read(port_num, 18, &val_h);
+ printf("switch trreg read tr_reg_control=%x, value_H=%x, value_L=%x\n", tr_reg_control, val_h, val_l);
+ } else if (argv[2][0] == 'w') {
+ if (argc != 9)
+ return -1;
+ mii_mgr_write(0, 0x1f, 0x52b5); // r31 = 0x52b5
+ port_num = strtoul(argv[3], NULL, 0);
+ if (port_num > MAX_PORT) {
+ printf("\n**Illegal port index and port:0~6\n");
+ return -1;
+ }
+ ch_addr = strtoul(argv[4], NULL, 0);
+ node_addr = strtoul(argv[5], NULL, 0);
+ data_addr = strtoul(argv[6], NULL, 0);
+ val_h = strtoul(argv[7], NULL, 0);
+ val_l = strtoul(argv[8], NULL, 0);
+ printf("port = %x, ch_addr = %x, node_addr=%x, data_addr=%x\n", port_num, ch_addr, node_addr, data_addr);
+ tr_reg_control = (1 << 15) | (0 << 13) | (ch_addr << 11) | (node_addr << 7) | (data_addr << 1);
+ mii_mgr_write(port_num, 17, val_l);
+ mii_mgr_write(port_num, 18, val_h);
+ mii_mgr_write(port_num, 16, tr_reg_control); // r16 = tr_reg_control
+ printf("switch trreg Write tr_reg_control=%x, value_H=%x, value_L=%x\n", tr_reg_control, val_h, val_l);
+ } else
+ return -1;
+ return 0;
+}
+
+void write_acl_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+{
+ unsigned int value, reg;
+ unsigned int max_index;
+
+ if (chip_name == 0x7531)
+ max_index = 256;
+ else
+ max_index = 64;
+
+ printf("Pattern_acl_tbl_idx:%d\n", tbl_idx);
+
+ if (tbl_idx >= max_index) {
+ printf(HELP_ACL_ACL_TBL_ADD);
+ return;
+ }
+
+ reg = REG_VTCR_ADDR;
+ while (1)
+ { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0) {
+ break;
+ }
+ }
+ reg_write(REG_VAWD1_ADDR, vawd1);
+ printf("write reg: %x, value: %x\n", REG_VAWD1_ADDR, vawd1);
+ reg_write(REG_VAWD2_ADDR, vawd2);
+ printf("write reg: %x, value: %x\n", REG_VAWD2_ADDR, vawd2);
+ reg = REG_VTCR_ADDR;
+ value = REG_VTCR_BUSY_MASK | (0x05 << REG_VTCR_FUNC_OFFT) | tbl_idx;
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+
+ while (1)
+ { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+}
+
+void acl_table_add(int argc, char *argv[])
+{
+ unsigned int vawd1, vawd2;
+ unsigned char tbl_idx;
+
+ tbl_idx = atoi(argv[3]);
+ vawd1 = strtoul(argv[4], (char **)NULL, 16);
+ vawd2 = strtoul(argv[5], (char **)NULL, 16);
+ write_acl_table(tbl_idx, vawd1, vawd2);
+}
+
+void write_acl_mask_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+{
+ unsigned int value, reg;
+ unsigned int max_index;
+
+ if (chip_name == 0x7531)
+ max_index = 128;
+ else
+ max_index = 32;
+
+ printf("Rule_mask_tbl_idx:%d\n", tbl_idx);
+
+ if (tbl_idx >= max_index) {
+ printf(HELP_ACL_MASK_TBL_ADD);
+ return;
+ }
+ reg = REG_VTCR_ADDR;
+ while (1)
+ { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+ reg_write(REG_VAWD1_ADDR, vawd1);
+ printf("write reg: %x, value: %x\n", REG_VAWD1_ADDR, vawd1);
+ reg_write(REG_VAWD2_ADDR, vawd2);
+ printf("write reg: %x, value: %x\n", REG_VAWD2_ADDR, vawd2);
+ reg = REG_VTCR_ADDR;
+ value = REG_VTCR_BUSY_MASK | (0x09 << REG_VTCR_FUNC_OFFT) | tbl_idx;
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+ while (1)
+ { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+}
+
+void acl_mask_table_add(int argc, char *argv[])
+{
+ unsigned int vawd1, vawd2;
+ unsigned char tbl_idx;
+
+ tbl_idx = atoi(argv[3]);
+ vawd1 = strtoul(argv[4], (char **)NULL, 16);
+ vawd2 = strtoul(argv[5], (char **)NULL, 16);
+ write_acl_mask_table(tbl_idx, vawd1, vawd2);
+}
+
+void write_acl_rule_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+{
+ unsigned int value, reg;
+ unsigned int max_index;
+
+ if (chip_name == 0x7531)
+ max_index = 128;
+ else
+ max_index = 32;
+
+ printf("Rule_control_tbl_idx:%d\n", tbl_idx);
+
+ if (tbl_idx >= max_index) { /*Check the input parameters is right or not.*/
+ printf(HELP_ACL_RULE_TBL_ADD);
+ return;
+ }
+ reg = REG_VTCR_ADDR;
+
+ while (1)
+ { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0) {
+ break;
+ }
+ }
+ reg_write(REG_VAWD1_ADDR, vawd1);
+ printf("write reg: %x, value: %x\n", REG_VAWD1_ADDR, vawd1);
+ reg_write(REG_VAWD2_ADDR, vawd2);
+ printf("write reg: %x, value: %x\n", REG_VAWD2_ADDR, vawd2);
+ reg = REG_VTCR_ADDR;
+ value = REG_VTCR_BUSY_MASK | (0x0B << REG_VTCR_FUNC_OFFT) | tbl_idx;
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+
+ while (1)
+ { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0) {
+ break;
+ }
+ }
+}
+
+void acl_rule_table_add(int argc, char *argv[])
+{
+ unsigned int vawd1, vawd2;
+ unsigned char tbl_idx;
+
+ tbl_idx = atoi(argv[3]);
+ vawd1 = strtoul(argv[4], (char **)NULL, 16);
+ vawd2 = strtoul(argv[5], (char **)NULL, 16);
+ write_acl_rule_table(tbl_idx, vawd1, vawd2);
+}
+
+void write_rate_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+{
+ unsigned int value, reg;
+ unsigned int max_index = 32;
+
+ printf("Rule_action_tbl_idx:%d\n", tbl_idx);
+
+ if (tbl_idx >= max_index) {
+ printf(HELP_ACL_RATE_TBL_ADD);
+ return;
+ }
+
+ reg = REG_VTCR_ADDR;
+ while (1) { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+
+ reg_write(REG_VAWD1_ADDR, vawd1);
+ printf("write reg: %x, value: %x\n", REG_VAWD1_ADDR, vawd1);
+ reg_write(REG_VAWD2_ADDR, vawd2);
+ printf("write reg: %x, value: %x\n", REG_VAWD2_ADDR, vawd2);
+ reg = REG_VTCR_ADDR;
+ value = REG_VTCR_BUSY_MASK | (0x0D << REG_VTCR_FUNC_OFFT) | tbl_idx;
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+
+ while (1) { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+}
+
+void acl_rate_table_add(int argc, char *argv[])
+{
+ unsigned int vawd1, vawd2;
+ unsigned char tbl_idx;
+
+ tbl_idx = atoi(argv[3]);
+ vawd1 = strtoul(argv[4], (char **)NULL, 16);
+ vawd2 = strtoul(argv[5], (char **)NULL, 16);
+
+ write_rate_table(tbl_idx, vawd1, vawd2);
+}
+
+void write_trTCM_table(unsigned char tbl_idx, unsigned int vawd1, unsigned int vawd2)
+{
+ unsigned int value, reg;
+ unsigned int max_index = 32;
+
+ printf("trTCM_tbl_idx:%d\n", tbl_idx);
+
+ if (tbl_idx >= max_index) {
+ printf(HELP_ACL_TRTCM_TBL_ADD);
+ return;
+ }
+
+ reg = REG_VTCR_ADDR;
+ while (1) { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+
+ reg_write(REG_VAWD1_ADDR, vawd1);
+ printf("write reg: %x, value: %x\n", REG_VAWD1_ADDR, vawd1);
+ reg_write(REG_VAWD2_ADDR, vawd2);
+ printf("write reg: %x, value: %x\n", REG_VAWD2_ADDR, vawd2);
+ reg = REG_VTCR_ADDR;
+ value = REG_VTCR_BUSY_MASK | (0x07 << REG_VTCR_FUNC_OFFT) | tbl_idx;
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+
+ while (1) { // wait until not busy
+ reg_read(reg, &value);
+ if ((value & REG_VTCR_BUSY_MASK) == 0)
+ break;
+ }
+}
+
+int acl_parameters_pre_del(int len1, int len2, int argc, char *argv[], int *port)
+{
+ int i;
+
+ *port = 0;
+ if (argc < len1) {
+ printf("insufficient arguments!\n");
+ return -1;
+ }
+
+ if (len2 == 12)
+ {
+ if (!argv[4] || strlen(argv[4]) != len2) {
+ printf("The [%s] format error, should be of length %d\n",argv[4], len2);
+ return -1;
+ }
+ }
+
+ if (!argv[5] || strlen(argv[5]) != 8) {
+ printf("portsmap format error, should be of length 7\n");
+ return -1;
+ }
+
+ for (i = 0; i < 7; i++) {
+ if (argv[5][i] != '0' && argv[5][i] != '1') {
+ printf("portmap format error, should be of combination of 0 or 1\n");
+ return -1;
+ }
+ *port += (argv[5][i] - '0') * (1 << i);
+ }
+ return 0;
+}
+
+void acl_compare_pattern(int ports, int comparion, int base, int word, unsigned char table_index)
+{
+ unsigned int value;
+
+ comparion |= 0xffff0000; //compare mask
+
+ value = ports << 8; //w_port_map
+ value |= 0x1 << 19; //enable
+ value |= base << 16; //mac header
+ value |= word << 1; //word offset
+
+ write_acl_table(table_index, comparion, value);
+}
+
+void acl_mac_add(int argc, char *argv[])
+{
+ unsigned int value;
+ int ports;
+ char tmpstr[5];
+ int ret;
+
+ ret = acl_parameters_pre_del(6, 12, argc, argv, &ports);
+ if (ret < 0)
+ return;
+ //set pattern
+ strncpy(tmpstr, argv[4], 4);
+ tmpstr[4] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ acl_compare_pattern(ports, value, 0x0, 0, 0);
+
+ strncpy(tmpstr, argv[4] + 4, 4);
+ tmpstr[4] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ acl_compare_pattern(ports, value, 0x0, 1, 1);
+
+ strncpy(tmpstr, argv[4] + 8, 4);
+ tmpstr[4] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ acl_compare_pattern(ports, value, 0x0, 2, 2);
+
+ //set mask
+ write_acl_mask_table(0,0x7,0);
+
+ //set action
+ value = 0x7; //drop
+ value |= 1 << 28; //acl intterupt enable
+ value |= 1 << 27; //acl hit count
+ value |= 2 << 24; //acl hit count group index (0~3)
+ write_acl_rule_table(0,value,0);
+}
+
+void acl_dip_meter(int argc, char *argv[])
+{
+ unsigned int value, ip_value, meter;
+ int ports;
+ int ret;
+
+ ip_value = 0;
+ ret = acl_parameters_pre_del(7, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+
+ str_to_ip(&ip_value, argv[4]);
+ //set pattern
+ value = (ip_value >> 16);
+ acl_compare_pattern(ports, value, 0x2, 0x8, 0);
+
+ //set pattern
+ value = (ip_value & 0xffff);
+ acl_compare_pattern(ports, value, 0x2, 0x9, 1);
+
+ //set mask
+ write_acl_mask_table(0,0x3,0);
+
+ //set action
+ meter = strtoul(argv[6], NULL, 0);
+ if (((chip_name == 0x7530) && (meter > 1000000)) ||
+ ((chip_name == 0x7531) && (meter > 2500000))) {
+ printf("\n**Illegal meter input, and 7530: 0~1000000Kpbs, 7531: 0~2500000Kpbs**\n");
+ return;
+ }
+ if (((chip_name == 0x7531) && (meter > 1000000))) {
+ reg_read(0xc,&value);
+ value |= 0x1 << 30;
+ reg_write(0xC,value);
+ printf("AGC: 0x%x\n",value);
+ value = meter / 1000; //uint is 1Mbps
+ } else {
+ reg_read(0xc,&value);
+ value &= ~(0x1 << 30);
+ reg_write(0xC,value);
+ printf("AGC: 0x%x\n",value);
+ value = meter >> 6; //uint is 64Kbps
+ }
+ value |= 0x1 << 15; //enable rate control
+ printf("Acl rate control:0x%x\n",value);
+ write_rate_table(0, value, 0);
+}
+
+void acl_dip_trtcm(int argc, char *argv[])
+{
+ unsigned int value, value2, ip_value;
+ unsigned int CIR, CBS, PIR, PBS;
+ int ports;
+ int ret;
+
+ ip_value = 0;
+ ret = acl_parameters_pre_del(10, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+
+ str_to_ip(&ip_value, argv[4]);
+ //set pattern
+ value = (ip_value >> 16);
+ acl_compare_pattern(ports, value, 0x2, 0x8, 0);
+
+ //set pattern
+ value = (ip_value & 0xffff);
+ acl_compare_pattern(ports, value, 0x2, 0x9, 1);
+
+ //set CBS PBS
+ CIR = strtoul(argv[6], NULL, 0);
+ CBS = strtoul(argv[7], NULL, 0);
+ PIR = strtoul(argv[8], NULL, 0);
+ PBS = strtoul(argv[9], NULL, 0);
+
+ if (CIR > 65535*64 || CBS > 65535 || PIR > 65535*64 || PBS > 65535) {
+ printf("\n**Illegal input parameters**\n");
+ return;
+ }
+
+ value = CBS << 16; //bit16~31
+ value |= PBS; //bit0~15
+ //value |= 1;//valid
+ CIR = CIR >> 6;
+ PIR = PIR >> 6;
+
+ value2 = CIR << 16; //bit16~31
+ value2 |= PIR; //bit0~15
+ write_trTCM_table(0,value,value2);
+
+ //set pattern
+ write_acl_mask_table(0,0x3,0);
+
+ //set action
+ value = 0x1 << (11 + 1); //TrTCM green meter#0 Low drop
+ value |= 0x2 << (8 + 1); //TrTCM yellow meter#0 Med drop
+ value |= 0x3 << (5 + 1); //TrTCM red meter#0 Hig drop
+ value |= 0x1 << 0; //TrTCM drop pcd select
+ write_acl_rule_table(0,0,value);
+}
+
+void acl_ethertype(int argc, char *argv[])
+{
+ unsigned int value, ethertype;
+ int ports;
+ int ret;
+
+ ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+ printf("ports:0x%x\n",ports);
+ ethertype = strtoul(argv[4], NULL, 16);
+ //set pattern
+ value = ethertype;
+ acl_compare_pattern(ports, value, 0x0, 0x6, 0);
+
+ //set pattern
+ write_acl_mask_table(0,0x1,0);
+
+ //set action(drop)
+ value = 0x7; //default. Nodrop
+ value |= 1 << 28; //acl intterupt enable
+ value |= 1 << 27; //acl hit count
+
+ write_acl_rule_table(0,value,0);
+}
+
+void acl_dip_modify(int argc, char *argv[])
+{
+ unsigned int value, ip_value;
+ int ports;
+ int priority;
+ int ret;
+
+ ip_value = 0;
+ priority = strtoul(argv[6], NULL, 16);
+ if (priority < 0 || priority > 7) {
+ printf("\n**Illegal priority value!**\n");
+ return;
+ }
+
+ ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+
+ str_to_ip(&ip_value, argv[4]);
+ //set pattern
+ value = (ip_value >> 16);
+ acl_compare_pattern(ports, value, 0x2, 0x8, 0);
+
+ //set pattern
+ value = (ip_value & 0xffff);
+ acl_compare_pattern(ports, value, 0x2, 0x9, 1);
+
+ //set pattern
+ write_acl_mask_table(0,0x3,0);
+
+ //set action
+ value = 0x0; //default. Nodrop
+ value |= 1 << 28; //acl intterupt enable
+ value |= 1 << 27; //acl hit count
+ value |= priority << 4; //acl UP
+ write_acl_rule_table(0,value,0);
+}
+
+void acl_dip_pppoe(int argc, char *argv[])
+{
+ unsigned int value, ip_value;
+ int ports;
+ int ret;
+
+ ip_value = 0;
+ ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+
+ str_to_ip(&ip_value, argv[4]);
+ //set pattern
+ value = (ip_value >> 16);
+ acl_compare_pattern(ports, value, 0x2, 0x8, 0);
+
+ //set pattern
+ value = (ip_value & 0xffff);
+ acl_compare_pattern(ports, value, 0x2, 0x9, 1);
+
+ //set pattern
+ write_acl_mask_table(0,0x3,0);
+
+ //set action
+ value = 0x0; //default. Nodrop
+ value |= 1 << 28; //acl intterupt enable
+ value |= 1 << 27; //acl hit count
+ value |= 1 << 20; //pppoe header remove
+ value |= 1 << 21; //SA MAC SWAP
+ value |= 1 << 22; //DA MAC SWAP
+ write_acl_rule_table(0,value,7);
+}
+
+void acl_dip_add(int argc, char *argv[])
+{
+ unsigned int value, ip_value;
+ int ports;
+ int ret;
+
+ ip_value = 0;
+ ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+
+ str_to_ip(&ip_value, argv[4]);
+ //set pattern
+ value = (ip_value >> 16);
+ acl_compare_pattern(ports, value, 0x2, 0x8, 0);
+
+ //set pattern
+ value = (ip_value & 0xffff);
+ acl_compare_pattern(ports, value, 0x2, 0x9, 1);
+
+ //set pattern
+ write_acl_mask_table(0,0x3,0);
+
+ //set action
+ //value = 0x0; //default
+ value = 0x7; //drop
+ value |= 1 << 28; //acl intterupt enable
+ value |= 1 << 27; //acl hit count
+ value |= 2 << 24; //acl hit count group index (0~3)
+ write_acl_rule_table(0,value,0);
+}
+
+void acl_l4_add(int argc, char *argv[])
+{
+ unsigned int value;
+ int ports;
+ int ret;
+
+ ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+
+ //set pattern
+ value = strtoul(argv[4], NULL, 16);
+ acl_compare_pattern(ports, value, 0x5, 0x0, 0);
+
+ //set rue mask
+ write_acl_mask_table(0,0x1,0);
+ //set action
+ value = 0x7; //drop
+ //value |= 1;//valid
+ write_acl_rule_table(0,value,0);
+}
+
+void acl_sp_add(int argc, char *argv[])
+{
+ unsigned int value;
+ int ports;
+ int ret;
+
+ ret = acl_parameters_pre_del(6, -1, argc, argv, &ports);
+ if (ret < 0)
+ return;
+ //set pattern
+ value = strtoul(argv[4], NULL, 0);
+ acl_compare_pattern(ports, value, 0x4, 0x0, 0);
+
+ //set rue mask
+ write_acl_mask_table(0,0x1,0);
+
+ //set action
+ value = 0x7; //drop
+ //value |= 1;//valid
+ write_acl_rule_table(0,value,0);
+}
+
+void acl_port_enable(int argc, char *argv[])
+{
+ unsigned int value, reg;
+ unsigned char acl_port, acl_en;
+
+ acl_port = atoi(argv[3]);
+ acl_en = atoi(argv[4]);
+
+ printf("acl_port:%d, acl_en:%d\n", acl_port, acl_en);
+
+ /*Check the input parameters is right or not.*/
+ if ((acl_port > SWITCH_MAX_PORT) || (acl_en > 1)) {
+ printf(HELP_ACL_SETPORTEN);
+ return;
+ }
+
+ reg = REG_PCR_P0_ADDR + (0x100 * acl_port); // 0x2004[10]
+ reg_read(reg, &value);
+ value &= (~REG_PORT_ACL_EN_MASK);
+ value |= (acl_en << REG_PORT_ACL_EN_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+}
+
+static void dip_dump_internal(int type)
+{
+ unsigned int i, j, value, mac, mac2, value2;
+ char tmpstr[16];
+ int table_size = 0;
+ int hit_value1 = 0;
+ int hit_value2 = 0;
+
+ if(type == GENERAL_TABLE) {
+ table_size = 0x800;
+ reg_write(REG_ATC_ADDR, 0x8104); //dip search command
+ } else {
+ table_size = 0x40;
+ reg_write(REG_ATC_ADDR, 0x811c); //dip search command
+ }
+ printf("hash port(0:6) rsp_cnt flag timer dip-address ATRD\n");
+ for (i = 0; i < table_size; i++) {
+ while (1)
+ {
+ reg_read(REG_ATC_ADDR, &value);
+ if(type == GENERAL_TABLE) {
+ hit_value1 = value & (0x1 << 13);
+ hit_value2 = 1;
+ }else {
+ hit_value1 = value & (0x1 << 13);
+ hit_value2 = value & (0x1 << 28);
+ }
+
+ if (hit_value1 && hit_value2 ) { //search_rdy
+ reg_read(REG_ATRD_ADDR, &value2);
+ //printf("REG_ATRD_ADDR=0x%x\n\r",value2);
+
+ printf("%03x: ", (value >> 16) & 0xfff); //hash_addr_lu
+ j = (value2 >> 4) & 0xff; //r_port_map
+ printf("%c", (j & 0x01) ? '1' : '-');
+ printf("%c", (j & 0x02) ? '1' : '-');
+ printf("%c", (j & 0x04) ? '1' : '-');
+ printf("%c ", (j & 0x08) ? '1' : '-');
+ printf("%c", (j & 0x10) ? '1' : '-');
+ printf("%c", (j & 0x20) ? '1' : '-');
+ printf("%c", (j & 0x40) ? '1' : '-');
+
+ reg_read(REG_TSRA2_ADDR, &mac2);
+
+ printf(" 0x%4x", (mac2 & 0xffff)); //RESP_CNT
+ printf(" 0x%2x", ((mac2 >> 16) & 0xff)); //RESP_FLAG
+ printf(" %3d", ((mac2 >> 24) & 0xff)); //RESP_TIMER
+ //printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+ reg_read(REG_TSRA1_ADDR, &mac);
+ ip_to_str(tmpstr, mac);
+ printf(" %s", tmpstr);
+ printf(" 0x%8x\n", value2); //ATRD
+ //printf("%04x", ((mac2 >> 16) & 0xffff));
+ //printf(" %c\n", (((value2 >> 20) & 0x03)== 0x03)? 'y':'-');
+ if (value & 0x4000) {
+ printf("end of table %d\n", i);
+ return;
+ }
+ break;
+ }
+ else if (value & 0x4000) { //at_table_end
+ printf("found the last entry %d (not ready)\n", i);
+ return;
+ }
+ usleep(5000);
+ }
+
+ if(type == GENERAL_TABLE)
+ reg_write(REG_ATC_ADDR, 0x8105); //search for next dip address
+ else
+ reg_write(REG_ATC_ADDR, 0x811d); //search for next dip address
+ usleep(5000);
+ }
+}
+
+void dip_dump(void)
+{
+ dip_dump_internal(GENERAL_TABLE);
+
+}
+
+void dip_add(int argc, char *argv[])
+{
+ unsigned int value = 0;
+ unsigned int i, j;
+
+ value = 0;
+
+ str_to_ip(&value, argv[3]);
+
+ reg_write(REG_ATA1_ADDR, value);
+ printf("REG_ATA1_ADDR is 0x%x\n\r", value);
+
+#if 0
+ reg_write(REG_ATA2_ADDR, value);
+ printf("REG_ATA2_ADDR is 0x%x\n\r", value);
+#endif
+ if (!argv[4] || strlen(argv[4]) != 8) {
+ printf("portmap format error, should be of length 7\n");
+ return;
+ }
+ j = 0;
+ for (i = 0; i < 7; i++) {
+ if (argv[4][i] != '0' && argv[4][i] != '1') {
+ printf("portmap format error, should be of combination of 0 or 1\n");
+ return;
+ }
+ j += (argv[4][i] - '0') * (1 << i);
+ }
+ value = j << 4; //w_port_map
+ value |= (0x3 << 2); //static
+
+ reg_write(REG_ATWD_ADDR, value);
+
+ usleep(5000);
+ reg_read(REG_ATWD_ADDR, &value);
+ printf("REG_ATWD_ADDR is 0x%x\n\r", value);
+
+ value = 0x8011; //single w_dip_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ usleep(1000);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void dip_del(int argc, char *argv[])
+{
+ unsigned int i, value;
+
+ value = 0;
+ str_to_ip(&value, argv[3]);
+
+ reg_write(REG_ATA1_ADDR, value);
+
+ value = 0;
+ reg_write(REG_ATA2_ADDR, value);
+
+ value = 0; //STATUS=0, delete dip
+ reg_write(REG_ATWD_ADDR, value);
+
+ value = 0x8011; //w_dip_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ if (argv[1] != NULL)
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void dip_clear(void)
+{
+
+ unsigned int value;
+
+ reg_write(REG_ATC_ADDR, 0x8102); //clear all dip
+ usleep(5000);
+ reg_read(REG_ATC_ADDR, &value);
+ printf("REG_ATC_ADDR is 0x%x\n\r", value);
+}
+
+static void sip_dump_internal(int type)
+{
+ unsigned int i, j, value, mac, mac2, value2;
+ int table_size = 0;
+ int hit_value1 = 0;
+ int hit_value2 = 0;
+ char tmpstr[16];
+
+ if (type == GENERAL_TABLE) {
+ table_size = 0x800;
+ reg_write(REG_ATC_ADDR, 0x8204); //sip search command
+ }else {
+ table_size = 0x40;
+ reg_write(REG_ATC_ADDR, 0x822c); //sip search command
+ }
+ printf("hash port(0:6) dip-address sip-address ATRD\n");
+ for (i = 0; i < table_size; i++) {
+ while (1)
+ {
+ reg_read(REG_ATC_ADDR, &value);
+ if(type == GENERAL_TABLE) {
+ hit_value1 = value & (0x1 << 13);
+ hit_value2 = 1;
+ } else {
+ hit_value1 = value & (0x1 << 13);
+ hit_value2 = value & (0x1 << 28);
+ }
+
+ if (hit_value1 && hit_value2) { //search_rdy
+ reg_read(REG_ATRD_ADDR, &value2);
+ //printf("REG_ATRD_ADDR=0x%x\n\r",value2);
+
+ printf("%03x: ", (value >> 16) & 0xfff); //hash_addr_lu
+ j = (value2 >> 4) & 0xff; //r_port_map
+ printf("%c", (j & 0x01) ? '1' : '-');
+ printf("%c", (j & 0x02) ? '1' : '-');
+ printf("%c", (j & 0x04) ? '1' : '-');
+ printf("%c", (j & 0x08) ? '1' : '-');
+ printf(" %c", (j & 0x10) ? '1' : '-');
+ printf("%c", (j & 0x20) ? '1' : '-');
+ printf("%c", (j & 0x40) ? '1' : '-');
+
+ reg_read(REG_TSRA2_ADDR, &mac2);
+
+ ip_to_str(tmpstr, mac2);
+ printf(" %s", tmpstr);
+
+ //printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+ reg_read(REG_TSRA1_ADDR, &mac);
+ ip_to_str(tmpstr, mac);
+ printf(" %s", tmpstr);
+ printf(" 0x%x\n", value2);
+ //printf("%04x", ((mac2 >> 16) & 0xffff));
+ //printf(" %c\n", (((value2 >> 20) & 0x03)== 0x03)? 'y':'-');
+ if (value & 0x4000) {
+ printf("end of table %d\n", i);
+ return;
+ }
+ break;
+ } else if (value & 0x4000) { //at_table_end
+ printf("found the last entry %d (not ready)\n", i);
+ return;
+ }
+ usleep(5000);
+ }
+
+ if(type == GENERAL_TABLE)
+ reg_write(REG_ATC_ADDR, 0x8205); //search for next sip address
+ else
+ reg_write(REG_ATC_ADDR, 0x822d); //search for next sip address
+ usleep(5000);
+ }
+}
+
+void sip_dump(void)
+{
+
+ sip_dump_internal(GENERAL_TABLE);
+
+}
+
+
+void sip_add(int argc, char *argv[])
+{
+ unsigned int i, j, value;
+
+ value = 0;
+ str_to_ip(&value, argv[3]); //SIP
+
+ reg_write(REG_ATA2_ADDR, value);
+ printf("REG_ATA2_ADDR is 0x%x\n\r", value);
+
+ value = 0;
+
+ str_to_ip(&value, argv[4]); //DIP
+ reg_write(REG_ATA1_ADDR, value);
+ printf("REG_ATA1_ADDR is 0x%x\n\r", value);
+
+ if (!argv[5] || strlen(argv[5]) != 8) {
+ printf("portmap format error, should be of length 7\n");
+ return;
+ }
+ j = 0;
+ for (i = 0; i < 7; i++) {
+ if (argv[5][i] != '0' && argv[5][i] != '1') {
+ printf("portmap format error, should be of combination of 0 or 1\n");
+ return;
+ }
+ j += (argv[5][i] - '0') * (1 << i);
+ }
+ value = j << 4; //w_port_map
+ value |= (0x3 << 2); //static
+
+ reg_write(REG_ATWD_ADDR, value);
+
+ usleep(5000);
+ reg_read(REG_ATWD_ADDR, &value);
+ printf("REG_ATWD_ADDR is 0x%x\n\r", value);
+
+ value = 0x8021; //single w_sip_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ usleep(1000);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void sip_del(int argc, char *argv[])
+{
+ unsigned int i, value;
+
+ value = 0;
+ str_to_ip(&value, argv[3]);
+
+ reg_write(REG_ATA2_ADDR, value); //SIP
+
+ str_to_ip(&value, argv[4]);
+ reg_write(REG_ATA1_ADDR, value); //DIP
+
+ value = 0; //STATUS=0, delete sip
+ reg_write(REG_ATWD_ADDR, value);
+
+ value = 0x8021; //w_sip_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ if (argv[1] != NULL)
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void sip_clear(void)
+{
+ unsigned int value;
+
+ reg_write(REG_ATC_ADDR, 0x8202); //clear all sip
+ usleep(5000);
+ reg_read(REG_ATC_ADDR, &value);
+ printf("REG_ATC_ADDR is 0x%x\n\r", value);
+}
+
+static void table_dump_internal(int type)
+{
+ unsigned int i, j, value, mac, mac2, value2;
+ int table_size = 0;
+ int table_end = 0;
+ int hit_value1 = 0;
+ int hit_value2 = 0;
+
+ if (type == GENERAL_TABLE){
+ table_size = 0x800;
+ table_end = 0x7FF;
+ reg_write(REG_ATC_ADDR, 0x8004);
+ } else {
+ table_size = 0x40;
+ table_end = 0x3F;
+ reg_write(REG_ATC_ADDR, 0x800C);
+ }
+ printf("hash port(0:6) fid vid age(s) mac-address filter my_mac\n");
+ for (i = 0; i < table_size; i++) {
+ while (1)
+ {
+ reg_read(REG_ATC_ADDR, &value);
+ //printf("ATC = 0x%x\n", value);
+ if(type == GENERAL_TABLE) {
+ hit_value1 = value & (0x1 << 13);
+ hit_value2 = 1;
+ } else {
+ hit_value1 = value & (0x1 << 13);
+ hit_value2 = value & (0x1 << 28);
+ }
+
+ if (hit_value1 && hit_value2 && (((value >> 15) & 0x1) == 0)) {
+ printf("%03x: ", (value >> 16) & 0xfff);
+ reg_read(REG_ATRD_ADDR, &value2);
+ j = (value2 >> 4) & 0xff; //r_port_map
+ printf("%c", (j & 0x01) ? '1' : '-');
+ printf("%c", (j & 0x02) ? '1' : '-');
+ printf("%c", (j & 0x04) ? '1' : '-');
+ printf("%c", (j & 0x08) ? '1' : '-');
+ printf("%c", (j & 0x10) ? '1' : '-');
+ printf("%c", (j & 0x20) ? '1' : '-');
+ printf("%c", (j & 0x40) ? '1' : '-');
+ printf("%c", (j & 0x80) ? '1' : '-');
+
+ reg_read(REG_TSRA2_ADDR, &mac2);
+
+ printf(" %2d", (mac2 >> 12) & 0x7); //FID
+ printf(" %4d", (mac2 & 0xfff));
+ if (((value2 >> 24) & 0xff) == 0xFF)
+ printf(" --- "); //r_age_field:static
+ else
+ printf(" %5d ", (((value2 >> 24) & 0xff)+1)*2); //r_age_field
+ reg_read(REG_TSRA1_ADDR, &mac);
+ printf(" %08x", mac);
+ printf("%04x", ((mac2 >> 16) & 0xffff));
+ printf(" %c", (((value2 >> 20) & 0x03) == 0x03) ? 'y' : '-');
+ printf(" %c\n", (((value2 >> 23) & 0x01) == 0x01) ? 'y' : '-');
+ if ((value & 0x4000) && (((value >> 16) & 0xfff) == table_end)) {
+ printf("end of table %d\n", i);
+ return;
+ }
+ break;
+ }
+ else if ((value & 0x4000) && (((value >> 15) & 0x1) == 0) && (((value >> 16) & 0xfff) == table_end)) { //at_table_end
+ printf("found the last entry %d (not ready)\n", i);
+ return;
+ }
+ else
+ usleep(5);
+ }
+
+ if(type == GENERAL_TABLE)
+ reg_write(REG_ATC_ADDR, 0x8005);//search for next address
+ else
+ reg_write(REG_ATC_ADDR, 0x800d);//search for next address
+ usleep(5);
+ }
+}
+
+void table_dump(void)
+{
+ table_dump_internal(GENERAL_TABLE);
+
+}
+
+
+void table_add(int argc, char *argv[])
+{
+ unsigned int i, j, value, is_filter, is_mymac;
+ char tmpstr[9];
+
+ is_filter = (argv[1][0] == 'f') ? 1 : 0;
+ is_mymac = (argv[1][0] == 'm') ? 1 : 0;
+ if (!argv[2] || strlen(argv[2]) != 12) {
+ printf("MAC address format error, should be of length 12\n");
+ return;
+ }
+ strncpy(tmpstr, argv[2], 8);
+ tmpstr[8] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ reg_write(REG_ATA1_ADDR, value);
+ printf("REG_ATA1_ADDR is 0x%x\n\r", value);
+
+ strncpy(tmpstr, argv[2] + 8, 4);
+ tmpstr[4] = '\0';
+
+ value = strtoul(tmpstr, NULL, 16);
+ value = (value << 16);
+ value |= (1 << 15); //IVL=1
+
+ if (argc > 4) {
+ j = strtoul(argv[4], NULL, 0);
+ if (4095 < j) {
+ printf("wrong vid range, should be within 0~4095\n");
+ return;
+ }
+ value |= j; //vid
+ }
+
+ reg_write(REG_ATA2_ADDR, value);
+ printf("REG_ATA2_ADDR is 0x%x\n\r", value);
+
+ if (!argv[3] || strlen(argv[3]) != 8) {
+ if (is_filter)
+ argv[3] = "11111111";
+ else {
+ printf("portmap format error, should be of length 8\n");
+ return;
+ }
+ }
+ j = 0;
+ for (i = 0; i < 7; i++) {
+ if (argv[3][i] != '0' && argv[3][i] != '1') {
+ printf("portmap format error, should be of combination of 0 or 1\n");
+ return;
+ }
+ j += (argv[3][i] - '0') * (1 << i);
+ }
+ value = j << 4; //w_port_map
+
+ if (argc > 5) {
+ j = strtoul(argv[5], NULL, 0);
+ if (j < 1 || 255 < j) {
+ printf("wrong age range, should be within 1~255\n");
+ return;
+ }
+ value |= (j << 24); //w_age_field
+ value |= (0x1 << 2); //dynamic
+ } else {
+ value |= (0xff << 24); //w_age_field
+ value |= (0x3 << 2); //static
+ }
+
+ if (argc > 6) {
+ j = strtoul(argv[6], NULL, 0);
+ if (7 < j) {
+ printf("wrong eg-tag range, should be within 0~7\n");
+ return;
+ }
+ value |= (j << 13); //EG_TAG
+ }
+
+ if (is_filter)
+ value |= (7 << 20); //sa_filter
+
+ if (is_mymac)
+ value |= (1 << 23);
+
+ reg_write(REG_ATWD_ADDR, value);
+
+ usleep(5000);
+ reg_read(REG_ATWD_ADDR, &value);
+ printf("REG_ATWD_ADDR is 0x%x\n\r", value);
+
+ value = 0x8001; //w_mac_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ usleep(1000);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void table_search_mac_vid(int argc, char *argv[])
+{
+ unsigned int i, j, value, mac, mac2, value2;
+ char tmpstr[9];
+
+ if (!argv[3] || strlen(argv[3]) != 12) {
+ printf("MAC address format error, should be of length 12\n");
+ return;
+ }
+ strncpy(tmpstr, argv[3], 8);
+ tmpstr[8] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ reg_write(REG_ATA1_ADDR, value);
+ //printf("REG_ATA1_ADDR is 0x%x\n\r",value);
+
+ strncpy(tmpstr, argv[3] + 8, 4);
+ tmpstr[4] = '\0';
+
+ value = strtoul(tmpstr, NULL, 16);
+ value = (value << 16);
+ value |= (1 << 15); //IVL=1
+
+ j = strtoul(argv[5], NULL, 0);
+ if (4095 < j) {
+ printf("wrong vid range, should be within 0~4095\n");
+ return;
+ }
+ value |= j; //vid
+
+ reg_write(REG_ATA2_ADDR, value);
+ //printf("REG_ATA2_ADDR is 0x%x\n\r",value);
+
+ value = 0x8000; //w_mac_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ usleep(1000);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ break;
+ }
+ usleep(1000);
+ }
+ if (i == 20) {
+ printf("search timeout.\n");
+ return;
+ }
+
+ if (value & 0x1000) {
+ printf("search no entry.\n");
+ return;
+ }
+
+ printf("search done.\n");
+ printf("hash port(0:6) fid vid age mac-address filter my_mac\n");
+
+ printf("%03x: ", (value >> 16) & 0xfff); //hash_addr_lu
+ reg_read(REG_ATRD_ADDR, &value2);
+ j = (value2 >> 4) & 0xff; //r_port_map
+ printf("%c", (j & 0x01) ? '1' : '-');
+ printf("%c", (j & 0x02) ? '1' : '-');
+ printf("%c", (j & 0x04) ? '1' : '-');
+ printf("%c ", (j & 0x08) ? '1' : '-');
+ printf("%c", (j & 0x10) ? '1' : '-');
+ printf("%c", (j & 0x20) ? '1' : '-');
+ printf("%c", (j & 0x40) ? '1' : '-');
+ printf("%c", (j & 0x80) ? '1' : '-');
+
+ reg_read(REG_TSRA2_ADDR, &mac2);
+
+ printf(" %2d", (mac2 >> 12) & 0x7); //FID
+ printf(" %4d", (mac2 & 0xfff));
+ printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+ reg_read(REG_TSRA1_ADDR, &mac);
+ printf(" %08x", mac);
+ printf("%04x", ((mac2 >> 16) & 0xffff));
+ printf(" %c", (((value2 >> 20) & 0x03) == 0x03) ? 'y' : '-');
+ printf(" %c\n", (((value2 >> 23) & 0x01) == 0x01) ? 'y' : '-');
+}
+
+void table_search_mac_fid(int argc, char *argv[])
+{
+ unsigned int i, j, value, mac, mac2, value2;
+ char tmpstr[9];
+
+ if (!argv[3] || strlen(argv[3]) != 12) {
+ printf("MAC address format error, should be of length 12\n");
+ return;
+ }
+ strncpy(tmpstr, argv[3], 8);
+ tmpstr[8] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ reg_write(REG_ATA1_ADDR, value);
+ //printf("REG_ATA1_ADDR is 0x%x\n\r",value);
+
+ strncpy(tmpstr, argv[3] + 8, 4);
+ tmpstr[4] = '\0';
+
+ value = strtoul(tmpstr, NULL, 16);
+ value = (value << 16);
+ value &= ~(1 << 15); //IVL=0
+
+ j = strtoul(argv[5], NULL, 0);
+ if (7 < j) {
+ printf("wrong fid range, should be within 0~7\n");
+ return;
+ }
+ value |= (j << 12); //vid
+
+ reg_write(REG_ATA2_ADDR, value);
+ //printf("REG_ATA2_ADDR is 0x%x\n\r",value);
+
+ value = 0x8000; //w_mac_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ usleep(1000);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ break;
+ }
+ usleep(1000);
+ }
+ if (i == 20) {
+ printf("search timeout.\n");
+ return;
+ }
+
+ if (value & 0x1000) {
+ printf("search no entry.\n");
+ return;
+ }
+
+ printf("search done.\n");
+ printf("hash port(0:6) fid vid age mac-address filter my_mac\n");
+
+ printf("%03x: ", (value >> 16) & 0xfff); //hash_addr_lu
+ reg_read(REG_ATRD_ADDR, &value2);
+ j = (value2 >> 4) & 0xff; //r_port_map
+ printf("%c", (j & 0x01) ? '1' : '-');
+ printf("%c", (j & 0x02) ? '1' : '-');
+ printf("%c", (j & 0x04) ? '1' : '-');
+ printf("%c ", (j & 0x08) ? '1' : '-');
+ printf("%c", (j & 0x10) ? '1' : '-');
+ printf("%c", (j & 0x20) ? '1' : '-');
+ printf("%c", (j & 0x40) ? '1' : '-');
+ printf("%c", (j & 0x80) ? '1' : '-');
+
+ reg_read(REG_TSRA2_ADDR, &mac2);
+
+ printf(" %2d", (mac2 >> 12) & 0x7); //FID
+ printf(" %4d", (mac2 & 0xfff));
+ printf(" %4d", (value2 >> 24) & 0xff); //r_age_field
+ reg_read(REG_TSRA1_ADDR, &mac);
+ printf(" %08x", mac);
+ printf("%04x", ((mac2 >> 16) & 0xffff));
+ printf(" %c", (((value2 >> 20) & 0x03) == 0x03) ? 'y' : '-');
+ printf(" %c\n", (((value2 >> 23) & 0x01) == 0x01) ? 'y' : '-');
+}
+
+void table_del_fid(int argc, char *argv[])
+{
+ unsigned int i, j, value;
+ char tmpstr[9];
+
+ if (!argv[3] || strlen(argv[3]) != 12) {
+ printf("MAC address format error, should be of length 12\n");
+ return;
+ }
+ strncpy(tmpstr, argv[3], 8);
+ tmpstr[8] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ reg_write(REG_ATA1_ADDR, value);
+ strncpy(tmpstr, argv[3] + 8, 4);
+ tmpstr[4] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ value = (value << 16);
+
+ if (argc > 5) {
+ j = strtoul(argv[5], NULL, 0);
+ if (j > 7) {
+ printf("wrong fid range, should be within 0~7\n");
+ return;
+ }
+ value |= (j << 12); //fid
+ }
+
+ reg_write(REG_ATA2_ADDR, value);
+
+ value = 0; //STATUS=0, delete mac
+ reg_write(REG_ATWD_ADDR, value);
+
+ value = 0x8001; //w_mac_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ if (argv[1] != NULL)
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void table_del_vid(int argc, char *argv[])
+{
+ unsigned int i, j, value;
+ char tmpstr[9];
+
+ if (!argv[3] || strlen(argv[3]) != 12) {
+ printf("MAC address format error, should be of length 12\n");
+ return;
+ }
+ strncpy(tmpstr, argv[3], 8);
+ tmpstr[8] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ reg_write(REG_ATA1_ADDR, value);
+
+ strncpy(tmpstr, argv[3] + 8, 4);
+ tmpstr[4] = '\0';
+ value = strtoul(tmpstr, NULL, 16);
+ value = (value << 16);
+
+ j = strtoul(argv[5], NULL, 0);
+ if (j > 4095) {
+ printf("wrong fid range, should be within 0~4095\n");
+ return;
+ }
+ value |= j; //vid
+ value |= 1 << 15;
+ reg_write(REG_ATA2_ADDR, value);
+
+ value = 0; //STATUS=0, delete mac
+ reg_write(REG_ATWD_ADDR, value);
+
+ value = 0x8001; //w_mac_cmd
+ reg_write(REG_ATC_ADDR, value);
+
+ for (i = 0; i < 20; i++) {
+ reg_read(REG_ATC_ADDR, &value);
+ if ((value & 0x8000) == 0) { //mac address busy
+ if (argv[1] != NULL)
+ printf("done.\n");
+ return;
+ }
+ usleep(1000);
+ }
+ if (i == 20)
+ printf("timeout.\n");
+}
+
+void table_clear(void)
+{
+ unsigned int value;
+ reg_write(REG_ATC_ADDR, 0x8002);
+ usleep(5000);
+ reg_read(REG_ATC_ADDR, &value);
+
+ printf("REG_ATC_ADDR is 0x%x\n\r", value);
+}
+
+void set_mirror_to(int argc, char *argv[])
+{
+ unsigned int value;
+ int idx;
+
+ idx = strtoul(argv[3], NULL, 0);
+ if (idx < 0 || MAX_PORT < idx) {
+ printf("wrong port member, should be within 0~%d\n", MAX_PORT);
+ return;
+ }
+ if (chip_name == 0x7530) {
+
+ reg_read(REG_MFC_ADDR, &value);
+ value |= 0x1 << 3;
+ value &= 0xfffffff8;
+ value |= idx << 0;
+
+ reg_write(REG_MFC_ADDR, value);
+ } else {
+
+ reg_read(REG_CFC_ADDR, &value);
+ value &= (~REG_CFC_MIRROR_EN_MASK);
+ value |= (1 << REG_CFC_MIRROR_EN_OFFT);
+ value &= (~REG_CFC_MIRROR_PORT_MASK);
+ value |= (idx << REG_CFC_MIRROR_PORT_OFFT);
+ reg_write(REG_CFC_ADDR, value);
+ }
+}
+
+void set_mirror_from(int argc, char *argv[])
+{
+ unsigned int offset, value;
+ int idx, mirror;
+
+ idx = strtoul(argv[3], NULL, 0);
+ mirror = strtoul(argv[4], NULL, 0);
+
+ if (idx < 0 || MAX_PORT < idx) {
+ printf("wrong port member, should be within 0~%d\n", MAX_PORT);
+ return;
+ }
+
+ if (mirror < 0 || 3 < mirror) {
+ printf("wrong mirror setting, should be within 0~3\n");
+ return;
+ }
+
+ offset = (0x2004 | (idx << 8));
+ reg_read(offset, &value);
+
+ value &= 0xfffffcff;
+ value |= mirror << 8;
+
+ reg_write(offset, value);
+}
+
+void vlan_dump(int argc, char *argv[])
+{
+ unsigned int i, j, value, value2;
+ int eg_tag = 0;
+
+ if (argc == 4) {
+ if (!strncmp(argv[3], "egtag", 6))
+ eg_tag = 1;
+ }
+
+ if (eg_tag)
+ printf(" vid fid portmap s-tag\teg_tag(0:untagged 2:tagged)\n");
+ else
+ printf(" vid fid portmap s-tag\n");
+
+ for (i = 1; i < 4095; i++) {
+ value = (0x80000000 + i); //r_vid_cmd
+ reg_write(REG_VTCR_ADDR, value);
+
+ for (j = 0; j < 20; j++) {
+ reg_read(REG_VTCR_ADDR, &value);
+ if ((value & 0x80000000) == 0) { //mac address busy
+ break;
+ }
+ usleep(1000);
+ }
+ if (j == 20)
+ printf("timeout.\n");
+
+ reg_read(REG_VAWD1_ADDR, &value);
+ reg_read(REG_VAWD2_ADDR, &value2);
+ //printf("REG_VAWD1_ADDR value%d is 0x%x\n\r", i, value);
+ //printf("REG_VAWD2_ADDR value%d is 0x%x\n\r", i, value2);
+
+ if ((value & 0x01) != 0) {
+ printf(" %4d ", i);
+ printf(" %2d ", ((value & 0xe) >> 1));
+ printf(" %c", (value & 0x00010000) ? '1' : '-');
+ printf("%c", (value & 0x00020000) ? '1' : '-');
+ printf("%c", (value & 0x00040000) ? '1' : '-');
+ printf("%c", (value & 0x00080000) ? '1' : '-');
+ printf("%c", (value & 0x00100000) ? '1' : '-');
+ printf("%c", (value & 0x00200000) ? '1' : '-');
+ printf("%c", (value & 0x00400000) ? '1' : '-');
+ printf("%c", (value & 0x00800000) ? '1' : '-');
+ printf(" %4d", ((value & 0xfff0) >> 4));
+ if (eg_tag) {
+ printf("\t");
+ if ((value & (0x3 << 28)) == (0x3 << 28)) {
+ /* VTAG_EN=1 and EG_CON=1 */
+ printf("CONSISTENT");
+ } else if (value & (0x1 << 28)) {
+ /* VTAG_EN=1 */
+ printf("%d", (value2 & 0x0003) >> 0);
+ printf("%d", (value2 & 0x000c) >> 2);
+ printf("%d", (value2 & 0x0030) >> 4);
+ printf("%d", (value2 & 0x00c0) >> 6);
+ printf("%d", (value2 & 0x0300) >> 8);
+ printf("%d", (value2 & 0x0c00) >> 10);
+ printf("%d", (value2 & 0x3000) >> 12);
+ printf("%d", (value2 & 0xc000) >> 14);
+ } else {
+ /* VTAG_EN=0 */
+ printf("DISABLED");
+ }
+ }
+ printf("\n");
+ } else {
+ /*print 16 vid for reference information*/
+ if (i <= 16) {
+ printf(" %4d ", i);
+ printf(" %2d ", ((value & 0xe) >> 1));
+ printf(" invalid\n");
+ }
+ }
+ }
+}
+
+
+static long timespec_diff_us(struct timespec start, struct timespec end)
+{
+ struct timespec temp;
+ unsigned long duration = 0;
+
+ if ((end.tv_nsec - start.tv_nsec) < 0) {
+ temp.tv_sec = end.tv_sec - start.tv_sec - 1;
+ temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
+ } else {
+ temp.tv_sec = end.tv_sec - start.tv_sec;
+ temp.tv_nsec = end.tv_nsec - start.tv_nsec;
+ }
+ /* calculate second part*/
+ duration += temp.tv_sec * 1000000;
+ /* calculate ns part*/
+ duration += temp.tv_nsec >> 10;
+
+ return duration;
+}
+
+
+void vlan_clear(int argc, char *argv[])
+{
+ unsigned int value;
+ int vid;
+ unsigned long duration_us = 0;
+ struct timespec start, end;
+
+ for (vid = 0; vid < 4096; vid++) {
+ clock_gettime(CLOCK_REALTIME, &start);
+ value = 0; //invalid
+ reg_write(REG_VAWD1_ADDR, value);
+
+ value = (0x80001000 + vid); //w_vid_cmd
+ reg_write(REG_VTCR_ADDR, value);
+ while (duration_us <= 1000) {
+ reg_read(REG_VTCR_ADDR, &value);
+ if ((value & 0x80000000) == 0) { //table busy
+ break;
+ }
+ clock_gettime(CLOCK_REALTIME, &end);
+ duration_us = timespec_diff_us(start, end);
+ }
+ if (duration_us > 1000)
+ printf("config vlan timeout: %ld.\n", duration_us);
+ }
+}
+
+void vlan_set(int argc, char *argv[])
+{
+ unsigned int vlan_mem = 0;
+ unsigned int value = 0;
+ unsigned int value2 = 0;
+ int i, vid, fid;
+ int stag = 0;
+ unsigned long eg_con = 0;
+ unsigned int eg_tag = 0;
+
+ if (argc < 5) {
+ printf("insufficient arguments!\n");
+ return;
+ }
+
+ fid = strtoul(argv[3], NULL, 0);
+ if (fid < 0 || fid > 7) {
+ printf("wrong filtering db id range, should be within 0~7\n");
+ return;
+ }
+ value |= (fid << 1);
+
+ vid = strtoul(argv[4], NULL, 0);
+ if (vid < 0 || 0xfff < vid) {
+ printf("wrong vlan id range, should be within 0~4095\n");
+ return;
+ }
+
+ if (strlen(argv[5]) != 8) {
+ printf("portmap format error, should be of length 7\n");
+ return;
+ }
+
+ vlan_mem = 0;
+ for (i = 0; i < 8; i++) {
+ if (argv[5][i] != '0' && argv[5][i] != '1') {
+ printf("portmap format error, should be of combination of 0 or 1\n");
+ return;
+ }
+ vlan_mem += (argv[5][i] - '0') * (1 << i);
+ }
+
+ /* VLAN stag */
+ if (argc > 6) {
+ stag = strtoul(argv[6], NULL, 16);
+ if (stag < 0 || 0xfff < stag) {
+ printf("wrong stag id range, should be within 0~4095\n");
+ return;
+ }
+ //printf("STAG is 0x%x\n", stag);
+ }
+
+ /* set vlan member */
+ value |= (vlan_mem << 16);
+ value |= (1 << 30); //IVL=1
+ value |= ((stag & 0xfff) << 4); //stag
+ value |= 1; //valid
+
+ if (argc > 7) {
+ eg_con = strtoul(argv[7], NULL, 2);
+ eg_con = !!eg_con;
+ value |= (eg_con << 29); //eg_con
+ value |= (1 << 28); //eg tag control enable
+ }
+
+ if (argc > 8 && !eg_con) {
+ if (strlen(argv[8]) != 8) {
+ printf("egtag portmap format error, should be of length 7\n");
+ return;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (argv[8][i] < '0' || argv[8][i] > '3') {
+ printf("egtag portmap format error, should be of combination of 0 or 3\n");
+ return;
+ }
+ //eg_tag += (argv[8][i] - '0') * (1 << i * 2);
+ eg_tag |= (argv[8][i] - '0') << (i * 2);
+ }
+
+ value |= (1 << 28); //eg tag control enable
+ value2 &= ~(0xffff);
+ value2 |= eg_tag;
+ }
+ reg_write(REG_VAWD1_ADDR, value);
+ reg_write(REG_VAWD2_ADDR, value2);
+ //printf("VAWD1=0x%08x VAWD2=0x%08x ", value, value2);
+
+ value = (0x80001000 + vid); //w_vid_cmd
+ reg_write(REG_VTCR_ADDR, value);
+ //printf("VTCR=0x%08x\n", value);
+
+ for (i = 0; i < 300; i++) {
+ usleep(1000);
+ reg_read(REG_VTCR_ADDR, &value);
+ if ((value & 0x80000000) == 0) //table busy
+ break;
+ }
+
+ if (i == 300)
+ printf("config vlan timeout.\n");
+}
+
+void igmp_on(int argc, char *argv[])
+{
+ unsigned int leaky_en = 0;
+ unsigned int wan_num = 4;
+ unsigned int port, offset, value;
+ char cmd[80];
+ int ret;
+
+ if (argc > 3)
+ leaky_en = strtoul(argv[3], NULL, 10);
+ if (argc > 4)
+ wan_num = strtoul(argv[4], NULL, 10);
+
+ if (leaky_en == 1) {
+ if (wan_num == 4) {
+ /* reg_write(0x2410, 0x810000c8); */
+ reg_read(0x2410, &value);
+ reg_write(0x2410, value | (1 << 3));
+ /* reg_write(0x2010, 0x810000c0); */
+ reg_read(0x2010, &value);
+ reg_write(0x2010, value & (~(1 << 3)));
+ reg_write(REG_ISC_ADDR, 0x10027d10);
+ } else {
+ /* reg_write(0x2010, 0x810000c8); */
+ reg_read(0x2010, &value);
+ reg_write(0x2010, value | (1 << 3));
+ /* reg_write(0x2410, 0x810000c0); */
+ reg_read(0x2410, &value);
+ reg_write(0x2410, value & (~(1 << 3)));
+ reg_write(REG_ISC_ADDR, 0x01027d01);
+ }
+ }
+ else
+ reg_write(REG_ISC_ADDR, 0x10027d60);
+
+ reg_write(0x1c, 0x08100810);
+ reg_write(0x2008, 0xb3ff);
+ reg_write(0x2108, 0xb3ff);
+ reg_write(0x2208, 0xb3ff);
+ reg_write(0x2308, 0xb3ff);
+ reg_write(0x2408, 0xb3ff);
+ reg_write(0x2608, 0xb3ff);
+ /* Enable Port ACL
+ * reg_write(0x2P04, 0xff0403);
+ */
+ for (port = 0; port <= 6; port++) {
+ offset = 0x2004 + port * 0x100;
+ reg_read(offset, &value);
+ reg_write(offset, value | (1 << 10));
+ }
+
+ /*IGMP query only p4 -> p5*/
+ reg_write(0x94, 0x00ff0002);
+ if (wan_num == 4)
+ reg_write(0x98, 0x000a1008);
+ else
+ reg_write(0x98, 0x000a0108);
+ reg_write(0x90, 0x80005000);
+ reg_write(0x94, 0xff001100);
+ if (wan_num == 4)
+ reg_write(0x98, 0x000B1000);
+ else
+ reg_write(0x98, 0x000B0100);
+ reg_write(0x90, 0x80005001);
+ reg_write(0x94, 0x3);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x80009000);
+ reg_write(0x94, 0x1a002080);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x8000b000);
+
+ /*IGMP p5 -> p4*/
+ reg_write(0x94, 0x00ff0002);
+ reg_write(0x98, 0x000a2008);
+ reg_write(0x90, 0x80005002);
+ reg_write(0x94, 0x4);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x80009001);
+ if (wan_num == 4)
+ reg_write(0x94, 0x1a001080);
+ else
+ reg_write(0x94, 0x1a000180);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x8000b001);
+
+ /*IGMP p0~p3 -> p6*/
+ reg_write(0x94, 0x00ff0002);
+ if (wan_num == 4)
+ reg_write(0x98, 0x000a0f08);
+ else
+ reg_write(0x98, 0x000a1e08);
+ reg_write(0x90, 0x80005003);
+ reg_write(0x94, 0x8);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x80009002);
+ reg_write(0x94, 0x1a004080);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x8000b002);
+
+ /*IGMP query only p6 -> p0~p3*/
+ reg_write(0x94, 0x00ff0002);
+ reg_write(0x98, 0x000a4008);
+ reg_write(0x90, 0x80005004);
+ reg_write(0x94, 0xff001100);
+ reg_write(0x98, 0x000B4000);
+ reg_write(0x90, 0x80005005);
+ reg_write(0x94, 0x30);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x80009003);
+ if (wan_num == 4)
+ reg_write(0x94, 0x1a000f80);
+ else
+ reg_write(0x94, 0x1a001e80);
+ reg_write(0x98, 0x0);
+ reg_write(0x90, 0x8000b003);
+
+ /*Force eth2 to receive all igmp packets*/
+ snprintf(cmd, sizeof(cmd), "echo 2 > /sys/devices/virtual/net/%s/brif/%s/multicast_router", BR_DEVNAME, ETH_DEVNAME);
+ ret = system(cmd);
+ if (ret)
+ printf("Failed to set /sys/devices/virtual/net/%s/brif/%s/multicast_router\n",
+ BR_DEVNAME, ETH_DEVNAME);
+}
+
+void igmp_disable(int argc, char *argv[])
+{
+ unsigned int reg_offset, value;
+ int port_num;
+
+ if (argc < 4) {
+ printf("insufficient arguments!\n");
+ return;
+ }
+ port_num = strtoul(argv[3], NULL, 0);
+ if (port_num < 0 || 6 < port_num) {
+ printf("wrong port range, should be within 0~6\n");
+ return;
+ }
+
+ //set ISC: IGMP Snooping Control Register (offset: 0x0018)
+ reg_offset = 0x2008;
+ reg_offset |= (port_num << 8);
+ value = 0x8000;
+
+ reg_write(reg_offset, value);
+}
+
+void igmp_enable(int argc, char *argv[])
+{
+ unsigned int reg_offset, value;
+ int port_num;
+
+ if (argc < 4) {
+ printf("insufficient arguments!\n");
+ return;
+ }
+ port_num = strtoul(argv[3], NULL, 0);
+ if (port_num < 0 || 6 < port_num) {
+ printf("wrong port range, should be within 0~6\n");
+ return;
+ }
+
+ //set ISC: IGMP Snooping Control Register (offset: 0x0018)
+ reg_offset = 0x2008;
+ reg_offset |= (port_num << 8);
+ value = 0x9755;
+ reg_write(reg_offset, value);
+}
+
+void igmp_off()
+{
+ unsigned int value;
+ //set ISC: IGMP Snooping Control Register (offset: 0x0018)
+ reg_read(REG_ISC_ADDR, &value);
+ value &= ~(1 << 18); //disable
+ reg_write(REG_ISC_ADDR, value);
+
+ /*restore wan port multicast leaky vlan function: default disabled*/
+ reg_read(0x2010, &value);
+ reg_write(0x2010, value & (~(1 << 3)));
+ reg_read(0x2410, &value);
+ reg_write(0x2410, value & (~(1 << 3)));
+
+ printf("config igmpsnoop off.\n");
+}
+
+void switch_reset(int argc, char *argv[])
+{
+ unsigned int value = 0;
+ /*Software Register Reset and Software System Reset */
+ reg_write(0x7000, 0x3);
+ reg_read(0x7000, &value);
+ printf("SYS_CTRL(0x7000) register value =0x%x \n", value);
+ if (chip_name == 0x7531) {
+ reg_write(0x7c0c, 0x11111111);
+ reg_read(0x7c0c, &value);
+ printf("GPIO Mode (0x7c0c) select value =0x%x \n", value);
+ }
+ printf("Switch Software Reset !!! \n");
+}
+
+int phy_set_fc(int argc, char *argv[])
+{
+ unsigned int port, pause_capable;
+ unsigned int phy_value;
+
+ port = atoi(argv[3]);
+ pause_capable = atoi(argv[4]);
+
+ /*Check the input parameters is right or not.*/
+ if (port > MAX_PORT - 2 || pause_capable > 1) {
+ printf("Illegal parameter (port:0~4, full_duplex_pause_capable:0|1)\n");
+ return -1;
+ }
+ printf("port=%d, full_duplex_pause_capable:%d\n", port, pause_capable);
+ mii_mgr_read(port, 4, &phy_value);
+ printf("read phy_value:0x%x\r\n", phy_value);
+ phy_value &= (~(0x1 << 10));
+ phy_value &= (~(0x1 << 11));
+ if (pause_capable == 1) {
+ phy_value |= (0x1 << 10);
+ phy_value |= (0x1 << 11);
+ }
+ mii_mgr_write(port, 4, phy_value);
+ printf("write phy_value:0x%x\r\n", phy_value);
+ return 0;
+} /*end phy_set_fc*/
+
+int phy_set_an(int argc, char *argv[])
+{
+ unsigned int port, auto_negotiation_en;
+ unsigned int phy_value;
+
+ port = atoi(argv[3]);
+ auto_negotiation_en = atoi(argv[4]);
+
+ /*Check the input parameters is right or not.*/
+ if (port > MAX_PORT - 2 || auto_negotiation_en > 1) {
+ printf("Illegal parameter (port:0~4, auto_negotiation_en:0|1)\n");
+ return -1;
+ }
+ printf("port=%d, auto_negotiation_en:%d\n", port, auto_negotiation_en);
+ mii_mgr_read(port, 0, &phy_value);
+ printf("read phy_value:0x%x\r\n", phy_value);
+ phy_value &= (~(1 << 12));
+ phy_value |= (auto_negotiation_en << 12);
+ mii_mgr_write(port, 0, phy_value);
+ printf("write phy_value:0x%x\r\n", phy_value);
+ return 0;
+} /*end phy_set_an*/
+
+int set_mac_pfc(int argc, char *argv[])
+{
+ unsigned int value;
+ int port, enable = 0;
+
+ port = atoi(argv[3]);
+ enable = atoi(argv[4]);
+ printf("enable: %d\n", enable);
+ if (port < 0 || port > 6 || enable < 0 || enable > 1) {
+ printf("Illegal parameter (port:0~6, enable|diable:0|1) \n");
+ return -1;
+ }
+ if (chip_name == 0x7531) {
+ reg_read(REG_PFC_CTRL_ADDR, &value);
+ value &= ~(1 << port);
+ value |= (enable << port);
+ printf("write reg: %x, value: %x\n", REG_PFC_CTRL_ADDR, value);
+ reg_write(REG_PFC_CTRL_ADDR, value);
+ }
+ else
+ printf("\nCommand not support by this chip.\n");
+ return 0;
+}
+
+int global_set_mac_fc(int argc, char *argv[])
+{
+ unsigned char enable = 0;
+ unsigned int value, reg;
+
+ if (chip_name == 0x7530) {
+ enable = atoi(argv[3]);
+ printf("enable: %d\n", enable);
+
+ /*Check the input parameters is right or not.*/
+ if (enable > 1) {
+ printf(HELP_MACCTL_FC);
+ return -1;
+ }
+ reg_write(0x7000, 0x3);
+ reg = REG_GFCCR0_ADDR;
+ reg_read(REG_GFCCR0_ADDR, &value);
+ value &= (~REG_FC_EN_MASK);
+ value |= (enable << REG_FC_EN_OFFT);
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(REG_GFCCR0_ADDR, value);
+ } else
+ printf("\r\nCommand not support by this chip.\n");
+ return 0;
+} /*end mac_set_fc*/
+
+int qos_sch_select(int argc, char *argv[])
+{
+ unsigned char port, queue;
+ unsigned char type = 0;
+ unsigned int value, reg;
+
+ if (argc < 7)
+ return -1;
+
+ port = atoi(argv[3]);
+ queue = atoi(argv[4]);
+ type = atoi(argv[6]);
+
+ if (port > 6 || queue > 7) {
+ printf("\n Illegal input parameters\n");
+ return -1;
+ }
+
+ if ((type != 0 && type != 1 && type != 2)) {
+ printf(HELP_QOS_TYPE);
+ return -1;
+ }
+
+ printf("\r\nswitch qos type: %d.\n",type);
+
+ if (!strncmp(argv[5], "min", 4)) {
+
+ if (type == 0) {
+ /*min sharper-->round roubin, disable min sharper rate limit*/
+ reg = GSW_MMSCR0_Q(queue) + 0x100 * port;
+ reg_read(reg, &value);
+ value = 0x0;
+ reg_write(reg, value);
+ } else if (type == 1) {
+ /*min sharper-->sp, disable min sharper rate limit*/
+ reg = GSW_MMSCR0_Q(queue) + 0x100 * port;
+ reg_read(reg, &value);
+ value = 0x0;
+ value |= (1 << 31);
+ reg_write(reg, value);
+ } else {
+ printf("min sharper only support: rr or sp\n");
+ return -1;
+ }
+ } else if (!strncmp(argv[5], "max", 4)) {
+ if (type == 1) {
+ /*max sharper-->sp, disable max sharper rate limit*/
+ reg = GSW_MMSCR1_Q(queue) + 0x100 * port;
+ reg_read(reg, &value);
+ value = 0x0;
+ value |= (1 << 31);
+ reg_write(reg, value);
+ } else if (type == 2) {
+ /*max sharper-->wfq, disable max sharper rate limit*/
+ reg = GSW_MMSCR1_Q(queue) + 0x100 * port;
+ reg_read(reg, &value);
+ value = 0x0;
+ reg_write(reg, value);
+ } else {
+ printf("max sharper only support: wfq or sp\n");
+ return -1;
+ }
+ } else {
+ printf("\r\nIllegal sharper:%s\n",argv[5]);
+ return -1;
+ }
+ printf("reg:0x%x--value:0x%x\n",reg,value);
+
+ return 0;
+}
+
+void get_upw(unsigned int *value, unsigned char base)
+{
+ *value &= (~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) |
+ (0x7 << 16) | (0x7 << 20)));
+ switch (base)
+ {
+ case 0: /* port-based 0x2x40[18:16] */
+ *value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+ (0x2 << 12) | (0x7 << 16) | (0x2 << 20));
+ break;
+ case 1: /* tagged-based 0x2x40[10:8] */
+ *value |= ((0x2 << 0) | (0x2 << 4) | (0x7 << 8) |
+ (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+ break;
+ case 2: /* DSCP-based 0x2x40[14:12] */
+ *value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+ (0x7 << 12) | (0x2 << 16) | (0x2 << 20));
+ break;
+ case 3: /* acl-based 0x2x40[2:0] */
+ *value |= ((0x7 << 0) | (0x2 << 4) | (0x2 << 8) |
+ (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+ break;
+ case 4: /* arl-based 0x2x40[22:20] */
+ *value |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8) |
+ (0x2 << 12) | (0x2 << 16) | (0x7 << 20));
+ break;
+ case 5: /* stag-based 0x2x40[6:4] */
+ *value |= ((0x2 << 0) | (0x7 << 4) | (0x2 << 8) |
+ (0x2 << 12) | (0x2 << 16) | (0x2 << 20));
+ break;
+ default:
+ break;
+ }
+}
+
+void qos_set_base(int argc, char *argv[])
+{
+ unsigned char base = 0;
+ unsigned char port;
+ unsigned int value;
+
+ if (argc < 5)
+ return;
+
+ port = atoi(argv[3]);
+ base = atoi(argv[4]);
+
+ if (base > 6) {
+ printf(HELP_QOS_BASE);
+ return;
+ }
+
+ if (port > 6) {
+ printf("Illegal port index:%d\n",port);
+ return;
+ }
+
+ printf("\r\nswitch qos base : %d. (port-based:0, tag-based:1,\
+ dscp-based:2, acl-based:3, arl-based:4, stag-based:5)\n",
+ base);
+ if (chip_name == 0x7530) {
+
+ reg_read(0x44, &value);
+ get_upw(&value, base);
+ reg_write(0x44, value);
+ printf("reg: 0x44, value: 0x%x\n", value);
+
+ } else if (chip_name == 0x7531) {
+
+ reg_read(GSW_UPW(port), &value);
+ get_upw(&value, base);
+ reg_write(GSW_UPW(port), value);
+ printf("reg:0x%x, value: 0x%x\n",GSW_UPW(port),value);
+
+ } else {
+ printf("unknown switch device");
+ return;
+ }
+}
+
+void qos_wfq_set_weight(int argc, char *argv[])
+{
+ int port, weight[8], i;
+ unsigned char queue;
+ unsigned int reg, value;
+
+ port = atoi(argv[3]);
+
+ for (i = 0; i < 8; i++) {
+ weight[i] = atoi(argv[i + 4]);
+ }
+
+ /* MT7530 total 7 port */
+ if (port < 0 || port > 6) {
+ printf(HELP_QOS_PORT_WEIGHT);
+ return;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (weight[i] < 1 || weight[i] > 16) {
+ printf(HELP_QOS_PORT_WEIGHT);
+ return;
+ }
+ }
+ printf("port: %x, q0: %x, q1: %x, q2: %x, q3: %x, \
+ q4: %x, q5: %x, q6: %x, q7: %x\n",
+ port, weight[0], weight[1], weight[2], weight[3], weight[4],
+ weight[5], weight[6], weight[7]);
+
+ for (queue = 0; queue < 8; queue++) {
+ reg = GSW_MMSCR1_Q(queue) + 0x100 * port;
+ reg_read(reg, &value);
+ value &= (~(0xf << 24)); //bit24~27
+ value |= (((weight[queue] - 1) & 0xf) << 24);
+ printf("reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+ }
+}
+
+void qos_set_portpri(int argc, char *argv[])
+{
+ unsigned char port, prio;
+ unsigned int value;
+
+ port = atoi(argv[3]);
+ prio = atoi(argv[4]);
+
+ if (port >= 7 || prio > 7) {
+ printf(HELP_QOS_PORT_PRIO);
+ return;
+ }
+
+ reg_read(GSW_PCR(port), &value);
+ value &= (~(0x7 << 24));
+ value |= (prio << 24);
+ reg_write(GSW_PCR(port), value);
+ printf("write reg: %x, value: %x\n", GSW_PCR(port), value);
+}
+
+void qos_set_dscppri(int argc, char *argv[])
+{
+ unsigned char prio, dscp, pim_n, pim_offset;
+ unsigned int reg, value;
+
+ dscp = atoi(argv[3]);
+ prio = atoi(argv[4]);
+
+ if (dscp > 63 || prio > 7) {
+ printf(HELP_QOS_DSCP_PRIO);
+ return;
+ }
+
+ pim_n = dscp / 10;
+ pim_offset = (dscp - pim_n * 10) * 3;
+ reg = 0x0058 + pim_n * 4;
+ reg_read(reg, &value);
+ value &= (~(0x7 << pim_offset));
+ value |= ((prio & 0x7) << pim_offset);
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+}
+
+void qos_pri_mapping_queue(int argc, char *argv[])
+{
+ unsigned char prio, queue, pem_n, port;
+ unsigned int reg, value;
+
+ if (argc < 6)
+ return;
+
+ port = atoi(argv[3]);
+ prio = atoi(argv[4]);
+ queue = atoi(argv[5]);
+
+ if (prio > 7 || queue > 7) {
+ printf(HELP_QOS_PRIO_QMAP);
+ return;
+ }
+ if (chip_name == 0x7530) {
+ pem_n = prio / 2;
+ reg = pem_n * 0x4 + 0x48;
+ reg_read(reg, &value);
+ if (prio % 2) {
+ value &= (~(0x7 << 24));
+ value |= ((queue & 0x7) << 24);
+ } else {
+ value &= (~(0x7 << 8));
+ value |= ((queue & 0x7) << 8);
+ }
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+ } else if (chip_name == 0x7531) {
+ pem_n = prio / 2;
+ reg = GSW_PEM(pem_n) + 0x100 * port;
+ reg_read(reg, &value);
+ if (prio % 2) { // 1 1
+ value &= (~(0x7 << 25));
+ value |= ((queue & 0x7) << 25);
+ } else { // 0 0
+ value &= (~(0x7 << 9));
+ value |= ((queue & 0x7) << 9);
+ }
+ reg_write(reg, value);
+ printf("write reg: %x, value: %x\n", reg, value);
+ }
+ else {
+ printf("unknown switch device");
+ return;
+ }
+}
+
+static int macMT753xVlanSetVid(unsigned char index, unsigned char active,
+ unsigned short vid, unsigned char portMap, unsigned char tagPortMap,
+ unsigned char ivl_en, unsigned char fid, unsigned short stag)
+{
+ unsigned int value = 0;
+ unsigned int value2 = 0;
+ unsigned int reg;
+ int i;
+
+ printf("index: %x, active: %x, vid: %x, portMap: %x, \
+ tagPortMap: %x, ivl_en: %x, fid: %x, stag: %x\n",
+ index, active, vid, portMap, tagPortMap, ivl_en, fid, stag);
+
+ value = (portMap << 16);
+ value |= (stag << 4);
+ value |= (ivl_en << 30);
+ value |= (fid << 1);
+ value |= (active ? 1 : 0);
+
+ // total 7 ports
+ for (i = 0; i < 7; i++) {
+ if (tagPortMap & (1 << i))
+ value2 |= 0x2 << (i * 2);
+ }
+
+ if (value2)
+ value |= (1 << 28); // eg_tag
+
+ reg = 0x98; // VAWD2
+ reg_write(reg, value2);
+
+ reg = 0x94; // VAWD1
+ reg_write(reg, value);
+
+ reg = 0x90; // VTCR
+ value = (0x80001000 + vid);
+ reg_write(reg, value);
+
+ reg = 0x90; // VTCR
+ while (1) {
+ reg_read(reg, &value);
+ if ((value & 0x80000000) == 0) //table busy
+ break;
+ }
+
+ /* switch clear */
+ reg = 0x80;
+ reg_write(reg, 0x8002);
+ usleep(5000);
+ reg_read(reg, &value);
+
+ printf("SetVid: index:%d active:%d vid:%d portMap:%x tagPortMap:%x\r\n",
+ index, active, vid, portMap, tagPortMap);
+ return 0;
+
+} /*end macMT753xVlanSetVid*/
+/*
+static int macMT753xVlanGetVtbl(unsigned short index)
+{
+ unsigned int reg, value, vawd1, vawd2;
+
+ reg = 0x90; // VTCR
+ value = (0x80000000 + index);
+
+ reg_write(reg, value);
+
+ reg = 0x90; // VTCR
+ while (1) {
+ reg_read(reg, &value);
+ if ((value & 0x80000000) == 0) //table busy
+ break;
+ }
+
+ reg = 0x94; // VAWD1
+ reg_read(reg, &vawd1);
+
+ reg = 0x98; // VAWD2
+ reg_read(reg, &vawd2);
+
+ if (vawd1 & 0x1) {
+ fprintf(stderr, "%d.%s vid:%d fid:%d portMap:0x%x \
+ tagMap:0x%x stag:0x%x ivl_en:0x%x\r\n",
+ index, (vawd1 & 0x1) ? "on" : "off", index, ((vawd1 & 0xe) >> 1),
+ (vawd1 & 0xff0000) >> 16, vawd2, (vawd1 & 0xfff0) >> 0x4, (vawd1 >> 30) & 0x1);
+ }
+ return 0;
+} */ /*end macMT753xVlanGetVtbl*/
+
+static int macMT753xVlanSetPvid(unsigned char port, unsigned short pvid)
+{
+ unsigned int value;
+ unsigned int reg;
+
+ /*Parameters is error*/
+ if (port > 6)
+ return -1;
+
+ reg = 0x2014 + (port * 0x100);
+ reg_read(reg, &value);
+ value &= ~0xfff;
+ value |= pvid;
+ reg_write(reg, value);
+
+ /* switch clear */
+ reg = 0x80;
+ reg_write(reg, 0x8002);
+ usleep(5000);
+ reg_read(reg, &value);
+
+ printf("SetPVID: port:%d pvid:%d\r\n", port, pvid);
+ return 0;
+}
+/*
+static int macMT753xVlanGetPvid(unsigned char port)
+{
+ unsigned int value;
+ unsigned int reg;
+
+ if (port > 6)
+ return -1;
+ reg = 0x2014 + (port * 0x100);
+ reg_read(reg, &value);
+ return (value & 0xfff);
+} */
+/*
+static int macMT753xVlanDisp(void)
+{
+ unsigned int i = 0;
+ unsigned int reg, value;
+
+ reg = 0x2604;
+ reg_read(reg, &value);
+ value &= 0x30000000;
+
+ fprintf(stderr, "VLAN function is %s\n", value ? ETHCMD_ENABLE : ETHCMD_DISABLE);
+ fprintf(stderr, "PVID e0:%02d e1:%02d e2:%02d e3:%02d e4:%02d e5:%02d e6:%02d\n",
+ macMT753xVlanGetPvid(0), macMT753xVlanGetPvid(1), macMT753xVlanGetPvid(2),
+ macMT753xVlanGetPvid(3), macMT753xVlanGetPvid(4), macMT753xVlanGetPvid(5), macMT753xVlanGetPvid(6));
+
+ for (i = 0; i < MAX_VID_VALUE; i++)
+ macMT753xVlanGetVtbl(i);
+
+ return 0;
+}*/ /*end macMT753xVlanDisp*/
+
+void doVlanSetPvid(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned short pvid = 0;
+
+ port = atoi(argv[3]);
+ pvid = atoi(argv[4]);
+ /*Check the input parameters is right or not.*/
+ if ((port >= SWITCH_MAX_PORT) || (pvid > MAX_VID_VALUE)) {
+ printf(HELP_VLAN_PVID);
+ return;
+ }
+
+ macMT753xVlanSetPvid(port, pvid);
+
+ printf("port:%d pvid:%d,vlancap: max_port:%d maxvid:%d\r\n",
+ port, pvid, SWITCH_MAX_PORT, MAX_VID_VALUE);
+} /*end doVlanSetPvid*/
+
+void doVlanSetVid(int argc, char *argv[])
+{
+ unsigned char index = 0;
+ unsigned char active = 0;
+ unsigned char portMap = 0;
+ unsigned char tagPortMap = 0;
+ unsigned short vid = 0;
+
+ unsigned char ivl_en = 0;
+ unsigned char fid = 0;
+ unsigned short stag = 0;
+
+ index = atoi(argv[3]);
+ active = atoi(argv[4]);
+ vid = atoi(argv[5]);
+
+ /*Check the input parameters is right or not.*/
+ if ((index >= MAX_VLAN_RULE) || (vid >= 4096) || (active > ACTIVED)) {
+ printf(HELP_VLAN_VID);
+ return;
+ }
+
+ /*CPU Port is always the membership*/
+ portMap = atoi(argv[6]);
+ tagPortMap = atoi(argv[7]);
+
+ printf("subcmd parameter argc = %d\r\n", argc);
+ if (argc >= 9) {
+ ivl_en = atoi(argv[8]);
+ if (argc >= 10) {
+ fid = atoi(argv[9]);
+ if (argc >= 11)
+ stag = atoi(argv[10]);
+ }
+ }
+ macMT753xVlanSetVid(index, active, vid, portMap, tagPortMap,
+ ivl_en, fid, stag);
+ printf("index:%d active:%d vid:%d\r\n", index, active, vid);
+} /*end doVlanSetVid*/
+
+void doVlanSetAccFrm(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned char type = 0;
+ unsigned int value;
+ unsigned int reg;
+
+ port = atoi(argv[3]);
+ type = atoi(argv[4]);
+
+ printf("port: %d, type: %d\n", port, type);
+
+ /*Check the input parameters is right or not.*/
+ if ((port > SWITCH_MAX_PORT) || (type > REG_PVC_ACC_FRM_RELMASK)) {
+ printf(HELP_VLAN_ACC_FRM);
+ return;
+ }
+
+ reg = REG_PVC_P0_ADDR + port * 0x100;
+ reg_read(reg, &value);
+ value &= (~REG_PVC_ACC_FRM_MASK);
+ value |= ((unsigned int)type << REG_PVC_ACC_FRM_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+} /*end doVlanSetAccFrm*/
+
+void doVlanSetPortAttr(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned char attr = 0;
+ unsigned int value;
+ unsigned int reg;
+
+ port = atoi(argv[3]);
+ attr = atoi(argv[4]);
+
+ printf("port: %x, attr: %x\n", port, attr);
+
+ /*Check the input parameters is right or not.*/
+ if (port > SWITCH_MAX_PORT || attr > 3) {
+ printf(HELP_VLAN_PORT_ATTR);
+ return;
+ }
+
+ reg = 0x2010 + port * 0x100;
+ reg_read(reg, &value);
+ value &= (0xffffff3f);
+ value |= (attr << 6);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+}
+
+void doVlanSetPortMode(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned char mode = 0;
+ unsigned int value;
+ unsigned int reg;
+ port = atoi(argv[3]);
+ mode = atoi(argv[4]);
+ printf("port: %x, mode: %x\n", port, mode);
+
+ /*Check the input parameters is right or not.*/
+ if (port > SWITCH_MAX_PORT || mode > 3) {
+ printf(HELP_VLAN_PORT_MODE);
+ return;
+ }
+
+ reg = 0x2004 + port * 0x100;
+ reg_read(reg, &value);
+ value &= (~((1 << 0) | (1 << 1)));
+ value |= (mode & 0x3);
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+}
+
+void doVlanSetEgressTagPCR(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned char eg_tag = 0;
+ unsigned int value;
+ unsigned int reg;
+
+ port = atoi(argv[3]);
+ eg_tag = atoi(argv[4]);
+
+ printf("port: %d, eg_tag: %d\n", port, eg_tag);
+
+ /*Check the input parameters is right or not.*/
+ if ((port > SWITCH_MAX_PORT) || (eg_tag > REG_PCR_EG_TAG_RELMASK)) {
+ printf(HELP_VLAN_EGRESS_TAG_PCR);
+ return;
+ }
+
+ reg = REG_PCR_P0_ADDR + port * 0x100;
+ reg_read(reg, &value);
+ value &= (~REG_PCR_EG_TAG_MASK);
+ value |= ((unsigned int)eg_tag << REG_PCR_EG_TAG_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+
+} /*end doVlanSetEgressTagPCR*/
+
+void doVlanSetEgressTagPVC(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned char eg_tag = 0;
+ unsigned int value;
+ unsigned int reg;
+
+ port = atoi(argv[3]);
+ eg_tag = atoi(argv[4]);
+
+ printf("port: %d, eg_tag: %d\n", port, eg_tag);
+
+ /*Check the input parameters is right or not.*/
+ if ((port > SWITCH_MAX_PORT) || (eg_tag > REG_PVC_EG_TAG_RELMASK)) {
+ printf(HELP_VLAN_EGRESS_TAG_PVC);
+ return;
+ }
+
+ reg = REG_PVC_P0_ADDR + port * 0x100;
+ reg_read(reg, &value);
+ value &= (~REG_PVC_EG_TAG_MASK);
+ value |= ((unsigned int)eg_tag << REG_PVC_EG_TAG_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+} /*end doVlanSetEgressTagPVC*/
+
+void doArlAging(int argc, char *argv[])
+{
+ unsigned char aging_en = 0;
+ unsigned int time = 0, aging_cnt = 0, aging_unit = 0, value, reg;
+ ;
+
+ aging_en = atoi(argv[3]);
+ time = atoi(argv[4]);
+ printf("aging_en: %x, aging time: %x\n", aging_en, time);
+
+ /*Check the input parameters is right or not.*/
+ if ((aging_en != 0 && aging_en != 1) || (time <= 0 || time > 65536)) {
+ printf(HELP_ARL_AGING);
+ return;
+ }
+
+ reg = 0xa0;
+ reg_read(reg, &value);
+ value &= (~(1 << 20));
+ if (!aging_en) {
+ value |= (1 << 20);
+ }
+
+ aging_unit = (time / 0x100) + 1;
+ aging_cnt = (time / aging_unit);
+ aging_unit--;
+ aging_cnt--;
+
+ value &= (0xfff00000);
+ value |= ((aging_cnt << 12) | aging_unit);
+
+ printf("aging_unit: %x, aging_cnt: %x\n", aging_unit, aging_cnt);
+ printf("write reg: %x, value: %x\n", reg, value);
+
+ reg_write(reg, value);
+}
+
+void doMirrorEn(int argc, char *argv[])
+{
+ unsigned char mirror_en;
+ unsigned char mirror_port;
+ unsigned int value, reg;
+
+ mirror_en = atoi(argv[3]);
+ mirror_port = atoi(argv[4]);
+
+ printf("mirror_en: %d, mirror_port: %d\n", mirror_en, mirror_port);
+
+ /*Check the input parameters is right or not.*/
+ if ((mirror_en > 1) || (mirror_port > REG_CFC_MIRROR_PORT_RELMASK)) {
+ printf(HELP_MIRROR_EN);
+ return;
+ }
+
+ reg = REG_CFC_ADDR;
+ reg_read(reg, &value);
+ value &= (~REG_CFC_MIRROR_EN_MASK);
+ value |= (mirror_en << REG_CFC_MIRROR_EN_OFFT);
+ value &= (~REG_CFC_MIRROR_PORT_MASK);
+ value |= (mirror_port << REG_CFC_MIRROR_PORT_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+
+} /*end doMirrorEn*/
+
+void doMirrorPortBased(int argc, char *argv[])
+{
+ unsigned char port, port_tx_mir, port_rx_mir, vlan_mis, acl_mir, igmp_mir;
+ unsigned int value, reg;
+
+ port = atoi(argv[3]);
+ port_tx_mir = atoi(argv[4]);
+ port_rx_mir = atoi(argv[5]);
+ acl_mir = atoi(argv[6]);
+ vlan_mis = atoi(argv[7]);
+ igmp_mir = atoi(argv[8]);
+
+ printf("port:%d, port_tx_mir:%d, port_rx_mir:%d, acl_mir:%d, vlan_mis:%d, igmp_mir:%d\n", port, port_tx_mir, port_rx_mir, acl_mir, vlan_mis, igmp_mir);
+
+ /*Check the input parameters is right or not.*/
+ //if((port >= vlanCap->max_port_no) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)){
+ if ((port >= 7) || (port_tx_mir > 1) || (port_rx_mir > 1) || (acl_mir > 1) || (vlan_mis > 1)) { // also allow CPU port (port6)
+ printf(HELP_MIRROR_PORTBASED);
+ return;
+ }
+
+ reg = REG_PCR_P0_ADDR + port * 0x100;
+ reg_read(reg, &value);
+ value &= ~(REG_PORT_TX_MIR_MASK | REG_PORT_RX_MIR_MASK | REG_PCR_ACL_MIR_MASK | REG_PCR_VLAN_MIS_MASK);
+ value |= (port_tx_mir << REG_PORT_TX_MIR_OFFT) + (port_rx_mir << REG_PORT_RX_MIR_OFFT);
+ value |= (acl_mir << REG_PCR_ACL_MIR_OFFT) + (vlan_mis << REG_PCR_VLAN_MIS_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+
+ reg = REG_PIC_P0_ADDR + port * 0x100;
+ reg_read(reg, &value);
+ value &= ~(REG_PIC_IGMP_MIR_MASK);
+ value |= (igmp_mir << REG_PIC_IGMP_MIR_OFFT);
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+
+} /*end doMirrorPortBased*/
+
+void doStp(int argc, char *argv[])
+{
+ unsigned char port = 0;
+ unsigned char fid = 0;
+ unsigned char state = 0;
+ unsigned int value;
+ unsigned int reg;
+
+ port = atoi(argv[2]);
+ fid = atoi(argv[3]);
+ state = atoi(argv[4]);
+
+ printf("port: %d, fid: %d, state: %d\n", port, fid, state);
+
+ /*Check the input parameters is right or not.*/
+ if ((port > MAX_PORT + 1) || (fid > 7) || (state > 3)) {
+ printf(HELP_STP);
+ return;
+ }
+
+ reg = REG_SSC_P0_ADDR + port * 0x100;
+ reg_read(reg, &value);
+ value &= (~(3 << (fid << 2)));
+ value |= ((unsigned int)state << (fid << 2));
+
+ printf("write reg: %x, value: %x\n", reg, value);
+ reg_write(reg, value);
+}
+
+int ingress_rate_set(int on_off, unsigned int port, unsigned int bw)
+{
+ unsigned int reg, value;
+
+ reg = 0x1800 + (0x100 * port);
+ value = 0;
+ /*token-bucket*/
+ if (on_off == 1) {
+ if (chip_name == 0x7530) {
+ if (bw > 1000000) {
+ printf("\n**Charge rate(%d) is larger than line rate(1000000kbps)**\n",bw);
+ return -1;
+ }
+ value = ((bw / 32) << 16) + (1 << 15) + (7 << 8) + (1 << 7) + 0x0f;
+ } else if (chip_name == 0x7531) {
+ if (bw > 2500000) {
+ printf("\n**Charge rate(%d) is larger than line rate(2500000kbps)**\n",bw);
+ return -1;
+ }
+ if (bw/32 >= 65536) //supoort 2.5G case
+ value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (1 << 12) + (7 << 8) + 0xf;
+ else
+ value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (7 << 8) + 0xf;
+ }
+ else
+ printf("unknow chip\n");
+ }
+
+#if leaky_bucket
+ reg_read(reg, &value);
+ value &= 0xffff0000;
+ if (on_off == 1)
+ {
+ value |= on_off << 15;
+ //7530 same as 7531
+ if (bw < 100) {
+ value |= (0x0 << 8);
+ value |= bw;
+ } else if (bw < 1000) {
+ value |= (0x1 << 8);
+ value |= bw / 10;
+ } else if (bw < 10000) {
+ value |= (0x2 << 8);
+ value |= bw / 100;
+ } else if (bw < 100000) {
+ value |= (0x3 << 8);
+ value |= bw / 1000;
+ } else {
+ value |= (0x4 << 8);
+ value |= bw / 10000;
+ }
+ }
+#endif
+ reg_write(reg, value);
+ reg = 0x1FFC;
+ reg_read(reg, &value);
+ value = 0x110104;
+ reg_write(reg, value);
+ return 0;
+}
+
+int egress_rate_set(int on_off, int port, int bw)
+{
+ unsigned int reg, value;
+
+ reg = 0x1040 + (0x100 * port);
+ value = 0;
+ /*token-bucket*/
+ if (on_off == 1) {
+ if (chip_name == 0x7530) {
+ if (bw < 0 || bw > 1000000) {
+ printf("\n**Charge rate(%d) is larger than line rate(1000000kbps)**\n",bw);
+ return -1;
+ }
+ value = ((bw / 32) << 16) + (1 << 15) + (7 << 8) + (1 << 7) + 0xf;
+ } else if (chip_name == 0x7531) {
+ if (bw < 0 || bw > 2500000) {
+ printf("\n**Charge rate(%d) is larger than line rate(2500000kbps)**\n",bw);
+ return -1;
+ }
+ if (bw/32 >= 65536) //support 2.5G cases
+ value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (1 << 12) + (7 << 8) + 0xf;
+ else
+ value = ((bw / 32) << 16) + (1 << 15) + (1 << 14) + (7 << 8) + 0xf;
+ }
+ else
+ printf("unknow chip\n");
+ }
+ reg_write(reg, value);
+ reg = 0x10E0;
+ reg_read(reg, &value);
+ value &= 0x18;
+ reg_write(reg, value);
+
+ return 0;
+}
+
+void rate_control(int argc, char *argv[])
+{
+ unsigned char dir = 0;
+ unsigned char port = 0;
+ unsigned int rate = 0;
+
+ dir = atoi(argv[2]);
+ port = atoi(argv[3]);
+ rate = atoi(argv[4]);
+
+ if (port > 6)
+ return;
+
+ if (dir == 1) //ingress
+ ingress_rate_set(1, port, rate);
+ else if (dir == 0) //egress
+ egress_rate_set(1, port, rate);
+ else
+ return;
+}
+
+int collision_pool_enable(int argc, char *argv[])
+{
+
+ unsigned char enable;
+ unsigned int value, reg;
+
+ enable = atoi(argv[3]);
+
+
+ printf("collision pool enable: %d \n", enable);
+
+ /*Check the input parameters is right or not.*/
+ if (enable > 1) {
+ printf(HELP_COLLISION_POOL_EN);
+ return -1;
+ }
+
+ if (chip_name == 0x7531) {
+ reg = REG_CPGC_ADDR;
+ if(enable == 1) {
+ /* active reset */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_RST_N_MASK);
+ reg_write(reg, value);
+
+ /* enanble clock */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_CLK_EN_MASK);
+ value |= (1 << REG_CPCG_COL_CLK_EN_OFFT);
+ reg_write(reg, value);
+
+ /* inactive reset */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_RST_N_MASK);
+ value |= (1 << REG_CPCG_COL_RST_N_OFFT);
+ reg_write(reg, value);
+
+ /* enable collision pool */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_EN_MASK);
+ value |= (1 << REG_CPCG_COL_EN_OFFT);
+ reg_write(reg, value);
+
+ reg_read(reg, &value);
+ printf("write reg: %x, value: %x\n", reg, value);
+ }else {
+
+ /* disable collision pool */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_EN_MASK);
+ reg_write(reg, value);
+
+ /* active reset */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_RST_N_MASK);
+ reg_write(reg, value);
+
+ /* inactive reset */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_RST_N_MASK);
+ value |= (1 << REG_CPCG_COL_RST_N_OFFT);
+ reg_write(reg, value);
+
+ /* disable clock */
+ reg_read(reg, &value);
+ value &= (~REG_CPCG_COL_CLK_EN_MASK);
+ reg_write(reg, value);
+
+ reg_read(reg, &value);
+ printf("write reg: %x, value: %x\n", reg, value);
+
+ }
+ }else{
+ printf("\nCommand not support by this chip.\n");
+}
+
+ return 0;
+}
+
+void collision_pool_mac_dump()
+{
+ unsigned int value, reg;
+
+ if (chip_name == 0x7531) {
+ reg = REG_CPGC_ADDR;
+ reg_read(reg, &value);
+ if(value & REG_CPCG_COL_EN_MASK)
+ table_dump_internal(COLLISION_TABLE);
+ else
+ printf("\ncollision pool is disabled, please enable it before use this command.\n");
+ }else {
+ printf("\nCommand not support by this chip.\n");
+ }
+}
+
+void collision_pool_dip_dump()
+{
+ unsigned int value, reg;
+
+ if (chip_name == 0x7531) {
+ reg = REG_CPGC_ADDR;
+ reg_read(reg, &value);
+ if(value & REG_CPCG_COL_EN_MASK)
+ dip_dump_internal(COLLISION_TABLE);
+ else
+ printf("\ncollision pool is disabled, please enable it before use this command.\n");
+ }else {
+ printf("\nCommand not support by this chip.\n");
+ }
+
+
+}
+
+void collision_pool_sip_dump()
+{
+ unsigned int value, reg;
+
+ if (chip_name == 0x7531) {
+ reg = REG_CPGC_ADDR;
+ reg_read(reg, &value);
+ if(value & REG_CPCG_COL_EN_MASK)
+ sip_dump_internal(COLLISION_TABLE);
+ else
+ printf("\ncollision pool is disabled, please enable it before use this command.\n");
+ }else {
+ printf("\nCommand not support by this chip.\n");
+ }
+
+
+}
+
+void pfc_get_rx_counter(int argc, char *argv[])
+{
+ int port;
+ unsigned int value, reg;
+ unsigned int user_pri;
+
+ port = strtoul(argv[3], NULL, 0);
+ if (port < 0 || 6 < port) {
+ printf("wrong port range, should be within 0~6\n");
+ return;
+ }
+
+ if (chip_name == 0x7531) {
+ reg= PFC_RX_COUNTER_L(port);
+ reg_read(reg, &value);
+ user_pri = value & 0xff;
+ printf("\n port %d rx pfc (up=0)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff00) >> 8;
+ printf("\n port %d rx pfc (up=1)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff0000) >> 16;
+ printf("\n port %d rx pfc (up=2)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff000000) >> 24;
+ printf("\n port %d rx pfc (up=3)pause on counter is %d.\n", port,user_pri);
+
+ reg= PFC_RX_COUNTER_H(port);
+ reg_read(reg, &value);
+ user_pri = value & 0xff;
+ printf("\n port %d rx pfc (up=4)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff00) >> 8;
+ printf("\n port %d rx pfc (up=5)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff0000) >> 16;
+ printf("\n port %d rx pfc (up=6)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff000000) >> 24;
+ printf("\n port %d rx pfc (up=7)pause on counter is %d.\n", port,user_pri);
+
+ /* for rx counter could be updated successfully */
+ reg_read(PMSR_P(port), &value);
+ reg_read(PMSR_P(port), &value);
+ }else {
+ printf("\nCommand not support by this chip.\n");
+ }
+
+}
+
+void pfc_get_tx_counter(int argc, char *argv[])
+{
+ int port;
+ unsigned int value, reg;
+ unsigned int user_pri;
+
+ port = strtoul(argv[3], NULL, 0);
+ if (port < 0 || 6 < port) {
+ printf("wrong port range, should be within 0~6\n");
+ return;
+ }
+
+ if (chip_name == 0x7531) {
+ reg= PFC_TX_COUNTER_L(port);
+ reg_read(reg, &value);
+ user_pri = value & 0xff;
+ printf("\n port %d tx pfc (up=0)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff00) >> 8;
+ printf("\n port %d tx pfc (up=1)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff0000) >> 16;
+ printf("\n port %d tx pfc (up=2)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff000000) >> 24;
+ printf("\n port %d tx pfc (up=3)pause on counter is %d.\n", port,user_pri);
+
+ reg= PFC_TX_COUNTER_H(port);
+ reg_read(reg, &value);
+ user_pri = value & 0xff;
+ printf("\n port %d tx pfc (up=4)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff00) >> 8;
+ printf("\n port %d tx pfc (up=5)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff0000) >> 16;
+ printf("\n port %d tx pfc (up=6)pause on counter is %d.\n", port,user_pri);
+ user_pri = (value & 0xff000000) >> 24;
+ printf("\n port %d tx pfc (up=7)pause on counter is %d.\n", port,user_pri);
+
+ /* for tx counter could be updated successfully */
+ reg_read(PMSR_P(port), &value);
+ reg_read(PMSR_P(port), &value);
+ }else {
+ printf("\nCommand not support by this chip.\n");
+ }
+}
+
+void read_output_queue_counters()
+{
+ unsigned int port=0;
+ unsigned int value, output_queue;
+ unsigned int base=0x220;
+
+ for (port = 0; port < 7; port++) {
+ reg_write(0x7038, base + (port *4));
+ reg_read(0x7034, &value);
+ output_queue = value & 0xff;
+ printf("\n port %d output queue 0 counter is %d.\n", port,output_queue);
+ output_queue = (value & 0xff00) >> 8;
+ printf("\n port %d output queue 1 counter is %d.\n", port,output_queue);
+
+ reg_write(0x7038, base + (port *4) + 1);
+ reg_read(0x7034, &value);
+ output_queue = value & 0xff;
+ printf("\n port %d output queue 2 counter is %d.\n", port,output_queue);
+ output_queue = (value & 0xff00) >> 8;
+ printf("\n port %d output queue 3 counter is %d.\n", port,output_queue);
+
+ reg_write(0x7038, base + (port *4) + 2);
+ reg_read(0x7034, &value);
+ output_queue = value & 0xff;
+ printf("\n port %d output queue 4 counter is %d.\n", port,output_queue);
+ output_queue = (value & 0xff00) >> 8;
+ printf("\n port %d output queue 5 counter is %d.\n", port,output_queue);
+
+ reg_write(0x7038, base + (port *4) + 3);
+ reg_read(0x7034, &value);
+ output_queue = value & 0xff;
+ printf("\n port %d output queue 6 counter is %d.\n", port,output_queue);
+ output_queue = (value & 0xff00) >> 8;
+ printf("\n port %d output queue 7 counter is %d.\n", port,output_queue);
+ }
+}
+
+void read_free_page_counters()
+{
+ unsigned int value;
+ unsigned int free_page,free_page_last_read;
+ unsigned int fc_free_blk_lothd,fc_free_blk_hithd;
+ unsigned int fc_port_blk_thd,fc_port_blk_hi_thd;
+ unsigned int queue[8]={0};
+
+ if (chip_name == 0x7531) {
+ /* get system free page link counter*/
+ reg_read(0x1fc0, &value);
+ free_page = value & 0xFFF;
+ free_page_last_read = (value & 0xFFF0000) >> 16;
+
+ /* get system flow control waterwark */
+ reg_read(0x1fe0, &value);
+ fc_free_blk_lothd = value & 0x3FF;
+ fc_free_blk_hithd = (value & 0x3FF0000) >> 16;
+
+ /* get port flow control waterwark */
+ reg_read(0x1fe4, &value);
+ fc_port_blk_thd = value & 0x3FF;
+ fc_port_blk_hi_thd = (value & 0x3FF0000) >> 16;
+
+ /* get queue flow control waterwark */
+ reg_read(0x1fe8, &value);
+ queue[0]= value & 0x3F;
+ queue[1]= (value & 0x3F00) >> 8;
+ queue[2]= (value & 0x3F0000) >> 16;
+ queue[3]= (value & 0x3F000000) >> 24;
+ reg_read(0x1fec, &value);
+ queue[4]= value & 0x3F;
+ queue[5]= (value & 0x3F00) >> 8;
+ queue[6]= (value & 0x3F0000) >> 16;
+ queue[7]= (value & 0x3F000000) >> 24;
+ } else {
+ /* get system free page link counter*/
+ reg_read(0x1fc0, &value);
+ free_page = value & 0x3FF;
+ free_page_last_read = (value & 0x3FF0000) >> 16;
+
+ /* get system flow control waterwark */
+ reg_read(0x1fe0, &value);
+ fc_free_blk_lothd = value & 0xFF;
+ fc_free_blk_hithd = (value & 0xFF00) >> 8;
+
+ /* get port flow control waterwark */
+ reg_read(0x1fe0, &value);
+ fc_port_blk_thd = (value & 0xFF0000) >> 16;
+ reg_read(0x1ff4, &value);
+ fc_port_blk_hi_thd = (value & 0xFF00) >> 8;
+
+ /* get queue flow control waterwark */
+ reg_read(0x1fe4, &value);
+ queue[0]= value & 0xF;
+ queue[1]= (value & 0xF0) >> 4;
+ queue[2]= (value & 0xF00) >> 8;
+ queue[3]= (value & 0xF000) >>12;
+ queue[4]= (value & 0xF0000) >>16;
+ queue[5]= (value & 0xF00000) >> 20;
+ queue[6]= (value & 0xF000000) >> 24;
+ queue[7]= (value & 0xF0000000) >> 28;
+ }
+
+ printf("<===Free Page=======Current=======Last Read access=====> \n ");
+ printf(" \n ");
+ printf(" page counter %u %u \n ",free_page,free_page_last_read);
+ printf(" \n ");
+ printf("========================================================= \n ");
+ printf("<===Type=======High threshold======Low threshold=========\n ");
+ printf(" \n ");
+ printf(" system: %u %u \n", fc_free_blk_hithd*2, fc_free_blk_lothd*2);
+ printf(" port: %u %u \n", fc_port_blk_hi_thd*2, fc_port_blk_thd*2);
+ printf(" queue 0: %u NA \n", queue[0]);
+ printf(" queue 1: %u NA \n", queue[1]);
+ printf(" queue 2: %u NA \n", queue[2]);
+ printf(" queue 3: %u NA \n", queue[3]);
+ printf(" queue 4: %u NA \n", queue[4]);
+ printf(" queue 5: %u NA \n", queue[5]);
+ printf(" queue 6: %u NA \n", queue[6]);
+ printf(" queue 7: %u NA \n", queue[7]);
+ printf("=========================================================\n ");
+}
+
+void eee_enable(int argc, char *argv[])
+{
+ unsigned long enable;
+ unsigned int value;
+ unsigned int eee_cap;
+ unsigned int eee_en_bitmap = 0;
+ unsigned long port_map;
+ long port_num = -1;
+ int p;
+
+ if (argc < 3)
+ goto error;
+
+ /*Check the input parameters is right or not.*/
+ if (!strncmp(argv[2], "enable", 7))
+ enable = 1;
+ else if (!strncmp(argv[2], "disable", 8))
+ enable = 0;
+ else
+ goto error;
+
+ if (argc > 3) {
+ if (strlen(argv[3]) == 1) {
+ port_num = strtol(argv[3], (char **)NULL, 10);
+ if (port_num < 0 || port_num > MAX_PHY_PORT - 1) {
+ printf("Illegal port index and port:0~4\n");
+ goto error;
+ }
+ port_map = 1 << port_num;
+ } else if (strlen(argv[3]) == 5) {
+ port_map = 0;
+ for (p = 0; p < MAX_PHY_PORT; p++) {
+ if (argv[3][p] != '0' && argv[3][p] != '1') {
+ printf("portmap format error, should be combination of 0 or 1\n");
+ goto error;
+ }
+ port_map |= ((argv[3][p] - '0') << p);
+ }
+ } else {
+ printf("port_no or portmap format error, should be length of 1 or 5\n");
+ goto error;
+ }
+ } else {
+ port_map = 0x1f;
+ }
+
+ eee_cap = (enable)? 6: 0;
+ for (p = 0; p < MAX_PHY_PORT; p++) {
+ /* port_map describe p0p1p2p3p4 from left to rignt */
+ if(!!(port_map & (1 << p)))
+ mii_mgr_c45_write(p, 0x7, 0x3c, eee_cap);
+
+ mii_mgr_c45_read(p, 0x7, 0x3c, &value);
+ /* mt7531: Always readback eee_cap = 0 when global EEE switch
+ * is turned off.
+ */
+ if (value | eee_cap)
+ eee_en_bitmap |= (1 << (MAX_PHY_PORT - 1 - p));
+ }
+
+ /* Turn on/off global EEE switch */
+ if (chip_name == 0x7531) {
+ mii_mgr_c45_read(0, 0x1f, 0x403, &value);
+ if (eee_en_bitmap)
+ value |= (1 << 6);
+ else
+ value &= ~(1 << 6);
+ mii_mgr_c45_write(0, 0x1f, 0x403, value);
+ } else {
+ printf("\nCommand not support by this chip.\n");
+ }
+
+ printf("EEE(802.3az) %s", (enable)? "enable": "disable");
+ if (argc == 4) {
+ if (port_num >= 0)
+ printf(" port%ld", port_num);
+ else
+ printf(" port_map: %s", argv[3]);
+ } else {
+ printf(" all ports");
+ }
+ printf("\n");
+
+ return;
+error:
+ printf(HELP_EEE_EN);
+ return;
+}
+
+void eee_dump(int argc, char *argv[])
+{
+ unsigned int cap, lp_cap;
+ long port = -1;
+ int p;
+
+ if (argc > 3) {
+ if (strlen(argv[3]) > 1) {
+ printf("port# format error, should be of length 1\n");
+ return;
+ }
+
+ port = strtol(argv[3], (char **)NULL, 0);
+ if (port < 0 || port > MAX_PHY_PORT) {
+ printf("port# format error, should be 0 to %d\n",
+ MAX_PHY_PORT);
+ return;
+ }
+ }
+
+ for (p = 0; p < MAX_PHY_PORT; p++) {
+ if (port >= 0 && p != port)
+ continue;
+
+ mii_mgr_c45_read(p, 0x7, 0x3c, &cap);
+ mii_mgr_c45_read(p, 0x7, 0x3d, &lp_cap);
+ printf("port%d EEE cap=0x%02x, link partner EEE cap=0x%02x",
+ p, cap, lp_cap);
+
+ if (port >= 0 && p == port) {
+ mii_mgr_c45_read(p, 0x3, 0x1, &cap);
+ printf(", st=0x%03x", cap);
+ }
+ printf("\n");
+ }
+}
+
+void dump_each_port(unsigned int base)
+{
+ unsigned int pkt_cnt = 0;
+ int i = 0;
+
+ for (i = 0; i < 7; i++) {
+ reg_read((base) + (i * 0x100), &pkt_cnt);
+ printf("%8u ", pkt_cnt);
+ }
+ printf("\n");
+}
+
+void read_mib_counters()
+{
+ printf("===================== %8s %8s %8s %8s %8s %8s %8s\n",
+ "Port0", "Port1", "Port2", "Port3", "Port4", "Port5", "Port6");
+ printf("Tx Drop Packet :");
+ dump_each_port(0x4000);
+ printf("Tx CRC Error :");
+ dump_each_port(0x4004);
+ printf("Tx Unicast Packet :");
+ dump_each_port(0x4008);
+ printf("Tx Multicast Packet :");
+ dump_each_port(0x400C);
+ printf("Tx Broadcast Packet :");
+ dump_each_port(0x4010);
+ printf("Tx Collision Event :");
+ dump_each_port(0x4014);
+ printf("Tx Pause Packet :");
+ dump_each_port(0x402C);
+ printf("Rx Drop Packet :");
+ dump_each_port(0x4060);
+ printf("Rx Filtering Packet :");
+ dump_each_port(0x4064);
+ printf("Rx Unicast Packet :");
+ dump_each_port(0x4068);
+ printf("Rx Multicast Packet :");
+ dump_each_port(0x406C);
+ printf("Rx Broadcast Packet :");
+ dump_each_port(0x4070);
+ printf("Rx Alignment Error :");
+ dump_each_port(0x4074);
+ printf("Rx CRC Error :");
+ dump_each_port(0x4078);
+ printf("Rx Undersize Error :");
+ dump_each_port(0x407C);
+ printf("Rx Fragment Error :");
+ dump_each_port(0x4080);
+ printf("Rx Oversize Error :");
+ dump_each_port(0x4084);
+ printf("Rx Jabber Error :");
+ dump_each_port(0x4088);
+ printf("Rx Pause Packet :");
+ dump_each_port(0x408C);
+}
+
+void clear_mib_counters()
+{
+ reg_write(0x4fe0, 0xf0);
+ read_mib_counters();
+ reg_write(0x4fe0, 0x800000f0);
+}
+
+
+void exit_free()
+{
+ free(attres);
+ attres = NULL;
+ switch_ioctl_fini();
+ mt753x_netlink_free();
+}
diff --git a/feed/switch/src/switch_fun.h b/feed/switch/src/switch_fun.h
new file mode 100644
index 0000000..95ff4b3
--- /dev/null
+++ b/feed/switch/src/switch_fun.h
@@ -0,0 +1,144 @@
+/*
+* switch_fun.h: switch function sets
+*/
+#ifndef SWITCH_FUN_H
+#define SWITCH_FUN_H
+
+#include <stdbool.h>
+
+#define MT7530_T10_TEST_CONTROL 0x145
+
+#define MAX_PORT 6
+#define MAX_PHY_PORT 5
+#define CONFIG_MTK_7531_DVT 1
+
+extern int chip_name;
+extern struct mt753x_attr *attres;
+extern bool nl_init_flag;
+
+/*basic operation*/
+int reg_read(unsigned int offset, unsigned int *value);
+int reg_write(unsigned int offset, unsigned int value);
+int mii_mgr_read(unsigned int port_num, unsigned int reg, unsigned int *value);
+int mii_mgr_write(unsigned int port_num, unsigned int reg, unsigned int value);
+int mii_mgr_c45_read(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int *value);
+int mii_mgr_c45_write(unsigned int port_num, unsigned int dev, unsigned int reg, unsigned int value);
+
+/*phy setting*/
+int phy_dump(int phy_addr);
+void phy_crossover(int argc, char *argv[]);
+int rw_phy_token_ring(int argc, char *argv[]);
+/*arl setting*/
+void doArlAging(int argc, char *argv[]);
+
+/*acl setting*/
+void acl_mac_add(int argc, char *argv[]);
+void acl_dip_meter(int argc, char *argv[]);
+void acl_dip_trtcm(int argc, char *argv[]);
+void acl_ethertype(int argc, char *argv[]);
+void acl_ethertype(int argc, char *argv[]);
+void acl_dip_modify(int argc, char *argv[]);
+void acl_dip_pppoe(int argc, char *argv[]);
+void acl_dip_add(int argc, char *argv[]);
+void acl_l4_add(int argc, char *argv[]);
+void acl_sp_add(int argc, char *argv[]);
+
+void acl_port_enable(int argc, char *argv[]);
+void acl_table_add(int argc, char *argv[]);
+void acl_mask_table_add(int argc, char *argv[]);
+void acl_rule_table_add(int argc, char *argv[]);
+void acl_rate_table_add(int argc, char *argv[]);
+
+/*dip table*/
+void dip_dump(void);
+void dip_add(int argc, char *argv[]);
+void dip_del(int argc, char *argv[]);
+void dip_clear(void);
+
+/*sip table*/
+void sip_dump(void);
+void sip_add(int argc, char *argv[]);
+void sip_del(int argc, char *argv[]);
+void sip_clear(void);
+
+/*stp*/
+void doStp(int argc, char *argv[]);
+
+/*mac table*/
+void table_dump(void);
+void table_add(int argc, char *argv[]);
+void table_search_mac_vid(int argc, char *argv[]);
+void table_search_mac_fid(int argc, char *argv[]);
+void table_del_fid(int argc, char *argv[]);
+void table_del_vid(int argc, char *argv[]);
+void table_clear(void);
+
+/*vlan table*/
+void vlan_dump(int argc, char *argv[]);
+void vlan_clear(int argc, char *argv[]);
+void vlan_set(int argc, char *argv[]);
+
+void doVlanSetPvid(int argc, char *argv[]);
+void doVlanSetVid(int argc, char *argv[]);
+void doVlanSetAccFrm(int argc, char *argv[]);
+void doVlanSetPortAttr(int argc, char *argv[]);
+void doVlanSetPortMode(int argc, char *argv[]);
+void doVlanSetEgressTagPCR(int argc, char *argv[]);
+void doVlanSetEgressTagPVC(int argc, char *argv[]);
+
+/*igmp function*/
+void igmp_on(int argc, char *argv[]);
+void igmp_off();
+void igmp_disable(int argc, char *argv[]);
+void igmp_enable(int argc, char *argv[]);
+
+/*mirror function*/
+void set_mirror_to(int argc, char *argv[]);
+void set_mirror_from(int argc, char *argv[]);
+void doMirrorPortBased(int argc, char *argv[]);
+void doMirrorEn(int argc, char *argv[]);
+
+/*rate control*/
+void rate_control(int argc, char *argv[]);
+int ingress_rate_set(int on_off, unsigned int port, unsigned int bw);
+int egress_rate_set(int on_off, int port, int bw);
+
+/*QoS*/
+int qos_sch_select(int argc, char *argv[]);
+void qos_set_base(int argc, char *argv[]);
+void qos_wfq_set_weight(int argc, char *argv[]);
+void qos_set_portpri(int argc, char *argv[]);
+void qos_set_dscppri(int argc, char *argv[]);
+void qos_pri_mapping_queue(int argc, char *argv[]);
+
+/*flow control*/
+int global_set_mac_fc(int argc, char *argv[]);
+int phy_set_fc(int argc, char *argv[]);
+int phy_set_an(int argc, char *argv[]);
+
+/* collision pool functions */
+int collision_pool_enable(int argc, char *argv[]);
+void collision_pool_mac_dump();
+void collision_pool_dip_dump();
+void collision_pool_sip_dump();
+
+/*pfc functions*/
+int set_mac_pfc(int argc, char *argv[]);
+void pfc_get_rx_counter(int argc, char *argv[]);
+void pfc_get_tx_counter(int argc, char *argv[]);
+
+/*switch reset*/
+void switch_reset(int argc, char *argv[]);
+
+/* EEE(802.3az) function */
+void eee_enable(int argc, char *argv[]);
+void eee_dump(int argc, char *argv[]);
+
+void read_mib_counters();
+void clear_mib_counters();
+void read_output_queue_counters();
+void read_free_page_counters();
+
+void phy_crossover(int argc, char *argv[]);
+void exit_free();
+#endif
diff --git a/feed/switch/src/switch_ioctl.c b/feed/switch/src/switch_ioctl.c
new file mode 100644
index 0000000..082eab1
--- /dev/null
+++ b/feed/switch/src/switch_ioctl.c
@@ -0,0 +1,346 @@
+/*
+ * switch_ioctl.c: switch(ioctl) set API
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+
+#include "switch_fun.h"
+#include "switch_ioctl.h"
+
+static int esw_fd;
+
+void switch_ioctl_init(void)
+{
+ esw_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (esw_fd < 0) {
+ perror("socket");
+ exit(0);
+ }
+}
+
+void switch_ioctl_fini(void)
+{
+ close(esw_fd);
+}
+
+int reg_read_ioctl(unsigned int offset, unsigned int *value)
+{
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+
+ mii.phy_id = 0x1f;
+ mii.reg_num = offset;
+
+ if (-1 == ioctl(esw_fd, RAETH_MII_READ, &ifr)) {
+ perror("ioctl");
+ close(esw_fd);
+ exit(0);
+ }
+ *value = mii.val_out;
+ return 0;
+}
+
+int reg_read_tr(int offset, int *value)
+{
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+
+ mii.phy_id = 0;
+ mii.reg_num = offset;
+
+ if (-1 == ioctl(esw_fd, RAETH_MII_READ, &ifr)) {
+ perror("ioctl");
+ close(esw_fd);
+ exit(0);
+ }
+ *value = mii.val_out;
+ return 0;
+}
+
+int reg_write_ioctl(unsigned int offset, unsigned int value)
+{
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+
+ mii.phy_id = 0x1f;
+ mii.reg_num = offset;
+ mii.val_in = value;
+
+ if (-1 == ioctl(esw_fd, RAETH_MII_WRITE, &ifr)) {
+ perror("ioctl");
+ close(esw_fd);
+ exit(0);
+ }
+ return 0;
+}
+
+int reg_write_tr(int offset, int value)
+{
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+
+ mii.phy_id = 0;
+ mii.reg_num = offset;
+ mii.val_in = value;
+
+ if (-1 == ioctl(esw_fd, RAETH_MII_WRITE, &ifr)) {
+ perror("ioctl");
+ close(esw_fd);
+ exit(0);
+ }
+ return 0;
+}
+
+int phy_dump_ioctl(unsigned int phy_addr)
+{
+ struct ifreq ifr;
+ struct esw_reg reg;
+
+ reg.val = phy_addr;
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = ®
+ if (-1 == ioctl(esw_fd, RAETH_ESW_PHY_DUMP, &ifr)) {
+ perror("ioctl");
+ close(esw_fd);
+ exit(0);
+ }
+ return 0;
+}
+
+int mii_mgr_cl22_read_ioctl(unsigned int port_num, unsigned int reg, unsigned int *value)
+{
+ unsigned int reg_value;
+ int loop_cnt;
+ int op_busy;
+
+ loop_cnt = 0;
+
+ /*Change to indirect access mode*/
+ /*if you need to use direct access mode, please change back manually by reset bit5*/
+ reg_read(0x7804, ®_value);
+ if (((reg_value >> 5) & 0x1) == 0) {
+ reg_value |= 1 << 5;
+ reg_write(0x7804, reg_value);
+ printf("Change to indirect access mode:0x%x\n", reg_value);
+ }
+ reg_value = 0x80090000 | (port_num << 20) | (reg << 25);
+ reg_write(0x701c, reg_value);
+ while (1)
+ {
+ reg_read(0x701c, ®_value);
+ op_busy = reg_value & (1 << 31);
+ if (!op_busy) {
+ reg_value = reg_value & 0xFFFF;
+ break;
+ } else if (loop_cnt < 10)
+ loop_cnt++;
+ else {
+ printf("MDIO read opeartion timeout\n");
+ reg_value = 0;
+ break;
+ }
+ }
+ printf(" PHY Indirect Access Control(0x701c) register read value =0x%x \n", reg_value);
+ *value = reg_value;
+
+ return 0;
+}
+
+int mii_mgr_cl22_write_ioctl(unsigned int port_num, unsigned int reg, unsigned int value)
+{
+ unsigned int reg_value;
+ int loop_cnt;
+ int op_busy;
+
+ loop_cnt = 0;
+ /*Change to indirect access mode*/
+ /*if you need to use direct access mode, please change back manually by reset bit5*/
+ reg_read(0x7804, ®_value);
+ if (((reg_value >> 5) & 0x1) == 0) {
+ reg_value |= 1 << 5;
+ reg_write(0x7804, reg_value);
+ printf("Change to indirect access mode:0x%x\n", reg_value);
+ }
+
+ reg_value = 0x80050000 | (port_num << 20) | (reg << 25) | value;
+ reg_write(0x701c, reg_value);
+ while (1)
+ {
+ reg_read(0x701c, ®_value);
+ op_busy = reg_value & (1 << 31);
+ if (!op_busy)
+ break;
+ else if (loop_cnt < 10)
+ loop_cnt++;
+ else {
+ printf("MDIO write opeartion timeout\n");
+ break;
+ }
+ }
+
+ printf(" PHY Indirect Access Control(0x701c) register write value =0x%x \n", reg_value);
+
+ return 0;
+}
+
+int mii_mgr_cl45_read_ioctl(unsigned int port_num, unsigned int dev,
+ unsigned int reg, unsigned int *value)
+{
+ int sk, method, ret;
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ if (!value)
+ return -1;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sk < 0) {
+ printf("Open socket failed\n");
+
+ return -1;
+ }
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 13;
+ mii.val_in = dev;
+ ret = ioctl(sk, method, &ifr);
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 14;
+ mii.val_in = reg;
+ ret = ioctl(sk, method, &ifr);
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 13;
+ mii.val_in = (0x6000 | dev);
+ ret = ioctl(sk, method, &ifr);
+
+ usleep(1000);
+
+ method = RAETH_MII_READ;
+ mii.phy_id = port_num;
+ mii.reg_num = 14;
+ ret = ioctl(sk, method, &ifr);
+
+ close(sk);
+ *value = mii.val_out;
+
+ return ret;
+}
+
+int mii_mgr_cl45_write_ioctl(unsigned int port_num, unsigned int dev,
+ unsigned int reg, unsigned int value)
+{
+ int sk, method, ret;
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sk < 0) {
+ printf("Open socket failed\n");
+
+ return -1;
+ }
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 13;
+ mii.val_in = dev;
+ ret = ioctl(sk, method, &ifr);
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 14;
+ mii.val_in = reg;
+ ret = ioctl(sk, method, &ifr);
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 13;
+ mii.val_in = (0x6000 | dev);
+ ret = ioctl(sk, method, &ifr);
+
+ usleep(1000);
+
+ method = RAETH_MII_WRITE;
+ mii.phy_id = port_num;
+ mii.reg_num = 14;
+ mii.val_in = value;
+ ret = ioctl(sk, method, &ifr);
+
+ close(sk);
+
+ return ret;
+}
+
+int dump_gphy(void)
+{
+ int cl22_reg[6] = {0x00, 0x01, 0x04, 0x05, 0x09, 0x0A};
+ int cl45_start_reg = 0x9B;
+ int cl45_end_reg = 0xA2;
+ unsigned int value;
+ int port_num = 5;
+ int i, j, ret;
+
+ int sk, method;
+ struct ifreq ifr;
+ struct ra_mii_ioctl_data mii;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sk < 0) {
+ printf("Open socket failed\n");
+ return -1;
+ }
+
+ strncpy(ifr.ifr_name, ETH_DEVNAME, 5);
+ ifr.ifr_data = &mii;
+ /* dump CL45 reg first*/
+ for (i = 0; i < port_num; i++) {
+ printf("== Port %d ==\n", i);
+ for (j = cl45_start_reg; j < (cl45_end_reg + 1); j++) {
+ ret = mii_mgr_cl45_read_ioctl(i, 0x1E, j, &value);
+ if (ret)
+ continue;
+ printf("dev1Eh_reg%xh = 0x%x\n", j, value);
+ }
+ }
+ printf("== Global ==\n");
+ for (i = 0; i < sizeof(cl22_reg) / sizeof(cl22_reg[0]); i++) {
+ method = RAETH_MII_READ;
+ mii.phy_id = 0;
+ mii.reg_num = cl22_reg[i];
+ ret = ioctl(sk, method, &ifr);
+ printf("Reg%xh = 0x%x\n", cl22_reg[i], mii.val_out);
+ }
+
+ close(sk);
+
+ return ret;
+}
diff --git a/feed/switch/src/switch_ioctl.h b/feed/switch/src/switch_ioctl.h
new file mode 100644
index 0000000..97946af
--- /dev/null
+++ b/feed/switch/src/switch_ioctl.h
@@ -0,0 +1,68 @@
+/*
+ * switch_ioctl.h: switch(ioctl) set API
+ */
+
+#ifndef SWITCH_IOCTL_H
+#define SWITCH_IOCTL_H
+
+#define ETH_DEVNAME "eth0"
+#define BR_DEVNAME "br-lan"
+
+#define RAETH_MII_READ 0x89F3
+#define RAETH_MII_WRITE 0x89F4
+#define RAETH_ESW_PHY_DUMP 0x89F7
+
+struct esw_reg {
+ unsigned int off;
+ unsigned int val;
+};
+
+struct ra_mii_ioctl_data {
+ __u32 phy_id;
+ __u32 reg_num;
+ __u32 val_in;
+ __u32 val_out;
+ __u32 port_num;
+ __u32 dev_addr;
+ __u32 reg_addr;
+};
+
+struct ra_switch_ioctl_data {
+ unsigned int cmd;
+ unsigned int on_off;
+ unsigned int port;
+ unsigned int bw;
+ unsigned int vid;
+ unsigned int fid;
+ unsigned int port_map;
+ unsigned int rx_port_map;
+ unsigned int tx_port_map;
+ unsigned int igmp_query_interval;
+ unsigned int reg_addr;
+ unsigned int reg_val;
+ unsigned int mode;
+ unsigned int qos_queue_num;
+ unsigned int qos_type;
+ unsigned int qos_pri;
+ unsigned int qos_dscp;
+ unsigned int qos_table_idx;
+ unsigned int qos_weight;
+ unsigned char mac[6];
+};
+
+extern int chip_name;
+
+void switch_ioctl_init(void);
+void switch_ioctl_fini(void);
+int reg_read_ioctl(unsigned int offset, unsigned int *value);
+int reg_write_ioctl(unsigned int offset, unsigned int value);
+int phy_dump_ioctl(unsigned int phy_addr);
+int mii_mgr_cl22_read_ioctl(unsigned int port_num, unsigned int reg,
+ unsigned int *value);
+int mii_mgr_cl22_write_ioctl(unsigned int port_num, unsigned int reg,
+ unsigned int value);
+int mii_mgr_cl45_read_ioctl(unsigned int port_num, unsigned int dev,
+ unsigned int reg, unsigned int *value);
+int mii_mgr_cl45_write_ioctl(unsigned int port_num, unsigned int dev,
+ unsigned int reg, unsigned int value);
+#endif
diff --git a/feed/switch/src/switch_netlink.c b/feed/switch/src/switch_netlink.c
new file mode 100644
index 0000000..90a4a19
--- /dev/null
+++ b/feed/switch/src/switch_netlink.c
@@ -0,0 +1,445 @@
+/*
+ * switch_netlink.c: switch(netlink) set API
+ *
+ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+
+#include "switch_netlink.h"
+
+static struct nl_sock *user_sock;
+static struct nl_cache *cache;
+static struct genl_family *family;
+static struct nlattr *attrs[MT753X_ATTR_TYPE_MAX + 1];
+
+static int wait_handler(struct nl_msg *msg, void *arg)
+{
+ int *finished = arg;
+
+ *finished = 1;
+ return NL_STOP;
+}
+
+static int list_swdevs(struct nl_msg *msg, void *arg)
+{
+ struct mt753x_attr *val = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL) < 0)
+ goto done;
+
+ if (gnlh->cmd == MT753X_CMD_REPLY) {
+ if (attrs[MT753X_ATTR_TYPE_MESG]) {
+ val->dev_info =
+ nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
+ printf("register switch dev:\n%s", val->dev_info);
+ }
+ else {
+ fprintf(stderr, "ERROR:No switch dev now\n");
+ goto done;
+ }
+ } else
+ goto done;
+ return 0;
+done:
+ return NL_SKIP;
+}
+
+static int construct_attrs(struct nl_msg *msg, void *arg)
+{
+ struct mt753x_attr *val = arg;
+ int type = val->type;
+
+ if (val->dev_id > -1)
+ NLA_PUT_U32(msg, MT753X_ATTR_TYPE_DEV_ID, val->dev_id);
+
+ if (val->op == 'r') {
+ if (val->phy_dev != -1)
+ NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
+ if (val->port_num >= 0)
+ NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
+ NLA_PUT_U32(msg, type, val->reg);
+ } else if (val->op == 'w') {
+ if (val->phy_dev != -1)
+ NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
+ if (val->port_num >= 0)
+ NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
+ NLA_PUT_U32(msg, type, val->reg);
+ NLA_PUT_U32(msg, MT753X_ATTR_TYPE_VAL, val->value);
+ } else {
+ printf("construct_attrs_message\n");
+ NLA_PUT_STRING(msg, type, "hello");
+ }
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+static int spilt_attrs(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct mt753x_attr *val = arg;
+ char *str;
+
+ if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL) < 0)
+ goto done;
+
+ if ((gnlh->cmd == MT753X_CMD_WRITE) || (gnlh->cmd == MT753X_CMD_READ)) {
+ if (attrs[MT753X_ATTR_TYPE_MESG]) {
+ str = nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
+ printf(" %s\n", str);
+ if (!strncmp(str, "No", 2))
+ goto done;
+ }
+ if (attrs[MT753X_ATTR_TYPE_REG]) {
+ val->reg =
+ nla_get_u32(attrs[MT753X_ATTR_TYPE_REG]);
+ }
+ if (attrs[MT753X_ATTR_TYPE_VAL]) {
+ val->value =
+ nla_get_u32(attrs[MT753X_ATTR_TYPE_VAL]);
+ }
+ }
+ else
+ goto done;
+
+ return 0;
+done:
+ return NL_SKIP;
+}
+
+static int mt753x_request_callback(int cmd, int (*spilt)(struct nl_msg *, void *),
+ int (*construct)(struct nl_msg *, void *),
+ void *arg)
+{
+ struct nl_msg *msg;
+ struct nl_cb *callback = NULL;
+ int finished;
+ int flags = 0;
+ int err;
+
+ /*Allocate an netllink message buffer*/
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "Failed to allocate netlink message\n");
+ exit(1);
+ }
+ if (!construct) {
+ if (cmd == MT753X_CMD_REQUEST)
+ flags |= NLM_F_REQUEST;
+ else
+ flags |= NLM_F_DUMP;
+ }
+ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family),
+ 0, flags, cmd, 0);
+
+ /*Fill attaribute of netlink message by construct function*/
+ if (construct) {
+ err = construct(msg, arg);
+ if (err < 0) {
+ fprintf(stderr, "attributes error\n");
+ goto nal_put_failure;
+ }
+ }
+
+ /*Allocate an new callback handler*/
+ callback = nl_cb_alloc(NL_CB_CUSTOM);
+ if (!callback) {
+ fprintf(stderr, "Failed to allocate callback handler\n");
+ exit(1);
+ }
+
+ /*Send netlink message*/
+ err = nl_send_auto_complete(user_sock, msg);
+ if (err < 0) {
+ fprintf(stderr, "nl_send_auto_complete failied:%d\n", err);
+ goto out;
+ }
+ finished = 0;
+ if (spilt)
+ nl_cb_set(callback, NL_CB_VALID, NL_CB_CUSTOM, spilt, arg);
+
+ if (construct)
+ nl_cb_set(callback, NL_CB_ACK, NL_CB_CUSTOM, wait_handler,
+ &finished);
+ else
+ nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler,
+ &finished);
+
+ /*receive message from kernel request*/
+ err = nl_recvmsgs(user_sock, callback);
+ if (err < 0)
+ goto out;
+
+ /*wait until an ACK is received for the latest not yet acknowledge*/
+ if (!finished)
+ err = nl_wait_for_ack(user_sock);
+out:
+ if (callback)
+ nl_cb_put(callback);
+
+nal_put_failure:
+ nlmsg_free(msg);
+ return err;
+}
+
+void mt753x_netlink_free(void)
+{
+ if (family)
+ nl_object_put((struct nl_object *)family);
+ if (cache)
+ nl_cache_free(cache);
+ if (user_sock)
+ nl_socket_free(user_sock);
+ user_sock = NULL;
+ cache = NULL;
+ family = NULL;
+}
+
+int mt753x_netlink_init(const char *name)
+{
+ int ret;
+
+ user_sock = NULL;
+ cache = NULL;
+ family = NULL;
+
+ /*Allocate an new netlink socket*/
+ user_sock = nl_socket_alloc();
+ if (!user_sock) {
+ fprintf(stderr, "Failed to create user socket\n");
+ goto err;
+ }
+ /*Connetct the genl controller*/
+ if (genl_connect(user_sock)) {
+ fprintf(stderr, "Failed to connetct to generic netlink\n");
+ goto err;
+ }
+ /*Allocate an new nl_cache*/
+ ret = genl_ctrl_alloc_cache(user_sock, &cache);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to allocate netlink cache\n");
+ goto err;
+ }
+
+ if (name == NULL)
+ return -EINVAL;
+
+ /*Look up generic netlik family by "mt753x" in the provided cache*/
+ family = genl_ctrl_search_by_name(cache, name);
+ if (!family) {
+ //fprintf(stderr,"switch(mt753x) API not be prepared\n");
+ goto err;
+ }
+ return 0;
+err:
+ mt753x_netlink_free();
+ return -EINVAL;
+}
+
+void mt753x_list_swdev(struct mt753x_attr *arg, int cmd)
+{
+ int err;
+
+ err = mt753x_request_callback(cmd, list_swdevs, NULL, arg);
+ if (err < 0)
+ fprintf(stderr, "mt753x list dev error\n");
+}
+
+static int mt753x_request(struct mt753x_attr *arg, int cmd)
+{
+ int err;
+
+ err = mt753x_request_callback(cmd, spilt_attrs, construct_attrs, arg);
+ if (err < 0) {
+ fprintf(stderr, "mt753x deal request error\n");
+ return err;
+ }
+ return 0;
+}
+
+static int phy_operate_netlink(char op, struct mt753x_attr *arg,
+ unsigned int port_num, unsigned int phy_dev,
+ unsigned int offset, unsigned int *value)
+{
+ int ret = 0;
+ struct mt753x_attr *attr = arg;
+
+ attr->port_num = port_num;
+ attr->phy_dev = phy_dev;
+ attr->reg = offset;
+ attr->value = -1;
+ attr->type = MT753X_ATTR_TYPE_REG;
+
+ switch (op)
+ {
+ case 'r':
+ attr->op = 'r';
+ ret = mt753x_request(attr, MT753X_CMD_READ);
+ *value = attr->value;
+ break;
+ case 'w':
+ attr->op = 'w';
+ attr->value = *value;
+ ret = mt753x_request(attr, MT753X_CMD_WRITE);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int reg_read_netlink(struct mt753x_attr *arg, unsigned int offset,
+ unsigned int *value)
+{
+ int ret;
+
+ ret = phy_operate_netlink('r', arg, -1, -1, offset, value);
+ return ret;
+}
+
+int reg_write_netlink(struct mt753x_attr *arg, unsigned int offset,
+ unsigned int value)
+{
+ int ret;
+
+ ret = phy_operate_netlink('w', arg, -1, -1, offset, &value);
+ return ret;
+}
+
+int phy_cl22_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_addr, unsigned int *value)
+{
+ int ret;
+
+ ret = phy_operate_netlink('r', arg, port_num, -1, phy_addr, value);
+ return ret;
+}
+
+int phy_cl22_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_addr, unsigned int value)
+{
+ int ret;
+
+ ret = phy_operate_netlink('w', arg, port_num, -1, phy_addr, &value);
+ return ret;
+}
+
+int phy_cl45_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_dev, unsigned int phy_addr,
+ unsigned int *value)
+{
+ int ret;
+
+ ret = phy_operate_netlink('r', arg, port_num, phy_dev, phy_addr, value);
+ return ret;
+}
+
+int phy_cl45_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_dev, unsigned int phy_addr,
+ unsigned int value)
+{
+ int ret;
+
+ ret = phy_operate_netlink('w', arg, port_num, phy_dev, phy_addr, &value);
+ return ret;
+}
+
+void dump_extend_phy_reg(struct mt753x_attr *arg, int port_no, int from,
+ int to, int is_local, int page_no)
+{
+ unsigned int temp = 0;
+ int r31 = 0;
+ int i = 0;
+
+ if (is_local == 0) {
+ printf("\n\nGlobal Register Page %d\n",page_no);
+ printf("===============");
+ r31 |= 0 << 15; //global
+ r31 |= ((page_no&0x7) << 12); //page no
+ phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
+ for (i = 16; i < 32; i++) {
+ if(i%8 == 0)
+ printf("\n");
+ phy_cl22_read_netlink(arg, port_no, i, &temp);
+ printf("%02d: %04X ", i, temp);
+ }
+ } else {
+ printf("\n\nLocal Register Port %d Page %d\n",port_no, page_no);
+ printf("===============");
+ r31 |= 1 << 15; //local
+ r31 |= ((page_no&0x7) << 12); //page no
+ phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
+ for (i = 16; i < 32; i++) {
+ if (i%8 == 0) {
+ printf("\n");
+ }
+ phy_cl22_read_netlink(arg, port_no, i, &temp);
+ printf("%02d: %04X ",i, temp);
+ }
+ }
+ printf("\n");
+}
+
+int phy_dump_netlink(struct mt753x_attr *arg, int phy_addr)
+{
+ int i;
+ int ret;
+ unsigned int offset, value;
+
+ if (phy_addr == 32) {
+ /*dump all phy register*/
+ for (i = 0; i < 5; i++) {
+ printf("\n[Port %d]=============", i);
+ for (offset = 0; offset < 16; offset++) {
+ if (offset % 8 == 0)
+ printf("\n");
+ ret = phy_cl22_read_netlink(arg, i, offset, &value);
+ printf("%02d: %04X ", offset, value);
+ }
+ }
+ } else {
+ printf("\n[Port %d]=============", phy_addr);
+ for (offset = 0; offset < 16; offset++) {
+ if (offset % 8 == 0)
+ printf("\n");
+ ret = phy_cl22_read_netlink(arg, phy_addr, offset, &value);
+ printf("%02d: %04X ", offset, value);
+ }
+ }
+ printf("\n");
+ for (offset = 0; offset < 5; offset++) { //global register page 0~4
+ if (phy_addr == 32) //dump all phy register
+ dump_extend_phy_reg(arg, 0, 16, 31, 0, offset);
+ else
+ dump_extend_phy_reg(arg, phy_addr, 16, 31, 0, offset);
+ }
+
+ if (phy_addr == 32) { //dump all phy register
+ for (offset = 0; offset < 5; offset++) { //local register port 0-port4
+ dump_extend_phy_reg(arg, offset, 16, 31, 1, 0); //dump local page 0
+ dump_extend_phy_reg(arg, offset, 16, 31, 1, 1); //dump local page 1
+ dump_extend_phy_reg(arg, offset, 16, 31, 1, 2); //dump local page 2
+ dump_extend_phy_reg(arg, offset, 16, 31, 1, 3); //dump local page 3
+ }
+ } else {
+ dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 0); //dump local page 0
+ dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 1); //dump local page 1
+ dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 2); //dump local page 2
+ dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 3); //dump local page 3
+ }
+ return ret;
+}
diff --git a/feed/switch/src/switch_netlink.h b/feed/switch/src/switch_netlink.h
new file mode 100644
index 0000000..b3f946e
--- /dev/null
+++ b/feed/switch/src/switch_netlink.h
@@ -0,0 +1,70 @@
+/*
+ * switch_netlink.h: switch(netlink) set API
+ *
+ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>
+ */
+#ifndef MT753X_NETLINK_H
+#define MT753X_NETLINK_H
+
+#define MT753X_GENL_NAME "mt753x"
+#define MT753X_DSA_GENL_NAME "mt753x_dsa"
+#define MT753X_GENL_VERSION 0X1
+
+/*add your cmd to here*/
+enum {
+ MT753X_CMD_UNSPEC = 0, /*Reserved*/
+ MT753X_CMD_REQUEST, /*user->kernelrequest/get-response*/
+ MT753X_CMD_REPLY, /*kernel->user event*/
+ MT753X_CMD_READ,
+ MT753X_CMD_WRITE,
+ __MT753X_CMD_MAX,
+};
+#define MT753X_CMD_MAX (__MT753X_CMD_MAX - 1)
+
+/*define attar types */
+enum
+{
+ MT753X_ATTR_TYPE_UNSPEC = 0,
+ MT753X_ATTR_TYPE_MESG, /*MT753X message*/
+ MT753X_ATTR_TYPE_PHY,
+ MT753X_ATTR_TYPE_PHY_DEV,
+ MT753X_ATTR_TYPE_REG,
+ MT753X_ATTR_TYPE_VAL,
+ MT753X_ATTR_TYPE_DEV_NAME,
+ MT753X_ATTR_TYPE_DEV_ID,
+ __MT753X_ATTR_TYPE_MAX,
+};
+#define MT753X_ATTR_TYPE_MAX (__MT753X_ATTR_TYPE_MAX - 1)
+
+struct mt753x_attr {
+ int port_num;
+ int phy_dev;
+ int reg;
+ int value;
+ int type;
+ char op;
+ char *dev_info;
+ int dev_name;
+ int dev_id;
+};
+
+int mt753x_netlink_init(const char *name);
+void mt753x_netlink_free(void);
+void mt753x_list_swdev(struct mt753x_attr *arg, int cmd);
+int reg_read_netlink(struct mt753x_attr *arg, unsigned int offset,
+ unsigned int *value);
+int reg_write_netlink(struct mt753x_attr *arg, unsigned int offset,
+ unsigned int value);
+int phy_cl22_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_addr, unsigned int *value);
+int phy_cl22_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_addr, unsigned int value);
+int phy_cl45_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_dev, unsigned int phy_addr,
+ unsigned int *value);
+int phy_cl45_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
+ unsigned int phy_dev, unsigned int phy_addr,
+ unsigned int value);
+int phy_dump_netlink(struct mt753x_attr *arg, int phy_addr);
+
+#endif
diff --git a/openwrt_patches-21.02/001-target-mediatek-add-mt7986-subtarget.patch b/openwrt_patches-21.02/001-target-mediatek-add-mt7986-subtarget.patch
new file mode 100644
index 0000000..f300666
--- /dev/null
+++ b/openwrt_patches-21.02/001-target-mediatek-add-mt7986-subtarget.patch
@@ -0,0 +1,13 @@
+diff --git a/target/linux/mediatek/Makefile b/target/linux/mediatek/Makefile
+index c8ab5e0..01e993d 100644
+--- a/target/linux/mediatek/Makefile
++++ b/target/linux/mediatek/Makefile
+@@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
+ ARCH:=arm
+ BOARD:=mediatek
+ BOARDNAME:=MediaTek Ralink ARM
+-SUBTARGETS:=mt7622 mt7623 mt7629
++SUBTARGETS:=mt7622 mt7623 mt7629 mt7986
+ FEATURES:=squashfs nand ramdisk fpu
+
+ KERNEL_PATCHVER:=5.4
diff --git a/openwrt_patches-21.02/101-fstool-add-mtk-patches.patch b/openwrt_patches-21.02/101-fstool-add-mtk-patches.patch
new file mode 100644
index 0000000..5afc342
--- /dev/null
+++ b/openwrt_patches-21.02/101-fstool-add-mtk-patches.patch
@@ -0,0 +1,18 @@
+diff -urN a/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch b/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch
+--- a/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch 2020-07-30 18:16:13.178070668 +0800
+@@ -0,0 +1,14 @@
++Index: fstools-2016-12-04-84b530a7/libfstools/mtd.c
++===================================================================
++--- fstools-2016-12-04-84b530a7.orig/libfstools/mtd.c 2017-08-29 15:00:46.824333000 +0800
+++++ fstools-2016-12-04-84b530a7/libfstools/mtd.c 2017-08-29 15:02:52.848520000 +0800
++@@ -218,6 +218,9 @@
++ if (v->type == UBIVOLUME && deadc0de == 0xffffffff) {
++ return FS_JFFS2;
++ }
+++ if (v->type == NANDFLASH && deadc0de == 0xffffffff) {
+++ return FS_JFFS2;
+++ }
++
++ return FS_NONE;
++ }
diff --git a/openwrt_patches-21.02/103-generic-kernel-config-for-mtk-snand-driver.patch b/openwrt_patches-21.02/103-generic-kernel-config-for-mtk-snand-driver.patch
new file mode 100644
index 0000000..4df19fd
--- /dev/null
+++ b/openwrt_patches-21.02/103-generic-kernel-config-for-mtk-snand-driver.patch
@@ -0,0 +1,10 @@
+--- a/target/linux/generic/config-5.4
++++ b/target/linux/generic/config-5.4
+@@ -3273,6 +3273,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y
+ # CONFIG_MTD_UIMAGE_SPLIT is not set
+ # CONFIG_MTD_VIRT_CONCAT is not set
+ # CONFIG_MTK_MMC is not set
++# CONFIG_MTK_SPI_NAND is not set
+ CONFIG_MULTIUSER=y
+ # CONFIG_MUTEX_SPIN_ON_OWNER is not set
+ # CONFIG_MV643XX_ETH is not set
diff --git a/openwrt_patches-21.02/104-enable-mtk-snand-for-mt7622.patch b/openwrt_patches-21.02/104-enable-mtk-snand-for-mt7622.patch
new file mode 100644
index 0000000..ee5059c
--- /dev/null
+++ b/openwrt_patches-21.02/104-enable-mtk-snand-for-mt7622.patch
@@ -0,0 +1,10 @@
+--- a/target/linux/mediatek/mt7622/config-5.4
++++ b/target/linux/mediatek/mt7622/config-5.4
+@@ -414,6 +414,7 @@ CONFIG_MTK_SCPSYS=y
+ CONFIG_MTK_THERMAL=y
+ CONFIG_MTK_TIMER=y
+ # CONFIG_MTK_UART_APDMA is not set
++CONFIG_MTK_SPI_NAND=y
+ CONFIG_MUTEX_SPIN_ON_OWNER=y
+ CONFIG_NEED_DMA_MAP_STATE=y
+ CONFIG_NEED_SG_DMA_LENGTH=y
diff --git a/openwrt_patches-21.02/105-enable-dm-verity-for-mt7622.patch b/openwrt_patches-21.02/105-enable-dm-verity-for-mt7622.patch
new file mode 100644
index 0000000..c4386ba
--- /dev/null
+++ b/openwrt_patches-21.02/105-enable-dm-verity-for-mt7622.patch
@@ -0,0 +1,38 @@
+diff --git a/target/linux/mediatek/mt7622/config-5.4 b/target/linux/mediatek/mt7622/config-5.4
+index edecba3..c95ad3f 100644
+--- a/target/linux/mediatek/mt7622/config-5.4
++++ b/target/linux/mediatek/mt7622/config-5.4
+@@ -114,6 +114,9 @@ CONFIG_ARM_PMU=y
+ CONFIG_ARM_PSCI_FW=y
+ CONFIG_ATA=y
+ CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
++CONFIG_BLK_DEV_DM=y
++CONFIG_BLK_DEV_DM_BUILTIN=y
++# CONFIG_BLK_DEV_MD is not set
+ CONFIG_BLK_DEV_SD=y
+ CONFIG_BLK_MQ_PCI=y
+ CONFIG_BLK_PM=y
+@@ -220,6 +223,15 @@ CONFIG_DMA_ENGINE_RAID=y
+ CONFIG_DMA_OF=y
+ CONFIG_DMA_REMAP=y
+ CONFIG_DMA_VIRTUAL_CHANNELS=y
++CONFIG_DM_BUFIO=y
++# CONFIG_DM_CRYPT is not set
++# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
++CONFIG_DM_INIT=y
++# CONFIG_DM_MIRROR is not set
++# CONFIG_DM_SNAPSHOT is not set
++CONFIG_DM_VERITY=y
++# CONFIG_DM_VERITY_FEC is not set
++# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
+ CONFIG_DRM_RCAR_WRITEBACK=y
+ CONFIG_DTC=y
+ CONFIG_DYNAMIC_DEBUG=y
+@@ -378,6 +390,7 @@ CONFIG_LOCK_SPIN_ON_OWNER=y
+ CONFIG_LZO_COMPRESS=y
+ CONFIG_LZO_DECOMPRESS=y
+ CONFIG_MAGIC_SYSRQ=y
++CONFIG_MD=y
+ CONFIG_MDIO_BUS=y
+ CONFIG_MDIO_DEVICE=y
+ CONFIG_MEDIATEK_MT6577_AUXADC=y
diff --git a/openwrt_patches-21.02/200-mt7621-modify-image-load-address.patch b/openwrt_patches-21.02/200-mt7621-modify-image-load-address.patch
new file mode 100644
index 0000000..6c85a34
--- /dev/null
+++ b/openwrt_patches-21.02/200-mt7621-modify-image-load-address.patch
@@ -0,0 +1,11 @@
+--- a/target/linux/ramips/image/Makefile
++++ b/target/linux/ramips/image/Makefile
+@@ -16,7 +16,7 @@ DEVICE_VARS += SERCOMM_PAD JCG_MAXSIZE
+
+ loadaddr-y := 0x80000000
+ loadaddr-$(CONFIG_TARGET_ramips_rt288x) := 0x88000000
+-loadaddr-$(CONFIG_TARGET_ramips_mt7621) := 0x80001000
++loadaddr-$(CONFIG_TARGET_ramips_mt7621) := 0x81001000
+
+ ldrplatform-y := ralink
+ ldrplatform-$(CONFIG_TARGET_ramips_mt7621) := mt7621
diff --git a/openwrt_patches-21.02/210-mt7622-modify-ubi-support.patch b/openwrt_patches-21.02/210-mt7622-modify-ubi-support.patch
new file mode 100644
index 0000000..7f2335f
--- /dev/null
+++ b/openwrt_patches-21.02/210-mt7622-modify-ubi-support.patch
@@ -0,0 +1,43 @@
+--- a/target/linux/mediatek/image/mt7622.mk
++++ b/target/linux/mediatek/image/mt7622.mk
+@@ -46,15 +46,15 @@ define Device/mediatek_mt7622-ubi
+ DEVICE_MODEL := MTK7622 AP (UBI)
+ DEVICE_DTS := mt7622-rfb1-ubi
+ DEVICE_DTS_DIR := $(DTS_DIR)/mediatek
++ SUPPORTED_DEVICES := mediatek,mt7622,ubi
+ UBINIZE_OPTS := -E 5
+ BLOCKSIZE := 128k
+ PAGESIZE := 2048
+- KERNEL_SIZE := 4194304
+- IMAGE_SIZE := 32768k
++ IMAGE_SIZE := 36864k
++ KERNEL_IN_UBI := 1
+ IMAGES += factory.bin
+- IMAGE/factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi | \
+- check-size $$$$(IMAGE_SIZE)
+- IMAGE/sysupgrade.bin := sysupgrade-tar
++ IMAGE/factory.bin := append-ubi | check-size $$$$(IMAGE_SIZE)
++ IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
+ DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-usb3 kmod-ata-ahci-mtk
+ endef
+ TARGET_DEVICES += mediatek_mt7622-ubi
+--- a/target/linux/mediatek/mt7622/base-files/lib/upgrade/platform.sh
++++ b/target/linux/mediatek/mt7622/base-files/lib/upgrade/platform.sh
+@@ -25,6 +25,17 @@ platform_check_image() {
+ [ "$#" -gt 1 ] && return 1
+
+ case "$board" in
++ mediatek,mt7622,ubi)
++ # tar magic `ustar`
++ magic="$(dd if="$1" bs=1 skip=257 count=5 2>/dev/null)"
++
++ [ "$magic" != "ustar" ] && {
++ echo "Invalid image type."
++ return 1
++ }
++
++ return 0
++ ;;
+ *)
+ [ "$magic" != "d00dfeed" ] && {
+ echo "Invalid image type."
diff --git a/openwrt_patches-21.02/300-mt7622-network-setup-mac.patch b/openwrt_patches-21.02/300-mt7622-network-setup-mac.patch
new file mode 100644
index 0000000..5fd7d00
--- /dev/null
+++ b/openwrt_patches-21.02/300-mt7622-network-setup-mac.patch
@@ -0,0 +1,30 @@
+diff --git a/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network b/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network
+index 3a409c8..4b19c0d 100755
+--- a/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network
++++ b/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network
+@@ -29,9 +29,25 @@ mediatek_setup_interfaces()
+ mediatek_setup_macs()
+ {
+ local board="$1"
++ local part_name="Factory"
++ local lan_mac=""
++ local wan_mac=""
++ local lan_mac_offset=""
++ local wan_mac_offset=""
+
+ case $board in
++ *)
++ #512k - 12 byte
++ lan_mac_offset="0x7FFF4"
++ wan_mac_offset="0x7FFFA"
++ ;;
+ esac
++
++ lan_mac=$(mtd_get_mac_binary $part_name $lan_mac_offset)
++ wan_mac=$(mtd_get_mac_binary $part_name $wan_mac_offset)
++
++ [ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" "$lan_mac"
++ [ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" "$wan_mac"
+ }
+
+ board_config_update
diff --git a/openwrt_patches/101-fstool-add-mtk-patches.patch b/openwrt_patches/101-fstool-add-mtk-patches.patch
new file mode 100644
index 0000000..5afc342
--- /dev/null
+++ b/openwrt_patches/101-fstool-add-mtk-patches.patch
@@ -0,0 +1,18 @@
+diff -urN a/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch b/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch
+--- a/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0101-jffs2-mount-on-mtk-flash-workaround.patch 2020-07-30 18:16:13.178070668 +0800
+@@ -0,0 +1,14 @@
++Index: fstools-2016-12-04-84b530a7/libfstools/mtd.c
++===================================================================
++--- fstools-2016-12-04-84b530a7.orig/libfstools/mtd.c 2017-08-29 15:00:46.824333000 +0800
+++++ fstools-2016-12-04-84b530a7/libfstools/mtd.c 2017-08-29 15:02:52.848520000 +0800
++@@ -218,6 +218,9 @@
++ if (v->type == UBIVOLUME && deadc0de == 0xffffffff) {
++ return FS_JFFS2;
++ }
+++ if (v->type == NANDFLASH && deadc0de == 0xffffffff) {
+++ return FS_JFFS2;
+++ }
++
++ return FS_NONE;
++ }
diff --git a/openwrt_patches/103-generic-kernel-config-for-mtk-snand-driver.patch b/openwrt_patches/103-generic-kernel-config-for-mtk-snand-driver.patch
new file mode 100644
index 0000000..4df19fd
--- /dev/null
+++ b/openwrt_patches/103-generic-kernel-config-for-mtk-snand-driver.patch
@@ -0,0 +1,10 @@
+--- a/target/linux/generic/config-5.4
++++ b/target/linux/generic/config-5.4
+@@ -3273,6 +3273,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y
+ # CONFIG_MTD_UIMAGE_SPLIT is not set
+ # CONFIG_MTD_VIRT_CONCAT is not set
+ # CONFIG_MTK_MMC is not set
++# CONFIG_MTK_SPI_NAND is not set
+ CONFIG_MULTIUSER=y
+ # CONFIG_MUTEX_SPIN_ON_OWNER is not set
+ # CONFIG_MV643XX_ETH is not set
diff --git a/openwrt_patches/200-mt7621-modify-image-load-address.patch b/openwrt_patches/200-mt7621-modify-image-load-address.patch
new file mode 100644
index 0000000..6c85a34
--- /dev/null
+++ b/openwrt_patches/200-mt7621-modify-image-load-address.patch
@@ -0,0 +1,11 @@
+--- a/target/linux/ramips/image/Makefile
++++ b/target/linux/ramips/image/Makefile
+@@ -16,7 +16,7 @@ DEVICE_VARS += SERCOMM_PAD JCG_MAXSIZE
+
+ loadaddr-y := 0x80000000
+ loadaddr-$(CONFIG_TARGET_ramips_rt288x) := 0x88000000
+-loadaddr-$(CONFIG_TARGET_ramips_mt7621) := 0x80001000
++loadaddr-$(CONFIG_TARGET_ramips_mt7621) := 0x81001000
+
+ ldrplatform-y := ralink
+ ldrplatform-$(CONFIG_TARGET_ramips_mt7621) := mt7621
diff --git a/prepare_sdk.sh b/prepare_sdk.sh
new file mode 100755
index 0000000..c3e7b87
--- /dev/null
+++ b/prepare_sdk.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+MTK_FEEDS_DIR=${1}
+
+OPENWRT_VER=`cat ./feeds.conf.default | grep "src-git packages" | awk -F ";openwrt" '{print $2}'`
+
+if [ -z ${1} ]; then
+ MTK_FEEDS_DIR=feeds/mtk_openwrt_feed
+fi
+
+remove_patches(){
+ echo "remove conflict patches"
+ for aa in `cat ${MTK_FEEDS_DIR}/remove.patch.list`
+ do
+ echo "rm $aa"
+ rm -rf ./$aa
+ done
+}
+
+sdk_patch(){
+ files=`find ${MTK_FEEDS_DIR}/openwrt_patches${OPENWRT_VER} -name "*.patch" | sort`
+ for file in $files
+ do
+ patch -f -p1 -i ${file} || exit 1
+ done
+}
+
+sdk_patch
+#cp mtk target to OpenWRT
+cp -fpR ${MTK_FEEDS_DIR}/target ./
+#remove patch if choose to not "keep" patch
+if [ -z ${2} ]; then
+ remove_patches
+fi
+
diff --git a/remove.patch.list b/remove.patch.list
new file mode 100644
index 0000000..46d32de
--- /dev/null
+++ b/remove.patch.list
@@ -0,0 +1,6 @@
+target/linux/generic/backport-5.4/760-net-ethernet-mediatek-Integrate-GDM-PSE-setup-operat.patch
+target/linux/generic/backport-5.4/761-net-ethernet-mediatek-Refine-the-timing-of-GDM-PSE-s.patch
+target/linux/generic/backport-5.4/762-net-ethernet-mediatek-Enable-GDM-GDMA_DROP_ALL-mode.patch
+target/linux/mediatek/patches-5.4/1011-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch
+target/linux/mediatek/patches-5.4/1012-pci-pcie-mediatek-add-support-for-coherent-DMA.patch
+target/linux/generic/pending-5.4/770-*.patch
diff --git a/target/linux/generic/pending-5.4/770-17-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch b/target/linux/generic/pending-5.4/770-17-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch
new file mode 100644
index 0000000..03f8057
--- /dev/null
+++ b/target/linux/generic/pending-5.4/770-17-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch
@@ -0,0 +1,182 @@
+Index: linux-5.4.77/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+===================================================================
+--- linux-5.4.77.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ linux-5.4.77/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1354,9 +1354,21 @@ static int mtk_poll_rx(struct napi_struc
+ skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
+
+ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX &&
+- (trxd.rxd2 & RX_DMA_VTAG))
+- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+- RX_DMA_VID(trxd.rxd3));
++ (trxd.rxd2 & RX_DMA_VTAG)) {
++ __vlan_hwaccel_put_tag(skb,
++ htons(RX_DMA_VPID(trxd.rxd3)),
++ RX_DMA_TCI(trxd.rxd3));
++
++ /* If netdev is attached to dsa switch, the special
++ * tag inserted in VLAN field by switch hardware can
++ * be offload by RX HW VLAN offload. Clears the VLAN
++ * information from @skb to avoid unexpected 8021d
++ * handler before packet enter dsa framework.
++ */
++ if (netdev_uses_dsa(netdev))
++ __vlan_hwaccel_clear_tag(skb);
++ }
++
+ if (mtk_offload_check_rx(eth, skb, trxd.rxd4) == 0) {
+ skb_record_rx_queue(skb, 0);
+ napi_gro_receive(napi, skb);
+@@ -2050,19 +2062,32 @@ static netdev_features_t mtk_fix_feature
+ }
+ }
+
++ if ((features & NETIF_F_HW_VLAN_CTAG_TX) && netdev_uses_dsa(dev)) {
++ netdev_info(dev, "TX vlan offload cannot be enabled when dsa is attached.\n");
++
++ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
++ }
++
+ return features;
+ }
+
+ static int mtk_set_features(struct net_device *dev, netdev_features_t features)
+ {
++ struct mtk_mac *mac = netdev_priv(dev);
++ struct mtk_eth *eth = mac->hw;
+ int err = 0;
+
+- if (!((dev->features ^ features) & NETIF_F_LRO))
++ if (!((dev->features ^ features) & MTK_SET_FEATURES))
+ return 0;
+
+ if (!(features & NETIF_F_LRO))
+ mtk_hwlro_netdev_disable(dev);
+
++ if (!(features & NETIF_F_HW_VLAN_CTAG_RX))
++ mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
++ else
++ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
++
+ return err;
+ }
+
+@@ -2326,6 +2351,15 @@ static int mtk_open(struct net_device *d
+
+ mtk_gdm_config(eth, gdm_config);
+
++ /* Indicates CDM to parse the MTK special tag from CPU */
++ if (netdev_uses_dsa(dev)) {
++ u32 val;
++ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
++ mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
++ val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
++ mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
++ }
++
+ napi_enable(ð->tx_napi);
+ napi_enable(ð->rx_napi);
+ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+@@ -2500,7 +2534,7 @@ static void mtk_dim_tx(struct work_struc
+
+ static int mtk_hw_init(struct mtk_eth *eth)
+ {
+- int i, val, ret;
++ int i, ret;
+
+ if (test_and_set_bit(MTK_HW_INIT, ð->state))
+ return 0;
+@@ -2555,12 +2589,6 @@ static int mtk_hw_init(struct mtk_eth *e
+ for (i = 0; i < MTK_MAC_COUNT; i++)
+ mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i));
+
+- /* Indicates CDM to parse the MTK special tag from CPU
+- * which also is working out for untag packets.
+- */
+- val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+- mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
+-
+ /* Enable RX VLan Offloading */
+ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+
+Index: linux-5.4.77/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+===================================================================
+--- linux-5.4.77.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ linux-5.4.77/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -42,6 +42,8 @@
+ NETIF_F_SG | NETIF_F_TSO | \
+ NETIF_F_TSO6 | \
+ NETIF_F_IPV6_CSUM)
++#define MTK_SET_FEATURES (NETIF_F_LRO | \
++ NETIF_F_HW_VLAN_CTAG_RX)
+ #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM)
+ #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1))
+
+@@ -78,6 +80,10 @@
+ #define MTK_CDMQ_IG_CTRL 0x1400
+ #define MTK_CDMQ_STAG_EN BIT(0)
+
++/* CDMP Ingress Control Register */
++#define MTK_CDMP_IG_CTRL 0x400
++#define MTK_CDMP_STAG_EN BIT(0)
++
+ /* CDMP Exgress Control Register */
+ #define MTK_CDMP_EG_CTRL 0x404
+
+@@ -307,7 +313,9 @@
+ #define RX_DMA_VTAG BIT(15)
+
+ /* QDMA descriptor rxd3 */
+-#define RX_DMA_VID(_x) ((_x) & 0xfff)
++#define RX_DMA_VID(_x) ((_x) & VLAN_VID_MASK)
++#define RX_DMA_TCI(_x) ((_x) & (VLAN_PRIO_MASK | VLAN_VID_MASK))
++#define RX_DMA_VPID(_x) (((_x) >> 16) & 0xffff)
+
+ /* QDMA descriptor rxd4 */
+ #define MTK_RXD4_FOE_ENTRY GENMASK(13, 0)
+Index: linux-5.4.77/net/dsa/tag_mtk.c
+===================================================================
+--- linux-5.4.77.orig/net/dsa/tag_mtk.c
++++ linux-5.4.77/net/dsa/tag_mtk.c
+@@ -73,22 +73,28 @@ static struct sk_buff *mtk_tag_rcv(struc
+ bool is_multicast_skb = is_multicast_ether_addr(dest) &&
+ !is_broadcast_ether_addr(dest);
+
+- if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
+- return NULL;
++ if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) {
++ hdr = ntohs(skb->vlan_proto);
++ skb->vlan_proto = 0;
++ skb->vlan_tci = 0;
++ } else {
++ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
++ return NULL;
+
+- /* The MTK header is added by the switch between src addr
+- * and ethertype at this point, skb->data points to 2 bytes
+- * after src addr so header should be 2 bytes right before.
+- */
+- phdr = (__be16 *)(skb->data - 2);
+- hdr = ntohs(*phdr);
++ /* The MTK header is added by the switch between src addr
++ * and ethertype at this point, skb->data points to 2 bytes
++ * after src addr so header should be 2 bytes right before.
++ */
++ phdr = (__be16 *)(skb->data - 2);
++ hdr = ntohs(*phdr);
+
+- /* Remove MTK tag and recalculate checksum. */
+- skb_pull_rcsum(skb, MTK_HDR_LEN);
++ /* Remove MTK tag and recalculate checksum. */
++ skb_pull_rcsum(skb, MTK_HDR_LEN);
+
+- memmove(skb->data - ETH_HLEN,
+- skb->data - ETH_HLEN - MTK_HDR_LEN,
+- 2 * ETH_ALEN);
++ memmove(skb->data - ETH_HLEN,
++ skb->data - ETH_HLEN - MTK_HDR_LEN,
++ 2 * ETH_ALEN);
++ }
+
+ /* Get source port information */
+ port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
diff --git a/target/linux/mediatek/base-files/etc/inittab b/target/linux/mediatek/base-files/etc/inittab
new file mode 100644
index 0000000..4374da2
--- /dev/null
+++ b/target/linux/mediatek/base-files/etc/inittab
@@ -0,0 +1,3 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+ttyS0::respawnlate:/usr/libexec/login.sh
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-rfb1-ubi.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-rfb1-ubi.dts
new file mode 100644
index 0000000..bf59b83
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-rfb1-ubi.dts
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#include "mt7622.dtsi"
+#include "mt6380.dtsi"
+
+/ {
+ model = "MT7622_MT7531 RFB";
+ compatible = "mediatek,mt7622,ubi";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
+ };
+
+ cpus {
+ cpu@0 {
+ proc-supply = <&mt6380_vcpu_reg>;
+ sram-supply = <&mt6380_vm_reg>;
+ };
+
+ cpu@1 {
+ proc-supply = <&mt6380_vcpu_reg>;
+ sram-supply = <&mt6380_vm_reg>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ factory {
+ label = "factory";
+ linux,code = <BTN_0>;
+ gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+ };
+
+ wps {
+ label = "wps";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&pio 102 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ gsw: gsw@0 {
+ compatible = "mediatek,mt753x";
+ mediatek,ethsys = <ðsys>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ green {
+ label = "bpi-r64:pio:green";
+ gpios = <&pio 89 GPIO_ACTIVE_HIGH>;
+ };
+
+ red {
+ label = "bpi-r64:pio:red";
+ gpios = <&pio 88 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ memory {
+ reg = <0 0x40000000 0 0x40000000>;
+ };
+
+ reg_1p8v: regulator-1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ reg_5v: regulator-5v {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-5V";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+};
+
+&btif {
+ status = "okay";
+};
+
+&cir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&irrx_pins>;
+ status = "okay";
+};
+
+ð {
+ status = "okay";
+ gmac0: mac@0 {
+ compatible = "mediatek,eth-mac";
+ reg = <0>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ gmac1: mac@1 {
+ compatible = "mediatek,eth-mac";
+ reg = <1>;
+ phy-mode = "rgmii";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ mdio: mdio-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+};
+
+&gsw {
+ mediatek,mdio = <&mdio>;
+ mediatek,portmap = "llllw";
+ mediatek,mdio_master_pinmux = <0>;
+ reset-gpios = <&pio 54 0>;
+ interrupt-parent = <&pio>;
+ interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+ status = "okay";
+
+ port5: port@5 {
+ compatible = "mediatek,mt753x-port";
+ reg = <5>;
+ phy-mode = "rgmii";
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ port6: port@6 {
+ compatible = "mediatek,mt753x-port";
+ reg = <6>;
+ phy-mode = "sgmii";
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ };
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&emmc_pins_default>;
+ pinctrl-1 = <&emmc_pins_uhs>;
+ status = "okay";
+ bus-width = <8>;
+ max-frequency = <50000000>;
+ cap-mmc-highspeed;
+ mmc-hs200-1_8v;
+ vmmc-supply = <®_3p3v>;
+ vqmmc-supply = <®_1p8v>;
+ assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+ non-removable;
+};
+
+&mmc1 {
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&sd0_pins_default>;
+ pinctrl-1 = <&sd0_pins_uhs>;
+ status = "okay";
+ bus-width = <4>;
+ max-frequency = <50000000>;
+ cap-sd-highspeed;
+ r_smpl = <1>;
+ cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <®_3p3v>;
+ vqmmc-supply = <®_3p3v>;
+ assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>;
+ assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+};
+
+&nandc {
+ pinctrl-names = "default";
+ pinctrl-0 = <¶llel_nand_pins>;
+ status = "disabled";
+};
+
+&nor_flash {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_nor_pins>;
+ status = "disabled";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ };
+};
+
+&pcie0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_pins>;
+ status = "okay";
+};
+
+&pcie1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie1_pins>;
+ status = "okay";
+};
+
+&pio {
+ /* Attention: GPIO 90 is used to switch between PCIe@1,0 and
+ * SATA functions. i.e. output-high: PCIe, output-low: SATA
+ */
+ asm_sel {
+ gpio-hog;
+ gpios = <90 GPIO_ACTIVE_HIGH>;
+ output-high;
+ };
+
+ /* eMMC is shared pin with parallel NAND */
+ emmc_pins_default: emmc-pins-default {
+ mux {
+ function = "emmc", "emmc_rst";
+ groups = "emmc";
+ };
+
+ /* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7",
+ * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4,
+ * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively
+ */
+ conf-cmd-dat {
+ pins = "NDL0", "NDL1", "NDL2",
+ "NDL3", "NDL4", "NDL5",
+ "NDL6", "NDL7", "NRB";
+ input-enable;
+ bias-pull-up;
+ };
+
+ conf-clk {
+ pins = "NCLE";
+ bias-pull-down;
+ };
+ };
+
+ emmc_pins_uhs: emmc-pins-uhs {
+ mux {
+ function = "emmc";
+ groups = "emmc";
+ };
+
+ conf-cmd-dat {
+ pins = "NDL0", "NDL1", "NDL2",
+ "NDL3", "NDL4", "NDL5",
+ "NDL6", "NDL7", "NRB";
+ input-enable;
+ drive-strength = <4>;
+ bias-pull-up;
+ };
+
+ conf-clk {
+ pins = "NCLE";
+ drive-strength = <4>;
+ bias-pull-down;
+ };
+ };
+
+ eth_pins: eth-pins {
+ mux {
+ function = "eth";
+ groups = "mdc_mdio", "rgmii_via_gmac2";
+ };
+ };
+
+ i2c1_pins: i2c1-pins {
+ mux {
+ function = "i2c";
+ groups = "i2c1_0";
+ };
+ };
+
+ i2c2_pins: i2c2-pins {
+ mux {
+ function = "i2c";
+ groups = "i2c2_0";
+ };
+ };
+
+ i2s1_pins: i2s1-pins {
+ mux {
+ function = "i2s";
+ groups = "i2s_out_mclk_bclk_ws",
+ "i2s1_in_data",
+ "i2s1_out_data";
+ };
+
+ conf {
+ pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK",
+ "I2S_WS", "I2S_MCLK";
+ drive-strength = <12>;
+ bias-pull-down;
+ };
+ };
+
+ irrx_pins: irrx-pins {
+ mux {
+ function = "ir";
+ groups = "ir_1_rx";
+ };
+ };
+
+ irtx_pins: irtx-pins {
+ mux {
+ function = "ir";
+ groups = "ir_1_tx";
+ };
+ };
+
+ /* Parallel nand is shared pin with eMMC */
+ parallel_nand_pins: parallel-nand-pins {
+ mux {
+ function = "flash";
+ groups = "par_nand";
+ };
+ };
+
+ pcie0_pins: pcie0-pins {
+ mux {
+ function = "pcie";
+ groups = "pcie0_pad_perst",
+ "pcie0_1_waken",
+ "pcie0_1_clkreq";
+ };
+ };
+
+ pcie1_pins: pcie1-pins {
+ mux {
+ function = "pcie";
+ groups = "pcie1_pad_perst",
+ "pcie1_0_waken",
+ "pcie1_0_clkreq";
+ };
+ };
+
+ pmic_bus_pins: pmic-bus-pins {
+ mux {
+ function = "pmic";
+ groups = "pmic_bus";
+ };
+ };
+
+ pwm7_pins: pwm1-2-pins {
+ mux {
+ function = "pwm";
+ groups = "pwm_ch7_2";
+ };
+ };
+
+ wled_pins: wled-pins {
+ mux {
+ function = "led";
+ groups = "wled";
+ };
+ };
+
+ sd0_pins_default: sd0-pins-default {
+ mux {
+ function = "sd";
+ groups = "sd_0";
+ };
+
+ /* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN",
+ * "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1,
+ * DAT2, DAT3, CMD, CLK for SD respectively.
+ */
+ conf-cmd-data {
+ pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+ "I2S2_IN","I2S4_OUT";
+ input-enable;
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ conf-clk {
+ pins = "I2S3_OUT";
+ drive-strength = <12>;
+ bias-pull-down;
+ };
+ conf-cd {
+ pins = "TXD3";
+ bias-pull-up;
+ };
+ };
+
+ sd0_pins_uhs: sd0-pins-uhs {
+ mux {
+ function = "sd";
+ groups = "sd_0";
+ };
+
+ conf-cmd-data {
+ pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+ "I2S2_IN","I2S4_OUT";
+ input-enable;
+ bias-pull-up;
+ };
+
+ conf-clk {
+ pins = "I2S3_OUT";
+ bias-pull-down;
+ };
+ };
+
+ /* Serial NAND is shared pin with SPI-NOR */
+ serial_nand_pins: serial-nand-pins {
+ mux {
+ function = "flash";
+ groups = "snfi";
+ };
+ };
+
+ spic0_pins: spic0-pins {
+ mux {
+ function = "spi";
+ groups = "spic0_0";
+ };
+ };
+
+ spic1_pins: spic1-pins {
+ mux {
+ function = "spi";
+ groups = "spic1_0";
+ };
+ };
+
+ /* SPI-NOR is shared pin with serial NAND */
+ spi_nor_pins: spi-nor-pins {
+ mux {
+ function = "flash";
+ groups = "spi_nor";
+ };
+ };
+
+ /* serial NAND is shared pin with SPI-NOR */
+ serial_nand_pins: serial-nand-pins {
+ mux {
+ function = "flash";
+ groups = "snfi";
+ };
+ };
+
+ uart0_pins: uart0-pins {
+ mux {
+ function = "uart";
+ groups = "uart0_0_tx_rx" ;
+ };
+ };
+
+ uart2_pins: uart2-pins {
+ mux {
+ function = "uart";
+ groups = "uart2_1_tx_rx" ;
+ };
+ };
+
+ watchdog_pins: watchdog-pins {
+ mux {
+ function = "watchdog";
+ groups = "watchdog";
+ };
+ };
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm7_pins>;
+ status = "okay";
+};
+
+&pwrap {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_bus_pins>;
+
+ status = "okay";
+};
+
+&sata {
+ status = "disable";
+};
+
+&sata_phy {
+ status = "disable";
+};
+
+&snand {
+ pinctrl-names = "default";
+ pinctrl-0 = <&serial_nand_pins>;
+ status = "okay";
+ mediatek,quad-spi;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "BL2";
+ reg = <0x00000 0x0080000>;
+ read-only;
+ };
+
+ partition@80000 {
+ label = "FIP";
+ reg = <0x80000 0x0200000>;
+ };
+
+ partition@280000 {
+ label = "Config";
+ reg = <0x280000 0x0080000>;
+ };
+
+ factory: partition@300000 {
+ label = "Factory";
+ reg = <0x300000 0x0100000>;
+ };
+
+ partition@400000 {
+ label = "ubi";
+ reg = <0x400000 0x2400000>;
+ };
+ };
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spic0_pins>;
+ status = "okay";
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spic1_pins>;
+ status = "okay";
+};
+
+&ssusb {
+ vusb33-supply = <®_3p3v>;
+ vbus-supply = <®_5v>;
+ status = "okay";
+};
+
+&u3phy {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&watchdog {
+ pinctrl-names = "default";
+ pinctrl-0 = <&watchdog_pins>;
+ status = "okay";
+};
+
+&wmac {
+ mediatek,mtd-eeprom = <&factory 0x0000>;
+ status = "okay";
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga-ubi.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga-ubi.dts
new file mode 100644
index 0000000..1f4125c
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga-ubi.dts
@@ -0,0 +1,170 @@
+/dts-v1/;
+#include "mt7986-fpga.dtsi"
+/ {
+ model = "MediaTek MT7986 FPGA (UBI)";
+ compatible = "mediatek,mt7986-fpga,ubi";
+ chosen {
+ bootargs = "console=ttyS0,115200n1 loglevel=8 \
+ earlycon=uart8250,mmio32,0x11002000";
+ };
+
+ memory {
+ // fpga ddr2: 128MB*2
+ reg = <0 0x40000000 0 0x10000000>;
+ };
+
+ wsys_adie: wsys_adie@0 {
+ // fpga cases need to manual change adie_id / sku_type for dvt only
+ compatible = "mediatek,rebb-mt7986-adie";
+ adie_id = <7976>;
+ sku_type = <6000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
+ status = "okay";
+ spi_nor@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <500000>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0060000>;
+ };
+ partition@60000 {
+ label = "u-boot-env";
+ reg = <0x60000 0x0010000>;
+ };
+ partition@70000 {
+ label = "Factory";
+ reg = <0x70000 0x00B0000>;
+ };
+ partition@120000 {
+ label = "BL31";
+ reg = <0x120000 0x0010000>;
+ };
+ partition@130000 {
+ label = "u-boot";
+ reg = <0x130000 0x00D0000>;
+ };
+ partition@200000 {
+ label = "firmware";
+ reg = <0x200000 0xE00000>;
+ };
+ };
+ spi_nand@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-nand";
+ reg = <1>;
+ spi-max-frequency = <500000>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ };
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x100000 0x0080000>;
+ };
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x00200000>;
+ };
+ partition@380000 {
+ label = "BL31";
+ reg = <0x380000 0x0080000>;
+ };
+ partition@400000 {
+ label = "u-boot";
+ reg = <0x400000 0x0180000>;
+ };
+ partition@580000 {
+ label = "firmware";
+ reg = <0x580000 0x7a80000>;
+ };
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ /* pin shared with snfi */
+ pinctrl-0 = <&spic_pins>;
+ status = "disabled";
+};
+
+&pio {
+ spi_flash_pins: spi0-pins {
+ mux {
+ function = "flash";
+ groups = "spi0", "spi0_wp_hold";
+ };
+ };
+
+ snfi_pins: snfi-pins {
+ mux {
+ function = "flash";
+ groups = "snfi";
+ };
+ };
+
+ spic_pins: spi1-pins {
+ mux {
+ function = "spi";
+ groups = "spi1_1";
+ };
+ };
+};
+
+&watchdog {
+ status = "disabled";
+};
+
+&snand {
+ pinctrl-names = "default";
+ /* pin shared with spic */
+ pinctrl-0 = <&snfi_pins>;
+ status = "okay";
+ mediatek,quad-spi;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x0100000 0x0080000>;
+ };
+
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x0200000>;
+ };
+
+ partition@380000 {
+ label = "FIP";
+ reg = <0x380000 0x0200000>;
+ };
+
+ partition@580000 {
+ label = "ubi";
+ reg = <0x580000 0x4000000>;
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dts
new file mode 100644
index 0000000..5f8ef81
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dts
@@ -0,0 +1,170 @@
+/dts-v1/;
+#include "mt7986-fpga.dtsi"
+/ {
+ model = "MediaTek MT7986 FPGA";
+ compatible = "mediatek,mt7986-fpga";
+ chosen {
+ bootargs = "console=ttyS0,115200n1 loglevel=8 \
+ earlycon=uart8250,mmio32,0x11002000";
+ };
+
+ memory {
+ // fpga ddr2: 128MB*2
+ reg = <0 0x40000000 0 0x10000000>;
+ };
+
+ wsys_adie: wsys_adie@0 {
+ // fpga cases need to manual change adie_id / sku_type for dvt only
+ compatible = "mediatek,rebb-mt7986-adie";
+ adie_id = <7976>;
+ sku_type = <6000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
+ status = "okay";
+ spi_nor@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <500000>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0060000>;
+ };
+ partition@60000 {
+ label = "u-boot-env";
+ reg = <0x60000 0x0010000>;
+ };
+ partition@70000 {
+ label = "Factory";
+ reg = <0x70000 0x00B0000>;
+ };
+ partition@120000 {
+ label = "BL31";
+ reg = <0x120000 0x0010000>;
+ };
+ partition@130000 {
+ label = "u-boot";
+ reg = <0x130000 0x00D0000>;
+ };
+ partition@200000 {
+ label = "firmware";
+ reg = <0x200000 0xE00000>;
+ };
+ };
+ spi_nand@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-nand";
+ reg = <1>;
+ spi-max-frequency = <500000>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ };
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x100000 0x0080000>;
+ };
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x00200000>;
+ };
+ partition@380000 {
+ label = "BL31";
+ reg = <0x380000 0x0080000>;
+ };
+ partition@400000 {
+ label = "u-boot";
+ reg = <0x400000 0x0180000>;
+ };
+ partition@580000 {
+ label = "firmware";
+ reg = <0x580000 0x7a80000>;
+ };
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ /* pin shared with snfi */
+ pinctrl-0 = <&spic_pins>;
+ status = "disabled";
+};
+
+&pio {
+ spi_flash_pins: spi0-pins {
+ mux {
+ function = "flash";
+ groups = "spi0", "spi0_wp_hold";
+ };
+ };
+
+ snfi_pins: snfi-pins {
+ mux {
+ function = "flash";
+ groups = "snfi";
+ };
+ };
+
+ spic_pins: spi1-pins {
+ mux {
+ function = "spi";
+ groups = "spi1_1";
+ };
+ };
+};
+
+&watchdog {
+ status = "disabled";
+};
+
+&snand {
+ pinctrl-names = "default";
+ /* pin shared with spic */
+ pinctrl-0 = <&snfi_pins>;
+ status = "okay";
+ mediatek,quad-spi;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "BL2";
+ reg = <0x00000 0x0080000>;
+ read-only;
+ };
+
+ partition@80000 {
+ label = "FIP";
+ reg = <0x80000 0x0200000>;
+ };
+
+ partition@280000 {
+ label = "u-boot-env";
+ reg = <0x280000 0x0080000>;
+ };
+
+ partition@300000 {
+ label = "Factory";
+ reg = <0x300000 0x0080000>;
+ };
+
+ partition@380000 {
+ label = "firmware";
+ reg = <0x380000 0x7c00000>;
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dtsi b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dtsi
new file mode 100644
index 0000000..d8fa26d
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dtsi
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+/ {
+ compatible = "mediatek,mt7986-fpga";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x1>;
+ };
+ };
+
+ wed: wed@15010000 {
+ compatible = "mediatek,wed";
+ wed_num = <2>;
+ /* add this property for wed get the pci slot number. */
+ pci_slot_map = <0>, <1>;
+ reg = <0 0x15010000 0 0x1000>,
+ <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wed2: wed2@15011000 {
+ compatible = "mediatek,wed2";
+ wed_num = <2>;
+ reg = <0 0x15010000 0 0x1000>,
+ <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wdma: wdma@15104800 {
+ compatible = "mediatek,wed-wdma";
+ reg = <0 0x15104800 0 0x400>,
+ <0 0x15104c00 0 0x400>;
+ };
+
+ ap2woccif: ap2woccif@151A5000 {
+ compatible = "mediatek,ap2woccif";
+ reg = <0 0x151A5000 0 0x1000>,
+ <0 0x151AD000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wocpu0_ilm: wocpu0_ilm@151E0000 {
+ compatible = "mediatek,wocpu0_ilm";
+ reg = <0 0x151E0000 0 0x8000>;
+ };
+
+ wocpu1_ilm: wocpu1_ilm@151F0000 {
+ compatible = "mediatek,wocpu1_ilm";
+ reg = <0 0x151F0000 0 0x8000>;
+ };
+
+ wocpu_dlm: wocpu_dlm@151E8000 {
+ compatible = "mediatek,wocpu_dlm";
+ reg = <0 0x151E8000 0 0x2000>,
+ <0 0x151F8000 0 0x2000>;
+
+ resets = <ðsysrst 0>;
+ reset-names = "wocpu_rst";
+ };
+
+ cpu_boot: wocpu_boot@15194000 {
+ compatible = "mediatek,wocpu_boot";
+ reg = <0 0x15194000 0 0x1000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved: secmon@43000000 {
+ reg = <0 0x43000000 0 0x30000>;
+ no-map;
+ };
+
+ wmcpu_emi: wmcpu-reserved@4FC00000 {
+ compatible = "mediatek,wmcpu-reserved";
+ no-map;
+ reg = <0 0x4FC00000 0 0x00100000>;
+ };
+
+ wocpu0_emi: wocpu0_emi@4FD00000 {
+ compatible = "mediatek,wocpu0_emi";
+ no-map;
+ reg = <0 0x4FD00000 0 0x40000>;
+ shared = <0>;
+ };
+
+ wocpu1_emi: wocpu1_emi@4FD80000 {
+ compatible = "mediatek,wocpu1_emi";
+ no-map;
+ reg = <0 0x4FD40000 0 0x40000>;
+ shared = <0>;
+ };
+
+ wocpu_data: wocpu_data@4FE00000 {
+ compatible = "mediatek,wocpu_data";
+ no-map;
+ reg = <0 0x4FD80000 0 0x200000>;
+ shared = <1>;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ system_clk: dummy13m {
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ #clock-cells = <0>;
+ };
+
+ rtc_clk: dummy32k {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+
+ uart_clk: dummy12m {
+ compatible = "fixed-clock";
+ clock-frequency = <12000000>;
+ #clock-cells = <0>;
+ };
+
+ gpt_clk: dummy6m {
+ compatible = "fixed-clock";
+ clock-frequency = <6000000>;
+ #clock-cells = <0>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&gic>;
+ clock-frequency = <12000000>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+ };
+
+ watchdog: watchdog@1001c000 {
+ compatible = "mediatek,mt7622-wdt",
+ "mediatek,mt6589-wdt";
+ reg = <0 0x1001c000 0 0x1000>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ #reset-cells = <1>;
+ };
+
+ gic: interrupt-controller@c000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ interrupt-controller;
+ reg = <0 0x0c000000 0 0x40000>, /* GICD */
+ <0 0x0c080000 0 0x200000>; /* GICR */
+
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11002000 0 0x400>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart1: serial@11003000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11003000 0 0x400>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart2: serial@11004000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11004000 0 0x400>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ pcie: pcie@11280000 {
+ compatible = "mediatek,mt7986-pcie";
+ device_type = "pci";
+ reg = <0 0x11280000 0 0x5000>;
+ reg-names = "port0";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x82000000 0 0x20000000
+ 0x0 0x20000000 0 0x10000000>;
+
+ pcie0: pcie@0,0 {
+ device_type = "pci";
+ reg = <0x0000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+ <0 0 0 2 &pcie_intc0 1>,
+ <0 0 0 3 &pcie_intc0 2>,
+ <0 0 0 4 &pcie_intc0 3>;
+ pcie_intc0: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+ };
+
+ pio: pinctrl@1001f000 {
+ compatible = "mediatek,mt7986-pinctrl";
+ reg = <0 0x1001f000 0 0x1000>,
+ <0 0x11c30000 0 0x1000>,
+ <0 0x11c40000 0 0x1000>,
+ <0 0x11e20000 0 0x1000>,
+ <0 0x11e30000 0 0x1000>,
+ <0 0x11f00000 0 0x1000>,
+ <0 0x11f10000 0 0x1000>,
+ <0 0x1000b000 0 0x1000>;
+ reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+ "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+ "iocfg_tl_base", "eint";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pio 0 0 100>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ #interrupt-cells = <2>;
+ };
+
+ ethsys: syscon@15000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "mediatek,mt7986-ethsys",
+ "syscon";
+ reg = <0 0x15000000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+
+ ethsysrst: reset-controller {
+ compatible = "ti,syscon-reset";
+ #reset-cells = <1>;
+ ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+ };
+ };
+
+ eth: ethernet@15100000 {
+ compatible = "mediatek,mt7986-eth";
+ reg = <0 0x15100000 0 0x80000>;
+ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+ mediatek,ethsys = <ðsys>;
+ #reset-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ snand: snfi@11005000 {
+ compatible = "mediatek,mt7986-snand";
+ reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+ reg-names = "nfi", "ecc";
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "nfi_clk", "pad_clk", "ecc_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ wed_pcie: wed_pcie@10003000 {
+ compatible = "mediatek,wed_pcie";
+ reg = <0 0x10003000 0 0x10>;
+ };
+
+ wbsys: wbsys@18000000 {
+ compatible = "mediatek,wbsys";
+ reg = <0 0x18000000 0 0x1000000>;
+ interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+ chip_id = <0x7986>;
+ };
+
+ spi0: spi@1100a000 {
+ compatible = "mediatek,ipm-spi";
+ reg = <0 0x1100a000 0 0x100>;
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ spi1: spi@1100b000 {
+ compatible = "mediatek,ipm-spi";
+ reg = <0 0x1100b000 0 0x100>;
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ consys: consys@10000000 {
+ compatible = "mediatek,mt7986-consys";
+ reg = <0 0x10000000 0 0x8600000>;
+ memory-region = <&wmcpu_emi>;
+ };
+
+ xhci: xhci@11200000 {
+ compatible = "mediatek,mt7986-xhci",
+ "mediatek,mtk-xhci";
+ reg = <0 0x11200000 0 0x2e00>,
+ <0 0x11203e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&u2port0 PHY_TYPE_USB2>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "sys_ck",
+ "xhci_ck",
+ "ref_ck",
+ "mcu_ck",
+ "dma_ck";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ mediatek,u3p-dis-msk=<0x01>;
+ status = "okay";
+ };
+
+ usbtphy: usb-phy@11203e00 {
+ compatible = "mediatek,a60810-u2phy",
+ "mediatek,a60931-u3phy",
+ "mediatek,a60xxx-usbphy";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "okay";
+
+ u2port0: usb-phy@11203ed0 {
+ reg = <0 0x11203ed0 0 0x008>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+
+ u3port0: usb-phy@11203ed8 {
+ reg = <0 0x11203ed8 0 0x008>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+
+ u2port1: usb-phy@11203ee0 {
+ reg = <0 0x11203ee0 0 0x008>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7975-ax6000-rfb1.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7975-ax6000-rfb1.dts
new file mode 100644
index 0000000..58d11b6
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7975-ax6000-rfb1.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+#include "mt7986a-rfb.dtsi"
+/ {
+ model = "MediaTek MT7986a RFB";
+ compatible = "mediatek,mt7986a-rfb";
+
+ wsys_adie: wsys_adie@0 {
+ compatible = "mediatek,rebb-mt7986-adie";
+ adie_id = <7975>;
+ sku_type = <6000>;
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7976-ax6000-rfb2.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7976-ax6000-rfb2.dts
new file mode 100644
index 0000000..60d2372
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7976-ax6000-rfb2.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+#include "mt7986a-rfb.dtsi"
+/ {
+ model = "MediaTek MT7986a RFB";
+ compatible = "mediatek,mt7986a-rfb";
+
+ wsys_adie: wsys_adie@0 {
+ compatible = "mediatek,rebb-mt7986-adie";
+ adie_id = <7976>;
+ sku_type = <6000>;
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7976-ax7800-rfb2.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7976-ax7800-rfb2.dts
new file mode 100644
index 0000000..5790653
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-mt7976-ax7800-rfb2.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+#include "mt7986a-rfb.dtsi"
+/ {
+ model = "MediaTek MT7986a RFB";
+ compatible = "mediatek,mt7986a-rfb";
+
+ wsys_adie: wsys_adie@0 {
+ compatible = "mediatek,rebb-mt7986-adie";
+ adie_id = <7976>;
+ sku_type = <7800>;
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi
new file mode 100644
index 0000000..6013acb
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi
@@ -0,0 +1,248 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+/ {
+ model = "MediaTek MT7986a RFB";
+ compatible = "mediatek,mt7986a-rfb";
+ chosen {
+ bootargs = "console=ttyS0,115200n1 loglevel=8 \
+ earlycon=uart8250,mmio32,0x11002000";
+ };
+
+ memory {
+ // fpga ddr2: 128MB*2
+ reg = <0 0x40000000 0 0x10000000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
+};
+
+ð {
+ status = "okay";
+
+ gmac0: mac@0 {
+ compatible = "mediatek,eth-mac";
+ reg = <0>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ gmac1: mac@1 {
+ compatible = "mediatek,eth-mac";
+ reg = <1>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ mdio: mdio-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch@0 {
+ compatible = "mediatek,mt7531";
+ reg = <0>;
+ reset-gpios = <&pio 5 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "lan1";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan2";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan3";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan4";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "wan";
+ };
+
+ port@6 {
+ reg = <6>;
+ label = "cpu";
+ ethernet = <&gmac0>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+ };
+ };
+ };
+};
+
+&hnat {
+ mtketh-wan = "eth1";
+ mtketh-max-gmac = <2>;
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
+ cs-gpios = <0>, <0>;
+ status = "okay";
+ spi_nor@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ spi-tx-buswidth = <4>;
+ spi-rx-buswidth = <4>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0040000>;
+ };
+ partition@40000 {
+ label = "u-boot-env";
+ reg = <0x40000 0x0010000>;
+ };
+ partition@50000 {
+ label = "Factory";
+ reg = <0x50000 0x00B0000>;
+ };
+ partition@100000 {
+ label = "FIP";
+ reg = <0x100000 0x0080000>;
+ };
+ partition@180000 {
+ label = "firmware";
+ reg = <0x180000 0xE00000>;
+ };
+ };
+ spi_nand@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-nand";
+ reg = <1>;
+ spi-max-frequency = <20000000>;
+ spi-tx-buswidth = <4>;
+ spi-rx-buswidth = <4>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ };
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x100000 0x0080000>;
+ };
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x00200000>;
+ };
+ partition@380000 {
+ label = "FIP";
+ reg = <0x380000 0x0200000>;
+ };
+ partition@580000 {
+ label = "ubi";
+ reg = <0x580000 0x4000000>;
+ };
+ };
+};
+
+&snand {
+ pinctrl-names = "default";
+ /* pin shared with spic */
+ pinctrl-0 = <&snfi_pins>;
+ status = "okay";
+ mediatek,quad-spi;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x0100000 0x0080000>;
+ };
+
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x0200000>;
+ };
+
+ partition@380000 {
+ label = "FIP";
+ reg = <0x380000 0x0200000>;
+ };
+
+ partition@580000 {
+ label = "ubi";
+ reg = <0x580000 0x4000000>;
+ };
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ /* pin shared with snfi */
+ pinctrl-0 = <&spic_pins>;
+ status = "okay";
+};
+
+&pio {
+ spi_flash_pins: spi0-pins {
+ mux {
+ function = "flash";
+ groups = "spi0", "spi0_wp_hold";
+ };
+ };
+
+ snfi_pins: snfi-pins {
+ mux {
+ function = "flash";
+ groups = "snfi";
+ };
+ };
+
+ spic_pins: spi1-pins {
+ mux {
+ function = "spi";
+ groups = "spi1_1";
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
new file mode 100644
index 0000000..b0891ad
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+/ {
+ compatible = "mediatek,mt7986a-rfb";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x1>;
+ };
+
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x2>;
+ };
+
+ cpu@3 {
+ device_type = "cpu";
+ enable-method = "psci";
+ compatible = "arm,cortex-a53";
+ reg = <0x3>;
+ };
+ };
+
+ wed: wed@15010000 {
+ compatible = "mediatek,wed";
+ wed_num = <2>;
+ /* add this property for wed get the pci slot number. */
+ pci_slot_map = <0>, <1>;
+ reg = <0 0x15010000 0 0x1000>,
+ <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wed2: wed2@15011000 {
+ compatible = "mediatek,wed2";
+ wed_num = <2>;
+ reg = <0 0x15010000 0 0x1000>,
+ <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wdma: wdma@15104800 {
+ compatible = "mediatek,wed-wdma";
+ reg = <0 0x15104800 0 0x400>,
+ <0 0x15104c00 0 0x400>;
+ };
+
+ ap2woccif: ap2woccif@151A5000 {
+ compatible = "mediatek,ap2woccif";
+ reg = <0 0x151A5000 0 0x1000>,
+ <0 0x151AD000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wocpu0_ilm: wocpu0_ilm@151E0000 {
+ compatible = "mediatek,wocpu0_ilm";
+ reg = <0 0x151E0000 0 0x8000>;
+ };
+
+ wocpu1_ilm: wocpu1_ilm@151F0000 {
+ compatible = "mediatek,wocpu1_ilm";
+ reg = <0 0x151F0000 0 0x8000>;
+ };
+
+ wocpu_dlm: wocpu_dlm@151E8000 {
+ compatible = "mediatek,wocpu_dlm";
+ reg = <0 0x151E8000 0 0x2000>,
+ <0 0x151F8000 0 0x2000>;
+
+ resets = <ðsysrst 0>;
+ reset-names = "wocpu_rst";
+ };
+
+ cpu_boot: wocpu_boot@15194000 {
+ compatible = "mediatek,wocpu_boot";
+ reg = <0 0x15194000 0 0x1000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved: secmon@43000000 {
+ reg = <0 0x43000000 0 0x30000>;
+ no-map;
+ };
+
+ wmcpu_emi: wmcpu-reserved@4FC00000 {
+ compatible = "mediatek,wmcpu-reserved";
+ no-map;
+ reg = <0 0x4FC00000 0 0x00100000>;
+ };
+
+ wocpu0_emi: wocpu0_emi@4FD00000 {
+ compatible = "mediatek,wocpu0_emi";
+ no-map;
+ reg = <0 0x4FD00000 0 0x40000>;
+ shared = <0>;
+ };
+
+ wocpu1_emi: wocpu1_emi@4FD80000 {
+ compatible = "mediatek,wocpu1_emi";
+ no-map;
+ reg = <0 0x4FD40000 0 0x40000>;
+ shared = <0>;
+ };
+
+ wocpu_data: wocpu_data@4FE00000 {
+ compatible = "mediatek,wocpu_data";
+ no-map;
+ reg = <0 0x4FD80000 0 0x200000>;
+ shared = <1>;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ system_clk: dummy_system_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ #clock-cells = <0>;
+ };
+
+ spi0_clk: dummy_spi0_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <208000000>;
+ #clock-cells = <0>;
+ };
+
+ spi1_clk: dummy_spi1_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ #clock-cells = <0>;
+ };
+
+ uart_clk: dummy_uart_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ #clock-cells = <0>;
+ };
+
+ gpt_clk: dummy_gpt_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <20000000>;
+ #clock-cells = <0>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&gic>;
+ clock-frequency = <40000000>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+ };
+
+ watchdog: watchdog@1001c000 {
+ compatible = "mediatek,mt7622-wdt",
+ "mediatek,mt6589-wdt";
+ reg = <0 0x1001c000 0 0x1000>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ #reset-cells = <1>;
+ };
+
+ gic: interrupt-controller@c000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ interrupt-controller;
+ reg = <0 0x0c000000 0 0x40000>, /* GICD */
+ <0 0x0c080000 0 0x200000>; /* GICR */
+
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11002000 0 0x400>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart1: serial@11003000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11003000 0 0x400>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart2: serial@11004000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11004000 0 0x400>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ pcie: pcie@11280000 {
+ compatible = "mediatek,mt7986-pcie";
+ device_type = "pci";
+ reg = <0 0x11280000 0 0x5000>;
+ reg-names = "port0";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x82000000 0 0x20000000
+ 0x0 0x20000000 0 0x10000000>;
+
+ pcie0: pcie@0,0 {
+ device_type = "pci";
+ reg = <0x0000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+ <0 0 0 2 &pcie_intc0 1>,
+ <0 0 0 3 &pcie_intc0 2>,
+ <0 0 0 4 &pcie_intc0 3>;
+ pcie_intc0: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+ };
+
+ pio: pinctrl@1001f000 {
+ compatible = "mediatek,mt7986-pinctrl";
+ reg = <0 0x1001f000 0 0x1000>,
+ <0 0x11c30000 0 0x1000>,
+ <0 0x11c40000 0 0x1000>,
+ <0 0x11e20000 0 0x1000>,
+ <0 0x11e30000 0 0x1000>,
+ <0 0x11f00000 0 0x1000>,
+ <0 0x11f10000 0 0x1000>,
+ <0 0x1000b000 0 0x1000>;
+ reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+ "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+ "iocfg_tl_base", "eint";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pio 0 0 100>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ #interrupt-cells = <2>;
+ };
+
+ ethsys: syscon@15000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "mediatek,mt7986-ethsys",
+ "syscon";
+ reg = <0 0x15000000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+
+ ethsysrst: reset-controller {
+ compatible = "ti,syscon-reset";
+ #reset-cells = <1>;
+ ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+ };
+ };
+
+ eth: ethernet@15100000 {
+ compatible = "mediatek,mt7986-eth";
+ reg = <0 0x15100000 0 0x80000>;
+ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+ "sgmii_tx250m", "sgmii_rx250m",
+ "sgmii_cdr_ref", "sgmii_cdr_fb",
+ "sgmii2_tx250m", "sgmii2_rx250m",
+ "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+ mediatek,ethsys = <ðsys>;
+ mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+ #reset-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ hnat: hnat@15000000 {
+ compatible = "mediatek,mtk-hnat_v4";
+ reg = <0 0x15100000 0 0x80000>;
+ resets = <ðsys 0>;
+ reset-names = "mtketh";
+ status = "disabled";
+ };
+
+ sgmiisys0: syscon@10060000 {
+ compatible = "mediatek,mt7986-sgmiisys", "syscon";
+ reg = <0 0x10060000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ sgmiisys1: syscon@10070000 {
+ compatible = "mediatek,mt7986-sgmiisys", "syscon";
+ reg = <0 0x10070000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ snand: snfi@11005000 {
+ compatible = "mediatek,mt7986-snand";
+ reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+ reg-names = "nfi", "ecc";
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "nfi_clk", "pad_clk", "ecc_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ wbsys: wbsys@18000000 {
+ compatible = "mediatek,wbsys";
+ reg = <0 0x18000000 0 0x1000000>;
+ interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+ chip_id = <0x7986>;
+ };
+
+ wed_pcie: wed_pcie@10003000 {
+ compatible = "mediatek,wed_pcie";
+ reg = <0 0x10003000 0 0x10>;
+ };
+
+ spi0: spi@1100a000 {
+ compatible = "mediatek,ipm-spi";
+ reg = <0 0x1100a000 0 0x100>;
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&spi0_clk>,
+ <&spi0_clk>,
+ <&spi0_clk>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk";
+ status = "disabled";
+ };
+
+ spi1: spi@1100b000 {
+ compatible = "mediatek,ipm-spi";
+ reg = <0 0x1100b000 0 0x100>;
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&spi1_clk>,
+ <&spi1_clk>,
+ <&spi1_clk>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk";
+ status = "disabled";
+ };
+
+ consys: consys@10000000 {
+ compatible = "mediatek,mt7986-consys";
+ reg = <0 0x10000000 0 0x8600000>;
+ memory-region = <&wmcpu_emi>;
+ };
+
+ xhci: xhci@11200000 {
+ compatible = "mediatek,mt7986-xhci",
+ "mediatek,mtk-xhci";
+ reg = <0 0x11200000 0 0x2e00>,
+ <0 0x11203e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&u2port0 PHY_TYPE_USB2>,
+ <&u3port0 PHY_TYPE_USB3>,
+ <&u2port1 PHY_TYPE_USB2>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "sys_ck",
+ "xhci_ck",
+ "ref_ck",
+ "mcu_ck",
+ "dma_ck";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ status = "okay";
+ };
+
+ usbtphy: usb-phy@11e10000 {
+ compatible = "mediatek,mt7986",
+ "mediatek,generic-tphy-v2";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "okay";
+
+ u2port0: usb-phy@11e10000 {
+ reg = <0 0x11e10000 0 0x700>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+
+ u3port0: usb-phy@11e10700 {
+ reg = <0 0x11e10700 0 0x900>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+
+ u2port1: usb-phy@11e11000 {
+ reg = <0 0x11e11000 0 0x700>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-mt7975-ax6000-rfb1.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-mt7975-ax6000-rfb1.dts
new file mode 100644
index 0000000..87e54d2
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-mt7975-ax6000-rfb1.dts
@@ -0,0 +1,12 @@
+/dts-v1/;
+#include "mt7986b-rfb.dtsi"
+/ {
+ model = "MediaTek MT7986b RFB";
+ compatible = "mediatek,mt7986b-rfb";
+
+ wsys_adie: wsys_adie@0 {
+ compatible = "mediatek,rebb-mt7986-adie";
+ adie_id = <7975>;
+ sku_type = <6000>;
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dtsi b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dtsi
new file mode 100644
index 0000000..12cd596
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dtsi
@@ -0,0 +1,248 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+/ {
+ model = "MediaTek MT7986b RFB";
+ compatible = "mediatek,mt7986b-rfb";
+ chosen {
+ bootargs = "console=ttyS0,115200n1 loglevel=8 \
+ earlycon=uart8250,mmio32,0x11002000";
+ };
+
+ memory {
+ // fpga ddr2: 128MB*2
+ reg = <0 0x40000000 0 0x10000000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
+};
+
+ð {
+ status = "okay";
+
+ gmac0: mac@0 {
+ compatible = "mediatek,eth-mac";
+ reg = <0>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ gmac1: mac@1 {
+ compatible = "mediatek,eth-mac";
+ reg = <1>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+
+ mdio: mdio-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch@0 {
+ compatible = "mediatek,mt7531";
+ reg = <0>;
+ reset-gpios = <&pio 5 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ label = "lan1";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan2";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan3";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan4";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "wan";
+ };
+
+ port@6 {
+ reg = <6>;
+ label = "cpu";
+ ethernet = <&gmac0>;
+ phy-mode = "2500base-x";
+
+ fixed-link {
+ speed = <2500>;
+ full-duplex;
+ pause;
+ };
+ };
+ };
+ };
+ };
+};
+
+&hnat {
+ mtketh-wan = "eth1";
+ mtketh-max-gmac = <2>;
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_flash_pins>;
+ cs-gpios = <0>, <0>;
+ status = "okay";
+ spi_nor@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ spi-tx-buswidth = <4>;
+ spi-rx-buswidth = <4>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0040000>;
+ };
+ partition@40000 {
+ label = "u-boot-env";
+ reg = <0x40000 0x0010000>;
+ };
+ partition@50000 {
+ label = "Factory";
+ reg = <0x50000 0x00B0000>;
+ };
+ partition@100000 {
+ label = "FIP";
+ reg = <0x100000 0x0080000>;
+ };
+ partition@180000 {
+ label = "firmware";
+ reg = <0x180000 0xE00000>;
+ };
+ };
+ spi_nand@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spi-nand";
+ reg = <1>;
+ spi-max-frequency = <20000000>;
+ spi-tx-buswidth = <4>;
+ spi-rx-buswidth = <4>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ };
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x100000 0x0080000>;
+ };
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x00200000>;
+ };
+ partition@380000 {
+ label = "FIP";
+ reg = <0x380000 0x0200000>;
+ };
+ partition@580000 {
+ label = "ubi";
+ reg = <0x580000 0x4000000>;
+ };
+ };
+};
+
+&snand {
+ pinctrl-names = "default";
+ /* pin shared with spic */
+ pinctrl-0 = <&snfi_pins>;
+ status = "okay";
+ mediatek,quad-spi;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x0100000 0x0080000>;
+ };
+
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x0200000>;
+ };
+
+ partition@380000 {
+ label = "FIP";
+ reg = <0x380000 0x0200000>;
+ };
+
+ partition@580000 {
+ label = "ubi";
+ reg = <0x580000 0x4000000>;
+ };
+ };
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ /* pin shared with snfi */
+ pinctrl-0 = <&spic_pins>;
+ status = "okay";
+};
+
+&pio {
+ spi_flash_pins: spi0-pins {
+ mux {
+ function = "flash";
+ groups = "spi0", "spi0_wp_hold";
+ };
+ };
+
+ snfi_pins: snfi-pins {
+ mux {
+ function = "flash";
+ groups = "snfi";
+ };
+ };
+
+ spic_pins: spi1-pins {
+ mux {
+ function = "spi";
+ groups = "spi1_1";
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
new file mode 100644
index 0000000..544c028
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+/ {
+ compatible = "mediatek,mt7986b-rfb";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x1>;
+ };
+
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a53";
+ enable-method = "psci";
+ reg = <0x2>;
+ };
+
+ cpu@3 {
+ device_type = "cpu";
+ enable-method = "psci";
+ compatible = "arm,cortex-a53";
+ reg = <0x3>;
+ };
+ };
+
+ wed: wed@15010000 {
+ compatible = "mediatek,wed";
+ wed_num = <2>;
+ /* add this property for wed get the pci slot number. */
+ pci_slot_map = <0>, <1>;
+ reg = <0 0x15010000 0 0x1000>,
+ <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wed2: wed2@15011000 {
+ compatible = "mediatek,wed2";
+ wed_num = <2>;
+ reg = <0 0x15010000 0 0x1000>,
+ <0 0x15011000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wdma: wdma@15104800 {
+ compatible = "mediatek,wed-wdma";
+ reg = <0 0x15104800 0 0x400>,
+ <0 0x15104c00 0 0x400>;
+ };
+
+ ap2woccif: ap2woccif@151A5000 {
+ compatible = "mediatek,ap2woccif";
+ reg = <0 0x151A5000 0 0x1000>,
+ <0 0x151AD000 0 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wocpu0_ilm: wocpu0_ilm@151E0000 {
+ compatible = "mediatek,wocpu0_ilm";
+ reg = <0 0x151E0000 0 0x8000>;
+ };
+
+ wocpu1_ilm: wocpu1_ilm@151F0000 {
+ compatible = "mediatek,wocpu1_ilm";
+ reg = <0 0x151F0000 0 0x8000>;
+ };
+
+ wocpu_dlm: wocpu_dlm@151E8000 {
+ compatible = "mediatek,wocpu_dlm";
+ reg = <0 0x151E8000 0 0x2000>,
+ <0 0x151F8000 0 0x2000>;
+
+ resets = <ðsysrst 0>;
+ reset-names = "wocpu_rst";
+ };
+
+ cpu_boot: wocpu_boot@15194000 {
+ compatible = "mediatek,wocpu_boot";
+ reg = <0 0x15194000 0 0x1000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved: secmon@43000000 {
+ reg = <0 0x43000000 0 0x30000>;
+ no-map;
+ };
+
+ wmcpu_emi: wmcpu-reserved@4FC00000 {
+ compatible = "mediatek,wmcpu-reserved";
+ no-map;
+ reg = <0 0x4FC00000 0 0x00100000>;
+ };
+
+ wocpu0_emi: wocpu0_emi@4FD00000 {
+ compatible = "mediatek,wocpu0_emi";
+ no-map;
+ reg = <0 0x4FD00000 0 0x40000>;
+ shared = <0>;
+ };
+
+ wocpu1_emi: wocpu1_emi@4FD80000 {
+ compatible = "mediatek,wocpu1_emi";
+ no-map;
+ reg = <0 0x4FD40000 0 0x40000>;
+ shared = <0>;
+ };
+
+ wocpu_data: wocpu_data@4FE00000 {
+ compatible = "mediatek,wocpu_data";
+ no-map;
+ reg = <0 0x4FD80000 0 0x200000>;
+ shared = <1>;
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ system_clk: dummy_system_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ #clock-cells = <0>;
+ };
+
+ spi0_clk: dummy_spi0_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <208000000>;
+ #clock-cells = <0>;
+ };
+
+ spi1_clk: dummy_spi1_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ #clock-cells = <0>;
+ };
+
+ uart_clk: dummy_uart_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ #clock-cells = <0>;
+ };
+
+ gpt_clk: dummy_gpt_clk {
+ compatible = "fixed-clock";
+ clock-frequency = <20000000>;
+ #clock-cells = <0>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&gic>;
+ clock-frequency = <40000000>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+ };
+
+ watchdog: watchdog@1001c000 {
+ compatible = "mediatek,mt7622-wdt",
+ "mediatek,mt6589-wdt";
+ reg = <0 0x1001c000 0 0x1000>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ #reset-cells = <1>;
+ };
+
+ gic: interrupt-controller@c000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ interrupt-parent = <&gic>;
+ interrupt-controller;
+ reg = <0 0x0c000000 0 0x40000>, /* GICD */
+ <0 0x0c080000 0 0x200000>; /* GICR */
+
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11002000 0 0x400>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart1: serial@11003000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11003000 0 0x400>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ uart2: serial@11004000 {
+ compatible = "mediatek,mt7986-uart",
+ "mediatek,mt6577-uart";
+ reg = <0 0x11004000 0 0x400>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
+
+ pcie: pcie@11280000 {
+ compatible = "mediatek,mt7986-pcie";
+ device_type = "pci";
+ reg = <0 0x11280000 0 0x5000>;
+ reg-names = "port0";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x82000000 0 0x20000000
+ 0x0 0x20000000 0 0x10000000>;
+
+ pcie0: pcie@0,0 {
+ device_type = "pci";
+ reg = <0x0000 0 0 0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+ <0 0 0 2 &pcie_intc0 1>,
+ <0 0 0 3 &pcie_intc0 2>,
+ <0 0 0 4 &pcie_intc0 3>;
+ pcie_intc0: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+ };
+ };
+
+ pio: pinctrl@1001f000 {
+ compatible = "mediatek,mt7986-pinctrl";
+ reg = <0 0x1001f000 0 0x1000>,
+ <0 0x11c30000 0 0x1000>,
+ <0 0x11c40000 0 0x1000>,
+ <0 0x11e20000 0 0x1000>,
+ <0 0x11e30000 0 0x1000>,
+ <0 0x11f00000 0 0x1000>,
+ <0 0x11f10000 0 0x1000>,
+ <0 0x1000b000 0 0x1000>;
+ reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+ "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+ "iocfg_tl_base", "eint";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pio 0 0 100>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gic>;
+ #interrupt-cells = <2>;
+ };
+
+ ethsys: syscon@15000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "mediatek,mt7986-ethsys",
+ "syscon";
+ reg = <0 0x15000000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+
+ ethsysrst: reset-controller {
+ compatible = "ti,syscon-reset";
+ #reset-cells = <1>;
+ ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+ };
+ };
+
+ eth: ethernet@15100000 {
+ compatible = "mediatek,mt7986-eth";
+ reg = <0 0x15100000 0 0x80000>;
+ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+ "sgmii_tx250m", "sgmii_rx250m",
+ "sgmii_cdr_ref", "sgmii_cdr_fb",
+ "sgmii2_tx250m", "sgmii2_rx250m",
+ "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+ mediatek,ethsys = <ðsys>;
+ mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+ #reset-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ hnat: hnat@15000000 {
+ compatible = "mediatek,mtk-hnat_v4";
+ reg = <0 0x15100000 0 0x80000>;
+ resets = <ðsys 0>;
+ reset-names = "mtketh";
+ status = "disabled";
+ };
+
+ sgmiisys0: syscon@10060000 {
+ compatible = "mediatek,mt7986-sgmiisys", "syscon";
+ reg = <0 0x10060000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ sgmiisys1: syscon@10070000 {
+ compatible = "mediatek,mt7986-sgmiisys", "syscon";
+ reg = <0 0x10070000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ snand: snfi@11005000 {
+ compatible = "mediatek,mt7986-snand";
+ reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+ reg-names = "nfi", "ecc";
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "nfi_clk", "pad_clk", "ecc_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ wbsys: wbsys@18000000 {
+ compatible = "mediatek,wbsys";
+ reg = <0 0x18000000 0 0x1000000>;
+ interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+ chip_id = <0x7986>;
+ };
+
+ wed_pcie: wed_pcie@10003000 {
+ compatible = "mediatek,wed_pcie";
+ reg = <0 0x10003000 0 0x10>;
+ };
+
+ spi0: spi@1100a000 {
+ compatible = "mediatek,ipm-spi";
+ reg = <0 0x1100a000 0 0x100>;
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&spi0_clk>,
+ <&spi0_clk>,
+ <&spi0_clk>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk";
+ status = "disabled";
+ };
+
+ spi1: spi@1100b000 {
+ compatible = "mediatek,ipm-spi";
+ reg = <0 0x1100b000 0 0x100>;
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&spi1_clk>,
+ <&spi1_clk>,
+ <&spi1_clk>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk";
+ status = "disabled";
+ };
+
+ consys: consys@10000000 {
+ compatible = "mediatek,mt7986-consys";
+ reg = <0 0x10000000 0 0x8600000>;
+ memory-region = <&wmcpu_emi>;
+ };
+
+ xhci: xhci@11200000 {
+ compatible = "mediatek,mt7986-xhci",
+ "mediatek,mtk-xhci";
+ reg = <0 0x11200000 0 0x2e00>,
+ <0 0x11203e00 0 0x0100>;
+ reg-names = "mac", "ippc";
+ interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&u2port0 PHY_TYPE_USB2>,
+ <&u3port0 PHY_TYPE_USB3>,
+ <&u2port1 PHY_TYPE_USB2>;
+ clocks = <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>,
+ <&system_clk>;
+ clock-names = "sys_ck",
+ "xhci_ck",
+ "ref_ck",
+ "mcu_ck",
+ "dma_ck";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ status = "okay";
+ };
+
+ usbtphy: usb-phy@11e10000 {
+ compatible = "mediatek,mt7986",
+ "mediatek,generic-tphy-v2";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "okay";
+
+ u2port0: usb-phy@11e10000 {
+ reg = <0 0x11e10000 0 0x700>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+
+ u3port0: usb-phy@11e10700 {
+ reg = <0 0x11e10700 0 0x900>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+
+ u2port1: usb-phy@11e11000 {
+ reg = <0 0x11e11000 0 0x700>;
+ clocks = <&system_clk>;
+ clock-names = "ref";
+ #phy-cells = <1>;
+ status = "okay";
+ };
+ };
+};
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/Kconfig b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/Kconfig
new file mode 100644
index 0000000..138b939
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/Kconfig
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2020 MediaTek Inc. All rights reserved.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+
+config MTK_SPI_NAND
+ tristate "MediaTek SPI NAND flash controller driver"
+ depends on MTD
+ default n
+ help
+ This option enables access to SPI-NAND flashes through the
+ MTD interface of MediaTek SPI NAND Flash Controller
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/Makefile b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/Makefile
new file mode 100644
index 0000000..a39f1ca
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (C) 2020 MediaTek Inc. All rights reserved.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+
+obj-y += mtk-snand.o mtk-snand-ecc.o mtk-snand-ids.o mtk-snand-os.o \
+ mtk-snand-mtd.o
+
+ccflags-y += -DPRIVATE_MTK_SNAND_HEADER
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-def.h b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-def.h
new file mode 100644
index 0000000..95c4bb3
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-def.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_SNAND_DEF_H_
+#define _MTK_SNAND_DEF_H_
+
+#include "mtk-snand-os.h"
+
+#ifdef PRIVATE_MTK_SNAND_HEADER
+#include "mtk-snand.h"
+#else
+#include <mtk-snand.h>
+#endif
+
+struct mtk_snand_plat_dev;
+
+enum snand_flash_io {
+ SNAND_IO_1_1_1,
+ SNAND_IO_1_1_2,
+ SNAND_IO_1_2_2,
+ SNAND_IO_1_1_4,
+ SNAND_IO_1_4_4,
+
+ __SNAND_IO_MAX
+};
+
+#define SPI_IO_1_1_1 BIT(SNAND_IO_1_1_1)
+#define SPI_IO_1_1_2 BIT(SNAND_IO_1_1_2)
+#define SPI_IO_1_2_2 BIT(SNAND_IO_1_2_2)
+#define SPI_IO_1_1_4 BIT(SNAND_IO_1_1_4)
+#define SPI_IO_1_4_4 BIT(SNAND_IO_1_4_4)
+
+struct snand_opcode {
+ uint8_t opcode;
+ uint8_t dummy;
+};
+
+struct snand_io_cap {
+ uint8_t caps;
+ struct snand_opcode opcodes[__SNAND_IO_MAX];
+};
+
+#define SNAND_OP(_io, _opcode, _dummy) [_io] = { .opcode = (_opcode), \
+ .dummy = (_dummy) }
+
+#define SNAND_IO_CAP(_name, _caps, ...) \
+ struct snand_io_cap _name = { .caps = (_caps), \
+ .opcodes = { __VA_ARGS__ } }
+
+#define SNAND_MAX_ID_LEN 4
+
+enum snand_id_type {
+ SNAND_ID_DYMMY,
+ SNAND_ID_ADDR = SNAND_ID_DYMMY,
+ SNAND_ID_DIRECT,
+
+ __SNAND_ID_TYPE_MAX
+};
+
+struct snand_id {
+ uint8_t type; /* enum snand_id_type */
+ uint8_t len;
+ uint8_t id[SNAND_MAX_ID_LEN];
+};
+
+#define SNAND_ID(_type, ...) \
+ { .type = (_type), .id = { __VA_ARGS__ }, \
+ .len = sizeof((uint8_t[]) { __VA_ARGS__ }) }
+
+struct snand_mem_org {
+ uint16_t pagesize;
+ uint16_t sparesize;
+ uint16_t pages_per_block;
+ uint16_t blocks_per_die;
+ uint16_t planes_per_die;
+ uint16_t ndies;
+};
+
+#define SNAND_MEMORG(_ps, _ss, _ppb, _bpd, _ppd, _nd) \
+ { .pagesize = (_ps), .sparesize = (_ss), .pages_per_block = (_ppb), \
+ .blocks_per_die = (_bpd), .planes_per_die = (_ppd), .ndies = (_nd) }
+
+typedef int (*snand_select_die_t)(struct mtk_snand *snf, uint32_t dieidx);
+
+struct snand_flash_info {
+ const char *model;
+ struct snand_id id;
+ const struct snand_mem_org memorg;
+ const struct snand_io_cap *cap_rd;
+ const struct snand_io_cap *cap_pl;
+ snand_select_die_t select_die;
+};
+
+#define SNAND_INFO(_model, _id, _memorg, _cap_rd, _cap_pl, ...) \
+ { .model = (_model), .id = _id, .memorg = _memorg, \
+ .cap_rd = (_cap_rd), .cap_pl = (_cap_pl), __VA_ARGS__ }
+
+const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type,
+ const uint8_t *id);
+
+struct mtk_snand_soc_data {
+ uint16_t sector_size;
+ uint16_t max_sectors;
+ uint16_t fdm_size;
+ uint16_t fdm_ecc_size;
+ uint16_t fifo_size;
+
+ bool bbm_swap;
+ bool empty_page_check;
+ uint32_t mastersta_mask;
+
+ const uint8_t *spare_sizes;
+ uint32_t num_spare_size;
+};
+
+enum mtk_ecc_regs {
+ ECC_DECDONE,
+};
+
+struct mtk_ecc_soc_data {
+ const uint8_t *ecc_caps;
+ uint32_t num_ecc_cap;
+ const uint32_t *regs;
+ uint16_t mode_shift;
+ uint8_t errnum_bits;
+ uint8_t errnum_shift;
+};
+
+struct mtk_snand {
+ struct mtk_snand_plat_dev *pdev;
+
+ void __iomem *nfi_base;
+ void __iomem *ecc_base;
+
+ enum mtk_snand_soc soc;
+ const struct mtk_snand_soc_data *nfi_soc;
+ const struct mtk_ecc_soc_data *ecc_soc;
+ bool snfi_quad_spi;
+ bool quad_spi_op;
+
+ const char *model;
+ uint64_t size;
+ uint64_t die_size;
+ uint32_t erasesize;
+ uint32_t writesize;
+ uint32_t oobsize;
+
+ uint32_t num_dies;
+ snand_select_die_t select_die;
+
+ uint8_t opcode_rfc;
+ uint8_t opcode_pl;
+ uint8_t dummy_rfc;
+ uint8_t mode_rfc;
+ uint8_t mode_pl;
+
+ uint32_t writesize_mask;
+ uint32_t writesize_shift;
+ uint32_t erasesize_mask;
+ uint32_t erasesize_shift;
+ uint64_t die_mask;
+ uint32_t die_shift;
+
+ uint32_t spare_per_sector;
+ uint32_t raw_sector_size;
+ uint32_t ecc_strength;
+ uint32_t ecc_steps;
+ uint32_t ecc_bytes;
+ uint32_t ecc_parity_bits;
+
+ uint8_t *page_cache; /* Used by read/write page */
+ uint8_t *buf_cache; /* Used by block bad/markbad & auto_oob */
+};
+
+enum mtk_snand_log_category {
+ SNAND_LOG_NFI,
+ SNAND_LOG_SNFI,
+ SNAND_LOG_ECC,
+ SNAND_LOG_CHIP,
+
+ __SNAND_LOG_CAT_MAX
+};
+
+int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes,
+ uint32_t msg_size);
+int mtk_snand_ecc_encoder_start(struct mtk_snand *snf);
+void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf);
+int mtk_snand_ecc_decoder_start(struct mtk_snand *snf);
+void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf);
+int mtk_ecc_wait_decoder_done(struct mtk_snand *snf);
+int mtk_ecc_check_decode_error(struct mtk_snand *snf, uint32_t page);
+
+int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen,
+ uint8_t *in, uint32_t inlen);
+int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val);
+
+int mtk_snand_log(struct mtk_snand_plat_dev *pdev,
+ enum mtk_snand_log_category cat, const char *fmt, ...);
+
+#define snand_log_nfi(pdev, fmt, ...) \
+ mtk_snand_log(pdev, SNAND_LOG_NFI, fmt, ##__VA_ARGS__)
+
+#define snand_log_snfi(pdev, fmt, ...) \
+ mtk_snand_log(pdev, SNAND_LOG_SNFI, fmt, ##__VA_ARGS__)
+
+#define snand_log_ecc(pdev, fmt, ...) \
+ mtk_snand_log(pdev, SNAND_LOG_ECC, fmt, ##__VA_ARGS__)
+
+#define snand_log_chip(pdev, fmt, ...) \
+ mtk_snand_log(pdev, SNAND_LOG_CHIP, fmt, ##__VA_ARGS__)
+
+/* ffs64 */
+static inline int mtk_snand_ffs64(uint64_t x)
+{
+ if (!x)
+ return 0;
+
+ if (!(x & 0xffffffff))
+ return ffs((uint32_t)(x >> 32)) + 32;
+
+ return ffs((uint32_t)(x & 0xffffffff));
+}
+
+/* NFI dummy commands */
+#define NFI_CMD_DUMMY_READ 0x00
+#define NFI_CMD_DUMMY_WRITE 0x80
+
+/* SPI-NAND opcodes */
+#define SNAND_CMD_RESET 0xff
+#define SNAND_CMD_BLOCK_ERASE 0xd8
+#define SNAND_CMD_READ_FROM_CACHE_QUAD 0xeb
+#define SNAND_CMD_WINBOND_SELECT_DIE 0xc2
+#define SNAND_CMD_READ_FROM_CACHE_DUAL 0xbb
+#define SNAND_CMD_READID 0x9f
+#define SNAND_CMD_READ_FROM_CACHE_X4 0x6b
+#define SNAND_CMD_READ_FROM_CACHE_X2 0x3b
+#define SNAND_CMD_PROGRAM_LOAD_X4 0x32
+#define SNAND_CMD_SET_FEATURE 0x1f
+#define SNAND_CMD_READ_TO_CACHE 0x13
+#define SNAND_CMD_PROGRAM_EXECUTE 0x10
+#define SNAND_CMD_GET_FEATURE 0x0f
+#define SNAND_CMD_READ_FROM_CACHE 0x0b
+#define SNAND_CMD_WRITE_ENABLE 0x06
+#define SNAND_CMD_PROGRAM_LOAD 0x02
+
+/* SPI-NAND feature addresses */
+#define SNAND_FEATURE_MICRON_DIE_ADDR 0xd0
+#define SNAND_MICRON_DIE_SEL_1 BIT(6)
+
+#define SNAND_FEATURE_STATUS_ADDR 0xc0
+#define SNAND_STATUS_OIP BIT(0)
+#define SNAND_STATUS_WEL BIT(1)
+#define SNAND_STATUS_ERASE_FAIL BIT(2)
+#define SNAND_STATUS_PROGRAM_FAIL BIT(3)
+
+#define SNAND_FEATURE_CONFIG_ADDR 0xb0
+#define SNAND_FEATURE_QUAD_ENABLE BIT(0)
+#define SNAND_FEATURE_ECC_EN BIT(4)
+
+#define SNAND_FEATURE_PROTECT_ADDR 0xa0
+
+#endif /* _MTK_SNAND_DEF_H_ */
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ecc.c b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ecc.c
new file mode 100644
index 0000000..57ba611
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ecc.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+/* ECC registers */
+#define ECC_ENCCON 0x000
+#define ENC_EN BIT(0)
+
+#define ECC_ENCCNFG 0x004
+#define ENC_MS_S 16
+#define ENC_BURST_EN BIT(8)
+#define ENC_TNUM_S 0
+
+#define ECC_ENCIDLE 0x00c
+#define ENC_IDLE BIT(0)
+
+#define ECC_DECCON 0x100
+#define DEC_EN BIT(0)
+
+#define ECC_DECCNFG 0x104
+#define DEC_EMPTY_EN BIT(31)
+#define DEC_CS_S 16
+#define DEC_CON_S 12
+#define DEC_CON_CORRECT 3
+#define DEC_BURST_EN BIT(8)
+#define DEC_TNUM_S 0
+
+#define ECC_DECIDLE 0x10c
+#define DEC_IDLE BIT(0)
+
+#define ECC_DECENUM0 0x114
+#define ECC_DECENUM(n) (ECC_DECENUM0 + (n) * 4)
+
+/* ECC_ENCIDLE & ECC_DECIDLE */
+#define ECC_IDLE BIT(0)
+
+/* ENC_MODE & DEC_MODE */
+#define ECC_MODE_NFI 1
+
+#define ECC_TIMEOUT 500000
+
+static const uint8_t mt7622_ecc_caps[] = { 4, 6, 8, 10, 12 };
+
+static const uint8_t mt7986_ecc_caps[] = {
+ 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24
+};
+
+static const uint32_t mt7622_ecc_regs[] = {
+ [ECC_DECDONE] = 0x11c,
+};
+
+static const uint32_t mt7986_ecc_regs[] = {
+ [ECC_DECDONE] = 0x124,
+};
+
+static const struct mtk_ecc_soc_data mtk_ecc_socs[__SNAND_SOC_MAX] = {
+ [SNAND_SOC_MT7622] = {
+ .ecc_caps = mt7622_ecc_caps,
+ .num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps),
+ .regs = mt7622_ecc_regs,
+ .mode_shift = 4,
+ .errnum_bits = 5,
+ .errnum_shift = 5,
+ },
+ [SNAND_SOC_MT7629] = {
+ .ecc_caps = mt7622_ecc_caps,
+ .num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps),
+ .regs = mt7622_ecc_regs,
+ .mode_shift = 4,
+ .errnum_bits = 5,
+ .errnum_shift = 5,
+ },
+ [SNAND_SOC_MT7986] = {
+ .ecc_caps = mt7986_ecc_caps,
+ .num_ecc_cap = ARRAY_SIZE(mt7986_ecc_caps),
+ .regs = mt7986_ecc_regs,
+ .mode_shift = 5,
+ .errnum_bits = 5,
+ .errnum_shift = 8,
+ },
+};
+
+static inline uint32_t ecc_read32(struct mtk_snand *snf, uint32_t reg)
+{
+ return readl(snf->ecc_base + reg);
+}
+
+static inline void ecc_write32(struct mtk_snand *snf, uint32_t reg,
+ uint32_t val)
+{
+ writel(val, snf->ecc_base + reg);
+}
+
+static inline void ecc_write16(struct mtk_snand *snf, uint32_t reg,
+ uint16_t val)
+{
+ writew(val, snf->ecc_base + reg);
+}
+
+static int mtk_ecc_poll(struct mtk_snand *snf, uint32_t reg, uint32_t bits)
+{
+ uint32_t val;
+
+ return read16_poll_timeout(snf->ecc_base + reg, val, (val & bits), 0,
+ ECC_TIMEOUT);
+}
+
+static int mtk_ecc_wait_idle(struct mtk_snand *snf, uint32_t reg)
+{
+ int ret;
+
+ ret = mtk_ecc_poll(snf, reg, ECC_IDLE);
+ if (ret) {
+ snand_log_ecc(snf->pdev, "ECC engine is busy\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes,
+ uint32_t msg_size)
+{
+ uint32_t i, val, ecc_msg_bits, ecc_strength;
+ int ret;
+
+ snf->ecc_soc = &mtk_ecc_socs[snf->soc];
+
+ snf->ecc_parity_bits = fls(1 + 8 * msg_size);
+ ecc_strength = max_ecc_bytes * 8 / snf->ecc_parity_bits;
+
+ for (i = snf->ecc_soc->num_ecc_cap - 1; i >= 0; i--) {
+ if (snf->ecc_soc->ecc_caps[i] <= ecc_strength)
+ break;
+ }
+
+ if (unlikely(i < 0)) {
+ snand_log_ecc(snf->pdev, "Page size %u+%u is not supported\n",
+ snf->writesize, snf->oobsize);
+ return -ENOTSUPP;
+ }
+
+ snf->ecc_strength = snf->ecc_soc->ecc_caps[i];
+ snf->ecc_bytes = DIV_ROUND_UP(snf->ecc_strength * snf->ecc_parity_bits,
+ 8);
+
+ /* Encoder config */
+ ecc_write16(snf, ECC_ENCCON, 0);
+ ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+ if (ret)
+ return ret;
+
+ ecc_msg_bits = msg_size * 8;
+ val = (ecc_msg_bits << ENC_MS_S) |
+ (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i;
+ ecc_write32(snf, ECC_ENCCNFG, val);
+
+ /* Decoder config */
+ ecc_write16(snf, ECC_DECCON, 0);
+ ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+ if (ret)
+ return ret;
+
+ ecc_msg_bits += snf->ecc_strength * snf->ecc_parity_bits;
+ val = DEC_EMPTY_EN | (ecc_msg_bits << DEC_CS_S) |
+ (DEC_CON_CORRECT << DEC_CON_S) |
+ (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i;
+ ecc_write32(snf, ECC_DECCNFG, val);
+
+ return 0;
+}
+
+int mtk_snand_ecc_encoder_start(struct mtk_snand *snf)
+{
+ int ret;
+
+ ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+ if (ret) {
+ ecc_write16(snf, ECC_ENCCON, 0);
+ mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+ }
+
+ ecc_write16(snf, ECC_ENCCON, ENC_EN);
+
+ return 0;
+}
+
+void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf)
+{
+ mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+ ecc_write16(snf, ECC_ENCCON, 0);
+}
+
+int mtk_snand_ecc_decoder_start(struct mtk_snand *snf)
+{
+ int ret;
+
+ ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+ if (ret) {
+ ecc_write16(snf, ECC_DECCON, 0);
+ mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+ }
+
+ ecc_write16(snf, ECC_DECCON, DEC_EN);
+
+ return 0;
+}
+
+void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf)
+{
+ mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+ ecc_write16(snf, ECC_DECCON, 0);
+}
+
+int mtk_ecc_wait_decoder_done(struct mtk_snand *snf)
+{
+ uint16_t val, step_mask = (1 << snf->ecc_steps) - 1;
+ uint32_t reg = snf->ecc_soc->regs[ECC_DECDONE];
+ int ret;
+
+ ret = read16_poll_timeout(snf->ecc_base + reg, val,
+ (val & step_mask) == step_mask, 0,
+ ECC_TIMEOUT);
+ if (ret)
+ snand_log_ecc(snf->pdev, "ECC decoder is busy\n");
+
+ return ret;
+}
+
+int mtk_ecc_check_decode_error(struct mtk_snand *snf, uint32_t page)
+{
+ uint32_t i, regi, fi, errnum;
+ uint32_t errnum_shift = snf->ecc_soc->errnum_shift;
+ uint32_t errnum_mask = (1 << snf->ecc_soc->errnum_bits) - 1;
+ int ret = 0;
+
+ for (i = 0; i < snf->ecc_steps; i++) {
+ regi = i / 4;
+ fi = i % 4;
+
+ errnum = ecc_read32(snf, ECC_DECENUM(regi));
+ errnum = (errnum >> (fi * errnum_shift)) & errnum_mask;
+ if (!errnum)
+ continue;
+
+ if (errnum <= snf->ecc_strength) {
+ if (ret >= 0)
+ ret += errnum;
+ continue;
+ }
+
+ snand_log_ecc(snf->pdev,
+ "Uncorrectable bitflips in page %u sect %u\n",
+ page, i);
+ ret = -EBADMSG;
+ }
+
+ return ret;
+}
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ids.c b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ids.c
new file mode 100644
index 0000000..1756ff7
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ids.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx);
+static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx);
+
+#define SNAND_MEMORG_512M_2K_64 SNAND_MEMORG(2048, 64, 64, 512, 1, 1)
+#define SNAND_MEMORG_1G_2K_64 SNAND_MEMORG(2048, 64, 64, 1024, 1, 1)
+#define SNAND_MEMORG_2G_2K_64 SNAND_MEMORG(2048, 64, 64, 2048, 1, 1)
+#define SNAND_MEMORG_2G_2K_120 SNAND_MEMORG(2048, 120, 64, 2048, 1, 1)
+#define SNAND_MEMORG_4G_2K_64 SNAND_MEMORG(2048, 64, 64, 4096, 1, 1)
+#define SNAND_MEMORG_1G_2K_120 SNAND_MEMORG(2048, 120, 64, 1024, 1, 1)
+#define SNAND_MEMORG_1G_2K_128 SNAND_MEMORG(2048, 128, 64, 1024, 1, 1)
+#define SNAND_MEMORG_2G_2K_128 SNAND_MEMORG(2048, 128, 64, 2048, 1, 1)
+#define SNAND_MEMORG_4G_2K_128 SNAND_MEMORG(2048, 128, 64, 4096, 1, 1)
+#define SNAND_MEMORG_4G_4K_240 SNAND_MEMORG(4096, 240, 64, 2048, 1, 1)
+#define SNAND_MEMORG_4G_4K_256 SNAND_MEMORG(4096, 256, 64, 2048, 1, 1)
+#define SNAND_MEMORG_8G_4K_256 SNAND_MEMORG(4096, 256, 64, 4096, 1, 1)
+#define SNAND_MEMORG_2G_2K_64_2P SNAND_MEMORG(2048, 64, 64, 2048, 2, 1)
+#define SNAND_MEMORG_2G_2K_64_2D SNAND_MEMORG(2048, 64, 64, 1024, 1, 2)
+#define SNAND_MEMORG_2G_2K_128_2P SNAND_MEMORG(2048, 128, 64, 2048, 2, 1)
+#define SNAND_MEMORG_4G_2K_64_2P SNAND_MEMORG(2048, 64, 64, 4096, 2, 1)
+#define SNAND_MEMORG_4G_2K_128_2P_2D SNAND_MEMORG(2048, 128, 64, 2048, 2, 2)
+#define SNAND_MEMORG_8G_4K_256_2D SNAND_MEMORG(4096, 256, 64, 2048, 1, 2)
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_quad,
+ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 |
+ SPI_IO_1_4_4,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+ SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4),
+ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8),
+ SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 4));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_q2d,
+ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 |
+ SPI_IO_1_4_4,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+ SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4),
+ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8),
+ SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 2));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_a8d,
+ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 |
+ SPI_IO_1_4_4,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+ SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 8),
+ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8),
+ SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 8));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_x4,
+ SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_1_4,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+ SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_x4_only,
+ SPI_IO_1_1_1 | SPI_IO_1_1_4,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8));
+
+static const SNAND_IO_CAP(snand_cap_program_load_x1,
+ SPI_IO_1_1_1,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0));
+
+static const SNAND_IO_CAP(snand_cap_program_load_x4,
+ SPI_IO_1_1_1 | SPI_IO_1_1_4,
+ SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0),
+ SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_PROGRAM_LOAD_X4, 0));
+
+static const struct snand_flash_info snand_flash_ids[] = {
+ SNAND_INFO("W25N512GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x20),
+ SNAND_MEMORG_512M_2K_64,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("W25N01GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x21),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("W25M02GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xab, 0x21),
+ SNAND_MEMORG_2G_2K_64_2D,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4,
+ mtk_snand_winbond_select_die),
+ SNAND_INFO("W25N02KV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x22),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("GD5F1GQ4UAWxx", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x10),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F1GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd1),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F1GQ4UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd9),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F1GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf1),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F2GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd2),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F2GQ5UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x32),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_a8d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F2GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf2),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F4GQ4UBxIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd4),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F4GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf4),
+ SNAND_MEMORG_4G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F2GQ5UExxG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x52),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("GD5F4GQ4UCxIG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0xb4),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("MX35LF1GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x12),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF1G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x14),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX31LF1GE4BC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x1e),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF2GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x22),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF2G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x24),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF2GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x26),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF2G14AC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x20),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF4G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x35),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MX35LF4GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x37),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("MT29F1G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x12),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x1),
+ SNAND_INFO("MT29F1G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x14),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MT29F2G01AAAED", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x9f),
+ SNAND_MEMORG_2G_2K_64_2P,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x1),
+ SNAND_INFO("MT29F2G01ABAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x24),
+ SNAND_MEMORG_2G_2K_128_2P,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MT29F4G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x32),
+ SNAND_MEMORG_4G_2K_64_2P,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x1),
+ SNAND_INFO("MT29F4G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x34),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("MT29F4G01ADAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x36),
+ SNAND_MEMORG_4G_2K_128_2P_2D,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4,
+ mtk_snand_micron_select_die),
+ SNAND_INFO("MT29F8G01ADAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x46),
+ SNAND_MEMORG_8G_4K_256_2D,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4,
+ mtk_snand_micron_select_die),
+
+ SNAND_INFO("TC58CVG0S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xc2),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x1),
+ SNAND_INFO("TC58CVG1S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcb),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x1),
+ SNAND_INFO("TC58CVG2S0HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcd),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x1),
+ SNAND_INFO("TC58CVG0S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe2),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("TC58CVG1S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xeb),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("TC58CVG2S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xed),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("TH58CVG3S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe4),
+ SNAND_MEMORG_8G_4K_256,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("F50L512M41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x20),
+ SNAND_MEMORG_512M_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("F50L1G41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("F50L1G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x01),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("F50L2G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x0a),
+ SNAND_MEMORG_2G_2K_64_2D,
+ &snand_cap_read_from_cache_quad,
+ &snand_cap_program_load_x4,
+ mtk_snand_winbond_select_die),
+
+ SNAND_INFO("CS11G0T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x00),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("CS11G0G0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x10),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("CS11G0S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x20),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("CS11G1T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x01),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("CS11G1S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x21),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("CS11G2T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x02),
+ SNAND_MEMORG_4G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("CS11G2S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x22),
+ SNAND_MEMORG_4G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("EM73B044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x01),
+ SNAND_MEMORG_512M_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x11),
+ SNAND_MEMORG_1G_2K_120,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x09),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x18),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x19),
+ SNAND_MEMORG(2048, 64, 128, 512, 1, 1),
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1c),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1e),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044VCC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x22),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044VCF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x25),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x31),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0a),
+ SNAND_MEMORG_2G_2K_120,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x12),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x10),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x13),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x14),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x17),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCH", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1b),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1f),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x20),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCL", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2e),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x32),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73E044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x03),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73E044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0b),
+ SNAND_MEMORG_4G_4K_240,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73E044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x23),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73E044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2c),
+ SNAND_MEMORG_4G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73E044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2f),
+ SNAND_MEMORG_4G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73F044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x24),
+ SNAND_MEMORG_8G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73F044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2d),
+ SNAND_MEMORG_8G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73E044SNE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0e),
+ SNAND_MEMORG_8G_4K_256,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73C044SNG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0c),
+ SNAND_MEMORG_1G_2K_120,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("EM73D044VCN", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0f),
+ SNAND_MEMORG_2G_2K_64,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("FM35Q1GA", SNAND_ID(SNAND_ID_DYMMY, 0xe5, 0x71),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("PN26G01A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe1),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("PN26G02A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe2),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("IS37SML01G1", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("ATO25D1GA", SNAND_ID(SNAND_ID_DYMMY, 0x9b, 0x12),
+ SNAND_MEMORG_1G_2K_64,
+ &snand_cap_read_from_cache_x4_only,
+ &snand_cap_program_load_x4),
+
+ SNAND_INFO("HYF1GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x51),
+ SNAND_MEMORG_1G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+ SNAND_INFO("HYF2GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x52),
+ SNAND_MEMORG_2G_2K_128,
+ &snand_cap_read_from_cache_quad_q2d,
+ &snand_cap_program_load_x4),
+};
+
+static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx)
+{
+ uint8_t op[2];
+
+ if (dieidx > 1) {
+ snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx);
+ return -EINVAL;
+ }
+
+ op[0] = SNAND_CMD_WINBOND_SELECT_DIE;
+ op[1] = (uint8_t)dieidx;
+
+ return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0);
+}
+
+static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx)
+{
+ int ret;
+
+ if (dieidx > 1) {
+ snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx);
+ return -EINVAL;
+ }
+
+ ret = mtk_snand_set_feature(snf, SNAND_FEATURE_MICRON_DIE_ADDR,
+ SNAND_MICRON_DIE_SEL_1);
+ if (ret) {
+ snand_log_chip(snf->pdev,
+ "Failed to set die selection feature\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type,
+ const uint8_t *id)
+{
+ const struct snand_id *fid;
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(snand_flash_ids); i++) {
+ if (snand_flash_ids[i].id.type != type)
+ continue;
+
+ fid = &snand_flash_ids[i].id;
+ if (memcmp(fid->id, id, fid->len))
+ continue;
+
+ return &snand_flash_ids[i];
+ }
+
+ return NULL;
+}
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-mtd.c b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-mtd.c
new file mode 100644
index 0000000..27cfb18
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-mtd.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_platform.h>
+
+#include "mtk-snand.h"
+#include "mtk-snand-os.h"
+
+struct mtk_snand_of_id {
+ enum mtk_snand_soc soc;
+};
+
+struct mtk_snand_mtd {
+ struct mtk_snand_plat_dev pdev;
+
+ struct clk *nfi_clk;
+ struct clk *pad_clk;
+ struct clk *ecc_clk;
+
+ void __iomem *nfi_regs;
+ void __iomem *ecc_regs;
+
+ int irq;
+
+ bool quad_spi;
+ enum mtk_snand_soc soc;
+
+ struct mtd_info mtd;
+ struct mtk_snand *snf;
+ struct mtk_snand_chip_info cinfo;
+ uint8_t *page_cache;
+ struct mutex lock;
+};
+
+#define mtd_to_msm(mtd) container_of(mtd, struct mtk_snand_mtd, mtd)
+
+static int mtk_snand_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+ u64 start_addr, end_addr;
+ int ret;
+
+ /* Do not allow write past end of device */
+ if ((instr->addr + instr->len) > mtd->size) {
+ dev_err(msm->pdev.dev,
+ "attempt to erase beyond end of device\n");
+ return -EINVAL;
+ }
+
+ start_addr = instr->addr & (~mtd->erasesize_mask);
+ end_addr = instr->addr + instr->len;
+ if (end_addr & mtd->erasesize_mask) {
+ end_addr = (end_addr + mtd->erasesize_mask) &
+ (~mtd->erasesize_mask);
+ }
+
+ mutex_lock(&msm->lock);
+
+ while (start_addr < end_addr) {
+ if (mtk_snand_block_isbad(msm->snf, start_addr)) {
+ instr->fail_addr = start_addr;
+ ret = -EIO;
+ break;
+ }
+
+ ret = mtk_snand_erase_block(msm->snf, start_addr);
+ if (ret) {
+ instr->fail_addr = start_addr;
+ break;
+ }
+
+ start_addr += mtd->erasesize;
+ }
+
+ mutex_unlock(&msm->lock);
+
+ return ret;
+}
+
+static int mtk_snand_mtd_read_data(struct mtk_snand_mtd *msm, uint64_t addr,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_info *mtd = &msm->mtd;
+ size_t len, ooblen, maxooblen, chklen;
+ uint32_t col, ooboffs;
+ uint8_t *datcache, *oobcache;
+ bool raw = ops->mode == MTD_OPS_RAW ? true : false;
+ int ret;
+
+ col = addr & mtd->writesize_mask;
+ addr &= ~mtd->writesize_mask;
+ maxooblen = mtd_oobavail(mtd, ops);
+ ooboffs = ops->ooboffs;
+ ooblen = ops->ooblen;
+ len = ops->len;
+
+ datcache = len ? msm->page_cache : NULL;
+ oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL;
+
+ ops->oobretlen = 0;
+ ops->retlen = 0;
+
+ while (len || ooblen) {
+ if (ops->mode == MTD_OPS_AUTO_OOB)
+ ret = mtk_snand_read_page_auto_oob(msm->snf, addr,
+ datcache, oobcache, maxooblen, NULL, raw);
+ else
+ ret = mtk_snand_read_page(msm->snf, addr, datcache,
+ oobcache, raw);
+
+ if (ret < 0)
+ return ret;
+
+ if (len) {
+ /* Move data */
+ chklen = mtd->writesize - col;
+ if (chklen > len)
+ chklen = len;
+
+ memcpy(ops->datbuf + ops->retlen, datcache + col,
+ chklen);
+ len -= chklen;
+ col = 0; /* (col + chklen) % */
+ ops->retlen += chklen;
+ }
+
+ if (ooblen) {
+ /* Move oob */
+ chklen = maxooblen - ooboffs;
+ if (chklen > ooblen)
+ chklen = ooblen;
+
+ memcpy(ops->oobbuf + ops->oobretlen, oobcache + ooboffs,
+ chklen);
+ ooblen -= chklen;
+ ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */
+ ops->oobretlen += chklen;
+ }
+
+ addr += mtd->writesize;
+ }
+
+ return 0;
+}
+
+static int mtk_snand_mtd_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+ uint32_t maxooblen;
+ int ret;
+
+ if (!ops->oobbuf && !ops->datbuf) {
+ if (ops->ooblen || ops->len)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ switch (ops->mode) {
+ case MTD_OPS_PLACE_OOB:
+ case MTD_OPS_AUTO_OOB:
+ case MTD_OPS_RAW:
+ break;
+ default:
+ dev_err(msm->pdev.dev, "unsupported oob mode: %u\n", ops->mode);
+ return -EINVAL;
+ }
+
+ maxooblen = mtd_oobavail(mtd, ops);
+
+ /* Do not allow read past end of device */
+ if (ops->datbuf && (from + ops->len) > mtd->size) {
+ dev_err(msm->pdev.dev,
+ "attempt to read beyond end of device\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(ops->ooboffs >= maxooblen)) {
+ dev_err(msm->pdev.dev, "attempt to start read outside oob\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(from >= mtd->size ||
+ ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) -
+ (from >> mtd->writesize_shift)) * maxooblen)) {
+ dev_err(msm->pdev.dev,
+ "attempt to read beyond end of device\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&msm->lock);
+ ret = mtk_snand_mtd_read_data(msm, from, ops);
+ mutex_unlock(&msm->lock);
+
+ return ret;
+}
+
+static int mtk_snand_mtd_write_data(struct mtk_snand_mtd *msm, uint64_t addr,
+ struct mtd_oob_ops *ops)
+{
+ struct mtd_info *mtd = &msm->mtd;
+ size_t len, ooblen, maxooblen, chklen, oobwrlen;
+ uint32_t col, ooboffs;
+ uint8_t *datcache, *oobcache;
+ bool raw = ops->mode == MTD_OPS_RAW ? true : false;
+ int ret;
+
+ col = addr & mtd->writesize_mask;
+ addr &= ~mtd->writesize_mask;
+ maxooblen = mtd_oobavail(mtd, ops);
+ ooboffs = ops->ooboffs;
+ ooblen = ops->ooblen;
+ len = ops->len;
+
+ datcache = len ? msm->page_cache : NULL;
+ oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL;
+
+ ops->oobretlen = 0;
+ ops->retlen = 0;
+
+ while (len || ooblen) {
+ if (len) {
+ /* Move data */
+ chklen = mtd->writesize - col;
+ if (chklen > len)
+ chklen = len;
+
+ memset(datcache, 0xff, col);
+ memcpy(datcache + col, ops->datbuf + ops->retlen,
+ chklen);
+ memset(datcache + col + chklen, 0xff,
+ mtd->writesize - col - chklen);
+ len -= chklen;
+ col = 0; /* (col + chklen) % */
+ ops->retlen += chklen;
+ }
+
+ oobwrlen = 0;
+ if (ooblen) {
+ /* Move oob */
+ chklen = maxooblen - ooboffs;
+ if (chklen > ooblen)
+ chklen = ooblen;
+
+ memset(oobcache, 0xff, ooboffs);
+ memcpy(oobcache + ooboffs,
+ ops->oobbuf + ops->oobretlen, chklen);
+ memset(oobcache + ooboffs + chklen, 0xff,
+ mtd->oobsize - ooboffs - chklen);
+ oobwrlen = chklen + ooboffs;
+ ooblen -= chklen;
+ ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */
+ ops->oobretlen += chklen;
+ }
+
+ if (ops->mode == MTD_OPS_AUTO_OOB)
+ ret = mtk_snand_write_page_auto_oob(msm->snf, addr,
+ datcache, oobcache, oobwrlen, NULL, raw);
+ else
+ ret = mtk_snand_write_page(msm->snf, addr, datcache,
+ oobcache, raw);
+
+ if (ret)
+ return ret;
+
+ addr += mtd->writesize;
+ }
+
+ return 0;
+}
+
+static int mtk_snand_mtd_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+ uint32_t maxooblen;
+ int ret;
+
+ if (!ops->oobbuf && !ops->datbuf) {
+ if (ops->ooblen || ops->len)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ switch (ops->mode) {
+ case MTD_OPS_PLACE_OOB:
+ case MTD_OPS_AUTO_OOB:
+ case MTD_OPS_RAW:
+ break;
+ default:
+ dev_err(msm->pdev.dev, "unsupported oob mode: %u\n", ops->mode);
+ return -EINVAL;
+ }
+
+ maxooblen = mtd_oobavail(mtd, ops);
+
+ /* Do not allow write past end of device */
+ if (ops->datbuf && (to + ops->len) > mtd->size) {
+ dev_err(msm->pdev.dev,
+ "attempt to write beyond end of device\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(ops->ooboffs >= maxooblen)) {
+ dev_err(msm->pdev.dev,
+ "attempt to start write outside oob\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(to >= mtd->size ||
+ ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) -
+ (to >> mtd->writesize_shift)) * maxooblen)) {
+ dev_err(msm->pdev.dev,
+ "attempt to write beyond end of device\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&msm->lock);
+ ret = mtk_snand_mtd_write_data(msm, to, ops);
+ mutex_unlock(&msm->lock);
+
+ return ret;
+}
+
+static int mtk_snand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+ int ret;
+
+ mutex_lock(&msm->lock);
+ ret = mtk_snand_block_isbad(msm->snf, offs);
+ mutex_unlock(&msm->lock);
+
+ return ret;
+}
+
+static int mtk_snand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+ int ret;
+
+ mutex_lock(&msm->lock);
+ ret = mtk_snand_block_markbad(msm->snf, offs);
+ mutex_unlock(&msm->lock);
+
+ return ret;
+}
+
+static int mtk_snand_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobecc)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+
+ if (section)
+ return -ERANGE;
+
+ oobecc->offset = msm->cinfo.fdm_size * msm->cinfo.num_sectors;
+ oobecc->length = mtd->oobsize - oobecc->offset;
+
+ return 0;
+}
+
+static int mtk_snand_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobfree)
+{
+ struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+
+ if (section >= msm->cinfo.num_sectors)
+ return -ERANGE;
+
+ oobfree->length = msm->cinfo.fdm_size - 1;
+ oobfree->offset = section * msm->cinfo.fdm_size + 1;
+
+ return 0;
+}
+
+static irqreturn_t mtk_snand_irq(int irq, void *id)
+{
+ struct mtk_snand_mtd *msm = id;
+ int ret;
+
+ ret = mtk_snand_irq_process(msm->snf);
+ if (ret > 0)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
+static int mtk_snand_enable_clk(struct mtk_snand_mtd *msm)
+{
+ int ret;
+
+ ret = clk_prepare_enable(msm->nfi_clk);
+ if (ret) {
+ dev_err(msm->pdev.dev, "unable to enable nfi clk\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(msm->pad_clk);
+ if (ret) {
+ dev_err(msm->pdev.dev, "unable to enable pad clk\n");
+ clk_disable_unprepare(msm->nfi_clk);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(msm->ecc_clk);
+ if (ret) {
+ dev_err(msm->pdev.dev, "unable to enable ecc clk\n");
+ clk_disable_unprepare(msm->nfi_clk);
+ clk_disable_unprepare(msm->pad_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mtk_snand_disable_clk(struct mtk_snand_mtd *msm)
+{
+ clk_disable_unprepare(msm->nfi_clk);
+ clk_disable_unprepare(msm->pad_clk);
+ clk_disable_unprepare(msm->ecc_clk);
+}
+
+static const struct mtd_ooblayout_ops mtk_snand_ooblayout = {
+ .ecc = mtk_snand_ooblayout_ecc,
+ .free = mtk_snand_ooblayout_free,
+};
+
+static struct mtk_snand_of_id mt7622_soc_id = { .soc = SNAND_SOC_MT7622 };
+static struct mtk_snand_of_id mt7629_soc_id = { .soc = SNAND_SOC_MT7629 };
+static struct mtk_snand_of_id mt7986_soc_id = { .soc = SNAND_SOC_MT7986 };
+
+static const struct of_device_id mtk_snand_ids[] = {
+ { .compatible = "mediatek,mt7622-snand", .data = &mt7622_soc_id },
+ { .compatible = "mediatek,mt7629-snand", .data = &mt7629_soc_id },
+ { .compatible = "mediatek,mt7986-snand", .data = &mt7986_soc_id },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, mtk_snand_ids);
+
+static int mtk_snand_probe(struct platform_device *pdev)
+{
+ struct mtk_snand_platdata mtk_snand_pdata = {};
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_soc_id;
+ const struct mtk_snand_of_id *soc_id;
+ struct mtk_snand_mtd *msm;
+ struct mtd_info *mtd;
+ struct resource *r;
+ uint32_t size;
+ int ret;
+
+ of_soc_id = of_match_node(mtk_snand_ids, np);
+ if (!of_soc_id)
+ return -EINVAL;
+
+ soc_id = of_soc_id->data;
+
+ msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
+ if (!msm)
+ return -ENOMEM;
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi");
+ msm->nfi_regs = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(msm->nfi_regs)) {
+ ret = PTR_ERR(msm->nfi_regs);
+ goto errout1;
+ }
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc");
+ msm->ecc_regs = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(msm->ecc_regs)) {
+ ret = PTR_ERR(msm->ecc_regs);
+ goto errout1;
+ }
+
+ msm->pdev.dev = &pdev->dev;
+ msm->quad_spi = of_property_read_bool(np, "mediatek,quad-spi");
+ msm->soc = soc_id->soc;
+
+ msm->nfi_clk = devm_clk_get(msm->pdev.dev, "nfi_clk");
+ if (IS_ERR(msm->nfi_clk)) {
+ ret = PTR_ERR(msm->nfi_clk);
+ dev_err(msm->pdev.dev, "unable to get nfi_clk, err = %d\n",
+ ret);
+ goto errout1;
+ }
+
+ msm->ecc_clk = devm_clk_get(msm->pdev.dev, "ecc_clk");
+ if (IS_ERR(msm->ecc_clk)) {
+ ret = PTR_ERR(msm->ecc_clk);
+ dev_err(msm->pdev.dev, "unable to get ecc_clk, err = %d\n",
+ ret);
+ goto errout1;
+ }
+
+ msm->pad_clk = devm_clk_get(msm->pdev.dev, "pad_clk");
+ if (IS_ERR(msm->pad_clk)) {
+ ret = PTR_ERR(msm->pad_clk);
+ dev_err(msm->pdev.dev, "unable to get pad_clk, err = %d\n",
+ ret);
+ goto errout1;
+ }
+
+ ret = mtk_snand_enable_clk(msm);
+ if (ret)
+ goto errout1;
+
+ /* Probe SPI-NAND Flash */
+ mtk_snand_pdata.soc = msm->soc;
+ mtk_snand_pdata.quad_spi = msm->quad_spi;
+ mtk_snand_pdata.nfi_base = msm->nfi_regs;
+ mtk_snand_pdata.ecc_base = msm->ecc_regs;
+
+ ret = mtk_snand_init(&msm->pdev, &mtk_snand_pdata, &msm->snf);
+ if (ret)
+ goto errout1;
+
+ msm->irq = platform_get_irq(pdev, 0);
+ if (msm->irq >= 0) {
+ ret = devm_request_irq(msm->pdev.dev, msm->irq, mtk_snand_irq,
+ 0x0, "mtk-snand", msm);
+ if (ret) {
+ dev_err(msm->pdev.dev, "failed to request snfi irq\n");
+ goto errout2;
+ }
+
+ ret = dma_set_mask(msm->pdev.dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(msm->pdev.dev, "failed to set dma mask\n");
+ goto errout3;
+ }
+ }
+
+ mtk_snand_get_chip_info(msm->snf, &msm->cinfo);
+
+ size = msm->cinfo.pagesize + msm->cinfo.sparesize;
+ msm->page_cache = devm_kmalloc(msm->pdev.dev, size, GFP_KERNEL);
+ if (!msm->page_cache) {
+ dev_err(msm->pdev.dev, "failed to allocate page cache\n");
+ ret = -ENOMEM;
+ goto errout3;
+ }
+
+ mutex_init(&msm->lock);
+
+ dev_info(msm->pdev.dev,
+ "chip is %s, size %lluMB, page size %u, oob size %u\n",
+ msm->cinfo.model, msm->cinfo.chipsize >> 20,
+ msm->cinfo.pagesize, msm->cinfo.sparesize);
+
+ /* Initialize mtd for SPI-NAND */
+ mtd = &msm->mtd;
+
+ mtd->owner = THIS_MODULE;
+ mtd->dev.parent = &pdev->dev;
+ mtd->type = MTD_NANDFLASH;
+ mtd->flags = MTD_CAP_NANDFLASH;
+
+ mtd_set_of_node(mtd, np);
+
+ mtd->size = msm->cinfo.chipsize;
+ mtd->erasesize = msm->cinfo.blocksize;
+ mtd->writesize = msm->cinfo.pagesize;
+ mtd->writebufsize = mtd->writesize;
+ mtd->oobsize = msm->cinfo.sparesize;
+ mtd->oobavail = msm->cinfo.num_sectors * (msm->cinfo.fdm_size - 1);
+
+ mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
+ mtd->writesize_shift = ffs(mtd->writesize) - 1;
+ mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
+ mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
+
+ mtd->ooblayout = &mtk_snand_ooblayout;
+
+ mtd->ecc_strength = msm->cinfo.ecc_strength * msm->cinfo.num_sectors;
+ mtd->bitflip_threshold = (mtd->ecc_strength * 3) / 4;
+ mtd->ecc_step_size = msm->cinfo.sector_size;
+
+ mtd->_erase = mtk_snand_mtd_erase;
+ mtd->_read_oob = mtk_snand_mtd_read_oob;
+ mtd->_write_oob = mtk_snand_mtd_write_oob;
+ mtd->_block_isbad = mtk_snand_mtd_block_isbad;
+ mtd->_block_markbad = mtk_snand_mtd_block_markbad;
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ dev_err(msm->pdev.dev, "failed to register mtd partition\n");
+ goto errout4;
+ }
+
+ platform_set_drvdata(pdev, msm);
+
+ return 0;
+
+errout4:
+ devm_kfree(msm->pdev.dev, msm->page_cache);
+
+errout3:
+ if (msm->irq >= 0)
+ devm_free_irq(msm->pdev.dev, msm->irq, msm);
+
+errout2:
+ mtk_snand_cleanup(msm->snf);
+
+errout1:
+ devm_kfree(msm->pdev.dev, msm);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int mtk_snand_remove(struct platform_device *pdev)
+{
+ struct mtk_snand_mtd *msm = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = &msm->mtd;
+ int ret;
+
+ ret = mtd_device_unregister(mtd);
+ if (ret)
+ return ret;
+
+ mtk_snand_cleanup(msm->snf);
+
+ if (msm->irq >= 0)
+ devm_free_irq(msm->pdev.dev, msm->irq, msm);
+
+ mtk_snand_disable_clk(msm);
+
+ devm_kfree(msm->pdev.dev, msm->page_cache);
+ devm_kfree(msm->pdev.dev, msm);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mtk_snand_driver = {
+ .probe = mtk_snand_probe,
+ .remove = mtk_snand_remove,
+ .driver = {
+ .name = "mtk-snand",
+ .of_match_table = mtk_snand_ids,
+ },
+};
+
+module_platform_driver(mtk_snand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
+MODULE_DESCRIPTION("MeidaTek SPI-NAND Flash Controller Driver");
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.c b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.c
new file mode 100644
index 0000000..0c3ffec
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+int mtk_snand_log(struct mtk_snand_plat_dev *pdev,
+ enum mtk_snand_log_category cat, const char *fmt, ...)
+{
+ const char *catname = "";
+ va_list ap;
+ char *msg;
+
+ switch (cat) {
+ case SNAND_LOG_NFI:
+ catname = "NFI";
+ break;
+ case SNAND_LOG_SNFI:
+ catname = "SNFI";
+ break;
+ case SNAND_LOG_ECC:
+ catname = "ECC";
+ break;
+ default:
+ break;
+ }
+
+ va_start(ap, fmt);
+ msg = kvasprintf(GFP_KERNEL, fmt, ap);
+ va_end(ap);
+
+ if (!msg) {
+ dev_warn(pdev->dev, "unable to print log\n");
+ return -1;
+ }
+
+ if (*catname)
+ dev_warn(pdev->dev, "%s: %s", catname, msg);
+ else
+ dev_warn(pdev->dev, "%s", msg);
+
+ kfree(msg);
+
+ return 0;
+}
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.h b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.h
new file mode 100644
index 0000000..223f73f
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_SNAND_OS_H_
+#define _MTK_SNAND_OS_H_
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/sizes.h>
+#include <linux/iopoll.h>
+#include <linux/hrtimer.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+
+struct mtk_snand_plat_dev {
+ struct device *dev;
+ struct completion done;
+};
+
+/* Polling helpers */
+#define read16_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+ readw_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us))
+
+#define read32_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+ readl_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us))
+
+/* Timer helpers */
+#define mtk_snand_time_t ktime_t
+
+static inline mtk_snand_time_t timer_get_ticks(void)
+{
+ return ktime_get();
+}
+
+static inline mtk_snand_time_t timer_time_to_tick(uint32_t timeout_us)
+{
+ return ktime_add_us(ktime_set(0, 0), timeout_us);
+}
+
+static inline bool timer_is_timeout(mtk_snand_time_t start_tick,
+ mtk_snand_time_t timeout_tick)
+{
+ ktime_t tmo = ktime_add(start_tick, timeout_tick);
+
+ return ktime_compare(ktime_get(), tmo) > 0;
+}
+
+/* Memory helpers */
+static inline void *generic_mem_alloc(struct mtk_snand_plat_dev *pdev,
+ size_t size)
+{
+ return devm_kzalloc(pdev->dev, size, GFP_KERNEL);
+}
+static inline void generic_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr)
+{
+ devm_kfree(pdev->dev, ptr);
+}
+
+static inline void *dma_mem_alloc(struct mtk_snand_plat_dev *pdev, size_t size)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+static inline void dma_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr)
+{
+ kfree(ptr);
+}
+
+static inline int dma_mem_map(struct mtk_snand_plat_dev *pdev, void *vaddr,
+ uintptr_t *dma_addr, size_t size, bool to_device)
+{
+ dma_addr_t addr;
+ int ret;
+
+ addr = dma_map_single(pdev->dev, vaddr, size,
+ to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ ret = dma_mapping_error(pdev->dev, addr);
+ if (ret)
+ return ret;
+
+ *dma_addr = (uintptr_t)addr;
+
+ return 0;
+}
+
+static inline void dma_mem_unmap(struct mtk_snand_plat_dev *pdev,
+ uintptr_t dma_addr, size_t size,
+ bool to_device)
+{
+ dma_unmap_single(pdev->dev, dma_addr, size,
+ to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+}
+
+/* Interrupt helpers */
+static inline void irq_completion_done(struct mtk_snand_plat_dev *pdev)
+{
+ complete(&pdev->done);
+}
+
+static inline void irq_completion_init(struct mtk_snand_plat_dev *pdev)
+{
+ init_completion(&pdev->done);
+}
+
+static inline int irq_completion_wait(struct mtk_snand_plat_dev *pdev,
+ void __iomem *reg, uint32_t bit,
+ uint32_t timeout_us)
+{
+#if 0
+ uint32_t val;
+
+ return read32_poll_timeout(reg, val, val & bit, 0, timeout_us);
+#else
+ int ret;
+
+ ret = wait_for_completion_timeout(&pdev->done,
+ usecs_to_jiffies(timeout_us));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+#endif
+}
+
+#endif /* _MTK_SNAND_OS_H_ */
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.c b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.c
new file mode 100644
index 0000000..17254a3
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.c
@@ -0,0 +1,1776 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+/* NFI registers */
+#define NFI_CNFG 0x000
+#define CNFG_OP_MODE_S 12
+#define CNFG_OP_MODE_CUST 6
+#define CNFG_OP_MODE_PROGRAM 3
+#define CNFG_AUTO_FMT_EN BIT(9)
+#define CNFG_HW_ECC_EN BIT(8)
+#define CNFG_DMA_BURST_EN BIT(2)
+#define CNFG_READ_MODE BIT(1)
+#define CNFG_DMA_MODE BIT(0)
+
+#define NFI_PAGEFMT 0x0004
+#define NFI_SPARE_SIZE_LS_S 16
+#define NFI_FDM_ECC_NUM_S 12
+#define NFI_FDM_NUM_S 8
+#define NFI_SPARE_SIZE_S 4
+#define NFI_SEC_SEL_512 BIT(2)
+#define NFI_PAGE_SIZE_S 0
+#define NFI_PAGE_SIZE_512_2K 0
+#define NFI_PAGE_SIZE_2K_4K 1
+#define NFI_PAGE_SIZE_4K_8K 2
+#define NFI_PAGE_SIZE_8K_16K 3
+
+#define NFI_CON 0x008
+#define CON_SEC_NUM_S 12
+#define CON_BWR BIT(9)
+#define CON_BRD BIT(8)
+#define CON_NFI_RST BIT(1)
+#define CON_FIFO_FLUSH BIT(0)
+
+#define NFI_INTR_EN 0x010
+#define NFI_INTR_STA 0x014
+#define NFI_IRQ_INTR_EN BIT(31)
+#define NFI_IRQ_CUS_READ BIT(8)
+#define NFI_IRQ_CUS_PG BIT(7)
+
+#define NFI_CMD 0x020
+
+#define NFI_STRDATA 0x040
+#define STR_DATA BIT(0)
+
+#define NFI_STA 0x060
+#define NFI_NAND_FSM GENMASK(28, 24)
+#define NFI_FSM GENMASK(19, 16)
+#define READ_EMPTY BIT(12)
+
+#define NFI_FIFOSTA 0x064
+#define FIFO_WR_REMAIN_S 8
+#define FIFO_RD_REMAIN_S 0
+
+#define NFI_STRADDR 0x080
+
+#define NFI_FDM0L 0x0a0
+#define NFI_FDM0M 0x0a4
+#define NFI_FDML(n) (NFI_FDM0L + (n) * 8)
+#define NFI_FDMM(n) (NFI_FDM0M + (n) * 8)
+
+#define NFI_DEBUG_CON1 0x220
+#define WBUF_EN BIT(2)
+
+#define NFI_MASTERSTA 0x224
+#define MAS_ADDR GENMASK(11, 9)
+#define MAS_RD GENMASK(8, 6)
+#define MAS_WR GENMASK(5, 3)
+#define MAS_RDDLY GENMASK(2, 0)
+#define NFI_MASTERSTA_MASK_7622 (MAS_ADDR | MAS_RD | MAS_WR | MAS_RDDLY)
+#define AHB_BUS_BUSY BIT(1)
+#define BUS_BUSY BIT(0)
+#define NFI_MASTERSTA_MASK_7986 (AHB_BUS_BUSY | BUS_BUSY)
+
+/* SNFI registers */
+#define SNF_MAC_CTL 0x500
+#define MAC_XIO_SEL BIT(4)
+#define SF_MAC_EN BIT(3)
+#define SF_TRIG BIT(2)
+#define WIP_READY BIT(1)
+#define WIP BIT(0)
+
+#define SNF_MAC_OUTL 0x504
+#define SNF_MAC_INL 0x508
+
+#define SNF_RD_CTL2 0x510
+#define DATA_READ_DUMMY_S 8
+#define DATA_READ_CMD_S 0
+
+#define SNF_RD_CTL3 0x514
+
+#define SNF_PG_CTL1 0x524
+#define PG_LOAD_CMD_S 8
+
+#define SNF_PG_CTL2 0x528
+
+#define SNF_MISC_CTL 0x538
+#define SW_RST BIT(28)
+#define FIFO_RD_LTC_S 25
+#define PG_LOAD_X4_EN BIT(20)
+#define DATA_READ_MODE_S 16
+#define DATA_READ_MODE GENMASK(18, 16)
+#define DATA_READ_MODE_X1 0
+#define DATA_READ_MODE_X2 1
+#define DATA_READ_MODE_X4 2
+#define DATA_READ_MODE_DUAL 5
+#define DATA_READ_MODE_QUAD 6
+#define PG_LOAD_CUSTOM_EN BIT(7)
+#define DATARD_CUSTOM_EN BIT(6)
+#define CS_DESELECT_CYC_S 0
+
+#define SNF_MISC_CTL2 0x53c
+#define PROGRAM_LOAD_BYTE_NUM_S 16
+#define READ_DATA_BYTE_NUM_S 11
+
+#define SNF_DLY_CTL3 0x548
+#define SFCK_SAM_DLY_S 0
+
+#define SNF_STA_CTL1 0x550
+#define CUS_PG_DONE BIT(28)
+#define CUS_READ_DONE BIT(27)
+#define SPI_STATE_S 0
+#define SPI_STATE GENMASK(3, 0)
+
+#define SNF_CFG 0x55c
+#define SPI_MODE BIT(0)
+
+#define SNF_GPRAM 0x800
+#define SNF_GPRAM_SIZE 0xa0
+
+#define SNFI_POLL_INTERVAL 1000000
+
+static const uint8_t mt7622_spare_sizes[] = { 16, 26, 27, 28 };
+
+static const uint8_t mt7986_spare_sizes[] = {
+ 16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64,
+ 67, 74
+};
+
+static const struct mtk_snand_soc_data mtk_snand_socs[__SNAND_SOC_MAX] = {
+ [SNAND_SOC_MT7622] = {
+ .sector_size = 512,
+ .max_sectors = 8,
+ .fdm_size = 8,
+ .fdm_ecc_size = 1,
+ .fifo_size = 32,
+ .bbm_swap = false,
+ .empty_page_check = false,
+ .mastersta_mask = NFI_MASTERSTA_MASK_7622,
+ .spare_sizes = mt7622_spare_sizes,
+ .num_spare_size = ARRAY_SIZE(mt7622_spare_sizes)
+ },
+ [SNAND_SOC_MT7629] = {
+ .sector_size = 512,
+ .max_sectors = 8,
+ .fdm_size = 8,
+ .fdm_ecc_size = 1,
+ .fifo_size = 32,
+ .bbm_swap = true,
+ .empty_page_check = false,
+ .mastersta_mask = NFI_MASTERSTA_MASK_7622,
+ .spare_sizes = mt7622_spare_sizes,
+ .num_spare_size = ARRAY_SIZE(mt7622_spare_sizes)
+ },
+ [SNAND_SOC_MT7986] = {
+ .sector_size = 1024,
+ .max_sectors = 16,
+ .fdm_size = 8,
+ .fdm_ecc_size = 1,
+ .fifo_size = 64,
+ .bbm_swap = true,
+ .empty_page_check = true,
+ .mastersta_mask = NFI_MASTERSTA_MASK_7986,
+ .spare_sizes = mt7986_spare_sizes,
+ .num_spare_size = ARRAY_SIZE(mt7986_spare_sizes)
+ },
+};
+
+static inline uint32_t nfi_read32(struct mtk_snand *snf, uint32_t reg)
+{
+ return readl(snf->nfi_base + reg);
+}
+
+static inline void nfi_write32(struct mtk_snand *snf, uint32_t reg,
+ uint32_t val)
+{
+ writel(val, snf->nfi_base + reg);
+}
+
+static inline void nfi_write16(struct mtk_snand *snf, uint32_t reg,
+ uint16_t val)
+{
+ writew(val, snf->nfi_base + reg);
+}
+
+static inline void nfi_rmw32(struct mtk_snand *snf, uint32_t reg, uint32_t clr,
+ uint32_t set)
+{
+ uint32_t val;
+
+ val = readl(snf->nfi_base + reg);
+ val &= ~clr;
+ val |= set;
+ writel(val, snf->nfi_base + reg);
+}
+
+static void nfi_write_data(struct mtk_snand *snf, uint32_t reg,
+ const uint8_t *data, uint32_t len)
+{
+ uint32_t i, val = 0, es = sizeof(uint32_t);
+
+ for (i = reg; i < reg + len; i++) {
+ val |= ((uint32_t)*data++) << (8 * (i % es));
+
+ if (i % es == es - 1 || i == reg + len - 1) {
+ nfi_write32(snf, i & ~(es - 1), val);
+ val = 0;
+ }
+ }
+}
+
+static void nfi_read_data(struct mtk_snand *snf, uint32_t reg, uint8_t *data,
+ uint32_t len)
+{
+ uint32_t i, val = 0, es = sizeof(uint32_t);
+
+ for (i = reg; i < reg + len; i++) {
+ if (i == reg || i % es == 0)
+ val = nfi_read32(snf, i & ~(es - 1));
+
+ *data++ = (uint8_t)(val >> (8 * (i % es)));
+ }
+}
+
+static inline void do_bm_swap(uint8_t *bm1, uint8_t *bm2)
+{
+ uint8_t tmp = *bm1;
+ *bm1 = *bm2;
+ *bm2 = tmp;
+}
+
+static void mtk_snand_bm_swap_raw(struct mtk_snand *snf)
+{
+ uint32_t fdm_bbm_pos;
+
+ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+ return;
+
+ fdm_bbm_pos = (snf->ecc_steps - 1) * snf->raw_sector_size +
+ snf->nfi_soc->sector_size;
+ do_bm_swap(&snf->page_cache[fdm_bbm_pos],
+ &snf->page_cache[snf->writesize]);
+}
+
+static void mtk_snand_bm_swap(struct mtk_snand *snf)
+{
+ uint32_t buf_bbm_pos, fdm_bbm_pos;
+
+ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+ return;
+
+ buf_bbm_pos = snf->writesize -
+ (snf->ecc_steps - 1) * snf->spare_per_sector;
+ fdm_bbm_pos = snf->writesize +
+ (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size;
+ do_bm_swap(&snf->page_cache[fdm_bbm_pos],
+ &snf->page_cache[buf_bbm_pos]);
+}
+
+static void mtk_snand_fdm_bm_swap_raw(struct mtk_snand *snf)
+{
+ uint32_t fdm_bbm_pos1, fdm_bbm_pos2;
+
+ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+ return;
+
+ fdm_bbm_pos1 = snf->nfi_soc->sector_size;
+ fdm_bbm_pos2 = (snf->ecc_steps - 1) * snf->raw_sector_size +
+ snf->nfi_soc->sector_size;
+ do_bm_swap(&snf->page_cache[fdm_bbm_pos1],
+ &snf->page_cache[fdm_bbm_pos2]);
+}
+
+static void mtk_snand_fdm_bm_swap(struct mtk_snand *snf)
+{
+ uint32_t fdm_bbm_pos1, fdm_bbm_pos2;
+
+ if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+ return;
+
+ fdm_bbm_pos1 = snf->writesize;
+ fdm_bbm_pos2 = snf->writesize +
+ (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size;
+ do_bm_swap(&snf->page_cache[fdm_bbm_pos1],
+ &snf->page_cache[fdm_bbm_pos2]);
+}
+
+static int mtk_nfi_reset(struct mtk_snand *snf)
+{
+ uint32_t val, fifo_mask;
+ int ret;
+
+ nfi_write32(snf, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
+
+ ret = read16_poll_timeout(snf->nfi_base + NFI_MASTERSTA, val,
+ !(val & snf->nfi_soc->mastersta_mask), 0,
+ SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_nfi(snf->pdev,
+ "NFI master is still busy after reset\n");
+ return ret;
+ }
+
+ ret = read32_poll_timeout(snf->nfi_base + NFI_STA, val,
+ !(val & (NFI_FSM | NFI_NAND_FSM)), 0,
+ SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_nfi(snf->pdev, "Failed to reset NFI\n");
+ return ret;
+ }
+
+ fifo_mask = ((snf->nfi_soc->fifo_size - 1) << FIFO_RD_REMAIN_S) |
+ ((snf->nfi_soc->fifo_size - 1) << FIFO_WR_REMAIN_S);
+ ret = read16_poll_timeout(snf->nfi_base + NFI_FIFOSTA, val,
+ !(val & fifo_mask), 0, SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_nfi(snf->pdev, "NFI FIFOs are not empty\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_snand_mac_reset(struct mtk_snand *snf)
+{
+ int ret;
+ uint32_t val;
+
+ nfi_rmw32(snf, SNF_MISC_CTL, 0, SW_RST);
+
+ ret = read32_poll_timeout(snf->nfi_base + SNF_STA_CTL1, val,
+ !(val & SPI_STATE), 0, SNFI_POLL_INTERVAL);
+ if (ret)
+ snand_log_snfi(snf->pdev, "Failed to reset SNFI MAC\n");
+
+ nfi_write32(snf, SNF_MISC_CTL, (2 << FIFO_RD_LTC_S) |
+ (10 << CS_DESELECT_CYC_S));
+
+ return ret;
+}
+
+static int mtk_snand_mac_trigger(struct mtk_snand *snf, uint32_t outlen,
+ uint32_t inlen)
+{
+ int ret;
+ uint32_t val;
+
+ nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN);
+ nfi_write32(snf, SNF_MAC_OUTL, outlen);
+ nfi_write32(snf, SNF_MAC_INL, inlen);
+
+ nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN | SF_TRIG);
+
+ ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val,
+ val & WIP_READY, 0, SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_snfi(snf->pdev, "Timed out waiting for WIP_READY\n");
+ goto cleanup;
+ }
+
+ ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val,
+ !(val & WIP), 0, SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_snfi(snf->pdev,
+ "Timed out waiting for WIP cleared\n");
+ }
+
+cleanup:
+ nfi_write32(snf, SNF_MAC_CTL, 0);
+
+ return ret;
+}
+
+int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen,
+ uint8_t *in, uint32_t inlen)
+{
+ int ret;
+
+ if (outlen + inlen > SNF_GPRAM_SIZE)
+ return -EINVAL;
+
+ mtk_snand_mac_reset(snf);
+
+ nfi_write_data(snf, SNF_GPRAM, out, outlen);
+
+ ret = mtk_snand_mac_trigger(snf, outlen, inlen);
+ if (ret)
+ return ret;
+
+ if (!inlen)
+ return 0;
+
+ nfi_read_data(snf, SNF_GPRAM + outlen, in, inlen);
+
+ return 0;
+}
+
+static int mtk_snand_get_feature(struct mtk_snand *snf, uint32_t addr)
+{
+ uint8_t op[2], val;
+ int ret;
+
+ op[0] = SNAND_CMD_GET_FEATURE;
+ op[1] = (uint8_t)addr;
+
+ ret = mtk_snand_mac_io(snf, op, sizeof(op), &val, 1);
+ if (ret)
+ return ret;
+
+ return val;
+}
+
+int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val)
+{
+ uint8_t op[3];
+
+ op[0] = SNAND_CMD_SET_FEATURE;
+ op[1] = (uint8_t)addr;
+ op[2] = (uint8_t)val;
+
+ return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0);
+}
+
+static int mtk_snand_poll_status(struct mtk_snand *snf, uint32_t wait_us)
+{
+ int val;
+ mtk_snand_time_t time_start, tmo;
+
+ time_start = timer_get_ticks();
+ tmo = timer_time_to_tick(wait_us);
+
+ do {
+ val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR);
+ if (!(val & SNAND_STATUS_OIP))
+ return val & (SNAND_STATUS_ERASE_FAIL |
+ SNAND_STATUS_PROGRAM_FAIL);
+ } while (!timer_is_timeout(time_start, tmo));
+
+ return -ETIMEDOUT;
+}
+
+int mtk_snand_chip_reset(struct mtk_snand *snf)
+{
+ uint8_t op = SNAND_CMD_RESET;
+ int ret;
+
+ ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mtk_snand_config_feature(struct mtk_snand *snf, uint8_t clr,
+ uint8_t set)
+{
+ int val, newval;
+ int ret;
+
+ val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR);
+ if (val < 0) {
+ snand_log_chip(snf->pdev,
+ "Failed to get configuration feature\n");
+ return val;
+ }
+
+ newval = (val & (~clr)) | set;
+
+ if (newval == val)
+ return 0;
+
+ ret = mtk_snand_set_feature(snf, SNAND_FEATURE_CONFIG_ADDR,
+ (uint8_t)newval);
+ if (val < 0) {
+ snand_log_chip(snf->pdev,
+ "Failed to set configuration feature\n");
+ return ret;
+ }
+
+ val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR);
+ if (val < 0) {
+ snand_log_chip(snf->pdev,
+ "Failed to get configuration feature\n");
+ return val;
+ }
+
+ if (newval != val)
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+static int mtk_snand_ondie_ecc_control(struct mtk_snand *snf, bool enable)
+{
+ int ret;
+
+ if (enable)
+ ret = mtk_snand_config_feature(snf, 0, SNAND_FEATURE_ECC_EN);
+ else
+ ret = mtk_snand_config_feature(snf, SNAND_FEATURE_ECC_EN, 0);
+
+ if (ret) {
+ snand_log_chip(snf->pdev, "Failed to %s On-Die ECC engine\n",
+ enable ? "enable" : "disable");
+ }
+
+ return ret;
+}
+
+static int mtk_snand_qspi_control(struct mtk_snand *snf, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ ret = mtk_snand_config_feature(snf, 0,
+ SNAND_FEATURE_QUAD_ENABLE);
+ } else {
+ ret = mtk_snand_config_feature(snf,
+ SNAND_FEATURE_QUAD_ENABLE, 0);
+ }
+
+ if (ret) {
+ snand_log_chip(snf->pdev, "Failed to %s quad spi\n",
+ enable ? "enable" : "disable");
+ }
+
+ return ret;
+}
+
+static int mtk_snand_unlock(struct mtk_snand *snf)
+{
+ int ret;
+
+ ret = mtk_snand_set_feature(snf, SNAND_FEATURE_PROTECT_ADDR, 0);
+ if (ret) {
+ snand_log_chip(snf->pdev, "Failed to set protection feature\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_snand_write_enable(struct mtk_snand *snf)
+{
+ uint8_t op = SNAND_CMD_WRITE_ENABLE;
+ int ret, val;
+
+ ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0);
+ if (ret)
+ return ret;
+
+ val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR);
+ if (val < 0)
+ return ret;
+
+ if (val & SNAND_STATUS_WEL)
+ return 0;
+
+ snand_log_chip(snf->pdev, "Failed to send write-enable command\n");
+
+ return -ENOTSUPP;
+}
+
+static int mtk_snand_select_die(struct mtk_snand *snf, uint32_t dieidx)
+{
+ if (!snf->select_die)
+ return 0;
+
+ return snf->select_die(snf, dieidx);
+}
+
+static uint64_t mtk_snand_select_die_address(struct mtk_snand *snf,
+ uint64_t addr)
+{
+ uint32_t dieidx;
+
+ if (!snf->select_die)
+ return addr;
+
+ dieidx = addr >> snf->die_shift;
+
+ mtk_snand_select_die(snf, dieidx);
+
+ return addr & snf->die_mask;
+}
+
+static uint32_t mtk_snand_get_plane_address(struct mtk_snand *snf,
+ uint32_t page)
+{
+ uint32_t pages_per_block;
+
+ pages_per_block = 1 << (snf->erasesize_shift - snf->writesize_shift);
+
+ if (page & pages_per_block)
+ return 1 << (snf->writesize_shift + 1);
+
+ return 0;
+}
+
+static int mtk_snand_page_op(struct mtk_snand *snf, uint32_t page, uint8_t cmd)
+{
+ uint8_t op[4];
+
+ op[0] = cmd;
+ op[1] = (page >> 16) & 0xff;
+ op[2] = (page >> 8) & 0xff;
+ op[3] = page & 0xff;
+
+ return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0);
+}
+
+static void mtk_snand_read_fdm(struct mtk_snand *snf, uint8_t *buf)
+{
+ uint32_t vall, valm;
+ uint8_t *oobptr = buf;
+ int i, j;
+
+ for (i = 0; i < snf->ecc_steps; i++) {
+ vall = nfi_read32(snf, NFI_FDML(i));
+ valm = nfi_read32(snf, NFI_FDMM(i));
+
+ for (j = 0; j < snf->nfi_soc->fdm_size; j++)
+ oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+
+ oobptr += snf->nfi_soc->fdm_size;
+ }
+}
+
+static int mtk_snand_read_cache(struct mtk_snand *snf, uint32_t page, bool raw)
+{
+ uint32_t coladdr, rwbytes, mode, len;
+ uintptr_t dma_addr;
+ int ret;
+
+ /* Column address with plane bit */
+ coladdr = mtk_snand_get_plane_address(snf, page);
+
+ mtk_snand_mac_reset(snf);
+ mtk_nfi_reset(snf);
+
+ /* Command and dummy cycles */
+ nfi_write32(snf, SNF_RD_CTL2,
+ ((uint32_t)snf->dummy_rfc << DATA_READ_DUMMY_S) |
+ (snf->opcode_rfc << DATA_READ_CMD_S));
+
+ /* Column address */
+ nfi_write32(snf, SNF_RD_CTL3, coladdr);
+
+ /* Set read mode */
+ mode = (uint32_t)snf->mode_rfc << DATA_READ_MODE_S;
+ nfi_rmw32(snf, SNF_MISC_CTL, DATA_READ_MODE, mode | DATARD_CUSTOM_EN);
+
+ /* Set bytes to read */
+ rwbytes = snf->ecc_steps * snf->raw_sector_size;
+ nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) |
+ rwbytes);
+
+ /* NFI read prepare */
+ mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN;
+ nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_CUST << CNFG_OP_MODE_S) |
+ CNFG_DMA_BURST_EN | CNFG_READ_MODE | CNFG_DMA_MODE | mode);
+
+ nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S));
+
+ /* Prepare for DMA read */
+ len = snf->writesize + snf->oobsize;
+ ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, false);
+ if (ret) {
+ snand_log_nfi(snf->pdev,
+ "DMA map from device failed with %d\n", ret);
+ return ret;
+ }
+
+ nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr);
+
+ if (!raw)
+ mtk_snand_ecc_decoder_start(snf);
+
+ /* Prepare for custom read interrupt */
+ nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_READ);
+ irq_completion_init(snf->pdev);
+
+ /* Trigger NFI into custom mode */
+ nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_READ);
+
+ /* Start DMA read */
+ nfi_rmw32(snf, NFI_CON, 0, CON_BRD);
+ nfi_write16(snf, NFI_STRDATA, STR_DATA);
+
+ /* Wait for operation finished */
+ ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1,
+ CUS_READ_DONE, SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_nfi(snf->pdev,
+ "DMA timed out for reading from cache\n");
+ goto cleanup;
+ }
+
+ if (!raw) {
+ ret = mtk_ecc_wait_decoder_done(snf);
+ if (ret)
+ goto cleanup;
+
+ mtk_snand_read_fdm(snf, snf->page_cache + snf->writesize);
+
+ /*
+ * For new IPs, ecc error may occure on empty pages.
+ * Use an specific indication bit to check empty page.
+ */
+ if (snf->nfi_soc->empty_page_check &&
+ (nfi_read32(snf, NFI_STA) & READ_EMPTY))
+ ret = 0;
+ else
+ ret = mtk_ecc_check_decode_error(snf, page);
+
+ mtk_snand_ecc_decoder_stop(snf);
+ }
+
+cleanup:
+ /* DMA cleanup */
+ dma_mem_unmap(snf->pdev, dma_addr, len, false);
+
+ /* Stop read */
+ nfi_write32(snf, NFI_CON, 0);
+
+ /* Clear SNF done flag */
+ nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE);
+ nfi_write32(snf, SNF_STA_CTL1, 0);
+
+ /* Disable interrupt */
+ nfi_read32(snf, NFI_INTR_STA);
+ nfi_write32(snf, NFI_INTR_EN, 0);
+
+ nfi_rmw32(snf, SNF_MISC_CTL, DATARD_CUSTOM_EN, 0);
+
+ return ret;
+}
+
+static void mtk_snand_from_raw_page(struct mtk_snand *snf, void *buf, void *oob)
+{
+ uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size;
+ uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size;
+ uint8_t *bufptr = buf, *oobptr = oob, *raw_sector;
+
+ for (i = 0; i < snf->ecc_steps; i++) {
+ raw_sector = snf->page_cache + i * snf->raw_sector_size;
+
+ if (buf) {
+ memcpy(bufptr, raw_sector, snf->nfi_soc->sector_size);
+ bufptr += snf->nfi_soc->sector_size;
+ }
+
+ raw_sector += snf->nfi_soc->sector_size;
+
+ if (oob) {
+ memcpy(oobptr, raw_sector, snf->nfi_soc->fdm_size);
+ oobptr += snf->nfi_soc->fdm_size;
+ raw_sector += snf->nfi_soc->fdm_size;
+
+ memcpy(eccptr, raw_sector, ecc_bytes);
+ eccptr += ecc_bytes;
+ }
+ }
+}
+
+static int mtk_snand_do_read_page(struct mtk_snand *snf, uint64_t addr,
+ void *buf, void *oob, bool raw, bool format)
+{
+ uint64_t die_addr;
+ uint32_t page;
+ int ret;
+
+ die_addr = mtk_snand_select_die_address(snf, addr);
+ page = die_addr >> snf->writesize_shift;
+
+ ret = mtk_snand_page_op(snf, page, SNAND_CMD_READ_TO_CACHE);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+ if (ret < 0) {
+ snand_log_chip(snf->pdev, "Read to cache command timed out\n");
+ return ret;
+ }
+
+ ret = mtk_snand_read_cache(snf, page, raw);
+ if (ret < 0 && ret != -EBADMSG)
+ return ret;
+
+ if (raw) {
+ if (format) {
+ mtk_snand_bm_swap_raw(snf);
+ mtk_snand_fdm_bm_swap_raw(snf);
+ mtk_snand_from_raw_page(snf, buf, oob);
+ } else {
+ if (buf)
+ memcpy(buf, snf->page_cache, snf->writesize);
+
+ if (oob) {
+ memset(oob, 0xff, snf->oobsize);
+ memcpy(oob, snf->page_cache + snf->writesize,
+ snf->ecc_steps * snf->spare_per_sector);
+ }
+ }
+ } else {
+ mtk_snand_bm_swap(snf);
+ mtk_snand_fdm_bm_swap(snf);
+
+ if (buf)
+ memcpy(buf, snf->page_cache, snf->writesize);
+
+ if (oob) {
+ memset(oob, 0xff, snf->oobsize);
+ memcpy(oob, snf->page_cache + snf->writesize,
+ snf->ecc_steps * snf->nfi_soc->fdm_size);
+ }
+ }
+
+ return ret;
+}
+
+int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf,
+ void *oob, bool raw)
+{
+ if (!snf || (!buf && !oob))
+ return -EINVAL;
+
+ if (addr >= snf->size)
+ return -EINVAL;
+
+ return mtk_snand_do_read_page(snf, addr, buf, oob, raw, true);
+}
+
+static void mtk_snand_write_fdm(struct mtk_snand *snf, const uint8_t *buf)
+{
+ uint32_t vall, valm, fdm_size = snf->nfi_soc->fdm_size;
+ const uint8_t *oobptr = buf;
+ int i, j;
+
+ for (i = 0; i < snf->ecc_steps; i++) {
+ vall = 0;
+ valm = 0;
+
+ for (j = 0; j < 8; j++) {
+ if (j < 4)
+ vall |= (j < fdm_size ? oobptr[j] : 0xff)
+ << (j * 8);
+ else
+ valm |= (j < fdm_size ? oobptr[j] : 0xff)
+ << ((j - 4) * 8);
+ }
+
+ nfi_write32(snf, NFI_FDML(i), vall);
+ nfi_write32(snf, NFI_FDMM(i), valm);
+
+ oobptr += fdm_size;
+ }
+}
+
+static int mtk_snand_program_load(struct mtk_snand *snf, uint32_t page,
+ bool raw)
+{
+ uint32_t coladdr, rwbytes, mode, len;
+ uintptr_t dma_addr;
+ int ret;
+
+ /* Column address with plane bit */
+ coladdr = mtk_snand_get_plane_address(snf, page);
+
+ mtk_snand_mac_reset(snf);
+ mtk_nfi_reset(snf);
+
+ /* Write FDM registers if necessary */
+ if (!raw)
+ mtk_snand_write_fdm(snf, snf->page_cache + snf->writesize);
+
+ /* Command */
+ nfi_write32(snf, SNF_PG_CTL1, (snf->opcode_pl << PG_LOAD_CMD_S));
+
+ /* Column address */
+ nfi_write32(snf, SNF_PG_CTL2, coladdr);
+
+ /* Set write mode */
+ mode = snf->mode_pl ? PG_LOAD_X4_EN : 0;
+ nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_X4_EN, mode | PG_LOAD_CUSTOM_EN);
+
+ /* Set bytes to write */
+ rwbytes = snf->ecc_steps * snf->raw_sector_size;
+ nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) |
+ rwbytes);
+
+ /* NFI write prepare */
+ mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN;
+ nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_PROGRAM << CNFG_OP_MODE_S) |
+ CNFG_DMA_BURST_EN | CNFG_DMA_MODE | mode);
+
+ nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S));
+
+ /* Prepare for DMA write */
+ len = snf->writesize + snf->oobsize;
+ ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, true);
+ if (ret) {
+ snand_log_nfi(snf->pdev,
+ "DMA map to device failed with %d\n", ret);
+ return ret;
+ }
+
+ nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr);
+
+ if (!raw)
+ mtk_snand_ecc_encoder_start(snf);
+
+ /* Prepare for custom write interrupt */
+ nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG);
+ irq_completion_init(snf->pdev);
+
+ /* Trigger NFI into custom mode */
+ nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE);
+
+ /* Start DMA write */
+ nfi_rmw32(snf, NFI_CON, 0, CON_BWR);
+ nfi_write16(snf, NFI_STRDATA, STR_DATA);
+
+ /* Wait for operation finished */
+ ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1,
+ CUS_PG_DONE, SNFI_POLL_INTERVAL);
+ if (ret) {
+ snand_log_nfi(snf->pdev,
+ "DMA timed out for program load\n");
+ goto cleanup;
+ }
+
+ if (!raw)
+ mtk_snand_ecc_encoder_stop(snf);
+
+cleanup:
+ /* DMA cleanup */
+ dma_mem_unmap(snf->pdev, dma_addr, len, true);
+
+ /* Stop write */
+ nfi_write16(snf, NFI_CON, 0);
+
+ /* Clear SNF done flag */
+ nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_PG_DONE);
+ nfi_write32(snf, SNF_STA_CTL1, 0);
+
+ /* Disable interrupt */
+ nfi_read32(snf, NFI_INTR_STA);
+ nfi_write32(snf, NFI_INTR_EN, 0);
+
+ nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_CUSTOM_EN, 0);
+
+ return ret;
+}
+
+static void mtk_snand_to_raw_page(struct mtk_snand *snf,
+ const void *buf, const void *oob,
+ bool empty_ecc)
+{
+ uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size;
+ const uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size;
+ const uint8_t *bufptr = buf, *oobptr = oob;
+ uint8_t *raw_sector;
+
+ memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize);
+ for (i = 0; i < snf->ecc_steps; i++) {
+ raw_sector = snf->page_cache + i * snf->raw_sector_size;
+
+ if (buf) {
+ memcpy(raw_sector, bufptr, snf->nfi_soc->sector_size);
+ bufptr += snf->nfi_soc->sector_size;
+ }
+
+ raw_sector += snf->nfi_soc->sector_size;
+
+ if (oob) {
+ memcpy(raw_sector, oobptr, snf->nfi_soc->fdm_size);
+ oobptr += snf->nfi_soc->fdm_size;
+ raw_sector += snf->nfi_soc->fdm_size;
+
+ if (empty_ecc)
+ memset(raw_sector, 0xff, ecc_bytes);
+ else
+ memcpy(raw_sector, eccptr, ecc_bytes);
+ eccptr += ecc_bytes;
+ }
+ }
+}
+
+static bool mtk_snand_is_empty_page(struct mtk_snand *snf, const void *buf,
+ const void *oob)
+{
+ const uint8_t *p = buf;
+ uint32_t i, j;
+
+ if (buf) {
+ for (i = 0; i < snf->writesize; i++) {
+ if (p[i] != 0xff)
+ return false;
+ }
+ }
+
+ if (oob) {
+ for (j = 0; j < snf->ecc_steps; j++) {
+ p = oob + j * snf->nfi_soc->fdm_size;
+
+ for (i = 0; i < snf->nfi_soc->fdm_ecc_size; i++) {
+ if (p[i] != 0xff)
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int mtk_snand_do_write_page(struct mtk_snand *snf, uint64_t addr,
+ const void *buf, const void *oob,
+ bool raw, bool format)
+{
+ uint64_t die_addr;
+ bool empty_ecc = false;
+ uint32_t page;
+ int ret;
+
+ die_addr = mtk_snand_select_die_address(snf, addr);
+ page = die_addr >> snf->writesize_shift;
+
+ if (!raw && mtk_snand_is_empty_page(snf, buf, oob)) {
+ /*
+ * If the data in the page to be ecc-ed is full 0xff,
+ * change to raw write mode
+ */
+ raw = true;
+ format = true;
+
+ /* fill ecc parity code region with 0xff */
+ empty_ecc = true;
+ }
+
+ if (raw) {
+ if (format) {
+ mtk_snand_to_raw_page(snf, buf, oob, empty_ecc);
+ mtk_snand_fdm_bm_swap_raw(snf);
+ mtk_snand_bm_swap_raw(snf);
+ } else {
+ memset(snf->page_cache, 0xff,
+ snf->writesize + snf->oobsize);
+
+ if (buf)
+ memcpy(snf->page_cache, buf, snf->writesize);
+
+ if (oob) {
+ memcpy(snf->page_cache + snf->writesize, oob,
+ snf->ecc_steps * snf->spare_per_sector);
+ }
+ }
+ } else {
+ memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize);
+ if (buf)
+ memcpy(snf->page_cache, buf, snf->writesize);
+
+ if (oob) {
+ memcpy(snf->page_cache + snf->writesize, oob,
+ snf->ecc_steps * snf->nfi_soc->fdm_size);
+ }
+
+ mtk_snand_fdm_bm_swap(snf);
+ mtk_snand_bm_swap(snf);
+ }
+
+ ret = mtk_snand_write_enable(snf);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_program_load(snf, page, raw);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_page_op(snf, page, SNAND_CMD_PROGRAM_EXECUTE);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+ if (ret < 0) {
+ snand_log_chip(snf->pdev,
+ "Page program command timed out on page %u\n",
+ page);
+ return ret;
+ }
+
+ if (ret & SNAND_STATUS_PROGRAM_FAIL) {
+ snand_log_chip(snf->pdev,
+ "Page program failed on page %u\n", page);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf,
+ const void *oob, bool raw)
+{
+ if (!snf || (!buf && !oob))
+ return -EINVAL;
+
+ if (addr >= snf->size)
+ return -EINVAL;
+
+ return mtk_snand_do_write_page(snf, addr, buf, oob, raw, true);
+}
+
+int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr)
+{
+ uint64_t die_addr;
+ uint32_t page, block;
+ int ret;
+
+ if (!snf)
+ return -EINVAL;
+
+ if (addr >= snf->size)
+ return -EINVAL;
+
+ die_addr = mtk_snand_select_die_address(snf, addr);
+ block = die_addr >> snf->erasesize_shift;
+ page = block << (snf->erasesize_shift - snf->writesize_shift);
+
+ ret = mtk_snand_write_enable(snf);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_page_op(snf, page, SNAND_CMD_BLOCK_ERASE);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+ if (ret < 0) {
+ snand_log_chip(snf->pdev,
+ "Block erase command timed out on block %u\n",
+ block);
+ return ret;
+ }
+
+ if (ret & SNAND_STATUS_ERASE_FAIL) {
+ snand_log_chip(snf->pdev,
+ "Block erase failed on block %u\n", block);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mtk_snand_block_isbad_std(struct mtk_snand *snf, uint64_t addr)
+{
+ int ret;
+
+ ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true,
+ false);
+ if (ret && ret != -EBADMSG)
+ return ret;
+
+ return snf->buf_cache[0] != 0xff;
+}
+
+static int mtk_snand_block_isbad_mtk(struct mtk_snand *snf, uint64_t addr)
+{
+ int ret;
+
+ ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true,
+ true);
+ if (ret && ret != -EBADMSG)
+ return ret;
+
+ return snf->buf_cache[0] != 0xff;
+}
+
+int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr)
+{
+ if (!snf)
+ return -EINVAL;
+
+ if (addr >= snf->size)
+ return -EINVAL;
+
+ addr &= ~snf->erasesize_mask;
+
+ if (snf->nfi_soc->bbm_swap)
+ return mtk_snand_block_isbad_std(snf, addr);
+
+ return mtk_snand_block_isbad_mtk(snf, addr);
+}
+
+static int mtk_snand_block_markbad_std(struct mtk_snand *snf, uint64_t addr)
+{
+ /* Standard BBM position */
+ memset(snf->buf_cache, 0xff, snf->oobsize);
+ snf->buf_cache[0] = 0;
+
+ return mtk_snand_do_write_page(snf, addr, NULL, snf->buf_cache, true,
+ false);
+}
+
+static int mtk_snand_block_markbad_mtk(struct mtk_snand *snf, uint64_t addr)
+{
+ /* Write the whole page with zeros */
+ memset(snf->buf_cache, 0, snf->writesize + snf->oobsize);
+
+ return mtk_snand_do_write_page(snf, addr, snf->buf_cache,
+ snf->buf_cache + snf->writesize, true,
+ true);
+}
+
+int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr)
+{
+ if (!snf)
+ return -EINVAL;
+
+ if (addr >= snf->size)
+ return -EINVAL;
+
+ addr &= ~snf->erasesize_mask;
+
+ if (snf->nfi_soc->bbm_swap)
+ return mtk_snand_block_markbad_std(snf, addr);
+
+ return mtk_snand_block_markbad_mtk(snf, addr);
+}
+
+int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw,
+ const uint8_t *oobbuf, size_t ooblen)
+{
+ size_t len = ooblen, sect_fdm_len;
+ const uint8_t *oob = oobbuf;
+ uint32_t step = 0;
+
+ if (!snf || !oobraw || !oob)
+ return -EINVAL;
+
+ while (len && step < snf->ecc_steps) {
+ sect_fdm_len = snf->nfi_soc->fdm_size - 1;
+ if (sect_fdm_len > len)
+ sect_fdm_len = len;
+
+ memcpy(oobraw + step * snf->nfi_soc->fdm_size + 1, oob,
+ sect_fdm_len);
+
+ len -= sect_fdm_len;
+ oob += sect_fdm_len;
+ step++;
+ }
+
+ return len;
+}
+
+int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf,
+ size_t ooblen, const uint8_t *oobraw)
+{
+ size_t len = ooblen, sect_fdm_len;
+ uint8_t *oob = oobbuf;
+ uint32_t step = 0;
+
+ if (!snf || !oobraw || !oob)
+ return -EINVAL;
+
+ while (len && step < snf->ecc_steps) {
+ sect_fdm_len = snf->nfi_soc->fdm_size - 1;
+ if (sect_fdm_len > len)
+ sect_fdm_len = len;
+
+ memcpy(oob, oobraw + step * snf->nfi_soc->fdm_size + 1,
+ sect_fdm_len);
+
+ len -= sect_fdm_len;
+ oob += sect_fdm_len;
+ step++;
+ }
+
+ return len;
+}
+
+int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+ void *buf, void *oob, size_t ooblen,
+ size_t *actualooblen, bool raw)
+{
+ int ret, oobremain;
+
+ if (!snf)
+ return -EINVAL;
+
+ if (!oob)
+ return mtk_snand_read_page(snf, addr, buf, NULL, raw);
+
+ ret = mtk_snand_read_page(snf, addr, buf, snf->buf_cache, raw);
+ if (ret && ret != -EBADMSG) {
+ if (actualooblen)
+ *actualooblen = 0;
+ return ret;
+ }
+
+ oobremain = mtk_snand_transfer_oob(snf, oob, ooblen, snf->buf_cache);
+ if (actualooblen)
+ *actualooblen = ooblen - oobremain;
+
+ return ret;
+}
+
+int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+ const void *buf, const void *oob,
+ size_t ooblen, size_t *actualooblen, bool raw)
+{
+ int oobremain;
+
+ if (!snf)
+ return -EINVAL;
+
+ if (!oob)
+ return mtk_snand_write_page(snf, addr, buf, NULL, raw);
+
+ memset(snf->buf_cache, 0xff, snf->oobsize);
+ oobremain = mtk_snand_fill_oob(snf, snf->buf_cache, oob, ooblen);
+ if (actualooblen)
+ *actualooblen = ooblen - oobremain;
+
+ return mtk_snand_write_page(snf, addr, buf, snf->buf_cache, raw);
+}
+
+int mtk_snand_get_chip_info(struct mtk_snand *snf,
+ struct mtk_snand_chip_info *info)
+{
+ if (!snf || !info)
+ return -EINVAL;
+
+ info->model = snf->model;
+ info->chipsize = snf->size;
+ info->blocksize = snf->erasesize;
+ info->pagesize = snf->writesize;
+ info->sparesize = snf->oobsize;
+ info->spare_per_sector = snf->spare_per_sector;
+ info->fdm_size = snf->nfi_soc->fdm_size;
+ info->fdm_ecc_size = snf->nfi_soc->fdm_ecc_size;
+ info->num_sectors = snf->ecc_steps;
+ info->sector_size = snf->nfi_soc->sector_size;
+ info->ecc_strength = snf->ecc_strength;
+ info->ecc_bytes = snf->ecc_bytes;
+
+ return 0;
+}
+
+int mtk_snand_irq_process(struct mtk_snand *snf)
+{
+ uint32_t sta, ien;
+
+ if (!snf)
+ return -EINVAL;
+
+ sta = nfi_read32(snf, NFI_INTR_STA);
+ ien = nfi_read32(snf, NFI_INTR_EN);
+
+ if (!(sta & ien))
+ return 0;
+
+ nfi_write32(snf, NFI_INTR_EN, 0);
+ irq_completion_done(snf->pdev);
+
+ return 1;
+}
+
+static int mtk_snand_select_spare_per_sector(struct mtk_snand *snf)
+{
+ uint32_t spare_per_step = snf->oobsize / snf->ecc_steps;
+ int i, mul = 1;
+
+ /*
+ * If we're using the 1KB sector size, HW will automatically
+ * double the spare size. So we should only use half of the value.
+ */
+ if (snf->nfi_soc->sector_size == 1024)
+ mul = 2;
+
+ spare_per_step /= mul;
+
+ for (i = snf->nfi_soc->num_spare_size - 1; i >= 0; i--) {
+ if (snf->nfi_soc->spare_sizes[i] <= spare_per_step) {
+ snf->spare_per_sector = snf->nfi_soc->spare_sizes[i];
+ snf->spare_per_sector *= mul;
+ return i;
+ }
+ }
+
+ snand_log_nfi(snf->pdev,
+ "Page size %u+%u is not supported\n", snf->writesize,
+ snf->oobsize);
+
+ return -1;
+}
+
+static int mtk_snand_pagefmt_setup(struct mtk_snand *snf)
+{
+ uint32_t spare_size_idx, spare_size_shift, pagesize_idx;
+ uint32_t sector_size_512;
+
+ if (snf->nfi_soc->sector_size == 512) {
+ sector_size_512 = NFI_SEC_SEL_512;
+ spare_size_shift = NFI_SPARE_SIZE_S;
+ } else {
+ sector_size_512 = 0;
+ spare_size_shift = NFI_SPARE_SIZE_LS_S;
+ }
+
+ switch (snf->writesize) {
+ case SZ_512:
+ pagesize_idx = NFI_PAGE_SIZE_512_2K;
+ break;
+ case SZ_2K:
+ if (snf->nfi_soc->sector_size == 512)
+ pagesize_idx = NFI_PAGE_SIZE_2K_4K;
+ else
+ pagesize_idx = NFI_PAGE_SIZE_512_2K;
+ break;
+ case SZ_4K:
+ if (snf->nfi_soc->sector_size == 512)
+ pagesize_idx = NFI_PAGE_SIZE_4K_8K;
+ else
+ pagesize_idx = NFI_PAGE_SIZE_2K_4K;
+ break;
+ case SZ_8K:
+ if (snf->nfi_soc->sector_size == 512)
+ pagesize_idx = NFI_PAGE_SIZE_8K_16K;
+ else
+ pagesize_idx = NFI_PAGE_SIZE_4K_8K;
+ break;
+ case SZ_16K:
+ pagesize_idx = NFI_PAGE_SIZE_8K_16K;
+ break;
+ default:
+ snand_log_nfi(snf->pdev, "Page size %u is not supported\n",
+ snf->writesize);
+ return -ENOTSUPP;
+ }
+
+ spare_size_idx = mtk_snand_select_spare_per_sector(snf);
+ if (unlikely(spare_size_idx < 0))
+ return -ENOTSUPP;
+
+ snf->raw_sector_size = snf->nfi_soc->sector_size +
+ snf->spare_per_sector;
+
+ /* Setup page format */
+ nfi_write32(snf, NFI_PAGEFMT,
+ (snf->nfi_soc->fdm_ecc_size << NFI_FDM_ECC_NUM_S) |
+ (snf->nfi_soc->fdm_size << NFI_FDM_NUM_S) |
+ (spare_size_idx << spare_size_shift) |
+ (pagesize_idx << NFI_PAGE_SIZE_S) |
+ sector_size_512);
+
+ return 0;
+}
+
+static enum snand_flash_io mtk_snand_select_opcode(struct mtk_snand *snf,
+ uint32_t snfi_caps, uint8_t *opcode,
+ uint8_t *dummy,
+ const struct snand_io_cap *op_cap)
+{
+ uint32_t i, caps;
+
+ caps = snfi_caps & op_cap->caps;
+
+ i = fls(caps);
+ if (i > 0) {
+ *opcode = op_cap->opcodes[i - 1].opcode;
+ if (dummy)
+ *dummy = op_cap->opcodes[i - 1].dummy;
+ return i - 1;
+ }
+
+ return __SNAND_IO_MAX;
+}
+
+static int mtk_snand_select_opcode_rfc(struct mtk_snand *snf,
+ uint32_t snfi_caps,
+ const struct snand_io_cap *op_cap)
+{
+ enum snand_flash_io idx;
+
+ static const uint8_t rfc_modes[__SNAND_IO_MAX] = {
+ [SNAND_IO_1_1_1] = DATA_READ_MODE_X1,
+ [SNAND_IO_1_1_2] = DATA_READ_MODE_X2,
+ [SNAND_IO_1_2_2] = DATA_READ_MODE_DUAL,
+ [SNAND_IO_1_1_4] = DATA_READ_MODE_X4,
+ [SNAND_IO_1_4_4] = DATA_READ_MODE_QUAD,
+ };
+
+ idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_rfc,
+ &snf->dummy_rfc, op_cap);
+ if (idx >= __SNAND_IO_MAX) {
+ snand_log_snfi(snf->pdev,
+ "No capable opcode for read from cache\n");
+ return -ENOTSUPP;
+ }
+
+ snf->mode_rfc = rfc_modes[idx];
+
+ if (idx == SNAND_IO_1_1_4 || idx == SNAND_IO_1_4_4)
+ snf->quad_spi_op = true;
+
+ return 0;
+}
+
+static int mtk_snand_select_opcode_pl(struct mtk_snand *snf, uint32_t snfi_caps,
+ const struct snand_io_cap *op_cap)
+{
+ enum snand_flash_io idx;
+
+ static const uint8_t pl_modes[__SNAND_IO_MAX] = {
+ [SNAND_IO_1_1_1] = 0,
+ [SNAND_IO_1_1_4] = 1,
+ };
+
+ idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_pl,
+ NULL, op_cap);
+ if (idx >= __SNAND_IO_MAX) {
+ snand_log_snfi(snf->pdev,
+ "No capable opcode for program load\n");
+ return -ENOTSUPP;
+ }
+
+ snf->mode_pl = pl_modes[idx];
+
+ if (idx == SNAND_IO_1_1_4)
+ snf->quad_spi_op = true;
+
+ return 0;
+}
+
+static int mtk_snand_setup(struct mtk_snand *snf,
+ const struct snand_flash_info *snand_info)
+{
+ const struct snand_mem_org *memorg = &snand_info->memorg;
+ uint32_t i, msg_size, snfi_caps;
+ int ret;
+
+ /* Calculate flash memory organization */
+ snf->model = snand_info->model;
+ snf->writesize = memorg->pagesize;
+ snf->oobsize = memorg->sparesize;
+ snf->erasesize = snf->writesize * memorg->pages_per_block;
+ snf->die_size = (uint64_t)snf->erasesize * memorg->blocks_per_die;
+ snf->size = snf->die_size * memorg->ndies;
+ snf->num_dies = memorg->ndies;
+
+ snf->writesize_mask = snf->writesize - 1;
+ snf->erasesize_mask = snf->erasesize - 1;
+ snf->die_mask = snf->die_size - 1;
+
+ snf->writesize_shift = ffs(snf->writesize) - 1;
+ snf->erasesize_shift = ffs(snf->erasesize) - 1;
+ snf->die_shift = mtk_snand_ffs64(snf->die_size) - 1;
+
+ snf->select_die = snand_info->select_die;
+
+ /* Determine opcodes for read from cache/program load */
+ snfi_caps = SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2;
+ if (snf->snfi_quad_spi)
+ snfi_caps |= SPI_IO_1_1_4 | SPI_IO_1_4_4;
+
+ ret = mtk_snand_select_opcode_rfc(snf, snfi_caps, snand_info->cap_rd);
+ if (ret)
+ return ret;
+
+ ret = mtk_snand_select_opcode_pl(snf, snfi_caps, snand_info->cap_pl);
+ if (ret)
+ return ret;
+
+ /* ECC and page format */
+ snf->ecc_steps = snf->writesize / snf->nfi_soc->sector_size;
+ if (snf->ecc_steps > snf->nfi_soc->max_sectors) {
+ snand_log_nfi(snf->pdev, "Page size %u is not supported\n",
+ snf->writesize);
+ return -ENOTSUPP;
+ }
+
+ ret = mtk_snand_pagefmt_setup(snf);
+ if (ret)
+ return ret;
+
+ msg_size = snf->nfi_soc->sector_size + snf->nfi_soc->fdm_ecc_size;
+ ret = mtk_ecc_setup(snf, snf->nfi_base + NFI_FDM0L,
+ snf->spare_per_sector - snf->nfi_soc->fdm_size,
+ msg_size);
+ if (ret)
+ return ret;
+
+ nfi_write16(snf, NFI_CNFG, 0);
+
+ /* Tuning options */
+ nfi_write16(snf, NFI_DEBUG_CON1, WBUF_EN);
+ nfi_write32(snf, SNF_DLY_CTL3, (40 << SFCK_SAM_DLY_S));
+
+ /* Interrupts */
+ nfi_read32(snf, NFI_INTR_STA);
+ nfi_write32(snf, NFI_INTR_EN, 0);
+
+ /* Clear SNF done flag */
+ nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE | CUS_PG_DONE);
+ nfi_write32(snf, SNF_STA_CTL1, 0);
+
+ /* Initialization on all dies */
+ for (i = 0; i < snf->num_dies; i++) {
+ mtk_snand_select_die(snf, i);
+
+ /* Disable On-Die ECC engine */
+ ret = mtk_snand_ondie_ecc_control(snf, false);
+ if (ret)
+ return ret;
+
+ /* Disable block protection */
+ mtk_snand_unlock(snf);
+
+ /* Enable/disable quad-spi */
+ mtk_snand_qspi_control(snf, snf->quad_spi_op);
+ }
+
+ mtk_snand_select_die(snf, 0);
+
+ return 0;
+}
+
+static int mtk_snand_id_probe(struct mtk_snand *snf,
+ const struct snand_flash_info **snand_info)
+{
+ uint8_t id[4], op[2];
+ int ret;
+
+ /* Read SPI-NAND JEDEC ID, OP + dummy/addr + ID */
+ op[0] = SNAND_CMD_READID;
+ op[1] = 0;
+ ret = mtk_snand_mac_io(snf, op, 2, id, sizeof(id));
+ if (ret)
+ return ret;
+
+ *snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id);
+ if (*snand_info)
+ return 0;
+
+ /* Read SPI-NAND JEDEC ID, OP + ID */
+ op[0] = SNAND_CMD_READID;
+ ret = mtk_snand_mac_io(snf, op, 1, id, sizeof(id));
+ if (ret)
+ return ret;
+
+ *snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id);
+ if (*snand_info)
+ return 0;
+
+ snand_log_chip(snf->pdev,
+ "Unrecognized SPI-NAND ID: %02x %02x %02x %02x\n",
+ id[0], id[1], id[2], id[3]);
+
+ return -EINVAL;
+}
+
+int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata,
+ struct mtk_snand **psnf)
+{
+ const struct snand_flash_info *snand_info;
+ struct mtk_snand tmpsnf, *snf;
+ uint32_t rawpage_size;
+ int ret;
+
+ if (!pdata || !psnf)
+ return -EINVAL;
+
+ if (pdata->soc >= __SNAND_SOC_MAX) {
+ snand_log_chip(dev, "Invalid SOC %u for MTK-SNAND\n",
+ pdata->soc);
+ return -EINVAL;
+ }
+
+ /* Dummy instance only for initial reset and id probe */
+ tmpsnf.nfi_base = pdata->nfi_base;
+ tmpsnf.ecc_base = pdata->ecc_base;
+ tmpsnf.soc = pdata->soc;
+ tmpsnf.nfi_soc = &mtk_snand_socs[pdata->soc];
+ tmpsnf.pdev = dev;
+
+ /* Switch to SNFI mode */
+ writel(SPI_MODE, tmpsnf.nfi_base + SNF_CFG);
+
+ /* Reset SNFI & NFI */
+ mtk_snand_mac_reset(&tmpsnf);
+ mtk_nfi_reset(&tmpsnf);
+
+ /* Reset SPI-NAND chip */
+ ret = mtk_snand_chip_reset(&tmpsnf);
+ if (ret) {
+ snand_log_chip(dev, "Failed to reset SPI-NAND chip\n");
+ return ret;
+ }
+
+ /* Probe SPI-NAND flash by JEDEC ID */
+ ret = mtk_snand_id_probe(&tmpsnf, &snand_info);
+ if (ret)
+ return ret;
+
+ rawpage_size = snand_info->memorg.pagesize +
+ snand_info->memorg.sparesize;
+
+ /* Allocate memory for instance and cache */
+ snf = generic_mem_alloc(dev, sizeof(*snf) + rawpage_size);
+ if (!snf) {
+ snand_log_chip(dev, "Failed to allocate memory for instance\n");
+ return -ENOMEM;
+ }
+
+ snf->buf_cache = (uint8_t *)((uintptr_t)snf + sizeof(*snf));
+
+ /* Allocate memory for DMA buffer */
+ snf->page_cache = dma_mem_alloc(dev, rawpage_size);
+ if (!snf->page_cache) {
+ generic_mem_free(dev, snf);
+ snand_log_chip(dev,
+ "Failed to allocate memory for DMA buffer\n");
+ return -ENOMEM;
+ }
+
+ /* Fill up instance */
+ snf->pdev = dev;
+ snf->nfi_base = pdata->nfi_base;
+ snf->ecc_base = pdata->ecc_base;
+ snf->soc = pdata->soc;
+ snf->nfi_soc = &mtk_snand_socs[pdata->soc];
+ snf->snfi_quad_spi = pdata->quad_spi;
+
+ /* Initialize SNFI & ECC engine */
+ ret = mtk_snand_setup(snf, snand_info);
+ if (ret) {
+ dma_mem_free(dev, snf->page_cache);
+ generic_mem_free(dev, snf);
+ return ret;
+ }
+
+ *psnf = snf;
+
+ return 0;
+}
+
+int mtk_snand_cleanup(struct mtk_snand *snf)
+{
+ if (!snf)
+ return 0;
+
+ dma_mem_free(snf->pdev, snf->page_cache);
+ generic_mem_free(snf->pdev, snf);
+
+ return 0;
+}
diff --git a/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.h b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.h
new file mode 100644
index 0000000..382f80c
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_SNAND_H_
+#define _MTK_SNAND_H_
+
+#ifndef PRIVATE_MTK_SNAND_HEADER
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#endif
+
+enum mtk_snand_soc {
+ SNAND_SOC_MT7622,
+ SNAND_SOC_MT7629,
+ SNAND_SOC_MT7986,
+
+ __SNAND_SOC_MAX
+};
+
+struct mtk_snand_platdata {
+ void *nfi_base;
+ void *ecc_base;
+ enum mtk_snand_soc soc;
+ bool quad_spi;
+};
+
+struct mtk_snand_chip_info {
+ const char *model;
+ uint64_t chipsize;
+ uint32_t blocksize;
+ uint32_t pagesize;
+ uint32_t sparesize;
+ uint32_t spare_per_sector;
+ uint32_t fdm_size;
+ uint32_t fdm_ecc_size;
+ uint32_t num_sectors;
+ uint32_t sector_size;
+ uint32_t ecc_strength;
+ uint32_t ecc_bytes;
+};
+
+struct mtk_snand;
+struct snand_flash_info;
+
+int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata,
+ struct mtk_snand **psnf);
+int mtk_snand_cleanup(struct mtk_snand *snf);
+
+int mtk_snand_chip_reset(struct mtk_snand *snf);
+int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf,
+ void *oob, bool raw);
+int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf,
+ const void *oob, bool raw);
+int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr);
+int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr);
+int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr);
+int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw,
+ const uint8_t *oobbuf, size_t ooblen);
+int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf,
+ size_t ooblen, const uint8_t *oobraw);
+int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+ void *buf, void *oob, size_t ooblen,
+ size_t *actualooblen, bool raw);
+int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+ const void *buf, const void *oob,
+ size_t ooblen, size_t *actualooblen,
+ bool raw);
+int mtk_snand_get_chip_info(struct mtk_snand *snf,
+ struct mtk_snand_chip_info *info);
+int mtk_snand_irq_process(struct mtk_snand *snf);
+
+#endif /* _MTK_SNAND_H_ */
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/Kconfig b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/Kconfig
new file mode 100755
index 0000000..b097f52
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/Kconfig
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config NET_VENDOR_MEDIATEK
+ bool "MediaTek ethernet driver"
+ depends on ARCH_MEDIATEK || SOC_MT7621 || SOC_MT7620
+ ---help---
+ If you have a Mediatek SoC with ethernet, say Y.
+
+if NET_VENDOR_MEDIATEK
+
+config NET_MEDIATEK_SOC
+ tristate "MediaTek SoC Gigabit Ethernet support"
+ select PHYLINK
+ ---help---
+ This driver supports the gigabit ethernet MACs in the
+ MediaTek SoC family.
+
+config MEDIATEK_NETSYS_V2
+ tristate "MediaTek Ethernet NETSYS V2 support"
+ depends on ARCH_MEDIATEK && NET_MEDIATEK_SOC
+ ---help---
+ This options enable MTK Ethernet NETSYS V2 support
+
+config NET_MEDIATEK_HNAT
+ tristate "MediaTek HW NAT support"
+ depends on NET_MEDIATEK_SOC && NF_CONNTRACK && IP_NF_NAT
+ ---help---
+ This driver supports the hardward Network Address Translation
+ in the MediaTek MT7986/MT2701/MT7622/MT7629/MT7621 chipset
+ family.
+
+config NET_MEDIATEK_HW_QOS
+ bool "Mediatek HW QoS support"
+ depends on NET_MEDIATEK_HNAT
+ default n
+ ---help---
+ This driver supports the hardward
+ quality of service (QoS) control
+ for the hardware NAT in the
+ MediaTek chipset family.
+
+endif #NET_VENDOR_MEDIATEK
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/Makefile b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/Makefile
new file mode 100755
index 0000000..f046e73
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Mediatek SoCs built-in ethernet macs
+#
+
+obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
+mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_eth_dbg.o
+obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtk_hnat/
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
new file mode 100755
index 0000000..82aa6ca
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/trace_seq.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/of_mdio.h>
+
+#include "mtk_eth_soc.h"
+#include "mtk_eth_dbg.h"
+
+struct mtk_eth_debug {
+ struct dentry *root;
+};
+
+struct mtk_eth *g_eth;
+
+struct mtk_eth_debug eth_debug;
+
+void mt7530_mdio_w32(struct mtk_eth *eth, u32 reg, u32 val)
+{
+ mutex_lock(ð->mii_bus->mdio_lock);
+
+ _mtk_mdio_write(eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+ _mtk_mdio_write(eth, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
+ _mtk_mdio_write(eth, 0x1f, 0x10, val >> 16);
+
+ mutex_unlock(ð->mii_bus->mdio_lock);
+}
+
+u32 mt7530_mdio_r32(struct mtk_eth *eth, u32 reg)
+{
+ u16 high, low;
+
+ mutex_lock(ð->mii_bus->mdio_lock);
+
+ _mtk_mdio_write(eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+ low = _mtk_mdio_read(eth, 0x1f, (reg >> 2) & 0xf);
+ high = _mtk_mdio_read(eth, 0x1f, 0x10);
+
+ mutex_unlock(ð->mii_bus->mdio_lock);
+
+ return (high << 16) | (low & 0xffff);
+}
+
+void mtk_switch_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+{
+ mtk_w32(eth, val, reg + 0x10000);
+}
+EXPORT_SYMBOL(mtk_switch_w32);
+
+u32 mtk_switch_r32(struct mtk_eth *eth, unsigned reg)
+{
+ return mtk_r32(eth, reg + 0x10000);
+}
+EXPORT_SYMBOL(mtk_switch_r32);
+
+static int mtketh_debug_show(struct seq_file *m, void *private)
+{
+ struct mtk_eth *eth = m->private;
+ struct mtk_mac *mac = 0;
+ u32 d;
+ int i, j = 0;
+
+ for (i = 0 ; i < MTK_MAX_DEVS ; i++) {
+ if (!eth->mac[i] ||
+ of_phy_is_fixed_link(eth->mac[i]->of_node))
+ continue;
+ mac = eth->mac[i];
+#if 0 //FIXME
+ while (j < 30) {
+ d = _mtk_mdio_read(eth, mac->phy_dev->addr, j);
+
+ seq_printf(m, "phy=%d, reg=0x%08x, data=0x%08x\n",
+ mac->phy_dev->addr, j, d);
+ j++;
+ }
+#endif
+ }
+ return 0;
+}
+
+static int mtketh_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtketh_debug_show, inode->i_private);
+}
+
+static const struct file_operations mtketh_debug_fops = {
+ .open = mtketh_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mtketh_mt7530sw_debug_show(struct seq_file *m, void *private)
+{
+ struct mtk_eth *eth = m->private;
+ u32 offset, data;
+ int i;
+ struct mt7530_ranges {
+ u32 start;
+ u32 end;
+ } ranges[] = {
+ {0x0, 0xac},
+ {0x1000, 0x10e0},
+ {0x1100, 0x1140},
+ {0x1200, 0x1240},
+ {0x1300, 0x1340},
+ {0x1400, 0x1440},
+ {0x1500, 0x1540},
+ {0x1600, 0x1640},
+ {0x1800, 0x1848},
+ {0x1900, 0x1948},
+ {0x1a00, 0x1a48},
+ {0x1b00, 0x1b48},
+ {0x1c00, 0x1c48},
+ {0x1d00, 0x1d48},
+ {0x1e00, 0x1e48},
+ {0x1f60, 0x1ffc},
+ {0x2000, 0x212c},
+ {0x2200, 0x222c},
+ {0x2300, 0x232c},
+ {0x2400, 0x242c},
+ {0x2500, 0x252c},
+ {0x2600, 0x262c},
+ {0x3000, 0x3014},
+ {0x30c0, 0x30f8},
+ {0x3100, 0x3114},
+ {0x3200, 0x3214},
+ {0x3300, 0x3314},
+ {0x3400, 0x3414},
+ {0x3500, 0x3514},
+ {0x3600, 0x3614},
+ {0x4000, 0x40d4},
+ {0x4100, 0x41d4},
+ {0x4200, 0x42d4},
+ {0x4300, 0x43d4},
+ {0x4400, 0x44d4},
+ {0x4500, 0x45d4},
+ {0x4600, 0x46d4},
+ {0x4f00, 0x461c},
+ {0x7000, 0x7038},
+ {0x7120, 0x7124},
+ {0x7800, 0x7804},
+ {0x7810, 0x7810},
+ {0x7830, 0x7830},
+ {0x7a00, 0x7a7c},
+ {0x7b00, 0x7b04},
+ {0x7e00, 0x7e04},
+ {0x7ffc, 0x7ffc},
+ };
+
+ if (!mt7530_exist(eth))
+ return -EOPNOTSUPP;
+
+ if ((!eth->mac[0] || !of_phy_is_fixed_link(eth->mac[0]->of_node)) &&
+ (!eth->mac[1] || !of_phy_is_fixed_link(eth->mac[1]->of_node))) {
+ seq_puts(m, "no switch found\n");
+ return 0;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(ranges) ; i++) {
+ for (offset = ranges[i].start;
+ offset <= ranges[i].end; offset += 4) {
+ data = mt7530_mdio_r32(eth, offset);
+ seq_printf(m, "mt7530 switch reg=0x%08x, data=0x%08x\n",
+ offset, data);
+ }
+ }
+
+ return 0;
+}
+
+static int mtketh_debug_mt7530sw_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtketh_mt7530sw_debug_show, inode->i_private);
+}
+
+static const struct file_operations mtketh_debug_mt7530sw_fops = {
+ .open = mtketh_debug_mt7530sw_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t mtketh_mt7530sw_debugfs_write(struct file *file,
+ const char __user *ptr,
+ size_t len, loff_t *off)
+{
+ struct mtk_eth *eth = file->private_data;
+ char buf[32], *token, *p = buf;
+ u32 reg, value, phy;
+ int ret;
+
+ if (!mt7530_exist(eth))
+ return -EOPNOTSUPP;
+
+ if (*off != 0)
+ return 0;
+
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+
+ ret = strncpy_from_user(buf, ptr, len);
+ if (ret < 0)
+ return ret;
+ buf[len] = '\0';
+
+ token = strsep(&p, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtoul(token, 16, (unsigned long *)&phy))
+ return -EINVAL;
+
+ token = strsep(&p, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtoul(token, 16, (unsigned long *)®))
+ return -EINVAL;
+
+ token = strsep(&p, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtoul(token, 16, (unsigned long *)&value))
+ return -EINVAL;
+
+ pr_info("%s:phy=%d, reg=0x%x, val=0x%x\n", __func__,
+ 0x1f, reg, value);
+ mt7530_mdio_w32(eth, reg, value);
+ pr_info("%s:phy=%d, reg=0x%x, val=0x%x confirm..\n", __func__,
+ 0x1f, reg, mt7530_mdio_r32(eth, reg));
+
+ return len;
+}
+
+static ssize_t mtketh_debugfs_write(struct file *file, const char __user *ptr,
+ size_t len, loff_t *off)
+{
+ struct mtk_eth *eth = file->private_data;
+ char buf[32], *token, *p = buf;
+ u32 reg, value, phy;
+ int ret;
+
+ if (*off != 0)
+ return 0;
+
+ if (len > sizeof(buf) - 1)
+ len = sizeof(buf) - 1;
+
+ ret = strncpy_from_user(buf, ptr, len);
+ if (ret < 0)
+ return ret;
+ buf[len] = '\0';
+
+ token = strsep(&p, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtoul(token, 16, (unsigned long *)&phy))
+ return -EINVAL;
+
+ token = strsep(&p, " ");
+
+ if (!token)
+ return -EINVAL;
+ if (kstrtoul(token, 16, (unsigned long *)®))
+ return -EINVAL;
+
+ token = strsep(&p, " ");
+
+ if (!token)
+ return -EINVAL;
+ if (kstrtoul(token, 16, (unsigned long *)&value))
+ return -EINVAL;
+
+ pr_info("%s:phy=%d, reg=0x%x, val=0x%x\n", __func__,
+ phy, reg, value);
+
+ _mtk_mdio_write(eth, phy, reg, value);
+
+ pr_info("%s:phy=%d, reg=0x%x, val=0x%x confirm..\n", __func__,
+ phy, reg, _mtk_mdio_read(eth, phy, reg));
+
+ return len;
+}
+
+static ssize_t mtketh_debugfs_reset(struct file *file, const char __user *ptr,
+ size_t len, loff_t *off)
+{
+ struct mtk_eth *eth = file->private_data;
+
+ schedule_work(ð->pending_work);
+ return len;
+}
+
+static const struct file_operations fops_reg_w = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = mtketh_debugfs_write,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations fops_eth_reset = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = mtketh_debugfs_reset,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations fops_mt7530sw_reg_w = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = mtketh_mt7530sw_debugfs_write,
+ .llseek = noop_llseek,
+};
+
+void mtketh_debugfs_exit(struct mtk_eth *eth)
+{
+ debugfs_remove_recursive(eth_debug.root);
+}
+
+int mtketh_debugfs_init(struct mtk_eth *eth)
+{
+ int ret = 0;
+
+ eth_debug.root = debugfs_create_dir("mtketh", NULL);
+ if (!eth_debug.root) {
+ dev_notice(eth->dev, "%s:err at %d\n", __func__, __LINE__);
+ ret = -ENOMEM;
+ }
+
+ debugfs_create_file("phy_regs", S_IRUGO,
+ eth_debug.root, eth, &mtketh_debug_fops);
+ debugfs_create_file("phy_reg_w", S_IFREG | S_IWUSR,
+ eth_debug.root, eth, &fops_reg_w);
+ debugfs_create_file("reset", S_IFREG | S_IWUSR,
+ eth_debug.root, eth, &fops_eth_reset);
+ if (mt7530_exist(eth)) {
+ debugfs_create_file("mt7530sw_regs", S_IRUGO,
+ eth_debug.root, eth,
+ &mtketh_debug_mt7530sw_fops);
+ debugfs_create_file("mt7530sw_reg_w", S_IFREG | S_IWUSR,
+ eth_debug.root, eth,
+ &fops_mt7530sw_reg_w);
+ }
+ return ret;
+}
+
+void mii_mgr_read_combine(struct mtk_eth *eth, u32 phy_addr, u32 phy_register,
+ u32 *read_data)
+{
+ if (mt7530_exist(eth) && phy_addr == 31)
+ *read_data = mt7530_mdio_r32(eth, phy_register);
+
+ else
+ *read_data = _mtk_mdio_read(eth, phy_addr, phy_register);
+}
+
+void mii_mgr_write_combine(struct mtk_eth *eth, u32 phy_addr, u32 phy_register,
+ u32 write_data)
+{
+ if (mt7530_exist(eth) && phy_addr == 31)
+ mt7530_mdio_w32(eth, phy_register, write_data);
+
+ else
+ _mtk_mdio_write(eth, phy_addr, phy_register, write_data);
+}
+
+static void mii_mgr_read_cl45(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 *data)
+{
+ mtk_cl45_ind_read(eth, port, devad, reg, data);
+}
+
+static void mii_mgr_write_cl45(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 data)
+{
+ mtk_cl45_ind_write(eth, port, devad, reg, data);
+}
+
+int mtk_do_priv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_mii_ioctl_data mii;
+ struct mtk_esw_reg reg;
+
+ switch (cmd) {
+ case MTKETH_MII_READ:
+ if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+ goto err_copy;
+ mii_mgr_read_combine(eth, mii.phy_id, mii.reg_num,
+ &mii.val_out);
+ if (copy_to_user(ifr->ifr_data, &mii, sizeof(mii)))
+ goto err_copy;
+
+ return 0;
+ case MTKETH_MII_WRITE:
+ if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+ goto err_copy;
+ mii_mgr_write_combine(eth, mii.phy_id, mii.reg_num,
+ mii.val_in);
+
+ return 0;
+ case MTKETH_MII_READ_CL45:
+ if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+ goto err_copy;
+ mii_mgr_read_cl45(eth, mii.port_num, mii.dev_addr, mii.reg_addr,
+ &mii.val_out);
+ if (copy_to_user(ifr->ifr_data, &mii, sizeof(mii)))
+ goto err_copy;
+
+ return 0;
+ case MTKETH_MII_WRITE_CL45:
+ if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+ goto err_copy;
+ mii_mgr_write_cl45(eth, mii.port_num, mii.dev_addr, mii.reg_addr,
+ mii.val_in);
+ return 0;
+ case MTKETH_ESW_REG_READ:
+ if (!mt7530_exist(eth))
+ return -EOPNOTSUPP;
+ if (copy_from_user(®, ifr->ifr_data, sizeof(reg)))
+ goto err_copy;
+ if (reg.off > REG_ESW_MAX)
+ return -EINVAL;
+ reg.val = mtk_switch_r32(eth, reg.off);
+
+ if (copy_to_user(ifr->ifr_data, ®, sizeof(reg)))
+ goto err_copy;
+
+ return 0;
+ case MTKETH_ESW_REG_WRITE:
+ if (!mt7530_exist(eth))
+ return -EOPNOTSUPP;
+ if (copy_from_user(®, ifr->ifr_data, sizeof(reg)))
+ goto err_copy;
+ if (reg.off > REG_ESW_MAX)
+ return -EINVAL;
+ mtk_switch_w32(eth, reg.val, reg.off);
+
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+err_copy:
+ return -EFAULT;
+}
+
+int esw_cnt_read(struct seq_file *seq, void *v)
+{
+ unsigned int pkt_cnt = 0;
+ int i = 0;
+ struct mtk_eth *eth = g_eth;
+ unsigned int mib_base = MTK_GDM1_TX_GBCNT;
+
+ seq_puts(seq, "\n <<CPU>>\n");
+ seq_puts(seq, " |\n");
+ seq_puts(seq, "+-----------------------------------------------+\n");
+ seq_puts(seq, "| <<PSE>> |\n");
+ seq_puts(seq, "+-----------------------------------------------+\n");
+ seq_puts(seq, " |\n");
+ seq_puts(seq, "+-----------------------------------------------+\n");
+ seq_puts(seq, "| <<GDMA>> |\n");
+ seq_printf(seq, "| GDMA1_RX_GBCNT : %010u (Rx Good Bytes) |\n",
+ mtk_r32(eth, mib_base));
+ seq_printf(seq, "| GDMA1_RX_GPCNT : %010u (Rx Good Pkts) |\n",
+ mtk_r32(eth, mib_base+0x08));
+ seq_printf(seq, "| GDMA1_RX_OERCNT : %010u (overflow error) |\n",
+ mtk_r32(eth, mib_base+0x10));
+ seq_printf(seq, "| GDMA1_RX_FERCNT : %010u (FCS error) |\n",
+ mtk_r32(eth, mib_base+0x14));
+ seq_printf(seq, "| GDMA1_RX_SERCNT : %010u (too short) |\n",
+ mtk_r32(eth, mib_base+0x18));
+ seq_printf(seq, "| GDMA1_RX_LERCNT : %010u (too long) |\n",
+ mtk_r32(eth, mib_base+0x1C));
+ seq_printf(seq, "| GDMA1_RX_CERCNT : %010u (checksum error) |\n",
+ mtk_r32(eth, mib_base+0x20));
+ seq_printf(seq, "| GDMA1_RX_FCCNT : %010u (flow control) |\n",
+ mtk_r32(eth, mib_base+0x24));
+ seq_printf(seq, "| GDMA1_TX_SKIPCNT: %010u (about count) |\n",
+ mtk_r32(eth, mib_base+0x28));
+ seq_printf(seq, "| GDMA1_TX_COLCNT : %010u (collision count) |\n",
+ mtk_r32(eth, mib_base+0x2C));
+ seq_printf(seq, "| GDMA1_TX_GBCNT : %010u (Tx Good Bytes) |\n",
+ mtk_r32(eth, mib_base+0x30));
+ seq_printf(seq, "| GDMA1_TX_GPCNT : %010u (Tx Good Pkts) |\n",
+ mtk_r32(eth, mib_base+0x38));
+ seq_puts(seq, "| |\n");
+ seq_printf(seq, "| GDMA2_RX_GBCNT : %010u (Rx Good Bytes) |\n",
+ mtk_r32(eth, mib_base+0x40));
+ seq_printf(seq, "| GDMA2_RX_GPCNT : %010u (Rx Good Pkts) |\n",
+ mtk_r32(eth, mib_base+0x48));
+ seq_printf(seq, "| GDMA2_RX_OERCNT : %010u (overflow error) |\n",
+ mtk_r32(eth, mib_base+0x50));
+ seq_printf(seq, "| GDMA2_RX_FERCNT : %010u (FCS error) |\n",
+ mtk_r32(eth, mib_base+0x54));
+ seq_printf(seq, "| GDMA2_RX_SERCNT : %010u (too short) |\n",
+ mtk_r32(eth, mib_base+0x58));
+ seq_printf(seq, "| GDMA2_RX_LERCNT : %010u (too long) |\n",
+ mtk_r32