[][MAC80211][app][Add atenl support in eagle]

[Description]
Add atenl support in eagle

[Release-log]
N/A

Change-Id: I9446e50d6b8f30c7b84edfccde2998c34047dde1
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6983438
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/1113-mt76-testmode-add-pre-cal-support.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/1113-mt76-testmode-add-pre-cal-support.patch
index ca0c5d5..d0487c4 100644
--- a/autobuild_mac80211_release/package/kernel/mt76/patches/1113-mt76-testmode-add-pre-cal-support.patch
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/1113-mt76-testmode-add-pre-cal-support.patch
@@ -1,7 +1,7 @@
-From 027cdfa4869e252c6f2dbef992b14fa5bab4218c Mon Sep 17 00:00:00 2001
+From 5a9a2fb84939e81c67a1508b56b2d59a5d7c5937 Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Wed, 31 Aug 2022 20:06:52 +0800
-Subject: [PATCH 1113/1131] mt76: testmode: add pre-cal support
+Subject: [PATCH] mt76: testmode: add pre-cal support
 
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Change-Id: Ibfbbc3443de994eeb4daa5e364b0a90f5d7d3bcd
@@ -735,7 +735,7 @@
  	TAM_ARB_OP_MODE_NORMAL = 1,
  	TAM_ARB_OP_MODE_TEST,
 diff --git a/testmode.c b/testmode.c
-index 7a9ed54..82b8e98 100644
+index 7a9ed54..42da6f0 100644
 --- a/testmode.c
 +++ b/testmode.c
 @@ -763,6 +763,18 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
@@ -763,19 +763,19 @@
  	    (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) ||
 -	     nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset)))
 +	     nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset) ||
-+	     nla_put_u8(msg, MT76_TM_ATTR_IS_MAIN_PHY, phy == &dev->phy)))
++	     nla_put_u8(msg, MT76_TM_ATTR_BAND_IDX, phy->band_idx)))
  		goto out;
  
  	if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
 diff --git a/testmode.h b/testmode.h
-index 57949f2..e2190e7 100644
+index 57949f2..34936e5 100644
 --- a/testmode.h
 +++ b/testmode.h
 @@ -19,6 +19,7 @@
   *
   * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string)
   * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
-+ * @MT76_TM_ATTR_IS_MAIN_PHY: Is current phy index the main phy or the ext phy (u8)
++ * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
   *
   * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
   *	state to MT76_TM_STATE_TX_FRAMES (u32)
@@ -795,7 +795,7 @@
  
  	MT76_TM_ATTR_MTD_PART,
  	MT76_TM_ATTR_MTD_OFFSET,
-+	MT76_TM_ATTR_IS_MAIN_PHY,
++	MT76_TM_ATTR_BAND_IDX,
  
  	MT76_TM_ATTR_TX_COUNT,
  	MT76_TM_ATTR_TX_LENGTH,
@@ -843,5 +843,5 @@
  
  static const char * const testmode_tx_mode[] = {
 -- 
-2.36.1
+2.18.0
 
diff --git a/feed/atenl/Makefile b/feed/atenl/Makefile
index d1c9d36..b0b4744 100644
--- a/feed/atenl/Makefile
+++ b/feed/atenl/Makefile
@@ -30,6 +30,7 @@
 	$(INSTALL_BIN) $(PKG_BUILD_DIR)/atenl $(1)/usr/sbin
 	$(INSTALL_BIN) ./files/ated.sh $(1)/usr/sbin/ated
 	$(INSTALL_BIN) ./files/iwpriv.sh $(1)/usr/sbin/iwpriv
+	$(INSTALL_BIN) ./files/iwpriv.sh $(1)/usr/sbin/mwctl
 endef
 
 $(eval $(call BuildPackage,atenl))
diff --git a/feed/atenl/files/ated.sh b/feed/atenl/files/ated.sh
index 1c24083..e989e44 100755
--- a/feed/atenl/files/ated.sh
+++ b/feed/atenl/files/ated.sh
@@ -9,6 +9,8 @@
 interface=""
 phy_idx=0
 ated_file="/tmp/interface"
+SOC_start_idx="0"
+is_eagle="0"
 
 function do_cmd() {
     case ${work_mode} in
@@ -26,68 +28,128 @@
 }
 
 function record_config() {
+    local config=$1
     local tmp_file=$3
+
+    # check it is SOC(mt7986)/Eagle or PCIE card (mt7915/7916), and write its config
+    if [ ${config} != "STARTIDX" ] && [ ${config} != "IS_EAGLE" ]; then
+        if [ $phy_idx -lt $SOC_start_idx ]; then
+            config="${config}_PCIE"
+        elif [ $phy_idx -ge $SOC_start_idx ]; then
+            config="${config}_SOC"
+        fi
+    fi
+
     if [ -f ${tmp_file} ]; then
-        if grep -q $1 ${tmp_file}; then
-            sed -i "/$1/c\\$1=$2" ${tmp_file}
+        if grep -q ${config} ${tmp_file}; then
+            sed -i "/${config}/c\\${config}=$2" ${tmp_file}
         else
-            echo "$1=$2" >> ${tmp_file}
+            echo "${config}=$2" >> ${tmp_file}
         fi
     else
-        echo "$1=$2" >> ${tmp_file}
+        echo "${config}=$2" >> ${tmp_file}
     fi
 }
 
 function get_config() {
+    local config=$1
     local tmp_file=$2
+
     if [ ! -f ${tmp_file} ]; then
         echo ""
         return
     fi
 
-    if grep -q $1 ${tmp_file}; then
-        echo "$(cat ${tmp_file} | grep $1 | sed s/=/' '/g | cut -d " " -f 2)"
+    # check it is SOC(mt7986)/Eagle or PCIE card (mt7915/7916), and write its config
+    if [ ${config} != "STARTIDX" ] && [ ${config} != "IS_EAGLE" ]; then
+        if [ $phy_idx -lt $SOC_start_idx ]; then
+            config="${config}_PCIE"
+        elif [ $phy_idx -ge $SOC_start_idx ]; then
+            config="${config}_SOC"
+        fi
+    fi
+
+    if grep -q ${config} ${tmp_file}; then
+        echo "$(cat ${tmp_file} | grep ${config} | sed s/=/' '/g | cut -d " " -f 2)"
     else
         echo ""
     fi
 }
 
 function convert_interface {
-    local start_idx_7986=$(get_config "STARTIDX" ${ated_file})
+    SOC_start_idx=$(get_config "STARTIDX" ${ated_file})
+    is_eagle=$(get_config "IS_EAGLE" ${ated_file})
     local eeprom_file=/sys/kernel/debug/ieee80211/phy0/mt76/eeprom
-    if [ -z "${start_idx_7986}" ]; then
+    if [ -z "${SOC_start_idx}" ] || [ -z "${is_eagle}" ]; then
         if [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7916")" ]; then
-            start_idx_7986="2"
+            SOC_start_idx="2"
+            is_eagle="0"
         elif [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7915")" ]; then
-            start_idx_7986="1"
+            SOC_start_idx="1"
+            is_eagle="0"
         elif [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7986")" ]; then
-            start_idx_7986="0"
+            SOC_start_idx="0"
+            is_eagle="0"
+        elif [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7990")" ]; then
+            SOC_start_idx="0"
+            is_eagle="1"
         else
-            echo "Interface conversion failed!"
-            echo "Please use ated -i <phy0/phy1/..> ... or configure the sku of your board manually by the following commands"
-            echo "For AX6000: echo STARTIDX=0 >> ${ated_file}"
+            echo "Interface Conversion Failed!"
+            echo "Please use iwpriv <phy0/phy1/..> set <...> or configure the sku of your board manually by the following commands"
+            echo "For AX6000/Eagle: echo STARTIDX=0 >> ${ated_file}"
             echo "For AX7800: echo STARTIDX=2 >> ${ated_file}"
             echo "For AX8400: echo STARTIDX=1 >> ${ated_file}"
-            return 0
+            exit 0
         fi
-        record_config "STARTIDX" ${start_idx_7986} ${ated_file}
+        record_config "STARTIDX" ${SOC_start_idx} ${ated_file}
+        record_config "IS_EAGLE" ${is_eagle} ${ated_file}
     fi
 
-    if [[ $1 == "raix"* ]]; then
-        interface="phy1"
-        phy_idx=1
-    elif [[ $1 == "rai"* ]]; then
-        interface="phy0"
-        phy_idx=0
-    elif [[ $1 == "rax"* ]]; then
-        phy_idx=$((start_idx_7986+1))
-        interface="phy${phy_idx}"
+
+    if [ ${is_eagle} == "0" ]; then
+        if [[ $1 == "raix"* ]]; then
+            phy_idx=1
+        elif [[ $1 == "rai"* ]]; then
+            phy_idx=0
+        elif [[ $1 == "rax"* ]]; then
+            phy_idx=$((SOC_start_idx+1))
+        else
+            phy_idx=$SOC_start_idx
+        fi
+
+        # convert phy index according to band idx
+        local band_idx=$(get_config "ATECTRLBANDIDX" ${ated_file})
+        if [ "${band_idx}" = "0" ]; then
+            if [[ $1 == "raix"* ]]; then
+                phy_idx=0
+            elif [[ $1 == "rax"* ]]; then
+                phy_idx=$SOC_start_idx
+            fi
+        elif [ "${band_idx}" = "1" ]; then
+            if [[ $1 == "rai"* ]]; then
+                # AX8400: mt7915 remain phy0
+                # AX7800: mt7916 becomes phy1
+                phy_idx=$((SOC_start_idx-1))
+            elif [[ $1 == "ra"* ]]; then
+                phy_idx=$((SOC_start_idx+1))
+            fi
+        fi
     else
-        phy_idx=$start_idx_7986
-        interface="phy${phy_idx}"
+        # Eagle has different mapping method
+        # phy0: ra0
+        # phy1: rai0
+        # phy2: rax0
+        if [[ $1 == "rai"* ]]; then
+            phy_idx=1
+        elif [[ $1 == "rax"* ]]; then
+            phy_idx=2
+        else
+            phy_idx=0
+        fi
     fi
-}
 
+    interface="phy${phy_idx}"
+}
 
 for i in "$@"
 do
diff --git a/feed/atenl/files/iwpriv.sh b/feed/atenl/files/iwpriv.sh
index f1162ba..f606f74 100755
--- a/feed/atenl/files/iwpriv.sh
+++ b/feed/atenl/files/iwpriv.sh
@@ -1,10 +1,11 @@
 #!/bin/ash
 
 interface=$1    # phy0/phy1/ra0
-cmd_type=$2     # set/show/e2p/mac
+cmd_type=$2     # set/show/e2p/mac/dump
 full_cmd=$3
 interface_ori=${interface}
-start_idx_7986="0"
+SOC_start_idx="0"
+is_eagle="0"
 
 work_mode="RUN" # RUN/PRINT/DEBUG
 iwpriv_file="/tmp/iwpriv_wrapper"
@@ -40,12 +41,12 @@
     local config=$1
     local tmp_file=$3
 
-    # check is mt7986 or mt7915/7916, and write its config
-    if [ ${config} != "STARTIDX" ]; then
-        if [ $phy_idx -lt $start_idx_7986 ]; then
+    # check it is SOC(mt7986)/Eagle or PCIE card (mt7915/7916), and write its config
+    if [ ${config} != "STARTIDX" ] && [ ${config} != "IS_EAGLE" ]; then
+        if [ $phy_idx -lt $SOC_start_idx ]; then
             config="${config}_PCIE"
-        elif [ $phy_idx -ge $start_idx_7986 ]; then
-            config="${config}_7986"
+        elif [ $phy_idx -ge $SOC_start_idx ]; then
+            config="${config}_SOC"
         fi
     fi
 
@@ -69,12 +70,12 @@
         return
     fi
 
-    # check is mt7986 or mt7915/7916, and load its config
-    if [ ${config} != "STARTIDX" ]; then
-        if [ $phy_idx -lt $start_idx_7986 ]; then
+    # check it is SOC(mt7986)/Eagle or PCIE card (mt7915/7916), and write its config
+    if [ ${config} != "STARTIDX" ] && [ ${config} != "IS_EAGLE" ]; then
+        if [ $phy_idx -lt $SOC_start_idx ]; then
             config="${config}_PCIE"
-        elif [ $phy_idx -ge $start_idx_7986 ]; then
-            config="${config}_7986"
+        elif [ $phy_idx -ge $SOC_start_idx ]; then
+            config="${config}_SOC"
         fi
     fi
 
@@ -86,51 +87,74 @@
 }
 
 function convert_interface {
-    start_idx_7986=$(get_config "STARTIDX" ${interface_file})
+    SOC_start_idx=$(get_config "STARTIDX" ${interface_file})
+    is_eagle=$(get_config "IS_EAGLE" ${interface_file})
     local eeprom_file=/sys/kernel/debug/ieee80211/phy0/mt76/eeprom
-    if [ -z "${start_idx_7986}" ]; then
+    if [ -z "${SOC_start_idx}" ] || [ -z "${is_eagle}" ]; then
         if [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7916")" ]; then
-            start_idx_7986="2"
+            SOC_start_idx="2"
+            is_eagle="0"
         elif [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7915")" ]; then
-            start_idx_7986="1"
+            SOC_start_idx="1"
+            is_eagle="0"
         elif [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7986")" ]; then
-            start_idx_7986="0"
+            SOC_start_idx="0"
+            is_eagle="0"
+        elif [ ! -z "$(head -c 2 ${eeprom_file} | hexdump | grep "7990")" ]; then
+            SOC_start_idx="0"
+            is_eagle="1"
         else
             echo "Interface Conversion Failed!"
             echo "Please use iwpriv <phy0/phy1/..> set <...> or configure the sku of your board manually by the following commands"
-            echo "For AX6000: echo STARTIDX=0 >> ${interface_file}"
+            echo "For AX6000/Eagle: echo STARTIDX=0 >> ${interface_file}"
             echo "For AX7800: echo STARTIDX=2 >> ${interface_file}"
             echo "For AX8400: echo STARTIDX=1 >> ${interface_file}"
             exit 0
         fi
-        record_config "STARTIDX" ${start_idx_7986} ${interface_file}
+        record_config "STARTIDX" ${SOC_start_idx} ${interface_file}
+        record_config "IS_EAGLE" ${is_eagle} ${interface_file}
     fi
 
-    if [[ $1 == "raix"* ]]; then
-        phy_idx=1
-    elif [[ $1 == "rai"* ]]; then
-        phy_idx=0
-    elif [[ $1 == "rax"* ]]; then
-        phy_idx=$((start_idx_7986+1))
-    else
-        phy_idx=$start_idx_7986
-    fi
 
-    # convert phy index according to band idx
-    local band_idx=$(get_config "ATECTRLBANDIDX" ${iwpriv_file})
-    if [ "${band_idx}" = "0" ]; then
+    if [ ${is_eagle} == "0" ]; then
         if [[ $1 == "raix"* ]]; then
+            phy_idx=1
+        elif [[ $1 == "rai"* ]]; then
             phy_idx=0
         elif [[ $1 == "rax"* ]]; then
-            phy_idx=$start_idx_7986
+            phy_idx=$((SOC_start_idx+1))
+        else
+            phy_idx=$SOC_start_idx
         fi
-    elif [ "${band_idx}" = "1" ]; then
+
+        # convert phy index according to band idx
+        local band_idx=$(get_config "ATECTRLBANDIDX" ${iwpriv_file})
+        if [ "${band_idx}" = "0" ]; then
+            if [[ $1 == "raix"* ]]; then
+                phy_idx=0
+            elif [[ $1 == "rax"* ]]; then
+                phy_idx=$SOC_start_idx
+            fi
+        elif [ "${band_idx}" = "1" ]; then
+            if [[ $1 == "rai"* ]]; then
+                # AX8400: mt7915 remain phy0
+                # AX7800: mt7916 becomes phy1
+                phy_idx=$((SOC_start_idx-1))
+            elif [[ $1 == "ra"* ]]; then
+                phy_idx=$((SOC_start_idx+1))
+            fi
+        fi
+    else
+        # Eagle has different mapping method
+        # phy0: ra0
+        # phy1: rai0
+        # phy2: rax0
         if [[ $1 == "rai"* ]]; then
-            # AX8400: mt7915 remain phy0
-            # AX7800: mt7916 becomes phy1
-            phy_idx=$((start_idx_7986-1))
-        elif [[ $1 == "ra"* ]]; then
-            phy_idx=$((start_idx_7986+1))
+            phy_idx=1
+        elif [[ $1 == "rax"* ]]; then
+            phy_idx=2
+        else
+            phy_idx=0
         fi
     fi
 
@@ -152,18 +176,18 @@
                     new_phy_idx=0
                 # rax0 & ra0 becomes ra0
                 elif [[ $interface_ori == "ra"* ]]; then
-                    new_phy_idx=$start_idx_7986
+                    new_phy_idx=$SOC_start_idx
                 fi
             elif [ "${new_idx}" = "1" ]; then
                 # raix0 & rai0 becomes raix0
                 if [[ $interface_ori == "rai"* ]]; then
                     # For AX8400 => don't change phy idx
-                    if [ ${start_idx_7986} != "1" ]; then
+                    if [ ${SOC_start_idx} != "1" ]; then
                         new_phy_idx=1
                     fi
                 # rax0 & ra0 becomes rax0
                 elif [[ $interface_ori == "ra"* ]]; then
-                    new_phy_idx=$((start_idx_7986+1))
+                    new_phy_idx=$((SOC_start_idx+1))
                 fi
             fi
         fi
@@ -331,7 +355,7 @@
             fi
         else
             # mt7915 in AX8400 case: band should be determined by only the input band
-            if [ "${start_idx_7986}" == "1" ] && [ ${phy_idx} == "0" ]; then
+            if [ "${SOC_start_idx}" == "1" ] && [ ${phy_idx} == "0" ]; then
                 local band=$((band))
             else
                 local band=$((ctrl_band_idx * band))
@@ -864,10 +888,10 @@
                 do_cmd "mt76-test ${interface} set aid=0"
             fi
 
-            if [ ${phy_idx} -lt ${start_idx_7986} ]; then
+            if [ ${phy_idx} -lt ${SOC_start_idx} ]; then
                 sed -i '/_PCIE=/d' ${iwpriv_file}
-            elif [ ${phy_idx} -ge ${start_idx_7986} ]; then
-                sed -i '/_7986=/d' ${iwpriv_file}
+            elif [ ${phy_idx} -ge ${SOC_start_idx} ]; then
+                sed -i '/_SOC=/d' ${iwpriv_file}
             fi
             ;;
         "TXCOMMIT")
@@ -924,9 +948,36 @@
     esac
 }
 
+function dump_usage {
+    echo "Usage:"
+    echo "  mwctl <interface> set csi ctrl=<opt1>,<opt2>,<opt3>,<opt4> (macaddr=<macaddr>)"
+    echo "  mwctl <interface> set csi interval=<interval (us)>"
+    echo "  mwctl <interface> dump csi <packet num> <filename>"
+    echo "  mwctl <interface> set amnt <index>(0x0~0xf) <mac addr>(xx:xx:xx:xx:xx:xx)"
+    echo "  mwctl <interface> dump amnt <index> (0x0~0xf or 0xff)"
+    echo "  mwctl <interface> set ap_rfeatures he_gi=<val>"
+    echo "  mwctl <interface> set ap_rfeatures he_ltf=<val>"
+    echo "  mwctl <interface> set ap_rfeatures trig_type=<enable>,<val> (val: 0-7)"
+    echo "  mwctl <interface> set ap_rfeatures ack_policy=<val> (val: 0-4)"
+    echo "  mwctl <interface> set ap_wireless fixed_mcs=<val>"
+    echo "  mwctl <interface> set ap_wireless ofdma=<val> (0: disable, 1: DL, 2: UL)"
+    echo "  mwctl <interface> set ap_wireless nusers_ofdma=<val>"
+    echo "  mwctl <interface> set ap_wireless ppdu_type=<val> (0: SU, 1: MU, 4: LEGACY)"
+    echo "  mwctl <interface> set ap_wireless add_ba_req_bufsize=<val>"
+    echo "  mwctl <interface> set ap_wireless mimo=<val> (0: DL, 1: UL)"
+    echo "  mwctl <interface> set ap_wireless ampdu=<enable>"
+    echo "  mwctl <interface> set ap_wireless amsdu=<enable>"
+    echo "  mwctl <interface> set ap_wireless cert=<enable>"
+    echo "  mwctl <interface> set hemu onoff=<val> (bitmap- UL MU-MIMO(bit3), DL MU-MIMO(bit2), UL OFDMA(bit1), DL OFDMA(bit0))"
+    echo "  mwctl <interface> dump phy_capa"
+}
+
 # main start here
 
-if [[ ${interface} == "ra"* ]]; then
+if [ -z ${interface} ]; then
+    dump_usage
+    exit
+elif [[ ${interface} == "ra"* ]]; then
     convert_interface $interface
 fi
 
@@ -942,6 +993,13 @@
 if [ "${cmd_type}" = "set" ]; then
     skip=0
     case ${cmd} in
+        ## In wifi 7 chipset, testmode & vendor command both use mwctl
+        ## Therefore this wrapper would translate it to either mt76-test or mt76-vendor based on the attribute of the command
+        ## Translate to mt76-vendor command
+        "csi"|"amnt"|"ap_rfeatures"|"ap_wireless"|"hemu")
+            do_cmd "mt76-vendor $*"
+            skip=1
+            ;;
         "ATE")
             do_ate_work ${param}
 
@@ -1051,37 +1109,51 @@
     fi
 
 elif [ "${cmd_type}" = "e2p" ]; then
-    offset=$(printf "0x%s" ${cmd})
-    val=$(printf "0x%s" ${param})
-
+    # support multiple read write
     # eeprom offset write
     if [[ ${full_cmd} == *"="* ]]; then
-        tmp=$((${val} & 0xff))
-        tmp=$(printf "0x%x" ${tmp})
-        do_cmd "atenl -i ${interface} -c \"eeprom set ${offset}=${tmp}\""
+        IFS=,
+        for tuple in $full_cmd
+        do
+            cmd=$(echo ${tuple} | sed s/=/' '/g | cut -d " " -f 1)
+            param=$(echo ${tuple} | sed s/=/' '/g | cut -d " " -f 2)
+            offset=$(printf "0x%s" ${cmd})
+            val=$(printf "0x%s" ${param})
+            tmp=$((${val} & 0xff))
+            tmp=$(printf "0x%x" ${tmp})
+            do_cmd "atenl -i ${interface} -c \"eeprom set ${offset}=${tmp}\""
 
-        offset=$((${offset}))
-        offset=$(expr ${offset} + "1")
-        offset=$(printf "0x%x" ${offset})
-        tmp=$(((${val} >> 8) & 0xff))
-        tmp=$(printf "0x%x" ${tmp})
-        do_cmd "atenl -i ${interface} -c \"eeprom set ${offset}=${tmp}\""
+            offset=$((${offset}))
+            offset=$(expr ${offset} + "1")
+            offset=$(printf "0x%x" ${offset})
+            tmp=$(((${val} >> 8) & 0xff))
+            tmp=$(printf "0x%x" ${tmp})
+            do_cmd "atenl -i ${interface} -c \"eeprom set ${offset}=${tmp}\""
+        done
     else
-        v1=$(do_cmd "atenl -i ${interface} -c \"eeprom read ${param}\"")
-        v1=$(echo "${v1}" | grep "val =" | cut -d '(' -f 2 | grep -o -E '[0-9]+')
+        IFS=,
+        for tuple in $full_cmd
+        do
+            cmd=$(echo ${tuple} | sed s/=/' '/g | cut -d " " -f 1)
+            param=$(echo ${tuple} | sed s/=/' '/g | cut -d " " -f 2)
+            offset=$(printf "0x%s" ${cmd})
+            val=$(printf "0x%s" ${param})
+            v1=$(do_cmd "atenl -i ${interface} -c \"eeprom read ${param}\"")
+            v1=$(echo "${v1}" | grep "val =" | cut -d '(' -f 2 | grep -o -E '[0-9]+')
 
-        tmp=$(printf "0x%s" ${param})
-        tmp=$((${tmp}))
-        param2=$(expr ${tmp} + "1")
-        param2=$(printf "%x" ${param2})
-        v2=$(do_cmd "atenl -i ${interface} -c \"eeprom read ${param2}\"")
-        v2=$(echo "${v2}" | grep "val =" | cut -d '(' -f 2 | grep -o -E '[0-9]+')
+            tmp=$(printf "0x%s" ${param})
+            tmp=$((${tmp}))
+            param2=$(expr ${tmp} + "1")
+            param2=$(printf "%x" ${param2})
+            v2=$(do_cmd "atenl -i ${interface} -c \"eeprom read ${param2}\"")
+            v2=$(echo "${v2}" | grep "val =" | cut -d '(' -f 2 | grep -o -E '[0-9]+')
 
-        param=$(printf "0x%s" ${param})
-        param=$(printf "%04x" ${param})
-        param=$(echo $param | tr 'a-z' 'A-Z')
-        printf "%s       e2p:\n" ${interface_ori}
-        printf "[0x%s]:0x%02x%02x\n" ${param} ${v2} ${v1}
+            param=$(printf "0x%s" ${param})
+            param=$(printf "%04x" ${param})
+            param=$(echo $param | tr 'a-z' 'A-Z')
+            printf "%s       e2p:\n" ${interface_ori}
+            printf "[0x%s]:0x%02x%02x\n" ${param} ${v2} ${v1}
+        done
     fi
 
 elif [ "${cmd_type}" = "mac" ]; then
@@ -1099,6 +1171,9 @@
     res=$(cat ${regval} | cut -d 'x' -f 2)
     printf "%s       mac:[%s]:%s\n" ${interface_ori} ${offset} ${res}
 
+## dump command is only for vendor commands
+elif [ "${cmd_type}" = "dump" ]; then
+    do_cmd "mt76-vendor $*"
 else
     echo "Unknown command"
 fi
diff --git a/feed/atenl/src/atenl.h b/feed/atenl/src/atenl.h
index 75ee474..13f7b95 100644
--- a/feed/atenl/src/atenl.h
+++ b/feed/atenl/src/atenl.h
@@ -19,11 +19,11 @@
 
 #define BRIDGE_NAME_OPENWRT	"br-lan"
 #define BRIDGE_NAME_RDKB	"brlan0"
-#define ETH_P_RACFG	0x2880
+#define ETH_P_RACFG		0x2880
 #define RACFG_PKT_MAX_SIZE	1600
-#define RACFG_HLEN	12
-#define RACFG_MAGIC_NO	0x18142880
-#define PRE_CAL_INFO 16
+#define RACFG_HLEN		12
+#define RACFG_MAGIC_NO		0x18142880
+#define PRE_CAL_INFO		16
 #define DPD_INFO_CH_SHIFT	24
 #define DPD_INFO_2G_SHIFT 	16
 #define DPD_INFO_5G_SHIFT	8
@@ -93,7 +93,7 @@
 
 	const char *mtd_part;
 	u32 mtd_offset;
-	u8 is_main_phy;
+	u8 band_idx;
 	u8 *eeprom_data;
 	int eeprom_fd;
 	u16 eeprom_size;
@@ -275,8 +275,20 @@
 	MT_EE_BAND_SEL_5G_6G,
 };
 
+/* for mt7996 */
+enum {
+	MT_EE_EAGLE_BAND_SEL_DEFAULT,
+	MT_EE_EAGLE_BAND_SEL_2GHZ,
+	MT_EE_EAGLE_BAND_SEL_5GHZ,
+	MT_EE_EAGLE_BAND_SEL_6GHZ,
+	MT_EE_EAGLE_BAND_SEL_5GHZ_6GHZ,
+};
+
 #define MT_EE_WIFI_CONF				0x190
 #define MT_EE_WIFI_CONF0_BAND_SEL		GENMASK(7, 6)
+#define MT_EE_WIFI_EAGLE_CONF0_BAND_SEL		GENMASK(2, 0)
+#define MT_EE_WIFI_EAGLE_CONF1_BAND_SEL		GENMASK(5, 3)
+#define MT_EE_WIFI_EAGLE_CONF2_BAND_SEL		GENMASK(2, 0)
 
 enum {
 	MT7976_ONE_ADIE_DBDC		= 0x7,
@@ -389,6 +401,11 @@
 	return an->chip_id == 0x7986;
 }
 
+static inline bool is_mt7996(struct atenl *an)
+{
+	return an->chip_id == 0x7990;
+}
+
 int atenl_eth_init(struct atenl *an);
 int atenl_eth_recv(struct atenl *an, struct atenl_data *data);
 int atenl_eth_send(struct atenl *an, struct atenl_data *data);
diff --git a/feed/atenl/src/eeprom.c b/feed/atenl/src/eeprom.c
index d18262e..b71708e 100644
--- a/feed/atenl/src/eeprom.c
+++ b/feed/atenl/src/eeprom.c
@@ -22,7 +22,7 @@
 		max_len = EEPROM_PART_SIZE;
 	} else {
 		atenl_dbg("%s: init eeprom with efuse mode\n", __func__);
-		max_len = 0x1000;
+		max_len = 0x1e00;
 	}
 
 	snprintf(fname, sizeof(fname),
@@ -147,6 +147,8 @@
 
 		an->sub_chip_id = sub_id;
 		an->adie_id = is_7975 ? 0x7975 : 0x7976;
+	} else if (is_mt7996(an)) {
+		/* TODO: parse info if required */
 	}
 }
 
@@ -164,6 +166,9 @@
 		an->eeprom_size = 4096;
 		an->eeprom_prek_offs = 0x19a;
 		break;
+	case 0x7990:
+		an->eeprom_size = 7680;
+		an->eeprom_prek_offs = 0x1a5;
 	default:
 		break;
 	}
@@ -172,6 +177,7 @@
 static void
 atenl_eeprom_init_band_cap(struct atenl *an)
 {
+#define EAGLE_BAND_SEL(index)	MT_EE_WIFI_EAGLE_CONF##index##_BAND_SEL
 	u8 *eeprom = an->eeprom_data;
 
 	if (is_mt7915(an)) {
@@ -228,6 +234,36 @@
 				break;
 			}
 		}
+	} else if (is_mt7996(an)) {
+		struct atenl_band *anb;
+		u8 val, band_sel;
+		u8 band_sel_mask[3] = {EAGLE_BAND_SEL(0), EAGLE_BAND_SEL(1),
+				       EAGLE_BAND_SEL(2)};
+		int i;
+
+		for (i = 0; i < 3; i++) {
+			val = eeprom[MT_EE_WIFI_CONF + i];
+			band_sel = FIELD_GET(band_sel_mask[i], val);
+			anb = &an->anb[i];
+
+			anb->valid = true;
+			switch (band_sel) {
+			case MT_EE_EAGLE_BAND_SEL_2GHZ:
+				anb->cap = BAND_TYPE_2G;
+				break;
+			case MT_EE_EAGLE_BAND_SEL_5GHZ:
+				anb->cap = BAND_TYPE_5G;
+				break;
+			case MT_EE_EAGLE_BAND_SEL_6GHZ:
+				anb->cap = BAND_TYPE_6G;
+				break;
+			case MT_EE_EAGLE_BAND_SEL_5GHZ_6GHZ:
+				anb->cap = BAND_TYPE_5G_6G;
+				break;
+			default:
+				break;
+			}
+		}
 	}
 }
 
@@ -247,6 +283,10 @@
 	} else if (is_mt7986(an)) {
 		an->anb[0].chainmask = 0xf;
 		an->anb[1].chainmask = 0xf;
+	} else if (is_mt7996(an)) {
+		an->anb[0].chainmask = 0xf;
+		an->anb[1].chainmask = 0xf;
+		an->anb[2].chainmask = 0xf;
 	}
 }
 
@@ -261,8 +301,9 @@
 	atenl_nl_check_mtd(an);
 	flash_mode = an->mtd_part != NULL;
 
+	// Get the first main phy index for this chip
 	if (flash_mode)
-		main_phy_idx = an->is_main_phy ? main_phy_idx : (main_phy_idx - 1);
+		main_phy_idx -= an->band_idx;
 
 	snprintf(buf, sizeof(buf), "/tmp/atenl-eeprom-phy%u", main_phy_idx);
 	eeprom_file = strdup(buf);
diff --git a/feed/atenl/src/nl.c b/feed/atenl/src/nl.c
index 7cbda0f..beada05 100644
--- a/feed/atenl/src/nl.c
+++ b/feed/atenl/src/nl.c
@@ -26,7 +26,7 @@
 	[MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
 	[MT76_TM_ATTR_MTD_PART] = { .type = NLA_STRING },
 	[MT76_TM_ATTR_MTD_OFFSET] = { .type = NLA_U32 },
-	[MT76_TM_ATTR_IS_MAIN_PHY] = { .type = NLA_U8 },
+	[MT76_TM_ATTR_BAND_IDX] = { .type = NLA_U8 },
 	[MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
 	[MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
 	[MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
@@ -1180,7 +1180,7 @@
 
 	an->mtd_part = strdup(nla_get_string(tb[MT76_TM_ATTR_MTD_PART]));
 	an->mtd_offset = nla_get_u32(tb[MT76_TM_ATTR_MTD_OFFSET]);
-	an->is_main_phy = nla_get_u32(tb[MT76_TM_ATTR_IS_MAIN_PHY]);
+	an->band_idx = nla_get_u32(tb[MT76_TM_ATTR_BAND_IDX]);
 
 	return NL_SKIP;
 }
diff --git a/feed/atenl/src/nl.h b/feed/atenl/src/nl.h
index 1c774c9..b76abfe 100644
--- a/feed/atenl/src/nl.h
+++ b/feed/atenl/src/nl.h
@@ -14,7 +14,7 @@
  *
  * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string)
  * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
- * @MT76_TM_ATTR_IS_MAIN_PHY: Is current phy index the main phy or the ext phy (u8)
+ * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
  *
  * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
  *	state to MT76_TM_STATE_TX_FRAMES (u32)
@@ -86,7 +86,7 @@
 
 	MT76_TM_ATTR_MTD_PART,
 	MT76_TM_ATTR_MTD_OFFSET,
-	MT76_TM_ATTR_IS_MAIN_PHY,
+	MT76_TM_ATTR_BAND_IDX,
 
 	MT76_TM_ATTR_TX_COUNT,
 	MT76_TM_ATTR_TX_LENGTH,
diff --git a/feed/mt76-vendor/Makefile b/feed/mt76-vendor/Makefile
index 6b4da99..7436e0d 100644
--- a/feed/mt76-vendor/Makefile
+++ b/feed/mt76-vendor/Makefile
@@ -24,7 +24,6 @@
 define Package/mt76-vendor/install
 	mkdir -p $(1)/usr/sbin
 	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mt76-vendor $(1)/usr/sbin
-	ln -s /usr/sbin/mt76-vendor $(1)/usr/sbin/mwctl
 endef
 
 $(eval $(call BuildPackage,mt76-vendor))