mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 17:42:41 +00:00
Compare commits
5 Commits
led_respec
...
staging-mt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26b61bbdd9 | ||
|
|
7f5f4ccad0 | ||
|
|
71e5c425e9 | ||
|
|
aadfd5ceff | ||
|
|
b2dacf060c |
2
.github/workflows/build-dev.yml
vendored
2
.github/workflows/build-dev.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [ 'cig_wf189h', 'cig_wf189w', 'cig_wf660a', 'cig_wf672', 'cig_wf186h', 'cig_wf186w', 'cig_wf188n', 'cig_wf189', 'cig_wf196', 'cig_wf196', 'cybertan_eww631-a1', 'cybertan_eww631-b1', 'sonicfi_rap630w-312g', 'sonicfi_rap63xc-211g', 'sonicfi_rap630c-311g', 'sonicfi_rap630w-311g', 'sonicfi_rap630w-211g', 'sonicfi_rap650c', 'sonicfi_rap7110c-341x', 'sonicfi_rap750e-h', 'sonicfi_rap750e-s', 'sonicfi_rap750w-311a', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_eap105', 'edgecore_eap111', 'edgecore_eap112', 'edgecore_oap101', 'edgecore_oap101-6e', 'edgecore_oap101e', 'edgecore_oap101e-6e', 'edgecore_oap103', 'hfcl_ion4xe', 'hfcl_ion4xi', 'hfcl_ion4x', 'hfcl_ion4x_2', 'hfcl_ion4x_3', 'hfcl_ion4xi_w', 'hfcl_ion4x_w', 'indio_um-305ax', 'senao_iap4300m', 'senao_iap2300m', 'senao_jeap6500', 'udaya_a6-id2', 'udaya_a6-od2', 'yuncore_ax820', 'yuncore_ax840', 'yuncore_fap640', 'yuncore_fap650', 'yuncore_fap655', 'emplus_wap588m', 'zyxel_nwa130be', 'sercomm_ap72tip-v4' ]
|
||||
target: [ ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@ let fs = require("fs");
|
||||
let ubus = require('ubus').connect();
|
||||
|
||||
let gps_info = ubus.call('gps', 'info');
|
||||
let latitude = gps_info.latitude || 0;
|
||||
let longitude = gps_info.longitude || 0;
|
||||
let latitude = gps_info.latitude ?? 0;
|
||||
let longitude = gps_info.longitude ?? 0;
|
||||
|
||||
// afc-location.json file content
|
||||
let afc_location = {};
|
||||
afc_location.location_type = "ellipse";
|
||||
afc_location.location = longitude + ":" + latitude ;
|
||||
afc_location.height = gps_info.elevation || 0;
|
||||
afc_location.height = gps_info.elevation ?? 0;
|
||||
afc_location.height_type = "AMSL";
|
||||
afc_location.major_axis = int(gps_info.major_axis) || 1;
|
||||
afc_location.minor_axis = int(gps_info.minor_axis) || 1;
|
||||
afc_location.orientation = gps_info.major_orientation || 0;
|
||||
afc_location.vertical_tolerance = int(gps_info.vdop) || 1;
|
||||
afc_location.major_axis = gps_info.major_axis ?? 0;
|
||||
afc_location.minor_axis = gps_info.minor_axis ?? 0;
|
||||
afc_location.orientation = gps_info.major_orientation ?? 0;
|
||||
afc_location.vertical_tolerance = gps_info.vdop ?? 0;
|
||||
|
||||
let afc_location_json = fs.open("/etc/ucentral/afc-location.json", "w");
|
||||
afc_location_json.write(afc_location);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
let libubus = require("ubus");
|
||||
import { open, readfile, writefile } from "fs";
|
||||
import { open, readfile } from "fs";
|
||||
import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open } from "common";
|
||||
|
||||
let uci = require('uci').cursor();
|
||||
let ubus = libubus.connect(null, 60);
|
||||
|
||||
hostapd.data.config = {};
|
||||
@@ -894,24 +893,10 @@ return {
|
||||
hostapd.ubus.disconnect();
|
||||
},
|
||||
afc_request: function(iface, data) {
|
||||
let wireless_config = uci.get_all('wireless');
|
||||
for (let l, afc_server in wireless_config) {
|
||||
if (afc_server['.type'] == 'afc-server' && afc_server.url && data) {
|
||||
hostapd.printf(`Sending AFC request: ${data}`);
|
||||
writefile("/tmp/afc-request.json", data);
|
||||
|
||||
if (afc_server.access_token)
|
||||
system(`curl -s -X POST ${afc_server.url} -H \'accept: \*\/\*\' -H \'Authorization: Bearer ${afc_server.access_token}\' -H \'Content-Type: application/json\' -d \'${data}\' --output /tmp/afc-response.json`);
|
||||
else if (afc_server.cert)
|
||||
system(`curl -s -X POST ${afc_server.url} -H \'accept: \*\/\*\' --cert \'${afc_server.cert}\' -H \'Content-Type: application/json\' -d \'${data}\' --output /tmp/afc-response.json`);
|
||||
|
||||
let afc_response = (readfile("/tmp/afc-response.json"));
|
||||
if (afc_response)
|
||||
return afc_response;
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
let ret = ubus.call("afc", "request", { data });
|
||||
if (type(ret) != "object")
|
||||
return;
|
||||
return ret.data;
|
||||
},
|
||||
bss_add: function(name, obj) {
|
||||
bss_event("add", name);
|
||||
|
||||
@@ -107,42 +107,29 @@ platform_do_upgrade() {
|
||||
|
||||
board=$(board_name)
|
||||
case $board in
|
||||
glinet,b3000|\
|
||||
edgecore,oap101|\
|
||||
edgecore,oap101-6e|\
|
||||
edgecore,oap101e|\
|
||||
edgecore,oap101e-6e|\
|
||||
edgecore,eap104)
|
||||
if [ "$(find_mtd_chardev rootfs)" ]; then
|
||||
CI_UBIPART="rootfs"
|
||||
else
|
||||
if grep -q rootfs1 /proc/cmdline; then
|
||||
CI_UBIPART="rootfs2"
|
||||
CI_FWSETENV="active 2"
|
||||
else
|
||||
CI_UBIPART="rootfs1"
|
||||
CI_FWSETENV="active 1"
|
||||
fi
|
||||
fi
|
||||
nand_upgrade_tar "$1"
|
||||
;;
|
||||
glinet,b3000)
|
||||
CI_UBIPART="rootfs1"
|
||||
[ "$(find_mtd_chardev rootfs)" ] && CI_UBIPART="rootfs"
|
||||
nand_upgrade_tar "$1"
|
||||
;;
|
||||
hfcl,ion4x_w|\
|
||||
hfcl,ion4x_w|\
|
||||
hfcl,ion4xi_w)
|
||||
wp_part=$(fw_printenv primary | cut -d = -f2)
|
||||
echo "Current Primary is $wp_part"
|
||||
if [[ $wp_part == 1 ]]; then
|
||||
CI_UBIPART="rootfs"
|
||||
CI_FWSETENV="primary 0"
|
||||
else
|
||||
CI_UBIPART="rootfs_1"
|
||||
CI_FWSETENV="primary 1"
|
||||
fi
|
||||
nand_upgrade_tar "$1"
|
||||
;;
|
||||
wp_part=$(fw_printenv primary | cut -d = -f2)
|
||||
echo "Current Primary is $wp_part"
|
||||
if [[ $wp_part == 1 ]]; then
|
||||
CI_UBIPART="rootfs"
|
||||
CI_FWSETENV="primary 0"
|
||||
else
|
||||
CI_UBIPART="rootfs_1"
|
||||
CI_FWSETENV="primary 1"
|
||||
fi
|
||||
nand_upgrade_tar "$1"
|
||||
;;
|
||||
cig,wf186w|\
|
||||
cig,wf186h|\
|
||||
emplus,wap385c|\
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
--- a/include/init/ssdk_plat.h
|
||||
+++ b/include/init/ssdk_plat.h
|
||||
@@ -330,6 +330,7 @@ struct qca_phy_priv {
|
||||
struct mii_bus *miibus;
|
||||
/*qca808x_end*/
|
||||
u64 *mib_counters;
|
||||
+ a_uint32_t mib_loop_cnt;
|
||||
/* dump buf */
|
||||
a_uint8_t buf[2048];
|
||||
a_uint32_t link_polling_required;
|
||||
--- a/src/ref/ref_mib.c
|
||||
+++ b/src/ref/ref_mib.c
|
||||
@@ -479,39 +479,37 @@ qca_ar8327_sw_get_port_mib(struct switch
|
||||
#endif
|
||||
|
||||
int
|
||||
-_qca_ar8327_sw_capture_port_tx_counter(struct qca_phy_priv *priv, int port)
|
||||
+_qca_ar8327_sw_capture_port_tx_counter(a_uint32_t dev_id, int port)
|
||||
{
|
||||
fal_mib_info_t mib_Info;
|
||||
|
||||
memset(&mib_Info, 0, sizeof(fal_mib_info_t));
|
||||
- fal_get_tx_mib_info(priv->device_id, port, &mib_Info);
|
||||
+ fal_get_tx_mib_info(dev_id, port, &mib_Info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
-_qca_ar8327_sw_capture_port_rx_counter(struct qca_phy_priv *priv, int port)
|
||||
+_qca_ar8327_sw_capture_port_rx_counter(a_uint32_t dev_id, int port)
|
||||
{
|
||||
fal_mib_info_t mib_Info;
|
||||
|
||||
memset(&mib_Info, 0, sizeof(fal_mib_info_t));
|
||||
- fal_get_rx_mib_info(priv->device_id, port, &mib_Info);
|
||||
+ fal_get_rx_mib_info(dev_id, port, &mib_Info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
qca_ar8327_sw_mib_task(struct qca_phy_priv *priv)
|
||||
{
|
||||
- static int loop = 0;
|
||||
-
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
- if ((loop % 2) == 0)
|
||||
- _qca_ar8327_sw_capture_port_rx_counter(priv, loop/2);
|
||||
+ if ((priv->mib_loop_cnt % 2) == 0)
|
||||
+ _qca_ar8327_sw_capture_port_rx_counter(priv->device_id, priv->mib_loop_cnt/2);
|
||||
else
|
||||
- _qca_ar8327_sw_capture_port_tx_counter(priv, loop/2);
|
||||
+ _qca_ar8327_sw_capture_port_tx_counter(priv->device_id, priv->mib_loop_cnt/2);
|
||||
|
||||
- if(++loop == (2 * (priv->ports))) {
|
||||
- loop = 0;
|
||||
+ if(++priv->mib_loop_cnt == (2 * (priv->ports))) {
|
||||
+ priv->mib_loop_cnt = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
@@ -1,15 +1,15 @@
|
||||
From 5c8d90efe02c47ce76a6d5383ea6aa90eb0c73d8 Mon Sep 17 00:00:00 2001
|
||||
From 991886a6f8840802d611e0f75e79aa4ec5e68ccc Mon Sep 17 00:00:00 2001
|
||||
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
Date: Mon, 20 Feb 2023 14:25:24 +0800
|
||||
Subject: [PATCH] mac80211: mtk: add sta-assisted DFS state update mechanism
|
||||
|
||||
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
---
|
||||
include/net/cfg80211.h | 14 +++++++++
|
||||
include/uapi/linux/nl80211.h | 6 ++++
|
||||
net/mac80211/mlme.c | 11 +++++++
|
||||
net/wireless/chan.c | 60 ++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 91 insertions(+)
|
||||
include/net/cfg80211.h | 14 ++++++
|
||||
include/uapi/linux/nl80211.h | 6 +++
|
||||
net/mac80211/mlme.c | 11 +++++
|
||||
net/wireless/chan.c | 92 ++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 123 insertions(+)
|
||||
|
||||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||||
index 77276db..03f072f 100644
|
||||
@@ -97,7 +97,7 @@ index 8ee325a..2dbc18c 100644
|
||||
drv_event_callback(sdata->local, sdata, &event);
|
||||
sdata_info(sdata, "associated\n");
|
||||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
|
||||
index c217276..9f651f9 100644
|
||||
index c217276..f48995c 100644
|
||||
--- a/net/wireless/chan.c
|
||||
+++ b/net/wireless/chan.c
|
||||
@@ -14,6 +14,7 @@
|
||||
@@ -108,7 +108,7 @@ index c217276..9f651f9 100644
|
||||
|
||||
static bool cfg80211_valid_60g_freq(u32 freq)
|
||||
{
|
||||
@@ -1393,3 +1394,62 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy,
|
||||
@@ -1393,3 +1394,94 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy,
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_any_usable_channels);
|
||||
@@ -133,26 +133,29 @@ index c217276..9f651f9 100644
|
||||
+ const struct cfg80211_chan_def *csa_chandef,
|
||||
+ bool associated)
|
||||
+{
|
||||
+ struct wiphy *wiphy = wdev->wiphy;
|
||||
+ bool csa_active = !!csa_chandef;
|
||||
+ enum nl80211_dfs_state dfs_state = NL80211_DFS_USABLE;
|
||||
+ enum nl80211_radar_event event = NL80211_RADAR_STA_CAC_EXPIRED;
|
||||
+
|
||||
+ ASSERT_WDEV_LOCK(wdev);
|
||||
+
|
||||
+ if (!bss_chandef)
|
||||
+ return;
|
||||
+
|
||||
+ /* assume csa channel is cac completed */
|
||||
+ if (csa_active &&
|
||||
+ (cfg80211_chandef_dfs_usable(wdev->wiphy, csa_chandef) ||
|
||||
+ cfg80211_chandef_dfs_available(wdev->wiphy, csa_chandef))) {
|
||||
+ cfg80211_set_dfs_state(wdev->wiphy, csa_chandef, NL80211_DFS_AVAILABLE);
|
||||
+ cfg80211_sta_radar_notify(wdev->wiphy, csa_chandef,
|
||||
+ (cfg80211_chandef_dfs_usable(wiphy, csa_chandef) ||
|
||||
+ cfg80211_chandef_dfs_available(wiphy, csa_chandef))) {
|
||||
+ cfg80211_set_dfs_state(wiphy, csa_chandef, NL80211_DFS_AVAILABLE);
|
||||
+ cfg80211_sta_radar_notify(wiphy, csa_chandef,
|
||||
+ NL80211_RADAR_STA_CAC_SKIPPED);
|
||||
+ netdev_info(wdev->netdev, "Set CSA channel's DFS state to available\n");
|
||||
+ }
|
||||
+
|
||||
+ /* avoid updating the dfs state during nop */
|
||||
+ if (!cfg80211_chandef_dfs_usable(wdev->wiphy, bss_chandef) &&
|
||||
+ !cfg80211_chandef_dfs_available(wdev->wiphy, bss_chandef))
|
||||
+ if (!cfg80211_chandef_dfs_usable(wiphy, bss_chandef) &&
|
||||
+ !cfg80211_chandef_dfs_available(wiphy, bss_chandef))
|
||||
+ return;
|
||||
+
|
||||
+ if (associated && !csa_active) {
|
||||
@@ -160,8 +163,37 @@ index c217276..9f651f9 100644
|
||||
+ event = NL80211_RADAR_STA_CAC_SKIPPED;
|
||||
+ }
|
||||
+
|
||||
+ cfg80211_set_dfs_state(wdev->wiphy, bss_chandef, dfs_state);
|
||||
+ cfg80211_sta_radar_notify(wdev->wiphy, bss_chandef, event);
|
||||
+ /* avoid setting the dfs state to usable
|
||||
+ * when other interfaces still operate on this channel
|
||||
+ */
|
||||
+ if (dfs_state == NL80211_DFS_USABLE) {
|
||||
+ struct wireless_dev *tmp_wdev;
|
||||
+
|
||||
+ if (cfg80211_offchan_chain_is_active(wiphy_to_rdev(wiphy),
|
||||
+ bss_chandef->chan))
|
||||
+ return;
|
||||
+
|
||||
+ list_for_each_entry(tmp_wdev, &wiphy->wdev_list, list) {
|
||||
+ /* avoid ABBA deadlock between two stations */
|
||||
+ if (tmp_wdev->iftype == NL80211_IFTYPE_STATION)
|
||||
+ continue;
|
||||
+
|
||||
+ wdev_lock(tmp_wdev);
|
||||
+ if (!cfg80211_beaconing_iface_active(tmp_wdev)) {
|
||||
+ wdev_unlock(tmp_wdev);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (cfg80211_is_sub_chan(&tmp_wdev->chandef, bss_chandef->chan)) {
|
||||
+ wdev_unlock(tmp_wdev);
|
||||
+ return;
|
||||
+ }
|
||||
+ wdev_unlock(tmp_wdev);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ cfg80211_set_dfs_state(wiphy, bss_chandef, dfs_state);
|
||||
+ cfg80211_sta_radar_notify(wiphy, bss_chandef, event);
|
||||
+
|
||||
+ if (csa_active)
|
||||
+ netdev_info(wdev->netdev, "Set origin channel's DFS state to usable\n");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From bb918e40dcc7d082f898234cf29cd545de78621e Mon Sep 17 00:00:00 2001
|
||||
From 70526aabf704d778796dfbaa042fe48e03aa7d61 Mon Sep 17 00:00:00 2001
|
||||
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
Date: Wed, 15 Nov 2023 15:05:17 +0800
|
||||
Subject: [PATCH] mac80211: mtk: add DFS CAC countdown in CSA flow
|
||||
@@ -10,11 +10,11 @@ Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
net/mac80211/ieee80211_i.h | 2 +
|
||||
net/mac80211/iface.c | 2 +
|
||||
net/mac80211/mlme.c | 6 ++-
|
||||
net/mac80211/util.c | 11 ++++-
|
||||
net/mac80211/util.c | 16 +++++++-
|
||||
net/wireless/chan.c | 72 ++++++++++++++++++++++++++++++++
|
||||
net/wireless/nl80211.c | 5 ++-
|
||||
net/wireless/rdev-ops.h | 17 ++++++++
|
||||
9 files changed, 221 insertions(+), 10 deletions(-)
|
||||
9 files changed, 226 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||||
index 03f072f..a443b0d 100644
|
||||
@@ -272,16 +272,21 @@ index 2dbc18c..ed81ebf 100644
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
GFP_KERNEL);
|
||||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
|
||||
index 26cd627..e07fe73 100644
|
||||
index 26cd627..1e8420d 100644
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3873,7 +3873,16 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
|
||||
@@ -3873,7 +3873,21 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chandef;
|
||||
- ieee80211_vif_release_channel(sdata);
|
||||
+ if (sdata->vif.csa_active) {
|
||||
+ sdata->vif.csa_active = false;
|
||||
+ if (sdata->csa_block_tx) {
|
||||
+ ieee80211_wake_vif_queues(local, sdata,
|
||||
+ IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
+ sdata->csa_block_tx = false;
|
||||
+ }
|
||||
+ if (sdata->u.ap.next_beacon) {
|
||||
+ kfree(sdata->u.ap.next_beacon->mbssid_ies);
|
||||
+ kfree(sdata->u.ap.next_beacon);
|
||||
@@ -294,7 +299,7 @@ index 26cd627..e07fe73 100644
|
||||
&chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
|
||||
index 9f651f9..f02598b 100644
|
||||
index f48995c..c7bfa6b 100644
|
||||
--- a/net/wireless/chan.c
|
||||
+++ b/net/wireless/chan.c
|
||||
@@ -1262,6 +1262,78 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
From 08661908d4c2fb5f8d7ca00e0e7e6b33a6ae6e31 Mon Sep 17 00:00:00 2001
|
||||
From b43f0f6528bff00b4fbb25e0cbb9ac88577d1467 Mon Sep 17 00:00:00 2001
|
||||
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
Date: Wed, 27 Dec 2023 14:26:22 +0800
|
||||
Subject: [PATCH] mac80211: mtk: send deauth frame if CAC is required during
|
||||
CSA
|
||||
|
||||
Avoid sending deauth in cert mode (11AC VHT4-2.16h-DFS).
|
||||
|
||||
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
---
|
||||
net/mac80211/cfg.c | 27 +++++++++++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
net/mac80211/cfg.c | 28 ++++++++++++++++++++++++++++
|
||||
1 file changed, 28 insertions(+)
|
||||
|
||||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
|
||||
index 3e6e903..eb73834 100644
|
||||
index 7a30ca6..2ee5b63 100644
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -3361,6 +3361,31 @@ static int ieee80211_start_radar_detection_post_csa(struct wiphy *wiphy,
|
||||
@@ -3361,6 +3361,32 @@ static int ieee80211_start_radar_detection_post_csa(struct wiphy *wiphy,
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -28,7 +30,8 @@ index 3e6e903..eb73834 100644
|
||||
+ &sdata->csa_chandef) &&
|
||||
+ !cfg80211_reg_can_beacon_relax(local->hw.wiphy,
|
||||
+ &sdata->csa_chandef,
|
||||
+ sdata->wdev.iftype);
|
||||
+ sdata->wdev.iftype) &&
|
||||
+ !ieee80211_is_cert_mode(&local->hw);
|
||||
+ /* broadcast deauth frame if CAC is required */
|
||||
+ if (!send_deauth)
|
||||
+ return;
|
||||
@@ -45,7 +48,7 @@ index 3e6e903..eb73834 100644
|
||||
static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@@ -3371,6 +3396,8 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
|
||||
@@ -3371,6 +3397,8 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
|
||||
lockdep_assert_held(&local->mtx);
|
||||
lockdep_assert_held(&local->chanctx_mtx);
|
||||
|
||||
@@ -55,5 +58,5 @@ index 3e6e903..eb73834 100644
|
||||
* using reservation isn't immediate as it may be deferred until later
|
||||
* with multi-vif. once reservation is complete it will re-schedule the
|
||||
--
|
||||
2.18.0
|
||||
2.45.2
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
From 843e2b25433dc6c3cbc2ff4a754bef091cabe54b Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
Date: Mon, 24 Jun 2024 17:50:08 +0800
|
||||
Subject: [PATCH] mac80211: mtk: add callback function to set QoS map in HW
|
||||
|
||||
The mapping from IP DSCP to IEEE 802.11 user priority may be customized.
|
||||
Therefore, the mapping needs to be passed to HW, so that the QoS type of traffic can be mapped in a consistent manner for both SW and HW paths.
|
||||
|
||||
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
---
|
||||
include/net/mac80211.h | 3 +++
|
||||
net/mac80211/cfg.c | 2 +-
|
||||
net/mac80211/driver-ops.h | 16 ++++++++++++++++
|
||||
net/mac80211/trace.h | 6 ++++++
|
||||
4 files changed, 26 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
|
||||
index 5c26752..b622c76 100644
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -3982,6 +3982,7 @@ struct ieee80211_prep_tx_info {
|
||||
* disable background CAC/radar detection.
|
||||
* @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
|
||||
* resolve a path for hardware flow offloading
|
||||
+ * @set_qos_map: Set QoS mapping information to driver.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@@ -4321,6 +4322,8 @@ struct ieee80211_ops {
|
||||
struct net_device_path_ctx *ctx,
|
||||
struct net_device_path *path);
|
||||
#endif
|
||||
+ int (*set_qos_map)(struct ieee80211_vif *vif,
|
||||
+ struct cfg80211_qos_map *qos_map);
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
|
||||
index ffb60a2..80fba54 100644
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -4040,7 +4040,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy,
|
||||
if (old_qos_map)
|
||||
kfree_rcu(old_qos_map, rcu_head);
|
||||
|
||||
- return 0;
|
||||
+ return drv_set_qos_map(sdata->local, sdata, qos_map);
|
||||
}
|
||||
|
||||
static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
|
||||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
|
||||
index 9e8003f..d4723dc 100644
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1525,4 +1525,20 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
||||
}
|
||||
#endif
|
||||
|
||||
+static inline int drv_set_qos_map(struct ieee80211_local *local,
|
||||
+ struct ieee80211_sub_if_data *sdata,
|
||||
+ struct cfg80211_qos_map *qos_map)
|
||||
+{
|
||||
+ int ret = -EOPNOTSUPP;
|
||||
+
|
||||
+ might_sleep();
|
||||
+
|
||||
+ trace_drv_set_qos_map(local, sdata);
|
||||
+ if (local->ops->set_qos_map)
|
||||
+ ret = local->ops->set_qos_map(&sdata->vif, qos_map);
|
||||
+ trace_drv_return_int(local, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
|
||||
index d15dadd..c6fc75e 100644
|
||||
--- a/net/mac80211/trace.h
|
||||
+++ b/net/mac80211/trace.h
|
||||
@@ -2929,6 +2929,12 @@ TRACE_EVENT(bss_color_bitmap,
|
||||
)
|
||||
);
|
||||
|
||||
+DEFINE_EVENT(local_sdata_evt, drv_set_qos_map,
|
||||
+ TP_PROTO(struct ieee80211_local *local,
|
||||
+ struct ieee80211_sub_if_data *sdata),
|
||||
+ TP_ARGS(local, sdata)
|
||||
+);
|
||||
+
|
||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
--
|
||||
2.18.0
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
From ac1e8443a250f418b6124e7b4f4ea65a03c4d02b Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
Date: Fri, 26 Apr 2024 09:29:39 +0800
|
||||
Subject: [PATCH] mac80211: mtk: add exported function for SoftMAC driver to
|
||||
get QoS map
|
||||
|
||||
The mapping from IP DSCP to IEEE 802.11 user priority may be customized.
|
||||
Therefore, driver needs to pass the mapping to HW, so that the QoS type of traffic can be mapped in a consistent manner for both SW and HW paths.
|
||||
|
||||
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
---
|
||||
include/net/mac80211.h | 12 ++++++++++++
|
||||
net/mac80211/util.c | 10 +++++++++-
|
||||
2 files changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
|
||||
index 5c26752..420963f 100644
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -6942,4 +6942,16 @@ static inline bool ieee80211_is_tx_data(struct sk_buff *skb)
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
*/
|
||||
unsigned long ieee80211_get_scanning(struct ieee80211_hw *hw);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_get_qos_map - get QoS mapping information.
|
||||
+ *
|
||||
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
+ *
|
||||
+ * Return: Pointer to the QoS mapping information.
|
||||
+ *
|
||||
+ * Note that the return value is an RCU-protected pointer, so rcu_read_lock()
|
||||
+ * must be held when calling this function.
|
||||
+ */
|
||||
+struct cfg80211_qos_map *ieee80211_get_qos_map(struct ieee80211_vif *vif);
|
||||
#endif /* MAC80211_H */
|
||||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
|
||||
index e07fe73..865c4ac 100644
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -4643,4 +4643,12 @@ unsigned long ieee80211_get_scanning(struct ieee80211_hw *hw)
|
||||
|
||||
return local->scanning;
|
||||
}
|
||||
-EXPORT_SYMBOL(ieee80211_get_scanning);
|
||||
\ No newline at end of file
|
||||
+EXPORT_SYMBOL(ieee80211_get_scanning);
|
||||
+
|
||||
+struct cfg80211_qos_map *ieee80211_get_qos_map(struct ieee80211_vif *vif)
|
||||
+{
|
||||
+ struct mac80211_qos_map *qos_map = rcu_dereference(vif_to_sdata(vif)->qos_map);
|
||||
+
|
||||
+ return qos_map ? &qos_map->qos_map : NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_get_qos_map);
|
||||
--
|
||||
2.18.0
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
From de4d3e25a555dedd70793d0362b1e501ed1a77f1 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
Date: Tue, 30 Apr 2024 10:28:29 +0800
|
||||
Subject: [PATCH] mac80211: mtk: fix inconsistent QoS mapping between AP and
|
||||
AP_VLAN VIFs
|
||||
|
||||
Fix inconsistent QoS mapping between AP and AP_VLAN IFs.
|
||||
Specifically, when WDS AP IF is connected by a WDS STA, the QoS map of the AP_VLAN VIF is NULL.
|
||||
So the QoS types of packets to the WDS STA will be determined using the default mapping rule.
|
||||
However, SoftMAC driver uses the QoS map of the AP VIF, which may already be set.
|
||||
Therefore, it is possible that the QoS mappings of SW and HW are inconsistent.
|
||||
Thus, sync QoS map of AP VIF to that of AP_VLAN VIF.
|
||||
|
||||
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
|
||||
---
|
||||
net/mac80211/iface.c | 23 ++++++++++++++++++++++-
|
||||
1 file changed, 22 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
||||
index ef32d53..138ad79 100644
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -297,8 +297,29 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
|
||||
* can only add VLANs to enabled APs
|
||||
*/
|
||||
if (iftype == NL80211_IFTYPE_AP_VLAN &&
|
||||
- nsdata->vif.type == NL80211_IFTYPE_AP)
|
||||
+ nsdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
+ struct mac80211_qos_map *old_qos_map, *new_qos_map = NULL;
|
||||
+
|
||||
sdata->bss = &nsdata->u.ap;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ old_qos_map = rcu_dereference(nsdata->qos_map);
|
||||
+ if (old_qos_map) {
|
||||
+ new_qos_map = kzalloc(sizeof(*new_qos_map), GFP_KERNEL);
|
||||
+ if (!new_qos_map) {
|
||||
+ rcu_read_unlock();
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ memcpy(&new_qos_map->qos_map, &old_qos_map->qos_map,
|
||||
+ sizeof(new_qos_map->qos_map));
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ old_qos_map = sdata_dereference(sdata->qos_map, sdata);
|
||||
+ rcu_assign_pointer(sdata->qos_map, new_qos_map);
|
||||
+ if (old_qos_map)
|
||||
+ kfree_rcu(old_qos_map, rcu_head);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.18.0
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
From 9c1bd48929ad7c6b55d4486e7c519c778f9900d6 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chiu <chui-hao.chiu@mediatek.com>
|
||||
Date: Mon, 14 Oct 2024 15:27:28 +0800
|
||||
Subject: [PATCH] mac80211: mtk: set IEEE80211_TX_CTL_USE_MINRATE when probing
|
||||
station
|
||||
|
||||
The TxS may not be reported to driver correctly when we set BA_DISALBE = 0.
|
||||
|
||||
When mac80211 set IEEE80211_TX_CTL_USE_MINRATE, mt76 would use fixed rate
|
||||
and set BA_DISABLE = 1 to transmit the packet. So mt76 can receive TxS
|
||||
correctly.
|
||||
|
||||
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
|
||||
---
|
||||
net/mac80211/cfg.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
|
||||
index 80fba54..4818dca 100644
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -3957,7 +3957,8 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||
- IEEE80211_TX_INTFL_NL80211_FRAME_TX;
|
||||
+ IEEE80211_TX_INTFL_NL80211_FRAME_TX |
|
||||
+ IEEE80211_TX_CTL_USE_MINRATE;
|
||||
info->band = band;
|
||||
|
||||
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
From d873d195bcb481b7b82be195cb17e3fc7f7ecf58 Mon Sep 17 00:00:00 2001
|
||||
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
Date: Wed, 11 Dec 2024 13:21:21 +0800
|
||||
Subject: [PATCH] mac80211: mtk: add dfs relax flag for scanning without dfs
|
||||
restrictions
|
||||
|
||||
Add dfs relax flag for scanning without dfs restrictions.
|
||||
If user turn on the dfs relax flag by entering the following command:
|
||||
echo 1 > /sys/kernel/debug/ieee80211/phyX/scan_dfs_relax
|
||||
Then, allow AP/STA to scan while operating on a DFS channel.
|
||||
|
||||
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
|
||||
---
|
||||
include/net/cfg80211.h | 4 +++
|
||||
net/mac80211/offchannel.c | 4 +--
|
||||
net/mac80211/scan.c | 3 ++-
|
||||
net/wireless/debugfs.c | 53 +++++++++++++++++++++++++++++++++++++++
|
||||
net/wireless/nl80211.c | 14 ++++++++---
|
||||
5 files changed, 71 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||||
index 67b0e6c..f159340 100644
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -5047,6 +5047,8 @@ struct wiphy_iftype_akm_suites {
|
||||
* @mbssid_max_ema_profile_periodicity: maximum profile periodicity supported by
|
||||
* the driver. Setting this field to a non-zero value indicates that the
|
||||
* driver supports enhanced multi-BSSID advertisements (EMA AP).
|
||||
+ *
|
||||
+ * @dfs_relax: a flag to relax the DFS restrictions during scanning
|
||||
*/
|
||||
struct wiphy {
|
||||
struct mutex mtx;
|
||||
@@ -5197,6 +5199,8 @@ struct wiphy {
|
||||
u8 mbssid_max_interfaces;
|
||||
u8 ema_max_profile_periodicity;
|
||||
|
||||
+ bool dfs_relax;
|
||||
+
|
||||
char priv[] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
||||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
|
||||
index 042b6fb..2cd8454 100644
|
||||
--- a/net/mac80211/offchannel.c
|
||||
+++ b/net/mac80211/offchannel.c
|
||||
@@ -579,8 +579,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
/* if there's no need to queue, handle it immediately */
|
||||
- if (list_empty(&local->roc_list) &&
|
||||
- !local->scanning && !ieee80211_is_radar_required(local)) {
|
||||
+ if (list_empty(&local->roc_list) && !local->scanning &&
|
||||
+ (local->hw.wiphy->dfs_relax || !ieee80211_is_radar_required(local))) {
|
||||
/* if not HW assist, just queue & schedule work */
|
||||
if (!local->ops->remain_on_channel) {
|
||||
list_add_tail(&roc->list, &local->roc_list);
|
||||
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
|
||||
index 9d53f1a..9ef5179 100644
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -572,7 +572,8 @@ static bool __ieee80211_can_leave_ch(struct ieee80211_sub_if_data *sdata)
|
||||
if (!ieee80211_is_radar_required(local))
|
||||
return true;
|
||||
|
||||
- if (!regulatory_pre_cac_allowed(local->hw.wiphy))
|
||||
+ if (!local->hw.wiphy->dfs_relax &&
|
||||
+ !regulatory_pre_cac_allowed(local->hw.wiphy))
|
||||
return false;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
|
||||
index 0637ed4..9fecbef 100644
|
||||
--- a/net/wireless/debugfs.c
|
||||
+++ b/net/wireless/debugfs.c
|
||||
@@ -388,6 +388,58 @@ dfs_available_reset(void *data, u64 val)
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(dfs_available_reset_ops, NULL,
|
||||
dfs_available_reset, "0x%08llx\n");
|
||||
|
||||
+
|
||||
+static ssize_t scan_dfs_relax_write(struct file *file,
|
||||
+ const char __user *user_buf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct wiphy *wiphy = file->private_data;
|
||||
+ char buf[16];
|
||||
+
|
||||
+ if (count >= sizeof(buf))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (copy_from_user(buf, user_buf, count))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ if (count && buf[count - 1] == '\n')
|
||||
+ buf[count - 1] = '\0';
|
||||
+ else
|
||||
+ buf[count] = '\0';
|
||||
+
|
||||
+ if (kstrtobool(buf, &wiphy->dfs_relax))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static ssize_t scan_dfs_relax_read(struct file *file, char __user *user_buf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct wiphy *wiphy = file->private_data;
|
||||
+ unsigned int r, offset, buf_size = PAGE_SIZE;
|
||||
+ char *buf;
|
||||
+
|
||||
+ buf = kzalloc(buf_size, GFP_KERNEL);
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ offset = scnprintf(buf, buf_size, "dfs relax: %u\n", wiphy->dfs_relax);
|
||||
+
|
||||
+ r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
|
||||
+
|
||||
+ kfree(buf);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations scan_dfs_relax_ops = {
|
||||
+ .write = scan_dfs_relax_write,
|
||||
+ .read = scan_dfs_relax_read,
|
||||
+ .open = simple_open,
|
||||
+ .llseek = default_llseek,
|
||||
+};
|
||||
+
|
||||
#define DEBUGFS_ADD(name, chmod) \
|
||||
debugfs_create_file(#name, chmod, phyd, &rdev->wiphy, &name## _ops)
|
||||
|
||||
@@ -404,4 +456,5 @@ void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
|
||||
DEBUGFS_ADD(dfs_skip_nop, 0600);
|
||||
DEBUGFS_ADD(dfs_skip_cac, 0600);
|
||||
DEBUGFS_ADD(dfs_available_reset, 0600);
|
||||
+ DEBUGFS_ADD(scan_dfs_relax, 0644);
|
||||
}
|
||||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
|
||||
index 4883b1f..3d22429 100644
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -8400,13 +8400,16 @@ int nl80211_parse_random_mac(struct nlattr **attrs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
|
||||
+static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev, bool dfs_relax)
|
||||
{
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!cfg80211_beaconing_iface_active(wdev))
|
||||
return true;
|
||||
|
||||
+ if (dfs_relax)
|
||||
+ return true;
|
||||
+
|
||||
if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return true;
|
||||
|
||||
@@ -8627,7 +8630,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
request->n_channels = i;
|
||||
|
||||
wdev_lock(wdev);
|
||||
- if (!cfg80211_off_channel_oper_allowed(wdev)) {
|
||||
+ if (!cfg80211_off_channel_oper_allowed(wdev, wiphy->dfs_relax)) {
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
if (request->n_channels != 1) {
|
||||
@@ -11549,8 +11552,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ if (wdev->cac_started)
|
||||
+ return -EBUSY;
|
||||
+
|
||||
wdev_lock(wdev);
|
||||
- if (!cfg80211_off_channel_oper_allowed(wdev) &&
|
||||
+ if (!cfg80211_off_channel_oper_allowed(wdev, rdev->wiphy.dfs_relax) &&
|
||||
!cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
|
||||
compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
|
||||
&chandef);
|
||||
@@ -11755,7 +11761,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
return -EINVAL;
|
||||
|
||||
wdev_lock(wdev);
|
||||
- if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
|
||||
+ if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev, false)) {
|
||||
wdev_unlock(wdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
--
|
||||
2.45.2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
From bad36168042569eb4c7ab6a549f7444a40e299c3 Mon Sep 17 00:00:00 2001
|
||||
From 026c9872e3460f1632b60324e062016887b31134 Mon Sep 17 00:00:00 2001
|
||||
From: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Date: Fri, 11 Mar 2022 11:34:11 +0800
|
||||
Subject: [PATCH 9900/9903] mac80211: mtk: mask kernel version limitation and
|
||||
Subject: [PATCH 9900/9902] mac80211: mtk: mask kernel version limitation and
|
||||
fill forward path in kernel 5.4
|
||||
|
||||
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
@@ -13,10 +13,10 @@ Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
4 files changed, 10 deletions(-)
|
||||
|
||||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
|
||||
index 91affd5..42192cd 100644
|
||||
index b622c76..c6625c2 100644
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -4307,13 +4307,11 @@ struct ieee80211_ops {
|
||||
@@ -4315,13 +4315,11 @@ struct ieee80211_ops {
|
||||
struct ieee80211_sta *sta, u8 flowid);
|
||||
int (*set_radar_background)(struct ieee80211_hw *hw,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
@@ -27,11 +27,11 @@ index 91affd5..42192cd 100644
|
||||
struct net_device_path_ctx *ctx,
|
||||
struct net_device_path *path);
|
||||
-#endif
|
||||
int (*set_qos_map)(struct ieee80211_vif *vif,
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
|
||||
index 9e8003f..19e2ada 100644
|
||||
index d4723dc..91ea8b2 100644
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1501,7 +1501,6 @@ static inline void drv_twt_teardown_request(struct ieee80211_local *local,
|
||||
@@ -42,18 +42,19 @@ index 9e8003f..19e2ada 100644
|
||||
static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta,
|
||||
@@ -1523,6 +1522,5 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
||||
@@ -1523,7 +1522,6 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
||||
|
||||
return ret;
|
||||
}
|
||||
-#endif
|
||||
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
static inline int drv_set_qos_map(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
||||
index 00b0443..a7169a5 100644
|
||||
index 138ad79..4b92867 100644
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -853,7 +853,6 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
|
||||
@@ -875,7 +875,6 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
|
||||
|
||||
};
|
||||
|
||||
@@ -61,7 +62,7 @@ index 00b0443..a7169a5 100644
|
||||
static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx,
|
||||
struct net_device_path *path)
|
||||
{
|
||||
@@ -911,7 +910,6 @@ out:
|
||||
@@ -933,7 +932,6 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -69,7 +70,7 @@ index 00b0443..a7169a5 100644
|
||||
|
||||
static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
#if LINUX_VERSION_IS_LESS(4,10,0)
|
||||
@@ -930,9 +928,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
@@ -952,9 +950,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
#else
|
||||
.ndo_get_stats64 = bp_ieee80211_get_stats64,
|
||||
#endif
|
||||
@@ -80,7 +81,7 @@ index 00b0443..a7169a5 100644
|
||||
|
||||
static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
|
||||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
|
||||
index d15dadd..8770033 100644
|
||||
index c6fc75e..6b7b46b 100644
|
||||
--- a/net/mac80211/trace.h
|
||||
+++ b/net/mac80211/trace.h
|
||||
@@ -2899,14 +2899,12 @@ TRACE_EVENT(drv_twt_teardown_request,
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
From 0161154c18a464bbb350bcb5ef620bd255940640 Mon Sep 17 00:00:00 2001
|
||||
From e5612cde83ef67f8fa4633f7d364e05bac6e02a3 Mon Sep 17 00:00:00 2001
|
||||
From: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Date: Wed, 18 May 2022 15:10:22 +0800
|
||||
Subject: [PATCH 9901/9903] mac80211: mtk: add fill receive path ops to get wed
|
||||
Subject: [PATCH 9901/9902] mac80211: mtk: add fill receive path ops to get wed
|
||||
idx
|
||||
|
||||
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
---
|
||||
include/net/mac80211.h | 12 ++++++++++++
|
||||
net/mac80211/driver-ops.h | 13 +++++++++++++
|
||||
net/mac80211/driver-ops.h | 14 +++++++++++++-
|
||||
net/mac80211/iface.c | 24 ++++++++++++++++++++++++
|
||||
net/mac80211/util.c | 9 +++++++++
|
||||
4 files changed, 58 insertions(+)
|
||||
4 files changed, 58 insertions(+), 1 deletion(-)
|
||||
mode change 100644 => 100755 include/net/mac80211.h
|
||||
mode change 100644 => 100755 net/mac80211/util.c
|
||||
|
||||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
|
||||
old mode 100644
|
||||
new mode 100755
|
||||
index 42192cd..8a71026
|
||||
index c6625c2..cb8b28d
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1798,6 +1798,13 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
|
||||
@@ -34,30 +34,30 @@ index 42192cd..8a71026
|
||||
/**
|
||||
* enum ieee80211_key_flags - key flags
|
||||
*
|
||||
@@ -3975,6 +3982,8 @@ struct ieee80211_prep_tx_info {
|
||||
@@ -3982,6 +3989,8 @@ struct ieee80211_prep_tx_info {
|
||||
* disable background CAC/radar detection.
|
||||
* @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
|
||||
* resolve a path for hardware flow offloading
|
||||
+ * @net_fill_receive_path: Called from .ndo_fill_receive_path in order to
|
||||
+ * get a path for hardware flow offloading
|
||||
* @set_qos_map: Set QoS mapping information to driver.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@@ -4312,6 +4321,9 @@ struct ieee80211_ops {
|
||||
@@ -4320,6 +4329,9 @@ struct ieee80211_ops {
|
||||
struct ieee80211_sta *sta,
|
||||
struct net_device_path_ctx *ctx,
|
||||
struct net_device_path *path);
|
||||
+ int (*net_fill_receive_path)(struct ieee80211_hw *hw,
|
||||
+ struct net_device_path_ctx *ctx,
|
||||
+ struct net_device_path *path);
|
||||
int (*set_qos_map)(struct ieee80211_vif *vif,
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
|
||||
index 19e2ada..88dedfc 100644
|
||||
index 91ea8b2..348f815 100644
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1523,4 +1523,17 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
||||
@@ -1523,6 +1523,19 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -74,12 +74,20 @@ index 19e2ada..88dedfc 100644
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static inline int drv_set_qos_map(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_qos_map *qos_map)
|
||||
@@ -1538,5 +1551,4 @@ static inline int drv_set_qos_map(struct ieee80211_local *local,
|
||||
|
||||
return ret;
|
||||
}
|
||||
-
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
||||
index a7169a5..8a4f4e1 100644
|
||||
index 4b92867..c08bfbe 100644
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -911,6 +911,29 @@ out:
|
||||
@@ -933,6 +933,29 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -109,7 +117,7 @@ index a7169a5..8a4f4e1 100644
|
||||
static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
#if LINUX_VERSION_IS_LESS(4,10,0)
|
||||
.ndo_change_mtu = __change_mtu,
|
||||
@@ -929,6 +952,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
@@ -951,6 +974,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
.ndo_get_stats64 = bp_ieee80211_get_stats64,
|
||||
#endif
|
||||
.ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
|
||||
@@ -120,7 +128,7 @@ index a7169a5..8a4f4e1 100644
|
||||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
|
||||
old mode 100644
|
||||
new mode 100755
|
||||
index 8d36b05..d26a2b8
|
||||
index e07fe73..809eb37
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -898,6 +898,15 @@ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
From fdc7f27785b716eae1e02df73c095ecfe2677d9f Mon Sep 17 00:00:00 2001
|
||||
From d62db23d46d1887aff58c76b0eb9960a46afb9bf Mon Sep 17 00:00:00 2001
|
||||
From: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Date: Tue, 28 Mar 2023 10:53:31 +0800
|
||||
Subject: [PATCH 9902/9903] mac80211: mtk: add support for letting drivers
|
||||
Subject: [PATCH 9902/9902] mac80211: mtk: add support for letting drivers
|
||||
register tc offload support
|
||||
|
||||
On newer MediaTek SoCs (e.g. MT7986), WLAN->WLAN or WLAN->Ethernet flows can
|
||||
@@ -18,10 +18,10 @@ Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
5 files changed, 70 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
|
||||
index 8a71026..861bc9a 100755
|
||||
index cb8b28d..6104072 100755
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -3984,6 +3984,10 @@ struct ieee80211_prep_tx_info {
|
||||
@@ -3991,6 +3991,10 @@ struct ieee80211_prep_tx_info {
|
||||
* resolve a path for hardware flow offloading
|
||||
* @net_fill_receive_path: Called from .ndo_fill_receive_path in order to
|
||||
* get a path for hardware flow offloading
|
||||
@@ -29,10 +29,10 @@ index 8a71026..861bc9a 100755
|
||||
+ * flow offloading for flows originating from the vif.
|
||||
+ * Note that the driver must not assume that the vif driver_data is valid
|
||||
+ * at this point, since the callback can be called during netdev teardown.
|
||||
* @set_qos_map: Set QoS mapping information to driver.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@@ -4324,6 +4328,11 @@ struct ieee80211_ops {
|
||||
@@ -4332,6 +4336,11 @@ struct ieee80211_ops {
|
||||
int (*net_fill_receive_path)(struct ieee80211_hw *hw,
|
||||
struct net_device_path_ctx *ctx,
|
||||
struct net_device_path *path);
|
||||
@@ -41,14 +41,14 @@ index 8a71026..861bc9a 100755
|
||||
+ struct net_device *dev,
|
||||
+ enum tc_setup_type type,
|
||||
+ void *type_data);
|
||||
int (*set_qos_map)(struct ieee80211_vif *vif,
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
|
||||
index 88dedfc..3ceba5e 100644
|
||||
index 348f815..f56a71f 100644
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1536,4 +1536,21 @@ static inline int drv_net_fill_receive_path(struct ieee80211_local *local,
|
||||
@@ -1536,6 +1536,23 @@ static inline int drv_net_fill_receive_path(struct ieee80211_local *local,
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -69,12 +69,14 @@ index 88dedfc..3ceba5e 100644
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
static inline int drv_set_qos_map(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_qos_map *qos_map)
|
||||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
|
||||
index 2519c14..fe7a03a 100644
|
||||
index bb5906d..b02ca21 100644
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1822,7 +1822,8 @@ void ieee80211_color_aging_work(struct work_struct *work);
|
||||
@@ -1824,7 +1824,8 @@ void ieee80211_color_aging_work(struct work_struct *work);
|
||||
/* interface handling */
|
||||
#define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
|
||||
NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
@@ -85,10 +87,10 @@ index 2519c14..fe7a03a 100644
|
||||
#define MAC80211_SUPPORTED_FEATURES (MAC80211_SUPPORTED_FEATURES_TX | \
|
||||
MAC80211_SUPPORTED_FEATURES_RX)
|
||||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
||||
index 8a4f4e1..f3bf837 100644
|
||||
index c08bfbe..ddeaa8f 100644
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -773,6 +773,21 @@ static int __change_mtu(struct net_device *ndev, int new_mtu){
|
||||
@@ -795,6 +795,21 @@ static int __change_mtu(struct net_device *ndev, int new_mtu){
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -110,7 +112,7 @@ index 8a4f4e1..f3bf837 100644
|
||||
static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
#if LINUX_VERSION_IS_LESS(4,10,0)
|
||||
.ndo_change_mtu = __change_mtu,
|
||||
@@ -790,6 +805,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
@@ -812,6 +827,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
#else
|
||||
.ndo_get_stats64 = bp_ieee80211_get_stats64,
|
||||
#endif
|
||||
@@ -118,7 +120,7 @@ index 8a4f4e1..f3bf837 100644
|
||||
|
||||
};
|
||||
|
||||
@@ -953,6 +969,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
@@ -975,6 +991,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
|
||||
#endif
|
||||
.ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
|
||||
.ndo_fill_receive_path = ieee80211_netdev_fill_receive_path,
|
||||
@@ -127,7 +129,7 @@ index 8a4f4e1..f3bf837 100644
|
||||
|
||||
static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
|
||||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
|
||||
index 8770033..78d9803 100644
|
||||
index 6b7b46b..5aea24a 100644
|
||||
--- a/net/mac80211/trace.h
|
||||
+++ b/net/mac80211/trace.h
|
||||
@@ -2906,6 +2906,31 @@ DEFINE_EVENT(sta_event, drv_net_fill_forward_path,
|
||||
|
||||
@@ -483,20 +483,21 @@
|
||||
};
|
||||
|
||||
mmc0: mmc@11230000 {
|
||||
compatible = "mediatek,mt7986-mmc",
|
||||
"mediatek,mt7981-mmc";
|
||||
reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&topckgen CK_TOP_EMMC_208M>,
|
||||
<&topckgen CK_TOP_EMMC_400M>,
|
||||
<&infracfg_ao CK_INFRA_MSDC_CK>;
|
||||
assigned-clocks = <&topckgen CK_TOP_EMMC_208M_SEL>,
|
||||
<&topckgen CK_TOP_EMMC_400M_SEL>;
|
||||
assigned-clock-parents = <&topckgen CK_TOP_CB_M_D2>,
|
||||
<&topckgen CK_TOP_CB_NET2_D2>;
|
||||
clock-names = "source", "hclk", "source_cg";
|
||||
status = "disabled";
|
||||
};
|
||||
compatible = "mediatek,mt7986-mmc",
|
||||
"mediatek,mt7981-mmc";
|
||||
reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&topckgen CK_TOP_EMMC_208M>,
|
||||
<&topckgen CK_TOP_EMMC_400M>,
|
||||
<&infracfg_ao CK_INFRA_MSDC_66M_CK>,
|
||||
<&infracfg_ao CK_INFRA_MSDC_CK>;
|
||||
assigned-clocks = <&topckgen CK_TOP_EMMC_208M_SEL>,
|
||||
<&topckgen CK_TOP_EMMC_400M_SEL>;
|
||||
assigned-clock-parents = <&topckgen CK_TOP_CB_M_D2>,
|
||||
<&topckgen CK_TOP_CB_NET2_D2>;
|
||||
clock-names = "source", "hclk", "bus_clk", "source_cg";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
wbsys: wbsys@18000000 {
|
||||
compatible = "mediatek,wbsys",
|
||||
|
||||
@@ -55,7 +55,7 @@ static const struct mtk_fixed_factor infra_divs[] __initconst = {
|
||||
FACTOR(CK_INFRA_MUX_SPI1, "infra_mux_spi1", "infra_spi1_sel", 1, 1),
|
||||
FACTOR(CK_INFRA_MUX_SPI2, "infra_mux_spi2", "infra_spi2_sel", 1, 1),
|
||||
FACTOR(CK_INFRA_RTC_32K, "infra_rtc_32k", "cb_rtc_32k", 1, 1),
|
||||
FACTOR(CK_INFRA_FMSDC_CK, "infra_fmsdc", "emmc_400m", 1, 1),
|
||||
FACTOR(CK_INFRA_FMSDC_CK, "infra_fmsdc", "emmc_208m", 1, 1),
|
||||
FACTOR(CK_INFRA_FMSDC_HCK_CK, "infra_fmsdc_hck", "emmc_208m", 1, 1),
|
||||
FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", "sysaxi", 1, 1),
|
||||
FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", "sysaxi", 1, 1),
|
||||
|
||||
@@ -488,6 +488,16 @@ static const struct mtk_gate_regs infra2_cg_regs = {
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
#define GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, _flags) { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_name = _parent, \
|
||||
.regs = &infra0_cg_regs, \
|
||||
.shift = _shift, \
|
||||
.flags = _flags, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
static const struct mtk_gate infra_clks[] __initconst = {
|
||||
/* INFRA0 */
|
||||
GATE_INFRA0(CK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1),
|
||||
@@ -506,7 +516,7 @@ static const struct mtk_gate infra_clks[] __initconst = {
|
||||
GATE_INFRA0(CK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16),
|
||||
GATE_INFRA0(CK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24),
|
||||
GATE_INFRA0(CK_INFRA_SEJ_13M_CK, "infra_sej_13m", "infra_ck_f26m", 25),
|
||||
GATE_INFRA0(CK_INFRA_TRNG_CK, "infra_trng", "infra_hd_133m", 26),
|
||||
GATE_INFRA0_FLAGS(CK_INFRA_TRNG_CK, "infra_trng", "infra_hd_133m", 26, CLK_IS_CRITICAL),
|
||||
/* INFRA1 */
|
||||
GATE_INFRA1(CK_INFRA_THERM_CK, "infra_therm", "infra_ck_f26m", 0),
|
||||
GATE_INFRA1(CK_INFRA_I2CO_CK, "infra_i2co", "infra_i2cs", 1),
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Author: Lu Tang <Lu.Tang@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mux.h"
|
||||
#include <dt-bindings/clock/mediatek,mt7987-clk.h>
|
||||
|
||||
#define MT7987_PLL_FMAX (2500UL * MHZ)
|
||||
#define MT7987_PCW_CHG_SHIFT 2
|
||||
|
||||
#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, \
|
||||
_pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \
|
||||
_tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, _div_table, \
|
||||
_parent_name) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg, \
|
||||
.en_mask = _en_mask, .flags = _flags, \
|
||||
.rst_bar_mask = BIT(_rst_bar_mask), .fmax = MT7987_PLL_FMAX, \
|
||||
.pcwbits = _pcwbits, .pd_reg = _pd_reg, .pd_shift = _pd_shift, \
|
||||
.tuner_reg = _tuner_reg, .tuner_en_reg = _tuner_en_reg, \
|
||||
.tuner_en_bit = _tuner_en_bit, .pcw_reg = _pcw_reg, \
|
||||
.pcw_shift = _pcw_shift, .pcw_chg_reg = _pcw_chg_reg, \
|
||||
.pcw_chg_shift = MT7987_PCW_CHG_SHIFT, \
|
||||
.div_table = _div_table, .parent_name = _parent_name, \
|
||||
}
|
||||
|
||||
#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, \
|
||||
_pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \
|
||||
_tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, _parent_name) \
|
||||
PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, \
|
||||
_pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \
|
||||
_tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, NULL, \
|
||||
_parent_name)
|
||||
|
||||
static const struct mtk_pll_div_table mt7987_arm_ll_div[] = {
|
||||
{ .div = 0, .freq = 2000000000 },
|
||||
{ .div = 1, .freq = 1500000000 },
|
||||
{ .div = 2, .freq = 750000000 },
|
||||
{ .div = 3, .freq = 375000000 },
|
||||
{} /* sentinel */
|
||||
};
|
||||
|
||||
static const struct mtk_pll_data plls[] = {
|
||||
PLL(CK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR,
|
||||
23, 32, 0x0114, 4, 0, 0, 0, 0x0118, 0, 0x0114, "clkxtal"),
|
||||
PLL(CK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32,
|
||||
0x0134, 4, 0x0704, 0x0700, 1, 0x0138, 0, 0x0134, "clkxtal"),
|
||||
PLL(CK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001,
|
||||
HAVE_RST_BAR, 23, 32, 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144,
|
||||
"clkxtal"),
|
||||
PLL(CK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001,
|
||||
HAVE_RST_BAR | PLL_AO, 23, 32, 0x0154, 4, 0, 0, 0, 0x0158, 0,
|
||||
0x0154, "clkxtal"),
|
||||
PLL(CK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, 0,
|
||||
32, 0x0164, 4, 0, 0, 0, 0x0168, 0, 0x0164, "clkxtal"),
|
||||
PLL(CK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32,
|
||||
0x0174, 4, 0, 0, 0, 0x0178, 0, 0x0174, "clkxtal"),
|
||||
PLL_B(CK_APMIXED_ARM_LL, "arm_ll", 0x0104, 0x0110, 0x00000001,
|
||||
PLL_AO, 0, 32, 0x0104, 4, 0, 0, 0, 0x0108, 0, 0x0104,
|
||||
mt7987_arm_ll_div, "clkxtal"),
|
||||
PLL(CK_APMIXED_MSDCPLL, "msdcpll", 0x0124, 0x0130, 0x00000001, 0, 0, 32,
|
||||
0x0124, 4, 0, 0, 0, 0x0128, 0, 0x0124, "clkxtal"),
|
||||
};
|
||||
|
||||
static struct clk_onecell_data *mt7987_pll_clk_data __initdata;
|
||||
|
||||
static void __init mtk_apmixedsys_init(struct device_node *node)
|
||||
{
|
||||
int r;
|
||||
|
||||
mt7987_pll_clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
|
||||
|
||||
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
|
||||
mt7987_pll_clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get,
|
||||
mt7987_pll_clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt7987-apmixedsys",
|
||||
mtk_apmixedsys_init);
|
||||
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Author: Lu Tang <Lu.Tang@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-gate.h"
|
||||
#include <dt-bindings/clock/mediatek,mt7987-clk.h>
|
||||
|
||||
static const struct mtk_gate_regs ethdma_cg_regs = {
|
||||
.set_ofs = 0x30,
|
||||
.clr_ofs = 0x30,
|
||||
.sta_ofs = 0x30,
|
||||
};
|
||||
|
||||
#define GATE_ETHDMA(_id, _name, _parent, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = ðdma_cg_regs, .shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
|
||||
}
|
||||
|
||||
static const struct mtk_gate ethdma_clks[] = {
|
||||
GATE_ETHDMA(CK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x_sel", 6),
|
||||
GATE_ETHDMA(CK_ETHDMA_GP2_EN, "ethdma_gp2_en", "netsys_500m_sel", 7),
|
||||
GATE_ETHDMA(CK_ETHDMA_GP1_EN, "ethdma_gp1_en", "netsys_500m_sel", 8),
|
||||
GATE_ETHDMA(CK_ETHDMA_GP3_EN, "ethdma_gp3_en", "netsys_500m_sel", 10),
|
||||
};
|
||||
|
||||
static const struct mtk_gate_regs sgmii_cg_regs = {
|
||||
.set_ofs = 0xe4,
|
||||
.clr_ofs = 0xe4,
|
||||
.sta_ofs = 0xe4,
|
||||
};
|
||||
|
||||
#define GATE_SGMII(_id, _name, _parent, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = &sgmii_cg_regs, .shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
|
||||
}
|
||||
|
||||
static const struct mtk_gate sgmii0_clks[] = {
|
||||
GATE_SGMII(CK_SGM0_TX_EN, "sgm0_tx_en", "clkxtal", 2),
|
||||
GATE_SGMII(CK_SGM0_RX_EN, "sgm0_rx_en", "clkxtal", 3),
|
||||
};
|
||||
|
||||
static const struct mtk_gate sgmii1_clks[] = {
|
||||
GATE_SGMII(CK_SGM1_TX_EN, "sgm1_tx_en", "clkxtal", 2),
|
||||
GATE_SGMII(CK_SGM1_RX_EN, "sgm1_rx_en", "clkxtal", 3),
|
||||
};
|
||||
|
||||
static void __init mtk_sgmiisys_0_init(struct device_node *node)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
int r;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_SGMII0_NR_CLK);
|
||||
|
||||
mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks),
|
||||
clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7987-sgmiisys_0",
|
||||
mtk_sgmiisys_0_init);
|
||||
|
||||
static void __init mtk_sgmiisys_1_init(struct device_node *node)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
int r;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_SGMII1_NR_CLK);
|
||||
|
||||
mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks),
|
||||
clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7987-sgmiisys_1",
|
||||
mtk_sgmiisys_1_init);
|
||||
|
||||
static void __init mtk_ethdma_init(struct device_node *node)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
int r;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_ETHDMA_NR_CLK);
|
||||
|
||||
mtk_clk_register_gates(node, ethdma_clks, ARRAY_SIZE(ethdma_clks),
|
||||
clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_ethdma, "mediatek,mt7987-ethsys", mtk_ethdma_init);
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Author: Lu Tang <Lu.Tang@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 <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-mux.h"
|
||||
#include "clk-gate.h"
|
||||
#include <dt-bindings/clock/mediatek,mt7987-clk.h>
|
||||
|
||||
static DEFINE_SPINLOCK(mt7987_clk_lock);
|
||||
|
||||
static const char *const infra_mux_uart0_parents[] = { "csw_infra_f26m_sel",
|
||||
"uart_sel" };
|
||||
|
||||
static const char *const infra_mux_uart1_parents[] = { "csw_infra_f26m_sel",
|
||||
"uart_sel" };
|
||||
|
||||
static const char *const infra_mux_uart2_parents[] = { "csw_infra_f26m_sel",
|
||||
"uart_sel" };
|
||||
|
||||
static const char *const infra_mux_spi0_parents[] = {
|
||||
"i2c_sel",
|
||||
"spi_sel"
|
||||
};
|
||||
|
||||
static const char *const infra_mux_spi1_parents[] = {
|
||||
"i2c_sel",
|
||||
"spim_mst_sel"
|
||||
};
|
||||
|
||||
static const char *const infra_mux_spi2_bck_parents[] = {
|
||||
"i2c_sel",
|
||||
"spi_sel"
|
||||
};
|
||||
|
||||
static const char *const infra_pwm_bck_parents[] = { "cb_rtc_32p7k",
|
||||
"csw_infra_f26m_sel",
|
||||
"sysaxi_sel", "pwm_sel" };
|
||||
|
||||
static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] = {
|
||||
"cb_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel",
|
||||
"pextp_tl_ck_sel"
|
||||
};
|
||||
|
||||
static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] = {
|
||||
"cb_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel",
|
||||
"pextp_tl_ck_p1_sel"
|
||||
};
|
||||
|
||||
static struct mtk_mux infra_muxes[] = {
|
||||
/* MODULE_CLK_SEL_0 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
|
||||
infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0,
|
||||
1, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
|
||||
infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1,
|
||||
1, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
|
||||
infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2,
|
||||
1, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel",
|
||||
infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 4,
|
||||
1, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel",
|
||||
infra_mux_spi1_parents, 0x0018, 0x0010, 0x0014, 5,
|
||||
1, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI2_BCK_SEL,
|
||||
"infra_mux_spi2_bck_sel",
|
||||
infra_mux_spi2_bck_parents, 0x0018, 0x0010, 0x0014,
|
||||
6, 1, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_BCK_SEL, "infra_pwm_bck_sel",
|
||||
infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 14,
|
||||
2, -1, -1, -1),
|
||||
/* MODULE_CLK_SEL_1 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P0_SEL,
|
||||
"infra_pcie_gfmux_tl_ck_o_p0_sel",
|
||||
infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028,
|
||||
0x0020, 0x0024, 0, 2, -1, -1, -1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P1_SEL,
|
||||
"infra_pcie_gfmux_tl_ck_o_p1_sel",
|
||||
infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028,
|
||||
0x0020, 0x0024, 2, 2, -1, -1, -1),
|
||||
};
|
||||
|
||||
static const struct mtk_gate_regs infra0_cg_regs = {
|
||||
.set_ofs = 0x10,
|
||||
.clr_ofs = 0x14,
|
||||
.sta_ofs = 0x18,
|
||||
};
|
||||
|
||||
static const struct mtk_gate_regs infra1_cg_regs = {
|
||||
.set_ofs = 0x40,
|
||||
.clr_ofs = 0x44,
|
||||
.sta_ofs = 0x48,
|
||||
};
|
||||
|
||||
static const struct mtk_gate_regs infra2_cg_regs = {
|
||||
.set_ofs = 0x50,
|
||||
.clr_ofs = 0x54,
|
||||
.sta_ofs = 0x58,
|
||||
};
|
||||
|
||||
static const struct mtk_gate_regs infra3_cg_regs = {
|
||||
.set_ofs = 0x60,
|
||||
.clr_ofs = 0x64,
|
||||
.sta_ofs = 0x68,
|
||||
};
|
||||
|
||||
#define GATE_INFRA0(_id, _name, _parent, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = &infra0_cg_regs, .shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
#define GATE_INFRA1(_id, _name, _parent, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = &infra1_cg_regs, .shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
#define GATE_INFRA2(_id, _name, _parent, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = &infra2_cg_regs, .shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
#define GATE_INFRA3(_id, _name, _parent, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = &infra3_cg_regs, .shift = _shift, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
#define GATE_CRITICAL(_id, _name, _parent, _regs, _shift) \
|
||||
{ \
|
||||
.id = _id, .name = _name, .parent_name = _parent, \
|
||||
.regs = _regs, .shift = _shift, .flags = CLK_IS_CRITICAL, \
|
||||
.ops = &mtk_clk_gate_ops_setclr, \
|
||||
}
|
||||
|
||||
static const struct mtk_gate infra_clks[] __initconst = {
|
||||
/* INFRA1 */
|
||||
GATE_INFRA1(CK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck", "sysaxi_sel",
|
||||
0),
|
||||
GATE_INFRA1(CK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck", "sysaxi_sel",
|
||||
1),
|
||||
GATE_INFRA1(CK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck",
|
||||
"infra_pwm_bck_sel", 2),
|
||||
GATE_INFRA1(CK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck",
|
||||
"sysaxi_sel", 12),
|
||||
GATE_INFRA1(CK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck",
|
||||
"sysaxi_sel", 13),
|
||||
GATE_INFRA1(CK_INFRA_AUD_26M, "infra_f_faud_26m", "csw_infra_f26m_sel",
|
||||
14),
|
||||
GATE_INFRA1(CK_INFRA_AUD_L, "infra_f_faud_l", "aud_l_sel", 15),
|
||||
GATE_INFRA1(CK_INFRA_AUD_AUD, "infra_f_aud_aud", "a1sys_sel", 16),
|
||||
GATE_INFRA1(CK_INFRA_AUD_EG2, "infra_f_faud_eg2", "a_tuner_sel", 18),
|
||||
GATE_INFRA1(CK_INFRA_DRAMC_F26M, "infra_dramc_f26m",
|
||||
"csw_infra_f26m_sel", 19),
|
||||
GATE_CRITICAL(CK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm",
|
||||
"sysaxi_sel", &infra1_cg_regs, 20),
|
||||
GATE_INFRA1(CK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck",
|
||||
"sysaxi_sel", 21),
|
||||
GATE_INFRA1(CK_INFRA_MSDC200_SRC, "infra_f_fmsdc200_src",
|
||||
"emmc_200m_sel", 28),
|
||||
GATE_CRITICAL(CK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck", "sysaxi_sel",
|
||||
&infra1_cg_regs, 29),
|
||||
GATE_CRITICAL(CK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m",
|
||||
"csw_infra_f26m_sel", &infra1_cg_regs, 30),
|
||||
GATE_CRITICAL(CK_INFRA_66M_TRNG, "infra_hf_66m_trng", "sysaxi_sel",
|
||||
&infra1_cg_regs, 31),
|
||||
/* INFRA2 */
|
||||
GATE_INFRA2(CK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system",
|
||||
"csw_infra_f26m_sel", 0),
|
||||
GATE_INFRA2(CK_INFRA_I2C_BCK, "infra_i2c_bck", "i2c_sel", 1),
|
||||
GATE_INFRA2(CK_INFRA_66M_UART0_PCK, "infra_hf_66m_uart0_pck",
|
||||
"sysaxi_sel", 3),
|
||||
GATE_INFRA2(CK_INFRA_66M_UART1_PCK, "infra_hf_66m_uart1_pck",
|
||||
"sysaxi_sel", 4),
|
||||
GATE_INFRA2(CK_INFRA_66M_UART2_PCK, "infra_hf_66m_uart2_pck",
|
||||
"sysaxi_sel", 5),
|
||||
GATE_INFRA2(CK_INFRA_52M_UART0_CK, "infra_f_52m_uart0",
|
||||
"infra_mux_uart0_sel", 3),
|
||||
GATE_INFRA2(CK_INFRA_52M_UART1_CK, "infra_f_52m_uart1",
|
||||
"infra_mux_uart1_sel", 4),
|
||||
GATE_INFRA2(CK_INFRA_52M_UART2_CK, "infra_f_52m_uart2",
|
||||
"infra_mux_uart2_sel", 5),
|
||||
GATE_INFRA2(CK_INFRA_NFI, "infra_f_fnfi", "nfi_sel", 9),
|
||||
GATE_CRITICAL(CK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck",
|
||||
"sysaxi_sel", &infra2_cg_regs, 11),
|
||||
GATE_INFRA2(CK_INFRA_104M_SPI0, "infra_hf_104m_spi0",
|
||||
"infra_mux_spi0_sel", 12),
|
||||
GATE_INFRA2(CK_INFRA_104M_SPI1, "infra_hf_104m_spi1",
|
||||
"infra_mux_spi1_sel", 13),
|
||||
GATE_INFRA2(CK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck",
|
||||
"infra_mux_spi2_bck_sel", 14),
|
||||
GATE_INFRA2(CK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck",
|
||||
"sysaxi_sel", 15),
|
||||
GATE_INFRA2(CK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck",
|
||||
"sysaxi_sel", 16),
|
||||
GATE_INFRA2(CK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck",
|
||||
"sysaxi_sel", 17),
|
||||
GATE_INFRA2(CK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi",
|
||||
"sysaxi_sel", 18),
|
||||
GATE_CRITICAL(CK_INFRA_RTC, "infra_f_frtc", "cb_rtc_32k",
|
||||
&infra2_cg_regs, 19),
|
||||
GATE_INFRA2(CK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck",
|
||||
"csw_infra_f26m_sel", 20),
|
||||
GATE_INFRA2(CK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck",
|
||||
21),
|
||||
GATE_INFRA2(CK_INFRA_MSDC400, "infra_f_fmsdc400", "emmc_400m_sel", 22),
|
||||
GATE_INFRA2(CK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck", "emmc_250m_sel",
|
||||
23),
|
||||
GATE_INFRA2(CK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck",
|
||||
"sysaxi_sel", 24),
|
||||
GATE_INFRA2(CK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck",
|
||||
"sysaxi_sel", 25),
|
||||
GATE_INFRA2(CK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck",
|
||||
"sysaxi_sel", 26),
|
||||
GATE_INFRA2(CK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "nfi_sel", 27),
|
||||
GATE_INFRA2(CK_INFRA_I2C_X16W_MCK_CK_P1, "infra_hf_i2c_x16w_mck_ck_p1",
|
||||
"sysaxi_sel", 29),
|
||||
GATE_INFRA2(CK_INFRA_I2C_X16W_PCK_CK_P1, "infra_hf_i2c_x16w_pck_ck_p1",
|
||||
"sysaxi_sel", 31),
|
||||
/* INFRA3 */
|
||||
GATE_INFRA3(CK_INFRA_133M_USB_HCK, "infra_133m_usb_hck", "sysaxi_sel",
|
||||
0),
|
||||
GATE_INFRA3(CK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1",
|
||||
"sysaxi_sel", 1),
|
||||
GATE_INFRA3(CK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "sysaxi_sel", 2),
|
||||
GATE_INFRA3(CK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1",
|
||||
"sysaxi_sel", 3),
|
||||
GATE_INFRA3(CK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1",
|
||||
"usb_sys_p1_sel", 5),
|
||||
GATE_INFRA3(CK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "cb_cksq_40m", 7),
|
||||
GATE_CRITICAL(CK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1",
|
||||
"cksq_40m_d2", &infra3_cg_regs, 9),
|
||||
GATE_CRITICAL(CK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1",
|
||||
"usb_phy_sel", &infra3_cg_regs, 11),
|
||||
GATE_INFRA3(CK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1", "clkxtal",
|
||||
13),
|
||||
GATE_INFRA3(CK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1",
|
||||
"usb_xhci_p1_sel", 15),
|
||||
GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0",
|
||||
"infra_pcie_gfmux_tl_ck_o_p0_sel", 20),
|
||||
GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1",
|
||||
"infra_pcie_gfmux_tl_ck_o_p1_sel", 21),
|
||||
GATE_INFRA3(CK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0", "clkxtal",
|
||||
24),
|
||||
GATE_INFRA3(CK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1", "clkxtal",
|
||||
25),
|
||||
GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0",
|
||||
"sysaxi_sel", 28),
|
||||
GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1",
|
||||
"sysaxi_sel", 29),
|
||||
/* INFRA0 */
|
||||
GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P0,
|
||||
"infra_pcie_peri_ck_26m_ck_p0", "csw_infra_f26m_sel", 7),
|
||||
GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P1,
|
||||
"infra_pcie_peri_ck_26m_ck_p1", "csw_infra_f26m_sel", 8),
|
||||
};
|
||||
|
||||
static struct clk_onecell_data *mt7987_infra_ao_clk_data __initdata;
|
||||
|
||||
static void __init mtk_infracfg_ao_init(struct device_node *node)
|
||||
{
|
||||
int r;
|
||||
void __iomem *base;
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base) {
|
||||
pr_err("%s(): ioremap failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mt7987_infra_ao_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
|
||||
|
||||
mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node,
|
||||
&mt7987_clk_lock, mt7987_infra_ao_clk_data);
|
||||
mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
|
||||
mt7987_infra_ao_clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get,
|
||||
mt7987_infra_ao_clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_infracfg_ao, "mediatek,mt7987-infracfg_ao",
|
||||
mtk_infracfg_ao_init);
|
||||
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Author: Sam Shih <sam.shih@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mux.h"
|
||||
#include <dt-bindings/clock/mediatek,mt7987-clk.h>
|
||||
|
||||
static DEFINE_SPINLOCK(mt7987_clk_lock);
|
||||
static const char *const mcu_bus_div_parents[] = { "cb_cksq_40m", "arm_ll" };
|
||||
|
||||
static struct mtk_mux mcu_muxes[] = {
|
||||
{
|
||||
.id = CK_MCU_BUS_DIV_SEL,
|
||||
.name = "mcu_bus_div_sel",
|
||||
.mux_ofs = 0x7C0,
|
||||
.mux_shift = 9,
|
||||
.mux_width = 1,
|
||||
.parent_names = mcu_bus_div_parents,
|
||||
.num_parents = ARRAY_SIZE(mcu_bus_div_parents),
|
||||
.ops = &mtk_mux_ops,
|
||||
.flags = CLK_IS_CRITICAL,
|
||||
}
|
||||
};
|
||||
|
||||
static void __init mtk_mcusys_init(struct device_node *node)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
int r;
|
||||
void __iomem *base;
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base) {
|
||||
pr_err("%s(): ioremap failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK);
|
||||
|
||||
mtk_clk_register_muxes(mcu_muxes, ARRAY_SIZE(mcu_muxes), node,
|
||||
&mt7987_clk_lock, clk_data);
|
||||
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_mcusys, "mediatek,mt7987-mcusys", mtk_mcusys_init);
|
||||
@@ -0,0 +1,310 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Author: Lu Tang <Lu.Tang@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mux.h"
|
||||
#include <dt-bindings/clock/mediatek,mt7987-clk.h>
|
||||
|
||||
static DEFINE_SPINLOCK(mt7987_clk_lock);
|
||||
|
||||
static const struct mtk_fixed_factor top_divs[] __initconst = {
|
||||
FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),
|
||||
FACTOR(CK_TOP_CB_M_D3, "cb_m_d3", "mpll", 1, 3),
|
||||
FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 6),
|
||||
FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),
|
||||
FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),
|
||||
FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),
|
||||
FACTOR(CK_TOP_CB_APLL2_D4, "cb_apll2_d4", "apll2", 1, 4),
|
||||
FACTOR(CK_TOP_CB_NET1_D3, "cb_net1_d3", "net1pll", 1, 3),
|
||||
FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),
|
||||
FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),
|
||||
FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),
|
||||
FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),
|
||||
FACTOR(CK_TOP_CB_NET1_D7, "cb_net1_d7", "net1pll", 1, 7),
|
||||
FACTOR(CK_TOP_NET1_D7_D2, "net1_d7_d2", "net1pll", 1, 14),
|
||||
FACTOR(CK_TOP_NET1_D7_D4, "net1_d7_d4", "net1pll", 1, 28),
|
||||
FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),
|
||||
FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),
|
||||
FACTOR(CK_TOP_NET1_D8_D8, "net1_d8_d8", "net1pll", 1, 64),
|
||||
FACTOR(CK_TOP_NET1_D8_D16, "net1_d8_d16", "net1pll", 1, 128),
|
||||
FACTOR(CK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2),
|
||||
FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),
|
||||
FACTOR(CK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16),
|
||||
FACTOR(CK_TOP_NET2_D4_D8, "net2_d4_d8", "net2pll", 1, 32),
|
||||
FACTOR(CK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6),
|
||||
FACTOR(CK_TOP_NET2_D7_D2, "net2_d7_d2", "net2pll", 1, 14),
|
||||
FACTOR(CK_TOP_CB_NET2_D8, "cb_net2_d8", "net2pll", 1, 8),
|
||||
FACTOR(CK_TOP_MSDC_D2, "msdc_d2", "msdcpll", 1, 2),
|
||||
FACTOR(CK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),
|
||||
FACTOR(CK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2),
|
||||
FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),
|
||||
FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1221),
|
||||
};
|
||||
|
||||
static const char *const netsys_parents[] = { "cb_cksq_40m", "cb_net2_d2" };
|
||||
|
||||
static const char *const netsys_500m_parents[] = { "cb_cksq_40m", "cb_net1_d5",
|
||||
"net1_d5_d2" };
|
||||
|
||||
static const char *const netsys_2x_parents[] = { "cb_cksq_40m", "net2pll" };
|
||||
|
||||
static const char *const eth_gmii_parents[] = { "cb_cksq_40m", "net1_d5_d4" };
|
||||
|
||||
static const char *const eip_parents[] = { "cb_cksq_40m", "cb_net1_d3",
|
||||
"net2pll", "cb_net1_d4",
|
||||
"cb_net1_d5" };
|
||||
|
||||
static const char *const axi_infra_parents[] = { "cb_cksq_40m", "net1_d8_d2" };
|
||||
|
||||
static const char *const uart_parents[] = { "cb_cksq_40m", "cb_m_d8",
|
||||
"m_d8_d2" };
|
||||
|
||||
static const char *const emmc_250m_parents[] = { "cb_cksq_40m", "net1_d5_d2",
|
||||
"net1_d7_d2" };
|
||||
|
||||
static const char *const emmc_400m_parents[] = { "cb_cksq_40m", "msdcpll",
|
||||
"cb_net1_d7", "cb_m_d2",
|
||||
"net1_d7_d2", "cb_net2_d6" };
|
||||
|
||||
static const char *const spi_parents[] = { "cb_cksq_40m", "cb_m_d2",
|
||||
"net1_d7_d2", "net1_d8_d2",
|
||||
"cb_net2_d6", "net1_d5_d4",
|
||||
"cb_m_d4", "net1_d8_d4" };
|
||||
|
||||
static const char *const nfi_parents[] = {
|
||||
"cksq_40m_d2", "net1_d8_d2", "cb_m_d3", "net1_d5_d4", "cb_m_d4",
|
||||
"net1_d7_d4", "net1_d8_d4", "m_d3_d2", "net2_d7_d2", "cb_m_d8"
|
||||
};
|
||||
|
||||
static const char *const pwm_parents[] = { "cb_cksq_40m", "net1_d8_d2",
|
||||
"net1_d5_d4", "cb_m_d4",
|
||||
"m_d8_d2", "cb_rtc_32k" };
|
||||
|
||||
static const char *const i2c_parents[] = { "cb_cksq_40m", "net1_d5_d4",
|
||||
"cb_m_d4", "net1_d8_d4" };
|
||||
|
||||
static const char *const pcie_mbist_250m_parents[] = { "cb_cksq_40m",
|
||||
"net1_d5_d2" };
|
||||
|
||||
static const char *const pextp_tl_ck_parents[] = { "cb_cksq_40m", "cb_net2_d6",
|
||||
"net1_d7_d4", "m_d8_d2",
|
||||
"cb_rtc_32k" };
|
||||
|
||||
static const char *const aud_parents[] = { "cb_cksq_40m", "apll2" };
|
||||
|
||||
static const char *const a1sys_parents[] = { "cb_cksq_40m", "cb_apll2_d4" };
|
||||
|
||||
static const char *const aud_l_parents[] = { "cb_cksq_40m", "apll2",
|
||||
"m_d8_d2" };
|
||||
|
||||
static const char *const usb_phy_parents[] = { "cksq_40m_d2", "m_d8_d2" };
|
||||
|
||||
static const char *const sgm_0_parents[] = { "cb_cksq_40m", "sgmpll" };
|
||||
|
||||
static const char *const sgm_sbus_0_parents[] = { "cb_cksq_40m", "net1_d8_d4" };
|
||||
|
||||
static const char *const sysapb_parents[] = { "cb_cksq_40m", "m_d3_d2" };
|
||||
|
||||
static const char *const eth_refck_50m_parents[] = { "cb_cksq_40m",
|
||||
"net2_d4_d4" };
|
||||
|
||||
static const char *const eth_sys_200m_parents[] = { "cb_cksq_40m",
|
||||
"cb_net2_d4" };
|
||||
|
||||
static const char *const eth_xgmii_parents[] = { "cksq_40m_d2", "net1_d8_d8",
|
||||
"net1_d8_d16" };
|
||||
|
||||
static const char *const dramc_md32_parents[] = { "cb_cksq_40m", "cb_m_d2",
|
||||
"wedmcupll" };
|
||||
|
||||
static const char *const da_xtp_glb_p0_parents[] = { "cb_cksq_40m",
|
||||
"cb_net2_d8" };
|
||||
|
||||
static const char *const da_ckm_xtal_parents[] = { "cb_cksq_40m", "m_d8_d2" };
|
||||
|
||||
static const char *const eth_mii_parents[] = { "cksq_40m_d2", "net2_d4_d8" };
|
||||
|
||||
static const char *const emmc_200m_parents[] = { "cb_cksq_40m", "msdc_d2",
|
||||
"net1_d7_d2", "cb_net2_d6",
|
||||
"net1_d7_d4" };
|
||||
|
||||
static struct mtk_mux top_muxes[] = {
|
||||
/* CLK_CFG_0 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents,
|
||||
0x000, 0x004, 0x008, 0, 1, 7, 0x1C0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",
|
||||
netsys_500m_parents, 0x000, 0x004, 0x008, 8, 2, 15,
|
||||
0x1C0, 1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",
|
||||
netsys_2x_parents, 0x000, 0x004, 0x008, 16, 1, 23,
|
||||
0x1C0, 2),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_GMII_SEL, "eth_gmii_sel",
|
||||
eth_gmii_parents, 0x000, 0x004, 0x008, 24, 1, 31,
|
||||
0x1C0, 3),
|
||||
/* CLK_CFG_1 */
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_EIP_SEL, "eip_sel", eip_parents,
|
||||
0x010, 0x014, 0x018, 0, 3, 7, 0x1C0, 4,
|
||||
CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_AXI_INFRA_SEL, "axi_infra_sel",
|
||||
axi_infra_parents, 0x010, 0x014, 0x018, 8,
|
||||
1, 15, 0x1C0, 5, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_UART_SEL, "uart_sel", uart_parents, 0x010,
|
||||
0x014, 0x018, 16, 2, 23, 0x1C0, 6),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_250M_SEL, "emmc_250m_sel",
|
||||
emmc_250m_parents, 0x010, 0x014, 0x018, 24, 2, 31,
|
||||
0x1C0, 7),
|
||||
/* CLK_CFG_2 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_400M_SEL, "emmc_400m_sel",
|
||||
emmc_400m_parents, 0x020, 0x024, 0x028, 0, 3, 7,
|
||||
0x1C0, 8),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x020,
|
||||
0x024, 0x028, 8, 3, 15, 0x1C0, 9),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents,
|
||||
0x020, 0x024, 0x028, 16, 3, 23, 0x1C0, 10),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_NFI_SEL, "nfi_sel", nfi_parents, 0x020,
|
||||
0x024, 0x028, 24, 4, 31, 0x1C0, 11),
|
||||
/* CLK_CFG_3 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x030,
|
||||
0x034, 0x038, 0, 3, 7, 0x1C0, 12),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x030,
|
||||
0x034, 0x038, 8, 2, 15, 0x1C0, 13),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_PCIE_MBIST_250M_SEL, "pcie_mbist_250m_sel",
|
||||
pcie_mbist_250m_parents, 0x030, 0x034, 0x038, 16,
|
||||
1, 23, 0x1C0, 14),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",
|
||||
pextp_tl_ck_parents, 0x030, 0x034, 0x038, 24, 3,
|
||||
31, 0x1C0, 15),
|
||||
/* CLK_CFG_4 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_ck_p1_sel",
|
||||
pextp_tl_ck_parents, 0x040, 0x044, 0x048, 0, 3, 7,
|
||||
0x1C0, 16),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel",
|
||||
eth_gmii_parents, 0x040, 0x044, 0x048, 8, 1, 15,
|
||||
0x1C0, 17),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel",
|
||||
eth_gmii_parents, 0x040, 0x044, 0x048, 16, 1, 23,
|
||||
0x1C0, 18),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x040,
|
||||
0x044, 0x048, 24, 1, 31, 0x1C0, 19),
|
||||
/* CLK_CFG_5 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
|
||||
0x050, 0x054, 0x058, 0, 1, 7, 0x1C0, 20),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
|
||||
0x050, 0x054, 0x058, 8, 2, 15, 0x1C0, 21),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents,
|
||||
0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_USB_PHY_SEL, "usb_phy_sel", usb_phy_parents,
|
||||
0x050, 0x054, 0x058, 24, 1, 31, 0x1C0, 23),
|
||||
/* CLK_CFG_6 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents,
|
||||
0x060, 0x064, 0x068, 0, 1, 7, 0x1C0, 24),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel",
|
||||
sgm_sbus_0_parents, 0x060, 0x064, 0x068, 8,
|
||||
1, 15, 0x1C0, 25, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents,
|
||||
0x060, 0x064, 0x068, 16, 1, 23, 0x1C0, 26),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel",
|
||||
sgm_sbus_0_parents, 0x060, 0x064, 0x068, 24,
|
||||
1, 31, 0x1C0, 27, CLK_IS_CRITICAL),
|
||||
/* CLK_CFG_7 */
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_SYSAXI_SEL, "sysaxi_sel",
|
||||
axi_infra_parents, 0x070, 0x074, 0x078, 0, 1,
|
||||
7, 0x1C0, 28, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_SYSAPB_SEL, "sysapb_sel",
|
||||
sysapb_parents, 0x070, 0x074, 0x078, 8, 1,
|
||||
15, 0x1C0, 29, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel",
|
||||
eth_refck_50m_parents, 0x070, 0x074, 0x078, 16, 1,
|
||||
23, 0x1C0, 30),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel",
|
||||
eth_sys_200m_parents, 0x070, 0x074, 0x078, 24, 1,
|
||||
31, 0x1C4, 0),
|
||||
/* CLK_CFG_8 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_SYS_SEL, "eth_sys_sel",
|
||||
pcie_mbist_250m_parents, 0x080, 0x084, 0x088, 0, 1,
|
||||
7, 0x1C4, 1),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel",
|
||||
eth_xgmii_parents, 0x080, 0x084, 0x088, 8, 2, 15,
|
||||
0x1C4, 2),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_DRAMC_SEL, "dramc_sel",
|
||||
usb_phy_parents, 0x080, 0x084, 0x088, 16, 1,
|
||||
23, 0x1C4, 3, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
|
||||
dramc_md32_parents, 0x080, 0x084, 0x088, 24,
|
||||
2, 31, 0x1C4, 4, CLK_IS_CRITICAL),
|
||||
/* CLK_CFG_9 */
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel",
|
||||
usb_phy_parents, 0x090, 0x094, 0x098, 0, 1,
|
||||
7, 0x1C4, 5, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_PEXTP_P0_SEL, "pextp_p0_sel",
|
||||
usb_phy_parents, 0x090, 0x094, 0x098, 8, 1,
|
||||
15, 0x1C4, 6, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD_FLAGS(CK_TOP_PEXTP_P1_SEL, "pextp_p1_sel",
|
||||
usb_phy_parents, 0x090, 0x094, 0x098, 16, 1,
|
||||
23, 0x1C4, 7, CLK_IS_CRITICAL),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel",
|
||||
da_xtp_glb_p0_parents, 0x090, 0x094, 0x098, 24, 1,
|
||||
31, 0x1C4, 8),
|
||||
/* CLK_CFG_10 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel",
|
||||
da_xtp_glb_p0_parents, 0x0A0, 0x0A4, 0x0A8, 0, 1,
|
||||
7, 0x1C4, 9),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_CKM_SEL, "ckm_sel", usb_phy_parents, 0x0A0,
|
||||
0x0A4, 0x0A8, 8, 1, 15, 0x1C4, 10),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_DA_CKM_XTAL_SEL, "da_ckm_xtal_sel",
|
||||
da_ckm_xtal_parents, 0x0A0, 0x0A4, 0x0A8, 16, 1,
|
||||
23, 0x1C4, 11),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_SEL, "pextp_sel", usb_phy_parents,
|
||||
0x0A0, 0x0A4, 0x0A8, 24, 1, 31, 0x1C4, 12),
|
||||
/* CLK_CFG_11 */
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_MII_SEL, "eth_mii_sel", eth_mii_parents,
|
||||
0x0B0, 0x0B4, 0x0B8, 0, 1, 7, 0x1C4, 13),
|
||||
MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_200M_SEL, "emmc_200m_sel",
|
||||
emmc_200m_parents, 0x0B0, 0x0B4, 0x0B8, 8, 3, 15,
|
||||
0x1C4, 14),
|
||||
};
|
||||
|
||||
static const struct mtk_composite top_adj_divs[] = {
|
||||
DIV_GATE(CK_TOP_AUD_I2S_M, "aud_i2s_m", "aud_sel", 0x0420, 0, 0x0420, 8,
|
||||
8),
|
||||
};
|
||||
|
||||
static struct clk_onecell_data *mt7987_top_clk_data __initdata;
|
||||
|
||||
static void __init mtk_topckgen_init(struct device_node *node)
|
||||
{
|
||||
int r;
|
||||
void __iomem *base;
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base) {
|
||||
pr_err("%s(): ioremap failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mt7987_top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
|
||||
|
||||
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
|
||||
mt7987_top_clk_data);
|
||||
mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
|
||||
&mt7987_clk_lock, mt7987_top_clk_data);
|
||||
mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs),
|
||||
base, &mt7987_clk_lock,
|
||||
mt7987_top_clk_data);
|
||||
r = of_clk_add_provider(node, of_clk_src_onecell_get,
|
||||
mt7987_top_clk_data);
|
||||
|
||||
if (r)
|
||||
pr_err("%s(): could not register clock provider: %d\n",
|
||||
__func__, r);
|
||||
}
|
||||
CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt7987-topckgen", mtk_topckgen_init);
|
||||
@@ -741,10 +741,10 @@ static const struct mtk_gate infra_clks[] __initconst = {
|
||||
"infra_133m_mck", &infra1_cg_regs, 20),
|
||||
GATE_INFRA1(CK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck",
|
||||
"infra_66m_mck", 21),
|
||||
GATE_INFRA1(CK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck",
|
||||
"infra_66m_mck", 29),
|
||||
GATE_INFRA1(CK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m",
|
||||
"infra_ck_f26m", 30),
|
||||
GATE_CRITICAL(CK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck",
|
||||
"infra_66m_mck", &infra1_cg_regs, 29),
|
||||
GATE_CRITICAL(CK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m",
|
||||
"infra_ck_f26m", &infra1_cg_regs, 30),
|
||||
/* INFRA2 */
|
||||
GATE_INFRA2(CK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system",
|
||||
"infra_ck_f26m", 0),
|
||||
@@ -812,10 +812,10 @@ static const struct mtk_gate infra_clks[] __initconst = {
|
||||
"infra_usb_frmcnt_o", &infra3_cg_regs, 8),
|
||||
GATE_CRITICAL(CK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1",
|
||||
"infra_usb_frmcnt_o_p1", &infra3_cg_regs, 9),
|
||||
GATE_INFRA3(CK_INFRA_USB_PIPE, "infra_usb_pipe", "infra_usb_pipe_o",
|
||||
10),
|
||||
GATE_INFRA3(CK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1",
|
||||
"infra_usb_pipe_o_p1", 11),
|
||||
GATE_CRITICAL(CK_INFRA_USB_PIPE, "infra_usb_pipe", "infra_usb_pipe_o",
|
||||
&infra3_cg_regs, 10),
|
||||
GATE_CRITICAL(CK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1",
|
||||
"infra_usb_pipe_o_p1", &infra3_cg_regs, 11),
|
||||
GATE_INFRA3(CK_INFRA_USB_UTMI, "infra_usb_utmi", "infra_usb_utmi_o",
|
||||
12),
|
||||
GATE_INFRA3(CK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1",
|
||||
|
||||
1218
feeds/mediatek-sdk/mediatek/files-5.4/drivers/iio/pressure/zts8232.c
Normal file
1218
feeds/mediatek-sdk/mediatek/files-5.4/drivers/iio/pressure/zts8232.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,12 +20,72 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <net/dsa.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "an8855.h"
|
||||
#include "an8855_nl.h"
|
||||
#include "an8855_phy.h"
|
||||
|
||||
/* AN8855 driver version */
|
||||
#define ARHT_AN8855_DSA_DRIVER_VER "1.0.1-L5.4"
|
||||
#define ARHT_AN8855_DSA_DRIVER_VER "1.0.2"
|
||||
|
||||
#define ARHT_CHIP_NAME "an8855"
|
||||
#define ARHT_PROC_DIR "air_sw"
|
||||
#define ARHT_PROC_NODE_DEVICE "device"
|
||||
|
||||
struct proc_dir_entry *proc_an8855_dsa_dir;
|
||||
|
||||
/* T830 AN8855 Reference Board */
|
||||
static const struct an8855_led_cfg led_cfg[] = {
|
||||
/*************************************************************************
|
||||
* Enable, LED idx, LED Polarity, LED ON event, LED Blink event LED Freq
|
||||
*************************************************************************
|
||||
*/
|
||||
/* GPIO0 */
|
||||
{1, P4_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO1 */
|
||||
{1, P4_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO2 */
|
||||
{1, P0_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO3 */
|
||||
{1, P0_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO4 */
|
||||
{1, P1_LED0, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO5 */
|
||||
{1, P1_LED1, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO6 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO7 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO8 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO9 */
|
||||
{1, P2_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO10 */
|
||||
{1, P2_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO11 */
|
||||
{1, P3_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO12 */
|
||||
{1, P3_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO13 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO14 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO15 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO16 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO17 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO18 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO19 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO20 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
};
|
||||
|
||||
/* String, offset, and register size in bytes if different from 4 bytes */
|
||||
static const struct an8855_mib_desc an8855_mib[] = {
|
||||
@@ -99,7 +159,6 @@ an8855_mii_write(struct an8855_priv *priv, u32 reg, u32 val)
|
||||
ret = bus->write(bus, priv->phy_base, 0x14, (val & 0xFFFF));
|
||||
|
||||
ret = bus->write(bus, priv->phy_base, 0x1f, 0);
|
||||
ret = bus->write(bus, priv->phy_base, 0x10, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&bus->dev, "failed to write an8855 register\n");
|
||||
@@ -130,7 +189,6 @@ an8855_mii_read(struct an8855_priv *priv, u32 reg)
|
||||
hi = bus->read(bus, priv->phy_base, 0x17);
|
||||
|
||||
ret = bus->write(bus, priv->phy_base, 0x1f, 0);
|
||||
ret = bus->write(bus, priv->phy_base, 0x10, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&bus->dev, "failed to read an8855 register\n");
|
||||
return ret;
|
||||
@@ -327,16 +385,22 @@ an8855_phy_write(struct dsa_switch *ds, int port, int regnum,
|
||||
static int
|
||||
an8855_cl45_read(struct an8855_priv *priv, int port, int devad, int regnum)
|
||||
{
|
||||
regnum = MII_ADDR_C45 | (devad << 16) | regnum;
|
||||
return mdiobus_read_nested(priv->bus, port, regnum);
|
||||
an8855_cl22_write(priv, port, 0x0d, devad);
|
||||
an8855_cl22_write(priv, port, 0x0e, regnum);
|
||||
an8855_cl22_write(priv, port, 0x0d, devad | (0x4000));
|
||||
return an8855_cl22_read(priv, port, 0x0e);
|
||||
}
|
||||
|
||||
static int
|
||||
an8855_cl45_write(struct an8855_priv *priv, int port, int devad, int regnum,
|
||||
u16 val)
|
||||
{
|
||||
regnum = MII_ADDR_C45 | (devad << 16) | regnum;
|
||||
return mdiobus_write_nested(priv->bus, port, regnum, val);
|
||||
an8855_cl22_write(priv, port, 0x0d, devad);
|
||||
an8855_cl22_write(priv, port, 0x0e, regnum);
|
||||
an8855_cl22_write(priv, port, 0x0d, devad | (0x4000));
|
||||
an8855_cl22_write(priv, port, 0x0e, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -457,7 +521,6 @@ an8855_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy)
|
||||
priv->ports[port].pm |= PORTMATRIX_MATRIX(BIT(AN8855_CPU_PORT));
|
||||
priv->ports[port].enable = true;
|
||||
an8855_write(priv, AN8855_PORTMATRIX_P(port), priv->ports[port].pm);
|
||||
an8855_clear(priv, AN8855_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
|
||||
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
|
||||
@@ -479,7 +542,6 @@ an8855_port_disable(struct dsa_switch *ds, int port)
|
||||
*/
|
||||
priv->ports[port].enable = false;
|
||||
an8855_write(priv, AN8855_PORTMATRIX_P(port), PORTMATRIX_CLR);
|
||||
an8855_clear(priv, AN8855_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
|
||||
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
}
|
||||
@@ -1089,13 +1151,223 @@ setup_unused_ports(struct dsa_switch *ds, u32 pm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_set_usr_def(struct dsa_switch *ds, u8 entity,
|
||||
int polar, u16 on_evt, u16 blk_evt, u8 led_freq)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
u32 cl45_data = 0;
|
||||
|
||||
if (polar == LED_HIGH)
|
||||
on_evt |= LED_ON_POL;
|
||||
else
|
||||
on_evt &= ~LED_ON_POL;
|
||||
|
||||
/* LED on event */
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_ON_CTRL(entity % 4), on_evt | LED_ON_EN);
|
||||
|
||||
/* LED blink event */
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_BLK_CTRL(entity % 4), blk_evt);
|
||||
|
||||
/* LED freq */
|
||||
switch (led_freq) {
|
||||
case AIR_LED_BLK_DUR_32M:
|
||||
cl45_data = 0x30e;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_64M:
|
||||
cl45_data = 0x61a;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_128M:
|
||||
cl45_data = 0xc35;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_256M:
|
||||
cl45_data = 0x186a;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_512M:
|
||||
cl45_data = 0x30d4;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_1024M:
|
||||
cl45_data = 0x61a8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_BLK_DUR(entity % 4), cl45_data);
|
||||
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_ON_DUR(entity % 4), (cl45_data >> 1));
|
||||
|
||||
/* Disable DATA & BAD_SSD for port LED blink behavior */
|
||||
cl45_data = an8855_phy_cl45_read(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_PMA_CTRL);
|
||||
cl45_data &= ~BIT(0);
|
||||
cl45_data &= ~BIT(15);
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_PMA_CTRL, cl45_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_set_mode(struct dsa_switch *ds, u8 mode)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
u16 cl45_data;
|
||||
|
||||
cl45_data = an8855_phy_cl45_read(priv, 0, PHY_DEV1F, PHY_LED_BCR);
|
||||
switch (mode) {
|
||||
case AN8855_LED_MODE_DISABLE:
|
||||
cl45_data &= ~LED_BCR_EXT_CTRL;
|
||||
cl45_data &= ~LED_BCR_MODE_MASK;
|
||||
cl45_data |= LED_BCR_MODE_DISABLE;
|
||||
break;
|
||||
case AN8855_LED_MODE_USER_DEFINE:
|
||||
cl45_data |= LED_BCR_EXT_CTRL;
|
||||
cl45_data |= LED_BCR_CLK_EN;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "LED mode%d is not supported!\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
an8855_phy_cl45_write(priv, 0, PHY_DEV1F, PHY_LED_BCR, cl45_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_set_state(struct dsa_switch *ds, u8 entity, u8 state)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
u16 cl45_data = 0;
|
||||
|
||||
/* Change to per port contorl */
|
||||
cl45_data = an8855_phy_cl45_read(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_LED_CTRL_SELECT);
|
||||
|
||||
if (state == 1)
|
||||
cl45_data |= (1 << (entity % 4));
|
||||
else
|
||||
cl45_data &= ~(1 << (entity % 4));
|
||||
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_LED_CTRL_SELECT, cl45_data);
|
||||
|
||||
/* LED enable setting */
|
||||
cl45_data = an8855_phy_cl45_read(priv, (entity / 4),
|
||||
PHY_DEV1E, PHY_SINGLE_LED_ON_CTRL(entity % 4));
|
||||
|
||||
if (state == 1)
|
||||
cl45_data |= LED_ON_EN;
|
||||
else
|
||||
cl45_data &= ~LED_ON_EN;
|
||||
|
||||
an8855_phy_cl45_write(priv, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_ON_CTRL(entity % 4), cl45_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_init(struct dsa_switch *ds)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
u32 val, led_count = ARRAY_SIZE(led_cfg);
|
||||
int ret = 0, id;
|
||||
u32 tmp_val = 0;
|
||||
u32 tmp_id = 0;
|
||||
|
||||
ret = an8855_led_set_mode(ds, AN8855_LED_MODE_USER_DEFINE);
|
||||
if (ret != 0) {
|
||||
dev_err(priv->dev, "led_set_mode fail(ret:%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (id = 0; id < led_count; id++) {
|
||||
ret = an8855_led_set_state(ds,
|
||||
led_cfg[id].phy_led_idx, led_cfg[id].en);
|
||||
if (ret != 0) {
|
||||
dev_err(priv->dev, "led_set_state fail(ret:%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (led_cfg[id].en == 1) {
|
||||
ret = an8855_led_set_usr_def(ds,
|
||||
led_cfg[id].phy_led_idx,
|
||||
led_cfg[id].pol, led_cfg[id].on_cfg,
|
||||
led_cfg[id].blk_cfg,
|
||||
led_cfg[id].led_freq);
|
||||
if (ret != 0) {
|
||||
dev_err(priv->dev, "led_set_usr_def fail!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Setting for System LED & Loop LED */
|
||||
an8855_write(priv, RG_GPIO_OE, 0x0);
|
||||
an8855_write(priv, RG_GPIO_CTRL, 0x0);
|
||||
val = 0;
|
||||
an8855_write(priv, RG_GPIO_L_INV, val);
|
||||
|
||||
val = 0x1001;
|
||||
an8855_write(priv, RG_GPIO_CTRL, val);
|
||||
val = an8855_read(priv, RG_GPIO_DATA);
|
||||
val |= BITS(1, 3);
|
||||
val &= ~(BIT(0));
|
||||
val &= ~(BIT(6));
|
||||
|
||||
an8855_write(priv, RG_GPIO_DATA, val);
|
||||
val = an8855_read(priv, RG_GPIO_OE);
|
||||
val |= 0x41;
|
||||
an8855_write(priv, RG_GPIO_OE, val);
|
||||
|
||||
/* Mapping between GPIO & LED */
|
||||
val = 0;
|
||||
for (id = 0; id < led_count; id++) {
|
||||
/* Skip GPIO6, due to GPIO6 does not support PORT LED */
|
||||
if (id == 6)
|
||||
continue;
|
||||
|
||||
if (led_cfg[id].en == 1) {
|
||||
if (id < 7)
|
||||
val |= led_cfg[id].phy_led_idx << ((id % 4) * 8);
|
||||
else
|
||||
val |= led_cfg[id].phy_led_idx << (((id - 1) % 4) * 8);
|
||||
}
|
||||
|
||||
if (id < 7)
|
||||
tmp_id = id;
|
||||
else
|
||||
tmp_id = id - 1;
|
||||
|
||||
if ((tmp_id % 4) == 0x3) {
|
||||
an8855_write(priv, RG_GPIO_LED_SEL(tmp_id / 4), val);
|
||||
tmp_val = an8855_read(priv, RG_GPIO_LED_SEL(tmp_id / 4));
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn on LAN LED mode */
|
||||
val = 0;
|
||||
for (id = 0; id < led_count; id++) {
|
||||
if (led_cfg[id].en == 1)
|
||||
val |= 0x1 << id;
|
||||
}
|
||||
an8855_write(priv, RG_GPIO_LED_MODE, val);
|
||||
|
||||
/* Force clear blink pulse for per port LED */
|
||||
an8855_phy_cl45_write(priv, 0, PHY_DEV1F, PHY_LED_BLINK_DUR_CTRL, 0x1f);
|
||||
usleep_range(1000, 5000);
|
||||
an8855_phy_cl45_write(priv, 0, PHY_DEV1F, PHY_LED_BLINK_DUR_CTRL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
an8855_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
struct an8855_dummy_poll p;
|
||||
u32 unused_pm = 0;
|
||||
u32 val, id;
|
||||
u32 val, id, led_count = ARRAY_SIZE(led_cfg);
|
||||
int ret, i;
|
||||
|
||||
/* Reset whole chip through gpio pin or memory-mapped registers for
|
||||
@@ -1130,6 +1402,63 @@ an8855_setup(struct dsa_switch *ds)
|
||||
priv->phy_base = priv->phy_base_new;
|
||||
}
|
||||
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++) {
|
||||
val = an8855_phy_read(ds, i, MII_BMCR);
|
||||
val |= BMCR_ISOLATE;
|
||||
an8855_phy_write(ds, i, MII_BMCR, val);
|
||||
}
|
||||
|
||||
/* AN8855H need to setup before switch init */
|
||||
val = an8855_read(priv, PKG_SEL);
|
||||
if ((val & 0x7) == PAG_SEL_AN8855H) {
|
||||
/* Invert for LED activity change */
|
||||
val = an8855_read(priv, RG_GPIO_L_INV);
|
||||
for (id = 0; id < led_count; id++) {
|
||||
if ((led_cfg[id].pol == LED_HIGH) &&
|
||||
(led_cfg[id].en == 1))
|
||||
val |= 0x1 << id;
|
||||
}
|
||||
an8855_write(priv, RG_GPIO_L_INV, (val | 0x1));
|
||||
|
||||
/* MCU NOP CMD */
|
||||
an8855_write(priv, RG_GDMP_RAM, 0x846);
|
||||
an8855_write(priv, RG_GDMP_RAM + 4, 0x4a);
|
||||
|
||||
/* Enable MCU */
|
||||
val = an8855_read(priv, RG_CLK_CPU_ICG);
|
||||
an8855_write(priv, RG_CLK_CPU_ICG, val | MCU_ENABLE);
|
||||
usleep_range(1000, 5000);
|
||||
|
||||
/* Disable MCU watchdog */
|
||||
val = an8855_read(priv, RG_TIMER_CTL);
|
||||
an8855_write(priv, RG_TIMER_CTL, (val & (~WDOG_ENABLE)));
|
||||
|
||||
/* Configure interrupt */
|
||||
an8855_write(priv, RG_INTB_MODE, (0x1 << priv->intr_pin));
|
||||
|
||||
/* LED settings for T830 reference board */
|
||||
ret = an8855_led_init(ds);
|
||||
if (ret < 0) {
|
||||
dev_err(priv->dev, "an8855_led_init fail. (ret=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust to reduce noise */
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++) {
|
||||
an8855_phy_cl45_write(priv, i, PHY_DEV1E,
|
||||
PHY_TX_PAIR_DLY_SEL_GBE, 0x4040);
|
||||
|
||||
an8855_phy_cl45_write(priv, i, PHY_DEV1E,
|
||||
PHY_RXADC_CTRL, 0x1010);
|
||||
|
||||
an8855_phy_cl45_write(priv, i, PHY_DEV1E,
|
||||
PHY_RXADC_REV_0, 0x100);
|
||||
|
||||
an8855_phy_cl45_write(priv, i, PHY_DEV1E,
|
||||
PHY_RXADC_REV_1, 0x100);
|
||||
}
|
||||
|
||||
/* Let phylink decide the interface later. */
|
||||
priv->p5_interface = PHY_INTERFACE_MODE_NA;
|
||||
|
||||
@@ -1139,6 +1468,10 @@ an8855_setup(struct dsa_switch *ds)
|
||||
an8855_rmw(priv, AN8855_BPC, AN8855_BPDU_PORT_FW_MASK,
|
||||
AN8855_BPDU_CPU_ONLY);
|
||||
|
||||
val = an8855_read(priv, AN8855_CKGCR);
|
||||
val &= ~(CKG_LNKDN_GLB_STOP | CKG_LNKDN_PORT_STOP);
|
||||
an8855_write(priv, AN8855_CKGCR, val);
|
||||
|
||||
/* Enable and reset MIB counters */
|
||||
an8855_mib_reset(ds);
|
||||
|
||||
@@ -1157,8 +1490,18 @@ an8855_setup(struct dsa_switch *ds)
|
||||
PVC_EG_TAG(AN8855_VLAN_EG_CONSISTENT));
|
||||
}
|
||||
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++) {
|
||||
val = an8855_phy_read(ds, i, MII_BMCR);
|
||||
val &= ~BMCR_ISOLATE;
|
||||
an8855_phy_write(ds, i, MII_BMCR, val);
|
||||
}
|
||||
|
||||
an8855_phy_setup(ds);
|
||||
|
||||
/* PHY restart AN*/
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++)
|
||||
an8855_phy_write(ds, i, MII_BMCR, 0x1240);
|
||||
|
||||
/* Group and enable unused ports as a standalone dumb switch. */
|
||||
setup_unused_ports(ds, unused_pm);
|
||||
|
||||
@@ -1255,6 +1598,28 @@ an8855_set_hsgmii_mode(struct an8855_priv *priv)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
/* TX FIR - improve TX EYE */
|
||||
val = an8855_read(priv, INTF_CTRL_10);
|
||||
val &= ~(0x3f << 16);
|
||||
val |= BIT(21);
|
||||
val &= ~(0x1f << 24);
|
||||
val |= (0x4 << 24);
|
||||
val |= BIT(29);
|
||||
an8855_write(priv, INTF_CTRL_10, val);
|
||||
|
||||
val = an8855_read(priv, INTF_CTRL_11);
|
||||
val &= ~(0x3f);
|
||||
val |= BIT(6);
|
||||
an8855_write(priv, INTF_CTRL_11, val);
|
||||
|
||||
/* RX CDR - improve RX Jitter Tolerance */
|
||||
val = an8855_read(priv, RG_QP_CDR_LPF_BOT_LIM);
|
||||
val &= ~(0x7 << 24);
|
||||
val |= (0x5 << 24);
|
||||
val &= ~(0x7 << 20);
|
||||
val |= (0x5 << 20);
|
||||
an8855_write(priv, RG_QP_CDR_LPF_BOT_LIM, val);
|
||||
|
||||
/* PLL */
|
||||
val = an8855_read(priv, QP_DIG_MODE_CTRL_1);
|
||||
val &= ~(0x3 << 2);
|
||||
@@ -1384,7 +1749,7 @@ an8855_set_hsgmii_mode(struct an8855_priv *priv)
|
||||
val &= ~(0xf << 25);
|
||||
val |= (0x1 << 25);
|
||||
val &= ~(0x7 << 29);
|
||||
val |= (0x3 << 29);
|
||||
val |= (0x6 << 29);
|
||||
an8855_write(priv, RG_QP_CDR_LPF_SETVALUE, val);
|
||||
|
||||
val = an8855_read(priv, RG_QP_CDR_PR_CKREF_DIV1);
|
||||
@@ -1415,12 +1780,9 @@ an8855_set_hsgmii_mode(struct an8855_priv *priv)
|
||||
val |= (0x4 << 24);
|
||||
an8855_write(priv, RG_QP_CDR_PR_CKREF_DIV1, val);
|
||||
|
||||
val = an8855_read(priv, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_write(priv, PLL_CTRL_0, val);
|
||||
|
||||
val = an8855_read(priv, RX_CTRL_26);
|
||||
val &= ~BIT(23);
|
||||
val |= BIT(23);
|
||||
val &= ~BIT(24);
|
||||
val |= BIT(26);
|
||||
an8855_write(priv, RX_CTRL_26, val);
|
||||
|
||||
@@ -1448,8 +1810,8 @@ an8855_set_hsgmii_mode(struct an8855_priv *priv)
|
||||
val = an8855_read(priv, RX_CTRL_8);
|
||||
val &= ~(0xfff << 16);
|
||||
val |= (0x200 << 16);
|
||||
val &= ~(0x7fff << 14);
|
||||
val |= (0xfff << 14);
|
||||
val &= ~(0x7fff << 0);
|
||||
val |= (0xfff << 0);
|
||||
an8855_write(priv, RX_CTRL_8, val);
|
||||
|
||||
/* Frequency memter */
|
||||
@@ -1468,6 +1830,10 @@ an8855_set_hsgmii_mode(struct an8855_priv *priv)
|
||||
val |= (0x2710 << 0);
|
||||
an8855_write(priv, RX_CTRL_7, val);
|
||||
|
||||
val = an8855_read(priv, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_write(priv, PLL_CTRL_0, val);
|
||||
|
||||
/* PCS Init */
|
||||
val = an8855_read(priv, RG_HSGMII_PCS_CTROL_1);
|
||||
val &= ~BIT(30);
|
||||
@@ -1507,6 +1873,28 @@ an8855_sgmii_setup(struct an8855_priv *priv, int mode)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
/* TX FIR - improve TX EYE */
|
||||
val = an8855_read(priv, INTF_CTRL_10);
|
||||
val &= ~(0x3f << 16);
|
||||
val |= BIT(21);
|
||||
val &= ~(0x1f << 24);
|
||||
val |= BIT(29);
|
||||
an8855_write(priv, INTF_CTRL_10, val);
|
||||
|
||||
val = an8855_read(priv, INTF_CTRL_11);
|
||||
val &= ~(0x3f);
|
||||
val |= (0xd << 0);
|
||||
val |= BIT(6);
|
||||
an8855_write(priv, INTF_CTRL_11, val);
|
||||
|
||||
/* RX CDR - improve RX Jitter Tolerance */
|
||||
val = an8855_read(priv, RG_QP_CDR_LPF_BOT_LIM);
|
||||
val &= ~(0x7 << 24);
|
||||
val |= (0x6 << 24);
|
||||
val &= ~(0x7 << 20);
|
||||
val |= (0x6 << 20);
|
||||
an8855_write(priv, RG_QP_CDR_LPF_BOT_LIM, val);
|
||||
|
||||
/* PMA Init */
|
||||
/* PLL */
|
||||
val = an8855_read(priv, QP_DIG_MODE_CTRL_1);
|
||||
@@ -1666,15 +2054,10 @@ an8855_sgmii_setup(struct an8855_priv *priv, int mode)
|
||||
val |= (0x4 << 24);
|
||||
an8855_write(priv, RG_QP_CDR_PR_CKREF_DIV1, val);
|
||||
|
||||
val = an8855_read(priv, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_write(priv, PLL_CTRL_0, val);
|
||||
|
||||
val = an8855_read(priv, RX_CTRL_26);
|
||||
val &= ~BIT(23);
|
||||
if (mode == SGMII_MODE_AN)
|
||||
val |= BIT(23);
|
||||
val &= ~BIT(24);
|
||||
val |= BIT(26);
|
||||
|
||||
an8855_write(priv, RX_CTRL_26, val);
|
||||
|
||||
val = an8855_read(priv, RX_DLY_0);
|
||||
@@ -1721,6 +2104,10 @@ an8855_sgmii_setup(struct an8855_priv *priv, int mode)
|
||||
val |= (0x2710 << 0);
|
||||
an8855_write(priv, RX_CTRL_7, val);
|
||||
|
||||
val = an8855_read(priv, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_write(priv, PLL_CTRL_0, val);
|
||||
|
||||
if (mode == SGMII_MODE_FORCE) {
|
||||
/* PCS Init */
|
||||
val = an8855_read(priv, QP_DIG_MODE_CTRL_0);
|
||||
@@ -1805,7 +2192,6 @@ an8855_sgmii_setup(struct an8855_priv *priv, int mode)
|
||||
/* Restart AN */
|
||||
val = an8855_read(priv, SGMII_REG_AN0);
|
||||
val |= BIT(9);
|
||||
val |= BIT(15);
|
||||
an8855_write(priv, SGMII_REG_AN0, val);
|
||||
}
|
||||
|
||||
@@ -1922,16 +2308,6 @@ unsupported:
|
||||
an8855_write(priv, AN8855_PMCR_P(port), mcr_new);
|
||||
}
|
||||
|
||||
static void
|
||||
an8855_phylink_mac_link_down(struct dsa_switch *ds, int port,
|
||||
unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
|
||||
an8855_clear(priv, AN8855_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
|
||||
}
|
||||
|
||||
static void
|
||||
an8855_phylink_mac_link_up(struct dsa_switch *ds, int port,
|
||||
unsigned int mode,
|
||||
@@ -2194,6 +2570,51 @@ an8855_sw_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
|
||||
return priv->info->phy_write(ds, port, regnum, val);
|
||||
}
|
||||
|
||||
static int an8855_proc_device_read(struct seq_file *seq, void *v)
|
||||
{
|
||||
seq_printf(seq, "%s\n", ARHT_CHIP_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_proc_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, an8855_proc_device_read, 0);
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE)
|
||||
static const struct proc_ops an8855_proc_device_fops = {
|
||||
.proc_open = an8855_proc_device_open,
|
||||
.proc_read = seq_read,
|
||||
.proc_lseek = seq_lseek,
|
||||
.proc_release = single_release,
|
||||
};
|
||||
#else
|
||||
static const struct file_operations an8855_proc_device_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = an8855_proc_device_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int an8855_proc_device_init(void)
|
||||
{
|
||||
if (!proc_an8855_dsa_dir)
|
||||
proc_an8855_dsa_dir = proc_mkdir(ARHT_PROC_DIR, 0);
|
||||
|
||||
proc_create(ARHT_PROC_NODE_DEVICE, 0400, proc_an8855_dsa_dir,
|
||||
&an8855_proc_device_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void an8855_proc_device_exit(void)
|
||||
{
|
||||
remove_proc_entry(ARHT_PROC_NODE_DEVICE, 0);
|
||||
}
|
||||
|
||||
static const struct dsa_switch_ops an8855_switch_ops = {
|
||||
.get_tag_protocol = air_get_tag_protocol,
|
||||
.setup = an8855_sw_setup,
|
||||
@@ -2217,10 +2638,6 @@ static const struct dsa_switch_ops an8855_switch_ops = {
|
||||
.port_mirror_add = an8855_port_mirror_add,
|
||||
.port_mirror_del = an8855_port_mirror_del,
|
||||
.phylink_validate = an8855_phylink_validate,
|
||||
.phylink_mac_link_state = an8855_sw_phylink_mac_link_state,
|
||||
.phylink_mac_config = an8855_phylink_mac_config,
|
||||
.phylink_mac_link_down = an8855_phylink_mac_link_down,
|
||||
.phylink_mac_link_up = an8855_phylink_mac_link_up,
|
||||
.get_mac_eee = an8855_get_mac_eee,
|
||||
.set_mac_eee = an8855_set_mac_eee,
|
||||
};
|
||||
@@ -2308,6 +2725,13 @@ an8855_probe(struct mdio_device *mdiodev)
|
||||
if ((ret < 0) || (priv->phy_base_new > 0x1f))
|
||||
priv->phy_base_new = -1;
|
||||
|
||||
/* Assign AN8855 interrupt pin */
|
||||
if (of_property_read_u32(dn, "airoha,intr", &priv->intr_pin))
|
||||
priv->intr_pin = AN8855_DFL_INTR_ID;
|
||||
|
||||
if (of_property_read_u32(dn, "airoha,extSurge", &priv->extSurge))
|
||||
priv->extSurge = AN8855_DFL_EXT_SURGE;
|
||||
|
||||
priv->bus = mdiodev->bus;
|
||||
priv->dev = &mdiodev->dev;
|
||||
priv->ds->priv = priv;
|
||||
@@ -2324,6 +2748,7 @@ an8855_probe(struct mdio_device *mdiodev)
|
||||
}
|
||||
an8855_nl_init(&priv);
|
||||
|
||||
an8855_proc_device_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2338,6 +2763,8 @@ an8855_remove(struct mdio_device *mdiodev)
|
||||
if (priv->base)
|
||||
iounmap(priv->base);
|
||||
|
||||
an8855_proc_device_exit();
|
||||
|
||||
an8855_nl_exit();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
|
||||
#define AN8855_NUM_PORTS 6
|
||||
#define AN8855_CPU_PORT 5
|
||||
#define AN8855_WORD_SIZE 4
|
||||
#define AN8855_NUM_FDB_RECORDS 2048
|
||||
#define AN8855_ALL_MEMBERS 0x3f
|
||||
#define AN8855_RESERVED_VLAN 2
|
||||
#define AN8855_GPHY_SMI_ADDR_DEFAULT 1
|
||||
#define AN8855_DFL_INTR_ID 0xd
|
||||
#define AN8855_DFL_EXT_SURGE 0x0
|
||||
|
||||
enum an8855_id {
|
||||
ID_AN8855 = 0,
|
||||
@@ -286,6 +289,8 @@ enum an8855_vlan_port_attr {
|
||||
#define AN8855_CKGCR (0x10213e1c)
|
||||
#define LPI_TXIDLE_THD 14
|
||||
#define LPI_TXIDLE_THD_MASK BITS(14, 31)
|
||||
#define CKG_LNKDN_GLB_STOP 0x01
|
||||
#define CKG_LNKDN_PORT_STOP 0x02
|
||||
|
||||
/* Register for MIB */
|
||||
#define AN8855_PORT_MIB_COUNTER(x) (0x10214000 + (x) * 0x200)
|
||||
@@ -303,18 +308,14 @@ enum an8855_vlan_port_attr {
|
||||
CCR_RX_OCT_CNT_BAD | \
|
||||
CCR_TX_OCT_CNT_GOOD | \
|
||||
CCR_TX_OCT_CNT_BAD | \
|
||||
CCR_RX_OCT_CNT_GOOD_2 | \
|
||||
CCR_RX_OCT_CNT_BAD_2 | \
|
||||
CCR_TX_OCT_CNT_GOOD_2 | \
|
||||
CCR_TX_OCT_CNT_BAD_2)
|
||||
#define CCR_MIB_ACTIVATE (CCR_MIB_ENABLE | \
|
||||
CCR_RX_OCT_CNT_GOOD | \
|
||||
CCR_RX_OCT_CNT_BAD | \
|
||||
CCR_TX_OCT_CNT_GOOD | \
|
||||
CCR_TX_OCT_CNT_BAD | \
|
||||
CCR_RX_OCT_CNT_GOOD_2 | \
|
||||
CCR_RX_OCT_CNT_BAD_2 | \
|
||||
CCR_TX_OCT_CNT_GOOD_2 | \
|
||||
CCR_TX_OCT_CNT_BAD_2)
|
||||
|
||||
/* AN8855 SGMII register group */
|
||||
@@ -331,6 +332,22 @@ enum an8855_vlan_port_attr {
|
||||
#define AN8855_RST_CTRL 0x100050c0
|
||||
#define SYS_CTRL_SYS_RST BIT(31)
|
||||
|
||||
#define INT_MASK 0x100050F0
|
||||
#define INT_SYS_BIT BIT(15)
|
||||
|
||||
#define RG_CLK_CPU_ICG 0x10005034
|
||||
#define MCU_ENABLE BIT(3)
|
||||
|
||||
#define RG_TIMER_CTL 0x1000a100
|
||||
#define WDOG_ENABLE BIT(25)
|
||||
|
||||
#define CKGCR 0x10213E1C
|
||||
#define CKG_LNKDN_GLB_STOP 0x01
|
||||
#define CKG_LNKDN_PORT_STOP 0x02
|
||||
|
||||
#define PKG_SEL 0x10000094
|
||||
#define PAG_SEL_AN8855H 0x2
|
||||
|
||||
/* Register for hw trap status */
|
||||
#define AN8855_HWTRAP 0x1000009c
|
||||
|
||||
@@ -339,6 +356,15 @@ enum an8855_vlan_port_attr {
|
||||
|
||||
#define SCU_BASE 0x10000000
|
||||
#define RG_RGMII_TXCK_C (SCU_BASE + 0x1d0)
|
||||
#define RG_GPIO_LED_MODE (SCU_BASE + 0x0054)
|
||||
#define RG_GPIO_LED_SEL(i) (SCU_BASE + (0x0058 + ((i) * 4)))
|
||||
#define RG_INTB_MODE (SCU_BASE + 0x0080)
|
||||
#define RG_GDMP_RAM (SCU_BASE + 0x10000)
|
||||
|
||||
#define RG_GPIO_L_INV (SCU_BASE + 0x0010)
|
||||
#define RG_GPIO_CTRL (SCU_BASE + 0xa300)
|
||||
#define RG_GPIO_DATA (SCU_BASE + 0xa304)
|
||||
#define RG_GPIO_OE (SCU_BASE + 0xa314)
|
||||
|
||||
#define HSGMII_AN_CSR_BASE 0x10220000
|
||||
#define SGMII_REG_AN0 (HSGMII_AN_CSR_BASE + 0x000)
|
||||
@@ -382,6 +408,8 @@ enum an8855_vlan_port_attr {
|
||||
#define SS_LCPLL_TDC_PCW_1 (QP_PMA_TOP_BASE + 0x248)
|
||||
#define INTF_CTRL_8 (QP_PMA_TOP_BASE + 0x320)
|
||||
#define INTF_CTRL_9 (QP_PMA_TOP_BASE + 0x324)
|
||||
#define INTF_CTRL_10 (QP_PMA_TOP_BASE + 0x328)
|
||||
#define INTF_CTRL_11 (QP_PMA_TOP_BASE + 0x32c)
|
||||
#define PLL_CTRL_0 (QP_PMA_TOP_BASE + 0x400)
|
||||
#define PLL_CTRL_2 (QP_PMA_TOP_BASE + 0x408)
|
||||
#define PLL_CTRL_3 (QP_PMA_TOP_BASE + 0x40c)
|
||||
@@ -399,6 +427,7 @@ enum an8855_vlan_port_attr {
|
||||
#define QP_ANA_CSR_BASE 0x1022f000
|
||||
#define RG_QP_RX_DAC_EN (QP_ANA_CSR_BASE + 0x00)
|
||||
#define RG_QP_RXAFE_RESERVE (QP_ANA_CSR_BASE + 0x04)
|
||||
#define RG_QP_CDR_LPF_BOT_LIM (QP_ANA_CSR_BASE + 0x08)
|
||||
#define RG_QP_CDR_LPF_MJV_LIM (QP_ANA_CSR_BASE + 0x0c)
|
||||
#define RG_QP_CDR_LPF_SETVALUE (QP_ANA_CSR_BASE + 0x14)
|
||||
#define RG_QP_CDR_PR_CKREF_DIV1 (QP_ANA_CSR_BASE + 0x18)
|
||||
@@ -437,6 +466,74 @@ struct an8855_fdb {
|
||||
u8 ivl;
|
||||
};
|
||||
|
||||
/* Definition of LED */
|
||||
#define LED_ON_EVENT (LED_ON_EVT_LINK_1000M | \
|
||||
LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M |\
|
||||
LED_ON_EVT_LINK_HD | LED_ON_EVT_LINK_FD)
|
||||
|
||||
#define LED_BLK_EVENT (LED_BLK_EVT_1000M_TX_ACT | \
|
||||
LED_BLK_EVT_1000M_RX_ACT | \
|
||||
LED_BLK_EVT_100M_TX_ACT | \
|
||||
LED_BLK_EVT_100M_RX_ACT | \
|
||||
LED_BLK_EVT_10M_TX_ACT | \
|
||||
LED_BLK_EVT_10M_RX_ACT)
|
||||
|
||||
#define LED_FREQ AIR_LED_BLK_DUR_64M
|
||||
|
||||
enum phy_led_idx {
|
||||
P0_LED0,
|
||||
P0_LED1,
|
||||
P0_LED2,
|
||||
P0_LED3,
|
||||
P1_LED0,
|
||||
P1_LED1,
|
||||
P1_LED2,
|
||||
P1_LED3,
|
||||
P2_LED0,
|
||||
P2_LED1,
|
||||
P2_LED2,
|
||||
P2_LED3,
|
||||
P3_LED0,
|
||||
P3_LED1,
|
||||
P3_LED2,
|
||||
P3_LED3,
|
||||
P4_LED0,
|
||||
P4_LED1,
|
||||
P4_LED2,
|
||||
P4_LED3,
|
||||
PHY_LED_MAX
|
||||
};
|
||||
|
||||
/* TBD */
|
||||
enum an8855_led_blk_dur {
|
||||
AIR_LED_BLK_DUR_32M,
|
||||
AIR_LED_BLK_DUR_64M,
|
||||
AIR_LED_BLK_DUR_128M,
|
||||
AIR_LED_BLK_DUR_256M,
|
||||
AIR_LED_BLK_DUR_512M,
|
||||
AIR_LED_BLK_DUR_1024M,
|
||||
AIR_LED_BLK_DUR_LAST
|
||||
};
|
||||
|
||||
enum an8855_led_polarity {
|
||||
LED_LOW,
|
||||
LED_HIGH,
|
||||
};
|
||||
enum an8855_led_mode {
|
||||
AN8855_LED_MODE_DISABLE,
|
||||
AN8855_LED_MODE_USER_DEFINE,
|
||||
AN8855_LED_MODE_LAST
|
||||
};
|
||||
|
||||
struct an8855_led_cfg {
|
||||
u16 en;
|
||||
u8 phy_led_idx;
|
||||
u16 pol;
|
||||
u16 on_cfg;
|
||||
u16 blk_cfg;
|
||||
u8 led_freq;
|
||||
};
|
||||
|
||||
/* struct an8855_port - This is the main data structure for holding the state
|
||||
* of the port.
|
||||
* @enable: The status used for show port is enabled or not.
|
||||
@@ -522,11 +619,13 @@ struct an8855_priv {
|
||||
unsigned int phy_base;
|
||||
int phy_base_new;
|
||||
unsigned int id;
|
||||
u32 intr_pin;
|
||||
phy_interface_t p5_interface;
|
||||
unsigned int p5_intf_sel;
|
||||
u8 mirror_rx;
|
||||
u8 mirror_tx;
|
||||
u8 eee_enable;
|
||||
u32 extSurge;
|
||||
|
||||
struct an8855_port ports[AN8855_NUM_PORTS];
|
||||
/* protect among processes for registers access */
|
||||
|
||||
@@ -45,8 +45,8 @@ static int an8855_nl_response(struct sk_buff *skb, struct genl_info *info);
|
||||
static const struct nla_policy an8855_nl_cmd_policy[] = {
|
||||
[AN8855_ATTR_TYPE_MESG] = {.type = NLA_STRING},
|
||||
[AN8855_ATTR_TYPE_PHY] = {.type = NLA_S32},
|
||||
[AN8855_ATTR_TYPE_REG] = {.type = NLA_S32},
|
||||
[AN8855_ATTR_TYPE_VAL] = {.type = NLA_S32},
|
||||
[AN8855_ATTR_TYPE_REG] = {.type = NLA_U32},
|
||||
[AN8855_ATTR_TYPE_VAL] = {.type = NLA_U32},
|
||||
[AN8855_ATTR_TYPE_DEV_NAME] = {.type = NLA_S32},
|
||||
[AN8855_ATTR_TYPE_DEV_ID] = {.type = NLA_S32},
|
||||
[AN8855_ATTR_TYPE_DEVAD] = {.type = NLA_S32},
|
||||
@@ -150,15 +150,15 @@ static int
|
||||
an8855_nl_reply_read(struct genl_info *info)
|
||||
{
|
||||
struct sk_buff *rep_skb = NULL;
|
||||
s32 phy, devad, reg;
|
||||
int value;
|
||||
s32 phy, devad;
|
||||
u32 reg = 0;
|
||||
int value = 0;
|
||||
int ret = 0;
|
||||
|
||||
phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
|
||||
devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
|
||||
reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
|
||||
|
||||
if (reg < 0)
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_REG, ®))
|
||||
goto err;
|
||||
|
||||
ret = an8855_nl_prepare_reply(info, AN8855_CMD_READ, &rep_skb);
|
||||
@@ -172,11 +172,11 @@ an8855_nl_reply_read(struct genl_info *info)
|
||||
devad, reg);
|
||||
} else
|
||||
value = an8855_read(an8855_sw_priv, reg);
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@@ -193,18 +193,16 @@ static int
|
||||
an8855_nl_reply_write(struct genl_info *info)
|
||||
{
|
||||
struct sk_buff *rep_skb = NULL;
|
||||
s32 phy, devad, reg;
|
||||
u32 value;
|
||||
s32 phy, devad;
|
||||
u32 value = 0, reg = 0;
|
||||
int ret = 0;
|
||||
|
||||
phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
|
||||
devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
|
||||
reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
|
||||
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_VAL, &value))
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_REG, ®))
|
||||
goto err;
|
||||
|
||||
if (reg < 0)
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_VAL, &value))
|
||||
goto err;
|
||||
|
||||
ret = an8855_nl_prepare_reply(info, AN8855_CMD_WRITE, &rep_skb);
|
||||
@@ -218,11 +216,11 @@ an8855_nl_reply_write(struct genl_info *info)
|
||||
value);
|
||||
} else
|
||||
an8855_write(an8855_sw_priv, reg, value);
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
|
||||
@@ -14,32 +14,36 @@
|
||||
#include "an8855.h"
|
||||
#include "an8855_phy.h"
|
||||
|
||||
#define AN8855_NUM_PHYS 5
|
||||
#define AN8855_EFUSE_DATA0 0x1000a500
|
||||
|
||||
static u32
|
||||
an8855_phy_read_dev_reg(struct dsa_switch *ds, u32 port_num,
|
||||
u32 dev_addr, u32 reg_addr)
|
||||
const u8 dsa_r50ohm_table[] = {
|
||||
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 126, 122, 117,
|
||||
112, 109, 104, 101, 97, 94, 90, 88, 84, 80,
|
||||
78, 74, 72, 68, 66, 64, 61, 58, 56, 53,
|
||||
51, 48, 47, 44, 42, 40, 38, 36, 34, 32,
|
||||
31, 28, 27, 24, 24, 22, 20, 18, 16, 16,
|
||||
14, 12, 11, 9
|
||||
};
|
||||
|
||||
static u8 shift_check(u8 base)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
u32 phy_val;
|
||||
u32 addr;
|
||||
u8 i;
|
||||
u32 sz = sizeof(dsa_r50ohm_table)/sizeof(u8);
|
||||
|
||||
addr = MII_ADDR_C45 | (dev_addr << 16) | (reg_addr & 0xffff);
|
||||
phy_val = priv->info->phy_read(ds, port_num, addr);
|
||||
for (i = 0; i < sz; ++i)
|
||||
if (dsa_r50ohm_table[i] == base)
|
||||
break;
|
||||
|
||||
return phy_val;
|
||||
if (i < 8 || i >= sz)
|
||||
return 25; /* index of 94 */
|
||||
|
||||
return (i - 8);
|
||||
}
|
||||
|
||||
static void
|
||||
an8855_phy_write_dev_reg(struct dsa_switch *ds, u32 port_num,
|
||||
u32 dev_addr, u32 reg_addr, u32 write_data)
|
||||
static u8 get_shift_val(u8 idx)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
u32 addr;
|
||||
|
||||
addr = MII_ADDR_C45 | (dev_addr << 16) | (reg_addr & 0xffff);
|
||||
|
||||
priv->info->phy_write(ds, port_num, addr, write_data);
|
||||
return dsa_r50ohm_table[idx];
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -64,7 +68,10 @@ static void
|
||||
an8855_phy_setting(struct dsa_switch *ds)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
int i;
|
||||
int i, j;
|
||||
u8 shift_sel = 0, rsel_tx_a = 0, rsel_tx_b = 0;
|
||||
u8 rsel_tx_c = 0, rsel_tx_d = 0;
|
||||
u16 cl45_data = 0;
|
||||
u32 val;
|
||||
|
||||
/* Release power down */
|
||||
@@ -82,48 +89,89 @@ an8855_phy_setting(struct dsa_switch *ds)
|
||||
val |= ADVERTISE_PAUSE_ASYM;
|
||||
an8855_switch_phy_write(ds, i, MII_ADVERTISE, val);
|
||||
}
|
||||
|
||||
if (priv->extSurge) {
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++) {
|
||||
/* Read data */
|
||||
for (j = 0; j < AN8855_WORD_SIZE; j++) {
|
||||
val = an8855_read(priv, AN8855_EFUSE_DATA0 +
|
||||
(AN8855_WORD_SIZE * (3 + j + (4 * i))));
|
||||
|
||||
shift_sel = shift_check((val & 0x7f000000) >> 24);
|
||||
switch (j) {
|
||||
case 0:
|
||||
rsel_tx_a = get_shift_val(shift_sel);
|
||||
break;
|
||||
case 1:
|
||||
rsel_tx_b = get_shift_val(shift_sel);
|
||||
break;
|
||||
case 2:
|
||||
rsel_tx_c = get_shift_val(shift_sel);
|
||||
break;
|
||||
case 3:
|
||||
rsel_tx_d = get_shift_val(shift_sel);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cl45_data = an8855_phy_cl45_read(priv, i, PHY_DEV1E, 0x174);
|
||||
cl45_data &= ~(0x7f7f);
|
||||
cl45_data |= (rsel_tx_a << 8);
|
||||
cl45_data |= rsel_tx_b;
|
||||
an8855_phy_cl45_write(priv, i, PHY_DEV1E, 0x174, cl45_data);
|
||||
cl45_data = an8855_phy_cl45_read(priv, i, PHY_DEV1E, 0x175);
|
||||
cl45_data &= ~(0x7f7f);
|
||||
cl45_data |= (rsel_tx_c << 8);
|
||||
cl45_data |= rsel_tx_d;
|
||||
an8855_phy_cl45_write(priv, i, PHY_DEV1E, 0x175, cl45_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
an8855_low_power_setting(struct dsa_switch *ds)
|
||||
{
|
||||
int port, addr;
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
|
||||
for (port = 0; port < AN8855_NUM_PHYS; port++) {
|
||||
an8855_phy_write_dev_reg(ds, port, 0x1e, 0x11, 0x0f00);
|
||||
an8855_phy_write_dev_reg(ds, port, 0x1e, 0x3c, 0x0000);
|
||||
an8855_phy_write_dev_reg(ds, port, 0x1e, 0x3d, 0x0000);
|
||||
an8855_phy_write_dev_reg(ds, port, 0x1e, 0x3e, 0x0000);
|
||||
an8855_phy_write_dev_reg(ds, port, 0x1e, 0xc6, 0x53aa);
|
||||
an8855_phy_cl45_write(priv, port, 0x1e, 0x11, 0x0f00);
|
||||
an8855_phy_cl45_write(priv, port, 0x1e, 0x3c, 0x0000);
|
||||
an8855_phy_cl45_write(priv, port, 0x1e, 0x3d, 0x0000);
|
||||
an8855_phy_cl45_write(priv, port, 0x1e, 0x3e, 0x0000);
|
||||
an8855_phy_cl45_write(priv, port, 0x1e, 0xc6, 0x53aa);
|
||||
}
|
||||
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x268, 0x07f1);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x269, 0x2111);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26a, 0x0000);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26b, 0x0074);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26e, 0x00f6);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x26f, 0x6666);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x271, 0x2c02);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x272, 0x0c22);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x700, 0x0001);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x701, 0x0803);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x702, 0x01b6);
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, 0x703, 0x2111);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x268, 0x07f1);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x269, 0x2111);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x26a, 0x0000);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x26b, 0x0074);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x26e, 0x00f6);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x26f, 0x6666);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x271, 0x2c02);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x272, 0x0c22);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x700, 0x0001);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x701, 0x0803);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x702, 0x01b6);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, 0x703, 0x2111);
|
||||
|
||||
an8855_phy_write_dev_reg(ds, 1, 0x1f, 0x700, 0x0001);
|
||||
an8855_phy_cl45_write(priv, 1, 0x1f, 0x700, 0x0001);
|
||||
|
||||
for (addr = 0x200; addr <= 0x230; addr += 2)
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, addr, 0x2020);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, addr, 0x2020);
|
||||
|
||||
for (addr = 0x201; addr <= 0x231; addr += 2)
|
||||
an8855_phy_write_dev_reg(ds, 0, 0x1f, addr, 0x0020);
|
||||
an8855_phy_cl45_write(priv, 0, 0x1f, addr, 0x0020);
|
||||
}
|
||||
|
||||
static void
|
||||
an8855_eee_setting(struct dsa_switch *ds, u32 port)
|
||||
{
|
||||
struct an8855_priv *priv = ds->priv;
|
||||
|
||||
/* Disable EEE */
|
||||
an8855_phy_write_dev_reg(ds, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
|
||||
an8855_phy_cl45_write(priv, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define AN8855_NUM_PHYS 5
|
||||
|
||||
/*phy calibration use*/
|
||||
#define DEV_1E 0x1E
|
||||
/*global device 0x1f, always set P0*/
|
||||
@@ -169,11 +171,69 @@
|
||||
/* PHY EEE Register bitmap of define */
|
||||
#define PHY_DEV07 0x07
|
||||
#define PHY_DEV07_REG_03C 0x3c
|
||||
#define ADV_EEE_100 0x2
|
||||
#define ADV_EEE_1000 0x4
|
||||
|
||||
/* PHY DEV 0x1e Register bitmap of define */
|
||||
#define PHY_DEV1E 0x1e
|
||||
/* PHY TX PAIR DELAY SELECT Register */
|
||||
#define PHY_TX_PAIR_DLY_SEL_GBE 0x013
|
||||
/* PHY ADC Register */
|
||||
#define PHY_RXADC_CTRL 0x0d8
|
||||
#define PHY_RXADC_REV_0 0x0d9
|
||||
#define PHY_RXADC_REV_1 0x0da
|
||||
|
||||
/* PHY LED Register bitmap of define */
|
||||
#define PHY_LED_CTRL_SELECT 0x3e8
|
||||
#define PHY_SINGLE_LED_ON_CTRL(i) (0x3e0 + ((i) * 2))
|
||||
#define PHY_SINGLE_LED_BLK_CTRL(i) (0x3e1 + ((i) * 2))
|
||||
#define PHY_SINGLE_LED_ON_DUR(i) (0x3e9 + ((i) * 2))
|
||||
#define PHY_SINGLE_LED_BLK_DUR(i) (0x3ea + ((i) * 2))
|
||||
|
||||
#define PHY_PMA_CTRL (0x340)
|
||||
|
||||
#define PHY_DEV1F 0x1f
|
||||
|
||||
#define PHY_LED_ON_CTRL(i) (0x24 + ((i) * 2))
|
||||
#define LED_ON_EN (1 << 15)
|
||||
#define LED_ON_POL (1 << 14)
|
||||
#define LED_ON_EVT_MASK (0x7f)
|
||||
|
||||
/* LED ON Event */
|
||||
#define LED_ON_EVT_FORCE (1 << 6)
|
||||
#define LED_ON_EVT_LINK_HD (1 << 5)
|
||||
#define LED_ON_EVT_LINK_FD (1 << 4)
|
||||
#define LED_ON_EVT_LINK_DOWN (1 << 3)
|
||||
#define LED_ON_EVT_LINK_10M (1 << 2)
|
||||
#define LED_ON_EVT_LINK_100M (1 << 1)
|
||||
#define LED_ON_EVT_LINK_1000M (1 << 0)
|
||||
|
||||
#define PHY_LED_BLK_CTRL(i) (0x25 + ((i) * 2))
|
||||
#define LED_BLK_EVT_MASK (0x3ff)
|
||||
/* LED Blinking Event */
|
||||
#define LED_BLK_EVT_FORCE (1 << 9)
|
||||
#define LED_BLK_EVT_10M_RX_ACT (1 << 5)
|
||||
#define LED_BLK_EVT_10M_TX_ACT (1 << 4)
|
||||
#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
|
||||
#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
|
||||
#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
|
||||
#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
|
||||
|
||||
#define PHY_LED_BCR (0x21)
|
||||
#define LED_BCR_EXT_CTRL (1 << 15)
|
||||
#define LED_BCR_CLK_EN (1 << 3)
|
||||
#define LED_BCR_TIME_TEST (1 << 2)
|
||||
#define LED_BCR_MODE_MASK (3)
|
||||
#define LED_BCR_MODE_DISABLE (0)
|
||||
|
||||
#define PHY_LED_ON_DUR (0x22)
|
||||
#define LED_ON_DUR_MASK (0xffff)
|
||||
|
||||
#define PHY_LED_BLK_DUR (0x23)
|
||||
#define LED_BLK_DUR_MASK (0xffff)
|
||||
|
||||
#define PHY_LED_BLINK_DUR_CTRL (0x720)
|
||||
|
||||
/* Proprietory Control Register of Internal Phy device 0x1e */
|
||||
#define PHY_TX_MLT3_BASE 0x0
|
||||
#define PHY_DEV1E_REG_13 0x13
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config NET_DSA_MXL862
|
||||
tristate "MaxLinear MxL862xx"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_TAG_MXL862
|
||||
help
|
||||
This enables support for the MaxLinear MxL862xx switch family.
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_NET_DSA_MXL862) += mxl862xx_dsa.o
|
||||
mxl862xx_dsa-y := mxl862xx.o host_api/mxl862xx_api.o host_api/mxl862xx_host_api_impl.o host_api/mxl862xx_mdio_relay.o
|
||||
@@ -0,0 +1,272 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_api.c - dsa driver for Maxlinear mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mxl862xx_host_api_impl.h"
|
||||
#include "mxl862xx_api.h"
|
||||
#include "mxl862xx_mmd_apis.h"
|
||||
|
||||
int sys_misc_fw_version(const mxl862xx_device_t *dev,
|
||||
struct sys_fw_image_version *sys_img_ver)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, SYS_MISC_FW_VERSION, sys_img_ver,
|
||||
sizeof(*sys_img_ver), 0, sizeof(*sys_img_ver));
|
||||
}
|
||||
|
||||
int mxl862xx_register_mod(const mxl862xx_device_t *dev, mxl862xx_register_mod_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_REGISTERMOD, parm, sizeof(*parm), 0,
|
||||
0);
|
||||
}
|
||||
|
||||
int mxl862xx_port_link_cfg_set(const mxl862xx_device_t *dev, mxl862xx_port_link_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_PORTLINKCFGSET, parm, sizeof(*parm),
|
||||
MXL862XX_COMMON_PORTLINKCFGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_port_cfg_get(const mxl862xx_device_t *dev, mxl862xx_port_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_PORTCFGGET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_port_cfg_set(const mxl862xx_device_t *dev, mxl862xx_port_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_PORTCFGSET, parm, sizeof(*parm),
|
||||
MXL862XX_COMMON_PORTCFGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_alloc(const mxl862xx_device_t *dev, mxl862xx_bridge_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGE_ALLOC, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
int mxl862xx_bridge_free(const mxl862xx_device_t *dev, mxl862xx_bridge_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGE_FREE, parm, sizeof(*parm), 0, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_config_set(const mxl862xx_device_t *dev, mxl862xx_bridge_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGE_CONFIGSET, parm, sizeof(*parm),
|
||||
MXL862XX_BRIDGE_CONFIGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_config_get(const mxl862xx_device_t *dev, mxl862xx_bridge_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGE_CONFIGGET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_port_alloc(const mxl862xx_device_t *dev, mxl862xx_bridge_port_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGEPORT_ALLOC, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_port_free(const mxl862xx_device_t *dev, mxl862xx_bridge_port_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGEPORT_FREE, parm, sizeof(*parm), 0, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_port_config_set(const mxl862xx_device_t *dev,
|
||||
mxl862xx_bridge_port_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGEPORT_CONFIGSET, parm, sizeof(*parm),
|
||||
MXL862XX_BRIDGEPORT_CONFIGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_bridge_port_config_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_bridge_port_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_BRIDGEPORT_CONFIGGET, parm, sizeof(*parm),
|
||||
0, sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_debug_rmon_port_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_debug_rmon_port_cnt_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_DEBUG_RMON_PORT_GET, parm, sizeof(*parm),
|
||||
0, sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_mac_table_clear(const mxl862xx_device_t *dev)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_MAC_TABLECLEAR, NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_mac_table_clear_cond(const mxl862xx_device_t *dev,
|
||||
mxl862xx_mac_table_clear_cond_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_MAC_TABLECLEARCOND, parm, sizeof(*parm), 0,
|
||||
0);
|
||||
}
|
||||
|
||||
int mxl862xx_mac_table_entry_read(const mxl862xx_device_t *dev,
|
||||
mxl862xx_mac_table_read_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_MAC_TABLEENTRYREAD, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_mac_table_entry_add(const mxl862xx_device_t *dev,
|
||||
mxl862xx_mac_table_add_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_MAC_TABLEENTRYADD, parm, sizeof(*parm), 0,
|
||||
0);
|
||||
}
|
||||
|
||||
int mxl862xx_mac_table_entry_remove(const mxl862xx_device_t *dev,
|
||||
mxl862xx_mac_table_remove_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_MAC_TABLEENTRYREMOVE, parm, sizeof(*parm),
|
||||
0, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_stp_port_cfg_set(const mxl862xx_device_t *dev, mxl862xx_stp_port_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_STP_PORTCFGSET, parm, sizeof(*parm),
|
||||
MXL862XX_STP_PORTCFGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_ss_sp_tag_get(const mxl862xx_device_t *dev, mxl862xx_ss_sp_tag_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_SS_SPTAG_GET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_ss_sp_tag_set(const mxl862xx_device_t *dev, mxl862xx_ss_sp_tag_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_SS_SPTAG_SET, parm, sizeof(*parm),
|
||||
MXL862XX_SS_SPTAG_GET, sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_ctp_port_config_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_ctp_port_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_CTP_PORTCONFIGGET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_ctp_port_config_set(const mxl862xx_device_t *dev,
|
||||
mxl862xx_ctp_port_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_CTP_PORTCONFIGSET, parm, sizeof(*parm),
|
||||
MXL862XX_CTP_PORTCONFIGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_ctp_port_assignment_set(const mxl862xx_device_t *dev,
|
||||
mxl862xx_ctp_port_assignment_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_CTP_PORTASSIGNMENTSET, parm, sizeof(*parm),
|
||||
MXL862XX_CTP_PORTASSIGNMENTGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_ctp_port_assignment_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_ctp_port_assignment_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_CTP_PORTASSIGNMENTGET, parm, sizeof(*parm),
|
||||
0, sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_monitor_port_cfg_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_monitor_port_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_MONITORPORTCFGGET, parm,
|
||||
sizeof(*parm), 0, sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_monitor_port_cfg_set(const mxl862xx_device_t *dev,
|
||||
mxl862xx_monitor_port_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_MONITORPORTCFGSET, parm,
|
||||
sizeof(*parm), MXL862XX_COMMON_MONITORPORTCFGGET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_extended_vlan_alloc(const mxl862xx_device_t *dev,
|
||||
mxl862xx_extendedvlan_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_EXTENDEDVLAN_ALLOC, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_extended_vlan_set(const mxl862xx_device_t *dev,
|
||||
mxl862xx_extendedvlan_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_EXTENDEDVLAN_SET, parm, sizeof(*parm),
|
||||
MXL862XX_EXTENDEDVLAN_GET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_extended_vlan_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_extendedvlan_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_EXTENDEDVLAN_GET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_extended_vlan_free(const mxl862xx_device_t *dev,
|
||||
mxl862xx_extendedvlan_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_EXTENDEDVLAN_FREE, parm, sizeof(*parm), 0,
|
||||
0);
|
||||
}
|
||||
|
||||
int mxl862xx_vlan_filter_alloc(const mxl862xx_device_t *dev,
|
||||
mxl862xx_vlanfilter_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_VLANFILTER_ALLOC, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_vlan_filter_set(const mxl862xx_device_t *dev,
|
||||
mxl862xx_vlanfilter_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_VLANFILTER_SET, parm, sizeof(*parm),
|
||||
MXL862XX_VLANFILTER_GET, 0);
|
||||
}
|
||||
|
||||
int mxl862xx_vlan_filter_get(const mxl862xx_device_t *dev,
|
||||
mxl862xx_vlanfilter_config_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_VLANFILTER_GET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_vlan_filter_free(const mxl862xx_device_t *dev,
|
||||
mxl862xx_vlanfilter_alloc_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_VLANFILTER_FREE, parm, sizeof(*parm), 0,
|
||||
0);
|
||||
}
|
||||
|
||||
int mxl862xx_cfg_get(const mxl862xx_device_t *dev, mxl862xx_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_CFGGET, parm, sizeof(*parm), 0,
|
||||
sizeof(*parm));
|
||||
}
|
||||
|
||||
int mxl862xx_cfg_set(const mxl862xx_device_t *dev, mxl862xx_cfg_t *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, MXL862XX_COMMON_CFGSET, parm, sizeof(*parm),
|
||||
MXL862XX_COMMON_CFGGET, 0);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,336 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_ctp.h - Header file for DSA Driver for MaxLinear Mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef _MXL862XX_CTP_H_
|
||||
#define _MXL862XX_CTP_H_
|
||||
|
||||
#include "mxl862xx_types.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#pragma scalar_storage_order little-endian
|
||||
|
||||
/** \brief Logical port mode.
|
||||
Used by \ref MXL862XX_CTP_port_assignment_t. */
|
||||
typedef enum {
|
||||
/** WLAN with 8-bit station ID */
|
||||
MXL862XX_LOGICAL_PORT_8BIT_WLAN = 0,
|
||||
/** WLAN with 9-bit station ID */
|
||||
MXL862XX_LOGICAL_PORT_9BIT_WLAN = 1,
|
||||
/** GPON OMCI context */
|
||||
MXL862XX_LOGICAL_PORT_GPON = 2,
|
||||
/** EPON context */
|
||||
MXL862XX_LOGICAL_PORT_EPON = 3,
|
||||
/** G.INT context */
|
||||
MXL862XX_LOGICAL_PORT_GINT = 4,
|
||||
/** Others (sub interface ID is 0 by default) */
|
||||
MXL862XX_LOGICAL_PORT_OTHER = 0xFF,
|
||||
} mxl862xx_logical_port_mode_t;
|
||||
|
||||
/** \brief CTP Port configuration mask.
|
||||
Used by \ref MXL862XX_CTP_port_config_t. */
|
||||
typedef enum {
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::bridge_port_id */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_BRIDGE_PORT_ID = 0x00000001,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_forced_traffic_class and
|
||||
\ref MXL862XX_CTP_port_config_t::n_default_traffic_class */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_FORCE_TRAFFIC_CLASS = 0x00000002,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_ingress_extended_vlan_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::n_ingress_extended_vlan_block_id */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_INGRESS_VLAN = 0x00000004,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_ingress_extended_vlan_igmp_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::n_ingress_extended_vlan_block_id_igmp */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_INGRESS_VLAN_IGMP = 0x00000008,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_egress_extended_vlan_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::n_egress_extended_vlan_block_id */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_EGRESS_VLAN = 0x00000010,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_egress_extended_vlan_igmp_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::n_egress_extended_vlan_block_id_igmp */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_EGRESS_VLAN_IGMP = 0x00000020,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_ingress_nto1Vlan_enable */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_INRESS_NTO1_VLAN = 0x00000040,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_egress_nto1Vlan_enable */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_EGRESS_NTO1_VLAN = 0x00000080,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::e_ingress_marking_mode */
|
||||
MXL862XX_CTP_PORT_CONFIG_INGRESS_MARKING = 0x00000100,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::e_egress_marking_mode */
|
||||
MXL862XX_CTP_PORT_CONFIG_EGRESS_MARKING = 0x00000200,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_egress_marking_override_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::e_egress_marking_mode_override */
|
||||
MXL862XX_CTP_PORT_CONFIG_EGRESS_MARKING_OVERRIDE = 0x00000400,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::e_egress_remarking_mode */
|
||||
MXL862XX_CTP_PORT_CONFIG_EGRESS_REMARKING = 0x00000800,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_ingress_metering_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::n_ingress_traffic_meter_id */
|
||||
MXL862XX_CTP_PORT_CONFIG_INGRESS_METER = 0x00001000,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_egress_metering_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::n_egress_traffic_meter_id */
|
||||
MXL862XX_CTP_PORT_CONFIG_EGRESS_METER = 0x00002000,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_bridging_bypass,
|
||||
\ref MXL862XX_CTP_port_config_t::n_dest_logical_port_id,
|
||||
\ref MXL862XX_CTP_port_config_t::b_pmapper_enable,
|
||||
\ref MXL862XX_CTP_port_config_t::n_dest_sub_if_id_group,
|
||||
\ref MXL862XX_CTP_port_config_t::e_pmapper_mapping_mode
|
||||
\ref mxl862xx_bridge_port_config_t::b_pmapper_id_valid and
|
||||
\ref MXL862XX_CTP_port_config_t::s_pmapper */
|
||||
MXL862XX_CTP_PORT_CONFIG_BRIDGING_BYPASS = 0x00004000,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::n_first_flow_entry_index and
|
||||
\ref MXL862XX_CTP_port_config_t::n_number_of_flow_entries */
|
||||
MXL862XX_CTP_PORT_CONFIG_FLOW_ENTRY = 0x00008000,
|
||||
/** Mask for \ref MXL862XX_CTP_port_config_t::b_ingress_loopback_enable,
|
||||
\ref MXL862XX_CTP_port_config_t::b_ingress_da_sa_swap_enable,
|
||||
\ref MXL862XX_CTP_port_config_t::b_egress_loopback_enable,
|
||||
\ref MXL862XX_CTP_port_config_t::b_egress_da_sa_swap_enable,
|
||||
\ref MXL862XX_CTP_port_config_t::b_ingress_mirror_enable and
|
||||
\ref MXL862XX_CTP_port_config_t::b_egress_mirror_enable */
|
||||
MXL862XX_CTP_PORT_CONFIG_LOOPBACK_AND_MIRROR = 0x00010000,
|
||||
|
||||
/** Enable all fields */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_ALL = 0x7FFFFFFF,
|
||||
/** Bypass any check for debug purpose */
|
||||
MXL862XX_CTP_PORT_CONFIG_MASK_FORCE = 0x80000000
|
||||
} mxl862xx_ctp_port_config_mask_t;
|
||||
|
||||
/** \brief CTP Port Assignment/association with logical port.
|
||||
Used by \ref MXL862XX_CTP_PORT_ASSIGNMENT_ALLOC, \ref MXL862XX_CTP_PORT_ASSIGNMENT_SET
|
||||
and \ref MXL862XX_CTP_PORT_ASSIGNMENT_GET. */
|
||||
typedef struct {
|
||||
/** Logical Port Id. The valid range is hardware dependent. */
|
||||
u8 logical_port_id;
|
||||
|
||||
/** First CTP Port ID mapped to above logical port ID.
|
||||
|
||||
\remarks
|
||||
For \ref MXL862XX_CTP_PORT_ASSIGNMENT_ALLOC, this is output when CTP
|
||||
allocation is successful. For other APIs, this is input. */
|
||||
u16 first_ctp_port_id;
|
||||
/** Total number of CTP Ports mapped above logical port ID. */
|
||||
u16 number_of_ctp_port;
|
||||
|
||||
/** Logical port mode to define sub interface ID format. */
|
||||
mxl862xx_logical_port_mode_t mode;
|
||||
|
||||
/** Bridge ID (FID)
|
||||
|
||||
\remarks
|
||||
For \ref MXL862XX_CTP_PORT_ASSIGNMENT_ALLOC, this is input. Each CTP allocated
|
||||
is mapped to Bridge Port given by this field. The Bridge Port will be
|
||||
configured to use first CTP
|
||||
(\ref MXL862XX_CTP_port_assignment_t::n_first_ctp_port_id) as egress CTP.
|
||||
For other APIs, this is ignored. */
|
||||
u16 bridge_port_id;
|
||||
} mxl862xx_ctp_port_assignment_t;
|
||||
|
||||
/** \brief CTP Port Configuration.
|
||||
Used by \ref MXL862XX_CTP_PORT_CONFIG_SET and \ref MXL862XX_CTP_PORT_CONFIG_GET. */
|
||||
typedef struct {
|
||||
/** Logical Port Id. The valid range is hardware dependent.
|
||||
If \ref MXL862XX_CTP_port_config_t::e_mask has
|
||||
\ref MXL862XX_Ctp_port_config_mask_t::MXL862XX_CTP_PORT_CONFIG_MASK_FORCE, this field
|
||||
is ignored. */
|
||||
u8 logical_port_id;
|
||||
|
||||
/** Sub interface ID group. The valid range is hardware/protocol dependent.
|
||||
|
||||
\remarks
|
||||
Sub interface ID group is defined for each of \ref MXL862XX_Logical_port_mode_t.
|
||||
For both \ref MXL862XX_LOGICAL_PORT_8BIT_WLAN and
|
||||
\ref MXL862XX_LOGICAL_PORT_9BIT_WLAN, this field is VAP.
|
||||
For \ref MXL862XX_LOGICAL_PORT_GPON, this field is GEM index.
|
||||
For \ref MXL862XX_LOGICAL_PORT_EPON, this field is stream index.
|
||||
For \ref MXL862XX_LOGICAL_PORT_GINT, this field is LLID.
|
||||
For others, this field is 0.
|
||||
If \ref MXL862XX_CTP_port_config_t::e_mask has
|
||||
\ref MXL862XX_Ctp_port_config_mask_t::MXL862XX_CTP_PORT_CONFIG_MASK_FORCE, this field
|
||||
is absolute index of CTP in hardware for debug purpose, bypassing
|
||||
any check. */
|
||||
u16 n_sub_if_id_group;
|
||||
|
||||
/** Mask for updating/retrieving fields. */
|
||||
mxl862xx_ctp_port_config_mask_t mask;
|
||||
|
||||
/** Ingress Bridge Port ID to which this CTP port is associated for ingress
|
||||
traffic. */
|
||||
u16 bridge_port_id;
|
||||
|
||||
/** Default traffic class can not be overridden by other rules (except
|
||||
traffic flow table and special tag) in processing stages. */
|
||||
bool forced_traffic_class;
|
||||
/** Default traffic class associated with all ingress traffic from this CTP
|
||||
Port. */
|
||||
u8 default_traffic_class;
|
||||
|
||||
/** Enable Extended VLAN processing for ingress non-IGMP traffic. */
|
||||
bool ingress_extended_vlan_enable;
|
||||
/** Extended VLAN block allocated for ingress non-IGMP traffic. It defines
|
||||
extended VLAN process for ingress non-IGMP traffic. Valid when
|
||||
b_ingress_extended_vlan_enable is TRUE. */
|
||||
u16 ingress_extended_vlan_block_id;
|
||||
/** Extended VLAN block size for ingress non-IGMP traffic. This is optional.
|
||||
If it is 0, the block size of n_ingress_extended_vlan_block_id will be used.
|
||||
Otherwise, this field will be used. */
|
||||
u16 ingress_extended_vlan_block_size;
|
||||
/** Enable extended VLAN processing for ingress IGMP traffic. */
|
||||
bool ingress_extended_vlan_igmp_enable;
|
||||
/** Extended VLAN block allocated for ingress IGMP traffic. It defines
|
||||
extended VLAN process for ingress IGMP traffic. Valid when
|
||||
b_ingress_extended_vlan_igmp_enable is TRUE. */
|
||||
u16 ingress_extended_vlan_block_id_igmp;
|
||||
/** Extended VLAN block size for ingress IGMP traffic. This is optional.
|
||||
If it is 0, the block size of n_ingress_extended_vlan_block_id_igmp will be
|
||||
used. Otherwise, this field will be used. */
|
||||
u16 ingress_extended_vlan_block_size_igmp;
|
||||
|
||||
/** Enable extended VLAN processing for egress non-IGMP traffic. */
|
||||
bool egress_extended_vlan_enable;
|
||||
/** Extended VLAN block allocated for egress non-IGMP traffic. It defines
|
||||
extended VLAN process for egress non-IGMP traffic. Valid when
|
||||
b_egress_extended_vlan_enable is TRUE. */
|
||||
u16 egress_extended_vlan_block_id;
|
||||
/** Extended VLAN block size for egress non-IGMP traffic. This is optional.
|
||||
If it is 0, the block size of n_egress_extended_vlan_block_id will be used.
|
||||
Otherwise, this field will be used. */
|
||||
u16 egress_extended_vlan_block_size;
|
||||
/** Enable extended VLAN processing for egress IGMP traffic. */
|
||||
bool egress_extended_vlan_igmp_enable;
|
||||
/** Extended VLAN block allocated for egress IGMP traffic. It defines
|
||||
extended VLAN process for egress IGMP traffic. Valid when
|
||||
b_egress_extended_vlan_igmp_enable is TRUE. */
|
||||
u16 egress_extended_vlan_block_id_igmp;
|
||||
/** Extended VLAN block size for egress IGMP traffic. This is optional.
|
||||
If it is 0, the block size of n_egress_extended_vlan_block_id_igmp will be
|
||||
used. Otherwise, this field will be used. */
|
||||
u16 egress_extended_vlan_block_size_igmp;
|
||||
|
||||
/** For WLAN type logical port, this should be FALSE. For other types, if
|
||||
enabled and ingress packet is VLAN tagged, outer VLAN ID is used for
|
||||
"n_sub_if_id" field in MAC table, otherwise, 0 is used for "n_sub_if_id". */
|
||||
bool ingress_nto1vlan_enable;
|
||||
/** For WLAN type logical port, this should be FALSE. For other types, if
|
||||
enabled and egress packet is known unicast, outer VLAN ID is from
|
||||
"n_sub_if_id" field in MAC table. */
|
||||
bool egress_nto1vlan_enable;
|
||||
|
||||
/** Ingress color marking mode for ingress traffic. */
|
||||
mxl862xx_color_marking_mode_t ingress_marking_mode;
|
||||
/** Egress color marking mode for ingress traffic at egress priority queue
|
||||
color marking stage */
|
||||
mxl862xx_color_marking_mode_t egress_marking_mode;
|
||||
/** Egress color marking mode override color marking mode from last stage. */
|
||||
bool egress_marking_override_enable;
|
||||
/** Egress color marking mode for egress traffic. Valid only when
|
||||
b_egress_marking_override is TRUE. */
|
||||
mxl862xx_color_marking_mode_t egress_marking_mode_override;
|
||||
|
||||
/** Color remarking for egress traffic. */
|
||||
mxl862xx_color_remarking_mode_t egress_remarking_mode;
|
||||
|
||||
/** Traffic metering on ingress traffic applies. */
|
||||
bool ingress_metering_enable;
|
||||
/** Meter for ingress CTP process.
|
||||
|
||||
\remarks
|
||||
Meter should be allocated with \ref MXL862XX_QOS_METER_ALLOC before CTP
|
||||
port configuration. If this CTP port is re-set, the last used meter
|
||||
should be released. */
|
||||
u16 ingress_traffic_meter_id;
|
||||
/** Traffic metering on egress traffic applies. */
|
||||
bool egress_metering_enable;
|
||||
/** Meter for egress CTP process.
|
||||
|
||||
\remarks
|
||||
Meter should be allocated with \ref MXL862XX_QOS_METER_ALLOC before CTP
|
||||
port configuration. If this CTP port is re-set, the last used meter
|
||||
should be released. */
|
||||
u16 egress_traffic_meter_id;
|
||||
|
||||
/** Ingress traffic bypass bridging/multicast processing. Following
|
||||
parameters are used to determine destination. Traffic flow table is not
|
||||
bypassed. */
|
||||
bool bridging_bypass;
|
||||
/** When b_bridging_bypass is TRUE, this field defines destination logical
|
||||
port. */
|
||||
u8 dest_logical_port_id;
|
||||
/** When b_bridging_bypass is TRUE, this field indicates whether to use
|
||||
\ref MXL862XX_CTP_port_config_t::n_dest_sub_if_id_group or
|
||||
\ref MXL862XX_CTP_port_config_t::e_pmapper_mapping_mode/
|
||||
\ref MXL862XX_CTP_port_config_t::s_pmapper. */
|
||||
bool pmapper_enable;
|
||||
/** When b_bridging_bypass is TRUE and b_pmapper_enable is FALSE, this field
|
||||
defines destination sub interface ID group. */
|
||||
u16 dest_sub_if_id_group;
|
||||
/** When b_bridging_bypass is TRUE and b_pmapper_enable is TRUE, this field
|
||||
selects either DSCP or PCP to derive sub interface ID. */
|
||||
mxl862xx_pmapper_mapping_mode_t pmapper_mapping_mode;
|
||||
/** When b_pmapper_enable is TRUE, P-mapper is used. This field determines
|
||||
whether s_pmapper.n_pmapper_id is valid. If this field is TRUE, the
|
||||
P-mapper is re-used and no allocation of new P-mapper or value
|
||||
change in the P-mapper. If this field is FALSE, allocation is
|
||||
taken care in the API implementation. */
|
||||
bool pmapper_id_valid;
|
||||
/** When b_bridging_bypass is TRUE and b_pmapper_enable is TRUE, P-mapper is
|
||||
used. If b_pmapper_id_valid is FALSE, API implementation need take care
|
||||
of P-mapper allocation, and maintain the reference counter of
|
||||
P-mapper used multiple times. If b_pmapper_id_valid is TRUE, only
|
||||
s_pmapper.n_pmapper_id is used to associate the P-mapper, and there is
|
||||
no allocation of new P-mapper or value change in the P-mapper. */
|
||||
mxl862xx_pmapper_t pmapper;
|
||||
|
||||
/** First traffic flow table entry is associated to this CTP port. Ingress
|
||||
traffic from this CTP port will go through traffic flow table search
|
||||
starting from n_first_flow_entry_index. Should be times of 4. */
|
||||
u16 first_flow_entry_index;
|
||||
/** Number of traffic flow table entries are associated to this CTP port.
|
||||
Ingress traffic from this CTP port will go through PCE rules search
|
||||
ending at (n_first_flow_entry_index+n_number_of_flow_entries)-1. Should
|
||||
be times of 4. */
|
||||
u16 number_of_flow_entries;
|
||||
|
||||
/** Ingress traffic from this CTP port will be redirected to ingress
|
||||
logical port of this CTP port with source sub interface ID used as
|
||||
destination sub interface ID. Following processing except traffic
|
||||
flow table search is bypassed if loopback enabled. */
|
||||
bool ingress_loopback_enable;
|
||||
/** Destination/Source MAC address of ingress traffic is swapped before
|
||||
transmitted (not swapped during PCE processing stages). If destination
|
||||
is multicast, there is no swap, but source MAC address is replaced
|
||||
with global configurable value. */
|
||||
bool ingress_da_sa_swap_enable;
|
||||
/** Egress traffic to this CTP port will be redirected to ingress logical
|
||||
port with same sub interface ID as ingress. */
|
||||
bool egress_loopback_enable;
|
||||
/** Destination/Source MAC address of egress traffic is swapped before
|
||||
transmitted. */
|
||||
bool egress_da_sa_swap_enable;
|
||||
|
||||
/** If enabled, ingress traffic is mirrored to the monitoring port.
|
||||
\remarks
|
||||
This should be used exclusive with b_ingress_loopback_enable. */
|
||||
bool ingress_mirror_enable;
|
||||
/** If enabled, egress traffic is mirrored to the monitoring port.
|
||||
\remarks
|
||||
This should be used exclusive with b_egress_loopback_enable. */
|
||||
bool egress_mirror_enable;
|
||||
} mxl862xx_ctp_port_config_t;
|
||||
|
||||
#pragma scalar_storage_order default
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif /*_MXL862XX_CTP_H */
|
||||
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_flow.h - Header file for DSA Driver for MaxLinear Mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MXL862XX_FLOW_H_
|
||||
#define _MXL862XX_FLOW_H_
|
||||
|
||||
#include "mxl862xx_types.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#pragma scalar_storage_order little-endian
|
||||
|
||||
#define MPCE_RULES_INDEX 0
|
||||
#define MPCE_RULES_INDEX_LAST (MPCE_RULES_INDEX + 7)
|
||||
#define EAPOL_PCE_RULE_INDEX 8
|
||||
#define BPDU_PCE_RULE_INDEX 9
|
||||
#define PFC_PCE_RULE_INDEX 10
|
||||
|
||||
/** \brief Register access parameter to directly modify internal registers.
|
||||
Used by \ref GSW_REGISTER_MOD. */
|
||||
typedef struct {
|
||||
/** Register Address Offset for modifiation. */
|
||||
u16 reg_addr;
|
||||
/** Value to write to 'reg_addr'. */
|
||||
u16 data;
|
||||
/** Mask of bits to be modified. 1 to modify, 0 to ignore. */
|
||||
u16 mask;
|
||||
} mxl862xx_register_mod_t;
|
||||
|
||||
#pragma scalar_storage_order default
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif /* _MXL862XX_FLOW_H_ */
|
||||
@@ -0,0 +1,514 @@
|
||||
// spdx-license-identifier: gpl-2.0
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_host_api_impl.c - dsa driver for maxlinear mxl862xx switch chips family
|
||||
*
|
||||
* copyright (c) 2024 maxlinear 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; 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., 51 franklin street, fifth floor, boston, ma 02110-1301, usa.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mxl862xx_mmd_apis.h"
|
||||
|
||||
#define CTRL_BUSY_MASK BIT(15)
|
||||
#define CTRL_CMD_MASK (BIT(15) - 1)
|
||||
|
||||
#define MAX_BUSY_LOOP 1000 /* roughly 10ms */
|
||||
|
||||
#define THR_RST_DATA 5
|
||||
|
||||
#define ENABLE_GETSET_OPT 1
|
||||
|
||||
//#define C22_MDIO
|
||||
|
||||
#if defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT
|
||||
static struct {
|
||||
uint16_t ctrl;
|
||||
int16_t ret;
|
||||
mmd_api_data_t data;
|
||||
} shadow = { .ctrl = ~0, .ret = -1, .data = { { 0 } } };
|
||||
#endif
|
||||
|
||||
/* required for Clause 22 extended read/write access */
|
||||
#define MXL862XX_MMDDATA 0xE
|
||||
#define MXL862XX_MMDCTRL 0xD
|
||||
|
||||
#define MXL862XX_ACTYPE_ADDRESS (0 << 14)
|
||||
#define MXL862XX_ACTYPE_DATA (1 << 14)
|
||||
|
||||
#ifndef LINUX_VERSION_CODE
|
||||
#include <linux/version.h>
|
||||
#else
|
||||
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
|
||||
#include <linux/delay.h>
|
||||
#endif
|
||||
|
||||
#ifdef C22_MDIO
|
||||
/**
|
||||
* write access to MMD register of PHYs via Clause 22 extended access
|
||||
*/
|
||||
static int __mxl862xx_c22_ext_mmd_write(const mxl862xx_device_t *dev, struct mii_bus *bus, int sw_addr, int mmd,
|
||||
int reg, u16 val)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Set the DevID for Write Command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDCTRL, mmd);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
/* Issue the write command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDDATA, reg);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
/* Set the DevID for Write Command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDCTRL, MXL862XX_ACTYPE_DATA | mmd);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
/* Issue the write command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDDATA, val);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
error:
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* read access to MMD register of PHYs via Clause 22 extended access
|
||||
*/
|
||||
static int __mxl862xx_c22_ext_mmd_read(const mxl862xx_device_t *dev, struct mii_bus *bus, int sw_addr, int mmd, int reg)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Set the DevID for Write Command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDCTRL, mmd);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
/* Issue the write command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDDATA, reg);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
/* Set the DevID for Write Command */
|
||||
res = __mdiobus_write(bus, sw_addr, MXL862XX_MMDCTRL, MXL862XX_ACTYPE_DATA | mmd);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
/* Read the data */
|
||||
res = __mdiobus_read(bus, sw_addr, MXL862XX_MMDDATA);
|
||||
if (res < 0)
|
||||
goto error;
|
||||
|
||||
error:
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mxl862xx_read(const mxl862xx_device_t *dev, uint32_t regaddr)
|
||||
{
|
||||
int mmd = MXL862XX_MMD_DEV;
|
||||
#ifdef C22_MDIO
|
||||
int ret = __mxl862xx_c22_ext_mmd_read(dev, dev->bus, dev->sw_addr, mmd, regaddr);
|
||||
#else
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
|
||||
u32 addr = MII_ADDR_C45 | (mmd << 16) | (regaddr & 0xffff);
|
||||
int ret = __mdiobus_read(dev->bus, dev->sw_addr, addr);
|
||||
#else
|
||||
int ret = __mdiobus_c45_read(dev->bus, dev->sw_addr, mmd, regaddr);
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxl862xx_write(const mxl862xx_device_t *dev, uint32_t regaddr, uint16_t data)
|
||||
{
|
||||
int mmd = MXL862XX_MMD_DEV;
|
||||
#ifdef C22_MDIO
|
||||
int ret = __mxl862xx_c22_ext_mmd_write(dev, dev->bus, dev->sw_addr, mmd, regaddr, data);
|
||||
#else
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
|
||||
u32 addr = MII_ADDR_C45 | (mmd << 16) | (regaddr & 0xffff);
|
||||
int ret = __mdiobus_write(dev->bus, dev->sw_addr, addr, data);
|
||||
#else
|
||||
int ret = __mdiobus_c45_write(dev->bus, dev->sw_addr, mmd, regaddr, data);
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __wait_ctrl_busy(const mxl862xx_device_t *dev)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < MAX_BUSY_LOOP; i++) {
|
||||
ret = mxl862xx_read(dev, MXL862XX_MMD_REG_CTRL);
|
||||
if (ret < 0) {
|
||||
goto busy_check_exit;
|
||||
}
|
||||
|
||||
if (!(ret & CTRL_BUSY_MASK)) {
|
||||
ret = 0;
|
||||
goto busy_check_exit;
|
||||
}
|
||||
|
||||
usleep_range(10, 15);
|
||||
}
|
||||
ret = -ETIMEDOUT;
|
||||
busy_check_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __mxl862xx_rst_data(const mxl862xx_device_t *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_LEN_RET, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_CTRL,
|
||||
MMD_API_RST_DATA | CTRL_BUSY_MASK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return __wait_ctrl_busy(dev);
|
||||
}
|
||||
|
||||
static int __mxl862xx_set_data(const mxl862xx_device_t *dev, uint16_t words)
|
||||
{
|
||||
int ret;
|
||||
uint16_t cmd;
|
||||
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_LEN_RET,
|
||||
MXL862XX_MMD_REG_DATA_MAX_SIZE * sizeof(uint16_t));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cmd = words / MXL862XX_MMD_REG_DATA_MAX_SIZE - 1;
|
||||
if (!(cmd < 2))
|
||||
return -EINVAL;
|
||||
|
||||
cmd += MMD_API_SET_DATA_0;
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_CTRL, cmd | CTRL_BUSY_MASK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return __wait_ctrl_busy(dev);
|
||||
}
|
||||
|
||||
static int __mxl862xx_get_data(const mxl862xx_device_t *dev, uint16_t words)
|
||||
{
|
||||
int ret;
|
||||
uint16_t cmd;
|
||||
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_LEN_RET,
|
||||
MXL862XX_MMD_REG_DATA_MAX_SIZE * sizeof(uint16_t));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cmd = words / MXL862XX_MMD_REG_DATA_MAX_SIZE;
|
||||
if (!(cmd > 0 && cmd < 3))
|
||||
return -EINVAL;
|
||||
cmd += MMD_API_GET_DATA_0;
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_CTRL, cmd | CTRL_BUSY_MASK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return __wait_ctrl_busy(dev);
|
||||
}
|
||||
|
||||
static int __mxl862xx_send_cmd(const mxl862xx_device_t *dev, uint16_t cmd, uint16_t size,
|
||||
int16_t *presult)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_LEN_RET, size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mxl862xx_write(dev, MXL862XX_MMD_REG_CTRL, cmd | CTRL_BUSY_MASK);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = __wait_ctrl_busy(dev);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mxl862xx_read(dev, MXL862XX_MMD_REG_LEN_RET);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*presult = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __mxl862xx_cmd_r_valid(uint16_t cmd_r)
|
||||
{
|
||||
#if defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT
|
||||
return (shadow.ctrl == cmd_r && shadow.ret >= 0) ? true : false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This is usually used to implement CFG_SET command.
|
||||
* With previous CFG_GET command executed properly, the retrieved data
|
||||
* are shadowed in local structure. WSP FW has a set of shadow too,
|
||||
* so that only the difference to be sent over SMDIO.
|
||||
*/
|
||||
static int __mxl862xx_api_wrap_cmd_r(const mxl862xx_device_t *dev, uint16_t cmd,
|
||||
void *pdata, uint16_t size, uint16_t r_size)
|
||||
{
|
||||
#if defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT
|
||||
int ret;
|
||||
|
||||
uint16_t max, i;
|
||||
uint16_t *data;
|
||||
int16_t result = 0;
|
||||
|
||||
max = (size + 1) / 2;
|
||||
data = pdata;
|
||||
|
||||
ret = __wait_ctrl_busy(dev);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint16_t off = i % MXL862XX_MMD_REG_DATA_MAX_SIZE;
|
||||
|
||||
if (i && off == 0) {
|
||||
/* Send command to set data when every
|
||||
* MXL862XX_MMD_REG_DATA_MAX_SIZE of WORDs are written
|
||||
* and reload next batch of data from last CFG_GET.
|
||||
*/
|
||||
ret = __mxl862xx_set_data(dev, i);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[i] == shadow.data.data[i])
|
||||
continue;
|
||||
|
||||
mxl862xx_write(dev, MXL862XX_MMD_REG_DATA_FIRST + off,
|
||||
le16_to_cpu(data[i]));
|
||||
//sys_le16_to_cpu(data[i]));
|
||||
}
|
||||
|
||||
ret = __mxl862xx_send_cmd(dev, cmd, size, &result);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
max = (r_size + 1) / 2;
|
||||
for (i = 0; i < max; i++) {
|
||||
uint16_t off = i % MXL862XX_MMD_REG_DATA_MAX_SIZE;
|
||||
|
||||
if (i && off == 0) {
|
||||
/* Send command to fetch next batch of data
|
||||
* when every MXL862XX_MMD_REG_DATA_MAX_SIZE of WORDs
|
||||
* are read.
|
||||
*/
|
||||
ret = __mxl862xx_get_data(dev, i);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = mxl862xx_read(dev, MXL862XX_MMD_REG_DATA_FIRST + off);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((i * 2 + 1) == r_size) {
|
||||
/* Special handling for last BYTE
|
||||
* if it's not WORD aligned.
|
||||
*/
|
||||
*(uint8_t *)&data[i] = ret & 0xFF;
|
||||
} else {
|
||||
data[i] = cpu_to_le16((uint16_t)ret);
|
||||
}
|
||||
}
|
||||
|
||||
shadow.data.data[max] = 0;
|
||||
memcpy(shadow.data.data, data, r_size);
|
||||
|
||||
return result;
|
||||
#else /* defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT */
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(cmd);
|
||||
ARG_UNUSED(pdata);
|
||||
ARG_UNUSED(size);
|
||||
return -ENOTSUP;
|
||||
#endif /* defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT */
|
||||
}
|
||||
|
||||
int mxl862xx_api_wrap(const mxl862xx_device_t *dev, uint16_t cmd, void *pdata,
|
||||
uint16_t size, uint16_t cmd_r, uint16_t r_size)
|
||||
{
|
||||
int ret;
|
||||
uint16_t max, i, cnt;
|
||||
uint16_t *data;
|
||||
int16_t result = 0;
|
||||
|
||||
if (!dev || (!pdata && size))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(size <= sizeof(mmd_api_data_t)) || !(r_size <= size))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock_nested(&dev->bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
if (__mxl862xx_cmd_r_valid(cmd_r)) {
|
||||
/* Special handling for GET and SET command pair. */
|
||||
ret = __mxl862xx_api_wrap_cmd_r(dev, cmd, pdata, size, r_size);
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
max = (size + 1) / 2;
|
||||
data = pdata;
|
||||
|
||||
/* Check whether it's worth to issue RST_DATA command. */
|
||||
for (i = cnt = 0; i < max && cnt < THR_RST_DATA; i++) {
|
||||
if (!data[i])
|
||||
cnt++;
|
||||
}
|
||||
|
||||
ret = __wait_ctrl_busy(dev);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
|
||||
if (cnt >= THR_RST_DATA) {
|
||||
/* Issue RST_DATA commdand. */
|
||||
ret = __mxl862xx_rst_data(dev);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
|
||||
for (i = 0, cnt = 0; i < max; i++) {
|
||||
uint16_t off = i % MXL862XX_MMD_REG_DATA_MAX_SIZE;
|
||||
|
||||
if (i && off == 0) {
|
||||
uint16_t cnt_old = cnt;
|
||||
|
||||
cnt = 0;
|
||||
|
||||
/* No actual data was written. */
|
||||
if (!cnt_old)
|
||||
continue;
|
||||
|
||||
/* Send command to set data when every
|
||||
* MXL862XX_MMD_REG_DATA_MAX_SIZE of WORDs are written
|
||||
* and clear the MMD register space.
|
||||
*/
|
||||
ret = __mxl862xx_set_data(dev, i);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
/* Skip '0' data. */
|
||||
if (!data[i])
|
||||
continue;
|
||||
|
||||
mxl862xx_write(dev, MXL862XX_MMD_REG_DATA_FIRST + off,
|
||||
le16_to_cpu(data[i]));
|
||||
cnt++;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < max; i++) {
|
||||
uint16_t off = i % MXL862XX_MMD_REG_DATA_MAX_SIZE;
|
||||
|
||||
if (i && off == 0) {
|
||||
/* Send command to set data when every
|
||||
* MXL862XX_MMD_REG_DATA_MAX_SIZE of WORDs are written.
|
||||
*/
|
||||
ret = __mxl862xx_set_data(dev, i);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
mxl862xx_write(dev, MXL862XX_MMD_REG_DATA_FIRST + off,
|
||||
le16_to_cpu(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
ret = __mxl862xx_send_cmd(dev, cmd, size, &result);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
|
||||
if (result < 0) {
|
||||
ret = result;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
max = (r_size + 1) / 2;
|
||||
for (i = 0; i < max; i++) {
|
||||
uint16_t off = i % MXL862XX_MMD_REG_DATA_MAX_SIZE;
|
||||
|
||||
if (i && off == 0) {
|
||||
/* Send command to fetch next batch of data
|
||||
* when every MXL862XX_MMD_REG_DATA_MAX_SIZE of WORDs
|
||||
* are read.
|
||||
*/
|
||||
ret = __mxl862xx_get_data(dev, i);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
ret = mxl862xx_read(dev, MXL862XX_MMD_REG_DATA_FIRST + off);
|
||||
if (ret < 0)
|
||||
goto EXIT;
|
||||
|
||||
if ((i * 2 + 1) == r_size) {
|
||||
/* Special handling for last BYTE
|
||||
* if it's not WORD aligned.
|
||||
*/
|
||||
*(uint8_t *)&data[i] = ret & 0xFF;
|
||||
} else {
|
||||
data[i] = cpu_to_le16((uint16_t)ret);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT
|
||||
if ((cmd != 0x1801) && (cmd != 0x1802))
|
||||
shadow.data.data[max] = 0;
|
||||
memcpy(shadow.data.data, data, r_size);
|
||||
#endif
|
||||
|
||||
ret = result;
|
||||
|
||||
EXIT:
|
||||
#if defined(ENABLE_GETSET_OPT) && ENABLE_GETSET_OPT
|
||||
shadow.ctrl = cmd;
|
||||
shadow.ret = ret;
|
||||
#endif
|
||||
mutex_unlock(&dev->bus->mdio_lock);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// spdx-license-identifier: gpl-2.0
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_host_api_impl.h - dsa driver for maxlinear mxl862xx switch chips family
|
||||
*
|
||||
* copyright (c) 2024 maxlinear 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; 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., 51 franklin street, fifth floor, boston, ma 02110-1301, usa.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MXL862XX_HOST_API_IMPL_H_
|
||||
#define _MXL862XX_HOST_API_IMPL_H_
|
||||
|
||||
#include "mxl862xx_types.h"
|
||||
|
||||
extern int mxl862xx_api_wrap(const mxl862xx_device_t *dev, uint16_t cmd, void *pdata,
|
||||
uint16_t size, uint16_t cmd_r, uint16_t r_size);
|
||||
|
||||
#endif /* _MXL862XX_HOST_API_IMPL_H_ */
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_mdio_relay.c - dsa driver for Maxlinear mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mxl862xx_mdio_relay.h"
|
||||
#include "mxl862xx_host_api_impl.h"
|
||||
#include "mxl862xx_mmd_apis.h"
|
||||
|
||||
int int_gphy_read(const mxl862xx_device_t *dev, struct mdio_relay_data *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, INT_GPHY_READ, parm, sizeof(*parm), 0,
|
||||
sizeof(parm->data));
|
||||
}
|
||||
|
||||
int int_gphy_write(const mxl862xx_device_t *dev, struct mdio_relay_data *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, INT_GPHY_WRITE, parm, sizeof(*parm), 0, 0);
|
||||
}
|
||||
|
||||
int int_gphy_mod(const mxl862xx_device_t *dev, struct mdio_relay_mod_data *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, INT_GPHY_MOD, parm, sizeof(*parm), 0, 0);
|
||||
}
|
||||
|
||||
int ext_mdio_read(const mxl862xx_device_t *dev, struct mdio_relay_data *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, EXT_MDIO_READ, parm, sizeof(*parm), 0,
|
||||
sizeof(parm->data));
|
||||
}
|
||||
|
||||
int ext_mdio_write(const mxl862xx_device_t *dev, struct mdio_relay_data *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, EXT_MDIO_WRITE, parm, sizeof(*parm), 0, 0);
|
||||
}
|
||||
|
||||
int ext_mdio_mod(const mxl862xx_device_t *dev, struct mdio_relay_mod_data *parm)
|
||||
{
|
||||
return mxl862xx_api_wrap(dev, EXT_MDIO_MOD, parm, sizeof(*parm), 0, 0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(int_gphy_write);
|
||||
EXPORT_SYMBOL(int_gphy_read);
|
||||
EXPORT_SYMBOL(int_gphy_mod);
|
||||
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_mdio_relay.h - Header file for DSA Driver for MaxLinear Mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MXL862XX_MDIO_RELAY_H_
|
||||
#define _MXL862XX_MDIO_RELAY_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "mxl862xx_types.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#pragma scalar_storage_order little-endian
|
||||
|
||||
struct mdio_relay_data {
|
||||
/* data to be read or written */
|
||||
uint16_t data;
|
||||
/* PHY index (0~7) for internal PHY
|
||||
* PHY address (0~31) for external PHY access via MDIO bus
|
||||
*/
|
||||
uint8_t phy;
|
||||
/* MMD device (0~31) */
|
||||
uint8_t mmd;
|
||||
/* Register Index
|
||||
* 0~31 if mmd is 0 (CL22)
|
||||
* 0~65535 otherwise (CL45)
|
||||
*/
|
||||
uint16_t reg;
|
||||
};
|
||||
|
||||
struct mdio_relay_mod_data {
|
||||
/* data to be written with mask */
|
||||
uint16_t data;
|
||||
/* PHY index (0~7) for internal PHY
|
||||
* PHY address (0~31) for external PHY access via MDIO bus
|
||||
*/
|
||||
uint8_t phy;
|
||||
/* MMD device (0~31) */
|
||||
uint8_t mmd;
|
||||
/* Register Index
|
||||
* 0~31 if mmd is 0 (CL22)
|
||||
* 0~65535 otherwise (CL45)
|
||||
*/
|
||||
uint16_t reg;
|
||||
/* mask of bit fields to be updated
|
||||
* 1 to write the bit
|
||||
* 0 to ignore
|
||||
*/
|
||||
uint16_t mask;
|
||||
};
|
||||
|
||||
#pragma scalar_storage_order default
|
||||
#pragma pack(pop)
|
||||
|
||||
/* read internal GPHY MDIO/MMD registers */
|
||||
int int_gphy_read(const mxl862xx_device_t *dev, struct mdio_relay_data *pdata);
|
||||
/* write internal GPHY MDIO/MMD registers */
|
||||
int int_gphy_write(const mxl862xx_device_t *dev, struct mdio_relay_data *pdata);
|
||||
/* modify internal GPHY MDIO/MMD registers */
|
||||
int int_gphy_mod(const mxl862xx_device_t *dev, struct mdio_relay_mod_data *pdata);
|
||||
|
||||
/* read external GPHY MDIO/MMD registers via MDIO bus */
|
||||
int ext_mdio_read(const mxl862xx_device_t *dev, struct mdio_relay_data *pdata);
|
||||
/* write external GPHY MDIO/MMD registers via MDIO bus */
|
||||
int ext_mdio_write(const mxl862xx_device_t *dev, struct mdio_relay_data *pdata);
|
||||
/* modify external GPHY MDIO/MMD registers via MDIO bus */
|
||||
int ext_mdio_mod(const mxl862xx_device_t *dev, struct mdio_relay_mod_data *pdata);
|
||||
|
||||
#endif /* _MXL862XX_MDIO_RELAY_H_ */
|
||||
@@ -0,0 +1,279 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_mmd_apis.h - Header file for DSA Driver for MaxLinear Mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MXL862XX_MMD_APIS_H_
|
||||
#define _MXL862XX_MMD_APIS_H_
|
||||
|
||||
#include "mxl862xx_api.h"
|
||||
#include "mxl862xx_mdio_relay.h"
|
||||
|
||||
#define MXL862XX_MMD_DEV 30
|
||||
#define MXL862XX_MMD_REG_CTRL 0
|
||||
#define MXL862XX_MMD_REG_LEN_RET 1
|
||||
#define MXL862XX_MMD_REG_DATA_FIRST 2
|
||||
#define MXL862XX_MMD_REG_DATA_LAST 95
|
||||
#define MXL862XX_MMD_REG_DATA_MAX_SIZE \
|
||||
(MXL862XX_MMD_REG_DATA_LAST - MXL862XX_MMD_REG_DATA_FIRST + 1)
|
||||
|
||||
typedef union mmd_api_data {
|
||||
uint16_t data[MXL862XX_MMD_REG_DATA_MAX_SIZE * 3]; //Maximum data size is GSW_PCE_rule_t (508)
|
||||
mxl862xx_register_mod_t mxl862xx_register_mod_t_data;
|
||||
mxl862xx_cpu_port_cfg_t mxl862xx_cpu_port_cfg_t_data;
|
||||
mxl862xx_port_link_cfg_t mxl862xx_port_link_cfg_t_data;
|
||||
mxl862xx_port_cfg_t mxl862xx_port_cfg_t_data;
|
||||
mxl862xx_bridge_alloc_t mxl862xx_bridge_alloc_t_data;
|
||||
mxl862xx_bridge_port_config_t mxl862xx_bridge_port_config_t_data;
|
||||
mxl862xx_debug_rmon_port_cnt_t mxl862xx_debug_rmon_port_cnt_t_data;
|
||||
mxl862xx_mac_table_clear_cond_t mxl862xx_mac_table_clear_cond_t_data;
|
||||
mxl862xx_mac_table_read_t mxl862xx_mac_table_read_t_data;
|
||||
mxl862xx_mac_table_add_t mxl862xx_mac_table_add_t_data;
|
||||
mxl862xx_mac_table_remove_t mxl862xx_mac_table_remove_t_data;
|
||||
mxl862xx_stp_port_cfg_t mxl862xx_stp_port_cfg_t_data;
|
||||
mxl862xx_ss_sp_tag_t mxl862xx_ss_sp_tag_t_data;
|
||||
mxl862xx_monitor_port_cfg_t mxl862xx_monitor_port_cfg_t_data;
|
||||
mxl862xx_ctp_port_config_t mxl862xx_ctp_port_config_t_data;
|
||||
|
||||
struct mdio_relay_data mdio_relay_data;
|
||||
struct mdio_relay_mod_data mdio_relay_mod_data;
|
||||
struct sys_fw_image_version img_ver_data;
|
||||
#ifdef CONFIG_SENSOR_MXL
|
||||
struct sys_sensor_value pvt_sensor_data;
|
||||
#endif
|
||||
} mmd_api_data_t;
|
||||
|
||||
#define MXL862XX_COMMON_MAGIC 0x100
|
||||
#define MXL862XX_TFLOW_MAGIC 0x200
|
||||
#define MXL862XX_BRDG_MAGIC 0x300
|
||||
#define MXL862XX_BRDGPORT_MAGIC 0x400
|
||||
#define MXL862XX_CTP_MAGIC 0x500
|
||||
#define MXL862XX_QOS_MAGIC 0x600
|
||||
#define MXL862XX_RMON_MAGIC 0x700
|
||||
#define MXL862XX_DEBUG_MAGIC 0x800
|
||||
#define MXL862XX_PMAC_MAGIC 0x900
|
||||
#define MXL862XX_SWMAC_MAGIC 0xA00
|
||||
#define MXL862XX_EXTVLAN_MAGIC 0xB00
|
||||
#define MXL862XX_VLANFILTER_MAGIC 0xC00
|
||||
#define MXL862XX_MULTICAST_MAGIC 0xD00
|
||||
#define MXL862XX_TRUNKING_MAGIC 0xE00
|
||||
#define MXL862XX_STP_MAGIC 0xF00
|
||||
#define MXL862XX_PBB_MAGIC 0x1000
|
||||
#define MXL862XX_VLAN_RMON_MAGIC 0x1100
|
||||
#define MXL862XX_SS_MAGIC 0x1600
|
||||
|
||||
#define GPY_GPY2XX_MAGIC 0x1800
|
||||
|
||||
#define SYS_MISC_MAGIC 0x1900
|
||||
|
||||
#ifdef MMD_API_TEST
|
||||
#define MMD_API_SIMPLE_TEST (0x0 + 0x1)
|
||||
#endif
|
||||
#define MMD_API_SET_DATA_0 (0x0 + 0x2)
|
||||
#define MMD_API_SET_DATA_1 (0x0 + 0x3)
|
||||
#define MMD_API_SET_DATA_2 (0x0 + 0x4)
|
||||
#define MMD_API_GET_DATA_0 (0x0 + 0x5)
|
||||
#define MMD_API_GET_DATA_1 (0x0 + 0x6)
|
||||
#define MMD_API_GET_DATA_2 (0x0 + 0x7)
|
||||
#define MMD_API_RST_DATA (0x0 + 0x8)
|
||||
|
||||
#define MXL862XX_COMMON_REGISTERGET (MXL862XX_COMMON_MAGIC + 0x1)
|
||||
#define MXL862XX_COMMON_REGISTERSET (MXL862XX_COMMON_MAGIC + 0x2)
|
||||
#define MXL862XX_COMMON_CPU_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x3)
|
||||
#define MXL862XX_COMMON_CPU_PORTCFGSET (MXL862XX_COMMON_MAGIC + 0x4)
|
||||
#define MXL862XX_COMMON_PORTLINKCFGGET (MXL862XX_COMMON_MAGIC + 0x5)
|
||||
#define MXL862XX_COMMON_PORTLINKCFGSET (MXL862XX_COMMON_MAGIC + 0x6)
|
||||
#define MXL862XX_COMMON_PORTCFGGET (MXL862XX_COMMON_MAGIC + 0x7)
|
||||
#define MXL862XX_COMMON_PORTCFGSET (MXL862XX_COMMON_MAGIC + 0x8)
|
||||
#define MXL862XX_COMMON_CFGGET (MXL862XX_COMMON_MAGIC + 0x9)
|
||||
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xA)
|
||||
#define MXL862XX_COMMON_MONITORPORTCFGGET (MXL862XX_COMMON_MAGIC + 0xD)
|
||||
#define MXL862XX_COMMON_MONITORPORTCFGSET (MXL862XX_COMMON_MAGIC + 0xE)
|
||||
#define MXL862XX_COMMON_FREEZE (MXL862XX_COMMON_MAGIC + 0xF)
|
||||
#define MXL862XX_COMMON_UNFREEZE (MXL862XX_COMMON_MAGIC + 0x10)
|
||||
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
|
||||
|
||||
#define MXL862XX_TFLOW_PCERULEREAD (MXL862XX_TFLOW_MAGIC + 0x1)
|
||||
#define MXL862XX_TFLOW_PCERULEWRITE (MXL862XX_TFLOW_MAGIC + 0x2)
|
||||
#define MXL862XX_TFLOW_PCERULEDELETE (MXL862XX_TFLOW_MAGIC + 0x3)
|
||||
#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
|
||||
#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
|
||||
#define MXL862XX_TFLOW_PCERULEENABLE (MXL862XX_TFLOW_MAGIC + 0x6)
|
||||
#define MXL862XX_TFLOW_PCERULEDISABLE (MXL862XX_TFLOW_MAGIC + 0x7)
|
||||
|
||||
#define MXL862XX_BRIDGE_ALLOC (MXL862XX_BRDG_MAGIC + 0x1)
|
||||
#define MXL862XX_BRIDGE_CONFIGSET (MXL862XX_BRDG_MAGIC + 0x2)
|
||||
#define MXL862XX_BRIDGE_CONFIGGET (MXL862XX_BRDG_MAGIC + 0x3)
|
||||
#define MXL862XX_BRIDGE_FREE (MXL862XX_BRDG_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_BRIDGEPORT_ALLOC (MXL862XX_BRDGPORT_MAGIC + 0x1)
|
||||
#define MXL862XX_BRIDGEPORT_CONFIGSET (MXL862XX_BRDGPORT_MAGIC + 0x2)
|
||||
#define MXL862XX_BRIDGEPORT_CONFIGGET (MXL862XX_BRDGPORT_MAGIC + 0x3)
|
||||
#define MXL862XX_BRIDGEPORT_FREE (MXL862XX_BRDGPORT_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_CTP_PORTASSIGNMENTALLOC (MXL862XX_CTP_MAGIC + 0x1)
|
||||
#define MXL862XX_CTP_PORTASSIGNMENTFREE (MXL862XX_CTP_MAGIC + 0x2)
|
||||
#define MXL862XX_CTP_PORTASSIGNMENTSET (MXL862XX_CTP_MAGIC + 0x3)
|
||||
#define MXL862XX_CTP_PORTASSIGNMENTGET (MXL862XX_CTP_MAGIC + 0x4)
|
||||
#define MXL862XX_CTP_PORTCONFIGSET (MXL862XX_CTP_MAGIC + 0x5)
|
||||
#define MXL862XX_CTP_PORTCONFIGGET (MXL862XX_CTP_MAGIC + 0x6)
|
||||
#define MXL862XX_CTP_PORTCONFIGRESET (MXL862XX_CTP_MAGIC + 0x7)
|
||||
|
||||
#define MXL862XX_QOS_METERCFGGET (MXL862XX_QOS_MAGIC + 0x1)
|
||||
#define MXL862XX_QOS_METERCFGSET (MXL862XX_QOS_MAGIC + 0x2)
|
||||
#define MXL862XX_QOS_DSCP_CLASSGET (MXL862XX_QOS_MAGIC + 0x4)
|
||||
#define MXL862XX_QOS_DSCP_CLASSSET (MXL862XX_QOS_MAGIC + 0x5)
|
||||
#define MXL862XX_QOS_DSCP_DROPPRECEDENCECFGGET (MXL862XX_QOS_MAGIC + 0x6)
|
||||
#define MXL862XX_QOS_DSCP_DROPPRECEDENCECFGSET (MXL862XX_QOS_MAGIC + 0x7)
|
||||
#define MXL862XX_QOS_PORTREMARKINGCFGGET (MXL862XX_QOS_MAGIC + 0x8)
|
||||
#define MXL862XX_QOS_PORTREMARKINGCFGSET (MXL862XX_QOS_MAGIC + 0x9)
|
||||
#define MXL862XX_QOS_PCP_CLASSGET (MXL862XX_QOS_MAGIC + 0xA)
|
||||
#define MXL862XX_QOS_PCP_CLASSSET (MXL862XX_QOS_MAGIC + 0xB)
|
||||
#define MXL862XX_QOS_PORTCFGGET (MXL862XX_QOS_MAGIC + 0xC)
|
||||
#define MXL862XX_QOS_PORTCFGSET (MXL862XX_QOS_MAGIC + 0xD)
|
||||
#define MXL862XX_QOS_QUEUEPORTGET (MXL862XX_QOS_MAGIC + 0xE)
|
||||
#define MXL862XX_QOS_QUEUEPORTSET (MXL862XX_QOS_MAGIC + 0xF)
|
||||
#define MXL862XX_QOS_SCHEDULERCFGGET (MXL862XX_QOS_MAGIC + 0x10)
|
||||
#define MXL862XX_QOS_SCHEDULERCFGSET (MXL862XX_QOS_MAGIC + 0x11)
|
||||
#define MXL862XX_QOS_SHAPERCFGGET (MXL862XX_QOS_MAGIC + 0x12)
|
||||
#define MXL862XX_QOS_SHAPERCFGSET (MXL862XX_QOS_MAGIC + 0x13)
|
||||
#define MXL862XX_QOS_SHAPERQUEUEASSIGN (MXL862XX_QOS_MAGIC + 0x14)
|
||||
#define MXL862XX_QOS_SHAPERQUEUEDEASSIGN (MXL862XX_QOS_MAGIC + 0x15)
|
||||
#define MXL862XX_QOS_SHAPERQUEUEGET (MXL862XX_QOS_MAGIC + 0x16)
|
||||
#define MXL862XX_QOS_STORMCFGSET (MXL862XX_QOS_MAGIC + 0x17)
|
||||
#define MXL862XX_QOS_STORMCFGGET (MXL862XX_QOS_MAGIC + 0x18)
|
||||
#define MXL862XX_QOS_WREDCFGGET (MXL862XX_QOS_MAGIC + 0x19)
|
||||
#define MXL862XX_QOS_WREDCFGSET (MXL862XX_QOS_MAGIC + 0x1A)
|
||||
#define MXL862XX_QOS_WREDQUEUECFGGET (MXL862XX_QOS_MAGIC + 0x1B)
|
||||
#define MXL862XX_QOS_WREDQUEUECFGSET (MXL862XX_QOS_MAGIC + 0x1C)
|
||||
#define MXL862XX_QOS_WREDPORTCFGGET (MXL862XX_QOS_MAGIC + 0x1D)
|
||||
#define MXL862XX_QOS_WREDPORTCFGSET (MXL862XX_QOS_MAGIC + 0x1E)
|
||||
#define MXL862XX_QOS_FLOWCTRLCFGGET (MXL862XX_QOS_MAGIC + 0x1F)
|
||||
#define MXL862XX_QOS_FLOWCTRLCFGSET (MXL862XX_QOS_MAGIC + 0x20)
|
||||
#define MXL862XX_QOS_FLOWCTRLPORTCFGGET (MXL862XX_QOS_MAGIC + 0x21)
|
||||
#define MXL862XX_QOS_FLOWCTRLPORTCFGSET (MXL862XX_QOS_MAGIC + 0x22)
|
||||
#define MXL862XX_QOS_QUEUEBUFFERRESERVECFGGET (MXL862XX_QOS_MAGIC + 0x23)
|
||||
#define MXL862XX_QOS_QUEUEBUFFERRESERVECFGSET (MXL862XX_QOS_MAGIC + 0x24)
|
||||
#define MXL862XX_QOS_COLORMARKINGTABLEGET (MXL862XX_QOS_MAGIC + 0x26)
|
||||
#define MXL862XX_QOS_COLORMARKINGTABLESET (MXL862XX_QOS_MAGIC + 0x27)
|
||||
#define MXL862XX_QOS_COLORREMARKINGTABLESET (MXL862XX_QOS_MAGIC + 0x28)
|
||||
#define MXL862XX_QOS_COLORREMARKINGTABLEGET (MXL862XX_QOS_MAGIC + 0x29)
|
||||
#define MXL862XX_QOS_METERALLOC (MXL862XX_QOS_MAGIC + 0x2A)
|
||||
#define MXL862XX_QOS_METERFREE (MXL862XX_QOS_MAGIC + 0x2B)
|
||||
#define MXL862XX_QOS_DSCP2PCPTABLESET (MXL862XX_QOS_MAGIC + 0x2C)
|
||||
#define MXL862XX_QOS_DSCP2PCPTABLEGET (MXL862XX_QOS_MAGIC + 0x2D)
|
||||
#define MXL862XX_QOS_PMAPPERTABLESET (MXL862XX_QOS_MAGIC + 0x2E)
|
||||
#define MXL862XX_QOS_PMAPPERTABLEGET (MXL862XX_QOS_MAGIC + 0x2F)
|
||||
#define MXL862XX_QOS_SVLAN_PCP_CLASSGET (MXL862XX_QOS_MAGIC + 0x30)
|
||||
#define MXL862XX_QOS_SVLAN_PCP_CLASSSET (MXL862XX_QOS_MAGIC + 0x31)
|
||||
|
||||
#define MXL862XX_RMON_PORT_GET (MXL862XX_RMON_MAGIC + 0x1)
|
||||
#define MXL862XX_RMON_MODE_SET (MXL862XX_RMON_MAGIC + 0x2)
|
||||
#define MXL862XX_RMON_METER_GET (MXL862XX_RMON_MAGIC + 0x3)
|
||||
#define MXL862XX_RMON_CLEAR (MXL862XX_RMON_MAGIC + 0x4)
|
||||
#define MXL862XX_RMON_TFLOWGET (MXL862XX_RMON_MAGIC + 0x5)
|
||||
#define MXL862XX_RMON_TFLOWCLEAR (MXL862XX_RMON_MAGIC + 0x6)
|
||||
#define MXL862XX_RMON_TFLOWCOUNTMODESET (MXL862XX_RMON_MAGIC + 0x7)
|
||||
#define MXL862XX_RMON_TFLOWCOUNTMODEGET (MXL862XX_RMON_MAGIC + 0x8)
|
||||
|
||||
#define MXL862XX_DEBUG_RMON_PORT_GET (MXL862XX_DEBUG_MAGIC + 0x1)
|
||||
|
||||
#define MXL862XX_PMAC_COUNTGET (MXL862XX_PMAC_MAGIC + 0x1)
|
||||
#define MXL862XX_PMAC_GBL_CFGSET (MXL862XX_PMAC_MAGIC + 0x2)
|
||||
#define MXL862XX_PMAC_GBL_CFGGET (MXL862XX_PMAC_MAGIC + 0x3)
|
||||
#define MXL862XX_PMAC_BM_CFGSET (MXL862XX_PMAC_MAGIC + 0x4)
|
||||
#define MXL862XX_PMAC_BM_CFGGET (MXL862XX_PMAC_MAGIC + 0x5)
|
||||
#define MXL862XX_PMAC_IG_CFGSET (MXL862XX_PMAC_MAGIC + 0x6)
|
||||
#define MXL862XX_PMAC_IG_CFGGET (MXL862XX_PMAC_MAGIC + 0x7)
|
||||
#define MXL862XX_PMAC_EG_CFGSET (MXL862XX_PMAC_MAGIC + 0x8)
|
||||
#define MXL862XX_PMAC_EG_CFGGET (MXL862XX_PMAC_MAGIC + 0x9)
|
||||
|
||||
#define MXL862XX_MAC_TABLECLEAR (MXL862XX_SWMAC_MAGIC + 0x1)
|
||||
#define MXL862XX_MAC_TABLEENTRYADD (MXL862XX_SWMAC_MAGIC + 0x2)
|
||||
#define MXL862XX_MAC_TABLEENTRYREAD (MXL862XX_SWMAC_MAGIC + 0x3)
|
||||
#define MXL862XX_MAC_TABLEENTRYQUERY (MXL862XX_SWMAC_MAGIC + 0x4)
|
||||
#define MXL862XX_MAC_TABLEENTRYREMOVE (MXL862XX_SWMAC_MAGIC + 0x5)
|
||||
#define MXL862XX_MAC_DEFAULTFILTERSET (MXL862XX_SWMAC_MAGIC + 0x6)
|
||||
#define MXL862XX_MAC_DEFAULTFILTERGET (MXL862XX_SWMAC_MAGIC + 0x7)
|
||||
#define MXL862XX_MAC_TABLECLEARCOND (MXL862XX_SWMAC_MAGIC + 0x8)
|
||||
|
||||
#define MXL862XX_EXTENDEDVLAN_ALLOC (MXL862XX_EXTVLAN_MAGIC + 0x1)
|
||||
#define MXL862XX_EXTENDEDVLAN_SET (MXL862XX_EXTVLAN_MAGIC + 0x2)
|
||||
#define MXL862XX_EXTENDEDVLAN_GET (MXL862XX_EXTVLAN_MAGIC + 0x3)
|
||||
#define MXL862XX_EXTENDEDVLAN_FREE (MXL862XX_EXTVLAN_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_VLANFILTER_ALLOC (MXL862XX_VLANFILTER_MAGIC + 0x1)
|
||||
#define MXL862XX_VLANFILTER_SET (MXL862XX_VLANFILTER_MAGIC + 0x2)
|
||||
#define MXL862XX_VLANFILTER_GET (MXL862XX_VLANFILTER_MAGIC + 0x3)
|
||||
#define MXL862XX_VLANFILTER_FREE (MXL862XX_VLANFILTER_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_VLAN_COUNTER_MAPPING_SET (MXL862XX_VLAN_RMON_MAGIC + 0x1)
|
||||
#define MXL862XX_VLAN_COUNTER_MAPPING_GET (MXL862XX_VLAN_RMON_MAGIC + 0x2)
|
||||
#define MXL862XX_VLAN_RMON_GET (MXL862XX_VLAN_RMON_MAGIC + 0x3)
|
||||
#define MXL862XX_VLAN_RMON_CLEAR (MXL862XX_VLAN_RMON_MAGIC + 0x4)
|
||||
#define MXL862XX_VLAN_RMON_CONTROL_SET (MXL862XX_VLAN_RMON_MAGIC + 0x5)
|
||||
#define MXL862XX_VLAN_RMON_CONTROL_GET (MXL862XX_VLAN_RMON_MAGIC + 0x6)
|
||||
|
||||
#define MXL862XX_MULTICAST_ROUTERPORTADD (MXL862XX_MULTICAST_MAGIC + 0x1)
|
||||
#define MXL862XX_MULTICAST_ROUTERPORTREAD (MXL862XX_MULTICAST_MAGIC + 0x2)
|
||||
#define MXL862XX_MULTICAST_ROUTERPORTREMOVE (MXL862XX_MULTICAST_MAGIC + 0x3)
|
||||
#define MXL862XX_MULTICAST_SNOOPCFGGET (MXL862XX_MULTICAST_MAGIC + 0x4)
|
||||
#define MXL862XX_MULTICAST_SNOOPCFGSET (MXL862XX_MULTICAST_MAGIC + 0x5)
|
||||
#define MXL862XX_MULTICAST_TABLEENTRYADD (MXL862XX_MULTICAST_MAGIC + 0x6)
|
||||
#define MXL862XX_MULTICAST_TABLEENTRYREAD (MXL862XX_MULTICAST_MAGIC + 0x7)
|
||||
#define MXL862XX_MULTICAST_TABLEENTRYREMOVE (MXL862XX_MULTICAST_MAGIC + 0x8)
|
||||
|
||||
#define MXL862XX_TRUNKING_CFGGET (MXL862XX_TRUNKING_MAGIC + 0x1)
|
||||
#define MXL862XX_TRUNKING_CFGSET (MXL862XX_TRUNKING_MAGIC + 0x2)
|
||||
#define MXL862XX_TRUNKING_PORTCFGGET (MXL862XX_TRUNKING_MAGIC + 0x3)
|
||||
#define MXL862XX_TRUNKING_PORTCFGSET (MXL862XX_TRUNKING_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_STP_PORTCFGGET (MXL862XX_STP_MAGIC + 0x1)
|
||||
#define MXL862XX_STP_PORTCFGSET (MXL862XX_STP_MAGIC + 0x2)
|
||||
#define MXL862XX_STP_BPDU_RULEGET (MXL862XX_STP_MAGIC + 0x3)
|
||||
#define MXL862XX_STP_BPDU_RULESET (MXL862XX_STP_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_PBB_TEMPLATEALLOC (MXL862XX_PBB_MAGIC + 0x1)
|
||||
#define MXL862XX_PBB_TEMPLATEFREE (MXL862XX_PBB_MAGIC + 0x2)
|
||||
#define MXL862XX_PBB_TEMPLATESET (MXL862XX_PBB_MAGIC + 0x3)
|
||||
#define MXL862XX_PBB_TEMPLATEGET (MXL862XX_PBB_MAGIC + 0x4)
|
||||
|
||||
#define MXL862XX_SS_SPTAG_GET (MXL862XX_SS_MAGIC + 0x01)
|
||||
#define MXL862XX_SS_SPTAG_SET (MXL862XX_SS_MAGIC + 0x02)
|
||||
|
||||
#define INT_GPHY_READ (GPY_GPY2XX_MAGIC + 0x01)
|
||||
#define INT_GPHY_WRITE (GPY_GPY2XX_MAGIC + 0x02)
|
||||
#define INT_GPHY_MOD (GPY_GPY2XX_MAGIC + 0x03)
|
||||
#define EXT_MDIO_READ (GPY_GPY2XX_MAGIC + 0x11)
|
||||
#define EXT_MDIO_WRITE (GPY_GPY2XX_MAGIC + 0x12)
|
||||
#define EXT_MDIO_MOD (GPY_GPY2XX_MAGIC + 0x13)
|
||||
|
||||
#define SYS_MISC_FW_UPDATE (SYS_MISC_MAGIC + 0x01)
|
||||
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x02)
|
||||
#define SYS_MISC_PVT_TEMP (SYS_MISC_MAGIC + 0x03)
|
||||
#define SYS_MISC_PVT_VOLTAGE (SYS_MISC_MAGIC + 0x04)
|
||||
|
||||
#define MMD_API_MAXIMUM_ID 0x7FFF
|
||||
|
||||
int mxl862xx_read(const mxl862xx_device_t *dev, uint32_t regaddr);
|
||||
int mxl862xx_write(const mxl862xx_device_t *dev, uint32_t regaddr, uint16_t data);
|
||||
|
||||
|
||||
#endif /* _MXL862XX_MMD_APIS_H_ */
|
||||
@@ -0,0 +1,509 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_rmon.h - dsa driver for Maxlinear mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MXL862XX_RMON_H_
|
||||
#define _MXL862XX_RMON_H_
|
||||
|
||||
#include "mxl862xx_types.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#pragma scalar_storage_order little-endian
|
||||
|
||||
/** \brief Port Type - GSWIP-3.1 only.
|
||||
Used by \ref MXL862XX_port_cfg_t. */
|
||||
typedef enum {
|
||||
/** Logical Port */
|
||||
MXL862XX_LOGICAL_PORT = 0,
|
||||
/** Physical Port
|
||||
Applicable only for GSWIP-3.1/3.2 */
|
||||
MXL862XX_PHYSICAL_PORT = 1,
|
||||
/** Connectivity Termination Port (CTP)
|
||||
Applicable only for GSWIP-3.1/3.2 */
|
||||
MXL862XX_CTP_PORT = 2,
|
||||
/** Bridge Port
|
||||
Applicable only for GSWIP-3.1/3.2 */
|
||||
MXL862XX_BRIDGE_PORT = 3
|
||||
} mxl862xx_port_type_t;
|
||||
|
||||
/**Defined as per RMON counter table structure
|
||||
Applicable only for GSWIP 3.1*/
|
||||
typedef enum {
|
||||
MXL862XX_RMON_CTP_PORT_RX = 0,
|
||||
MXL862XX_RMON_CTP_PORT_TX = 1,
|
||||
MXL862XX_RMON_BRIDGE_PORT_RX = 2,
|
||||
MXL862XX_RMON_BRIDGE_PORT_TX = 3,
|
||||
MXL862XX_RMON_CTP_PORT_PCE_BYPASS = 4,
|
||||
MXL862XX_RMON_TFLOW_RX = 5,
|
||||
MXL862XX_RMON_TFLOW_TX = 6,
|
||||
MXL862XX_RMON_QMAP = 0x0E,
|
||||
MXL862XX_RMON_METER = 0x19,
|
||||
MXL862XX_RMON_PMAC = 0x1C,
|
||||
} mxl862xx_rmon_port_type_t;
|
||||
|
||||
/** Defined as per RMON counter table structure
|
||||
* Applicable only for GSWIP 3.0
|
||||
*/
|
||||
typedef enum {
|
||||
MXL862XX_RMON_REDIRECTION = 0X18,
|
||||
MXL862XX_RMON_IF = 0x1A,
|
||||
MXL862XX_RMON_ROUTE = 0x1B,
|
||||
MXL862XX_RMON_PMACIG = 0x1C,
|
||||
} mxl862xx_rmon_port_t;
|
||||
|
||||
typedef enum {
|
||||
/** Parser microcode table */
|
||||
PMAC_BPMAP_INDEX = 0x00,
|
||||
PMAC_IGCFG_INDEX = 0x01,
|
||||
PMAC_EGCFG_INDEX = 0x02,
|
||||
} pm_tbl_cmds_t;
|
||||
/** \brief RMON Counters Type enumeration.
|
||||
Used by \ref MXL862XX_RMON_clear_t and \ref MXL862XX_RMON_mode_t. */
|
||||
typedef enum {
|
||||
/** All RMON Types Counters */
|
||||
MXL862XX_RMON_ALL_TYPE = 0,
|
||||
/** All PMAC RMON Counters */
|
||||
MXL862XX_RMON_PMAC_TYPE = 1,
|
||||
/** Port based RMON Counters */
|
||||
MXL862XX_RMON_PORT_TYPE = 2,
|
||||
/** Meter based RMON Counters */
|
||||
MXL862XX_RMON_METER_TYPE = 3,
|
||||
/** Interface based RMON Counters */
|
||||
MXL862XX_RMON_IF_TYPE = 4,
|
||||
/** Route based RMON Counters */
|
||||
MXL862XX_RMON_ROUTE_TYPE = 5,
|
||||
/** Redirected Traffic based RMON Counters */
|
||||
MXL862XX_RMON_REDIRECT_TYPE = 6,
|
||||
/** Bridge Port based RMON Counters */
|
||||
MXL862XX_RMON_BRIDGE_TYPE = 7,
|
||||
/** CTP Port based RMON Counters */
|
||||
MXL862XX_RMON_CTP_TYPE = 8,
|
||||
} mxl862xx_rmon_type_t;
|
||||
|
||||
/** \brief RMON Counters Mode Enumeration.
|
||||
This enumeration defines Counters mode - Packets based or Bytes based counting.
|
||||
Metering and Routing Sessions RMON counting support either Byte based or packets based only. */
|
||||
typedef enum {
|
||||
/** Packet based RMON Counters */
|
||||
MXL862XX_RMON_COUNT_PKTS = 0,
|
||||
/** Bytes based RMON Counters */
|
||||
MXL862XX_RMON_COUNT_BYTES = 1,
|
||||
/** number of dropped frames, supported only for interface cunters */
|
||||
MXL862XX_RMON_DROP_COUNT = 2,
|
||||
} mxl862xx_rmon_count_mode_t;
|
||||
|
||||
/** \brief Used for getting metering RMON counters.
|
||||
Used by \ref MXL862XX_RMON_METER_GET */
|
||||
typedef enum {
|
||||
/* Resereved */
|
||||
MXL862XX_RMON_METER_COLOR_RES = 0,
|
||||
/* Green color */
|
||||
MXL862XX_RMON_METER_COLOR_GREEN = 1,
|
||||
/* Yellow color */
|
||||
MXL862XX_RMON_METER_COLOR_YELLOW = 2,
|
||||
/* Red color */
|
||||
MXL862XX_RMON_METER_COLOR_RED = 3,
|
||||
} mxl862xx_rmon_meter_color_t;
|
||||
|
||||
/* TFLOW counter type */
|
||||
typedef enum {
|
||||
/* Set all Rx/Tx/PCE-Bp-Tx registers to same value */
|
||||
MXL862XX_TFLOW_COUNTER_ALL = 0, //Default for 'set' function.
|
||||
/* SEt PCE Rx register config only */
|
||||
MXL862XX_TFLOW_COUNTER_PCE_Rx = 1, //Default for 'get' function.
|
||||
/* SEt PCE Tx register config only */
|
||||
MXL862XX_TFLOW_COUNTER_PCE_Tx = 2,
|
||||
/* SEt PCE-Bypass Tx register config only */
|
||||
MXL862XX_TFLOW_COUNTER_PCE_BP_Tx = 3,
|
||||
} mxl862xx_tflow_count_conf_type_t;
|
||||
|
||||
/* TFLOW counter mode type */
|
||||
typedef enum {
|
||||
/* Global mode */
|
||||
MXL862XX_TFLOW_CMODE_GLOBAL = 0,
|
||||
/* Logical mode */
|
||||
MXL862XX_TFLOW_CMODE_LOGICAL = 1,
|
||||
/* CTP port mode */
|
||||
MXL862XX_TFLOW_CMODE_CTP = 2,
|
||||
/* Bridge port mode */
|
||||
MXL862XX_TFLOW_CMODE_BRIDGE = 3,
|
||||
} mxl862xx_tflow_cmode_type_t;
|
||||
|
||||
/* TFLOW CTP counter LSB bits */
|
||||
typedef enum {
|
||||
/* Num of valid bits */
|
||||
MXL862XX_TCM_CTP_VAL_BITS_0 = 0,
|
||||
MXL862XX_TCM_CTP_VAL_BITS_1 = 1,
|
||||
MXL862XX_TCM_CTP_VAL_BITS_2 = 2,
|
||||
MXL862XX_TCM_CTP_VAL_BITS_3 = 3,
|
||||
MXL862XX_TCM_CTP_VAL_BITS_4 = 4,
|
||||
MXL862XX_TCM_CTP_VAL_BITS_5 = 5,
|
||||
MXL862XX_TCM_CTP_VAL_BITS_6 = 6,
|
||||
} mxl862xx_tflow_ctp_val_bits_t;
|
||||
|
||||
/* TFLOW bridge port counter LSB bits */
|
||||
typedef enum {
|
||||
/* Num of valid bits */
|
||||
MXL862XX_TCM_BRP_VAL_BITS_2 = 2,
|
||||
MXL862XX_TCM_BRP_VAL_BITS_3 = 3,
|
||||
MXL862XX_TCM_BRP_VAL_BITS_4 = 4,
|
||||
MXL862XX_TCM_BRP_VAL_BITS_5 = 5,
|
||||
MXL862XX_TCM_BRP_VAL_BITS_6 = 6,
|
||||
} mxl862xx_tflow_brp_val_bits_t;
|
||||
|
||||
/**
|
||||
\brief RMON Counters for individual Port.
|
||||
This structure contains the RMON counters of an Ethernet Switch Port.
|
||||
Used by \ref MXL862XX_RMON_PORT_GET. */
|
||||
typedef struct {
|
||||
/** Port Type. This gives information which type of port to get RMON.
|
||||
port_id should be based on this field.
|
||||
This is new in GSWIP-3.1. For GSWIP-2.1/2.2/3.0, this field is always
|
||||
ZERO (MXL862XX_LOGICAL_PORT). */
|
||||
mxl862xx_port_type_t port_type;
|
||||
/** Ethernet Port number (zero-based counting). The valid range is hardware
|
||||
dependent. An error code is delivered if the selected port is not
|
||||
available. This parameter specifies for which MAC port the RMON
|
||||
counter is read. It has to be set by the application before
|
||||
calling \ref MXL862XX_RMON_PORT_GET. */
|
||||
u16 port_id;
|
||||
/** Sub interface ID group. The valid range is hardware/protocol dependent.
|
||||
|
||||
\remarks
|
||||
This field is valid when \ref MXL862XX_RMON_Port_cnt_t::e_port_type is
|
||||
\ref MXL862XX_port_type_t::MXL862XX_CTP_PORT.
|
||||
Sub interface ID group is defined for each of \ref MXL862XX_Logical_port_mode_t.
|
||||
For both \ref MXL862XX_LOGICAL_PORT_8BIT_WLAN and
|
||||
\ref MXL862XX_LOGICAL_PORT_9BIT_WLAN, this field is VAP.
|
||||
For \ref MXL862XX_LOGICAL_PORT_GPON, this field is GEM index.
|
||||
For \ref MXL862XX_LOGICAL_PORT_EPON, this field is stream index.
|
||||
For \ref MXL862XX_LOGICAL_PORT_GINT, this field is LLID.
|
||||
For others, this field is 0. */
|
||||
u16 sub_if_id_group;
|
||||
/** Separate set of CTP Tx counters when PCE is bypassed. GSWIP-3.1 only.*/
|
||||
bool pce_bypass;
|
||||
/*Applicable only for GSWIP 3.1*/
|
||||
/** Discarded at Extended VLAN Operation Packet Count. GSWIP-3.1 only. */
|
||||
u32 rx_extended_vlan_discard_pkts;
|
||||
/** Discarded MTU Exceeded Packet Count. GSWIP-3.1 only. */
|
||||
u32 mtu_exceed_discard_pkts;
|
||||
/** Tx Undersize (<64) Packet Count. GSWIP-3.1 only. */
|
||||
u32 tx_under_size_good_pkts;
|
||||
/** Tx Oversize (>1518) Packet Count. GSWIP-3.1 only. */
|
||||
u32 tx_oversize_good_pkts;
|
||||
/** Receive Packet Count (only packets that are accepted and not discarded). */
|
||||
u32 rx_good_pkts;
|
||||
/** Receive Unicast Packet Count. */
|
||||
u32 rx_unicast_pkts;
|
||||
/** Receive Broadcast Packet Count. */
|
||||
u32 rx_broadcast_pkts;
|
||||
/** Receive Multicast Packet Count. */
|
||||
u32 rx_multicast_pkts;
|
||||
/** Receive FCS Error Packet Count. */
|
||||
u32 rx_fCSError_pkts;
|
||||
/** Receive Undersize Good Packet Count. */
|
||||
u32 rx_under_size_good_pkts;
|
||||
/** Receive Oversize Good Packet Count. */
|
||||
u32 rx_oversize_good_pkts;
|
||||
/** Receive Undersize Error Packet Count. */
|
||||
u32 rx_under_size_error_pkts;
|
||||
/** Receive Good Pause Packet Count. */
|
||||
u32 rx_good_pause_pkts;
|
||||
/** Receive Oversize Error Packet Count. */
|
||||
u32 rx_oversize_error_pkts;
|
||||
/** Receive Align Error Packet Count. */
|
||||
u32 rx_align_error_pkts;
|
||||
/** Filtered Packet Count. */
|
||||
u32 rx_filtered_pkts;
|
||||
/** Receive Size 64 Bytes Packet Count. */
|
||||
u32 rx64Byte_pkts;
|
||||
/** Receive Size 65-127 Bytes Packet Count. */
|
||||
u32 rx127Byte_pkts;
|
||||
/** Receive Size 128-255 Bytes Packet Count. */
|
||||
u32 rx255Byte_pkts;
|
||||
/** Receive Size 256-511 Bytes Packet Count. */
|
||||
u32 rx511Byte_pkts;
|
||||
/** Receive Size 512-1023 Bytes Packet Count. */
|
||||
u32 rx1023Byte_pkts;
|
||||
/** Receive Size 1024-1522 Bytes (or more, if configured) Packet Count. */
|
||||
u32 rx_max_byte_pkts;
|
||||
/** Overall Transmit Good Packets Count. */
|
||||
u32 tx_good_pkts;
|
||||
/** Transmit Unicast Packet Count. */
|
||||
u32 tx_unicast_pkts;
|
||||
/** Transmit Broadcast Packet Count. */
|
||||
u32 tx_broadcast_pkts;
|
||||
/** Transmit Multicast Packet Count. */
|
||||
u32 tx_multicast_pkts;
|
||||
/** Transmit Single Collision Count. */
|
||||
u32 tx_single_coll_count;
|
||||
/** Transmit Multiple Collision Count. */
|
||||
u32 tx_mult_coll_count;
|
||||
/** Transmit Late Collision Count. */
|
||||
u32 tx_late_coll_count;
|
||||
/** Transmit Excessive Collision Count. */
|
||||
u32 tx_excess_coll_count;
|
||||
/** Transmit Collision Count. */
|
||||
u32 tx_coll_count;
|
||||
/** Transmit Pause Packet Count. */
|
||||
u32 tx_pause_count;
|
||||
/** Transmit Size 64 Bytes Packet Count. */
|
||||
u32 tx64Byte_pkts;
|
||||
/** Transmit Size 65-127 Bytes Packet Count. */
|
||||
u32 tx127Byte_pkts;
|
||||
/** Transmit Size 128-255 Bytes Packet Count. */
|
||||
u32 tx255Byte_pkts;
|
||||
/** Transmit Size 256-511 Bytes Packet Count. */
|
||||
u32 tx511Byte_pkts;
|
||||
/** Transmit Size 512-1023 Bytes Packet Count. */
|
||||
u32 tx1023Byte_pkts;
|
||||
/** Transmit Size 1024-1522 Bytes (or more, if configured) Packet Count. */
|
||||
u32 tx_max_byte_pkts;
|
||||
/** Transmit Drop Packet Count. */
|
||||
u32 tx_dropped_pkts;
|
||||
/** Transmit Dropped Packet Count, based on Congestion Management. */
|
||||
u32 tx_acm_dropped_pkts;
|
||||
/** Receive Dropped Packet Count. */
|
||||
u32 rx_dropped_pkts;
|
||||
/** Receive Good Byte Count (64 bit). */
|
||||
u64 rx_good_bytes;
|
||||
/** Receive Bad Byte Count (64 bit). */
|
||||
u64 rx_bad_bytes;
|
||||
/** Transmit Good Byte Count (64 bit). */
|
||||
u64 tx_good_bytes;
|
||||
} mxl862xx_rmon_port_cnt_t;
|
||||
|
||||
/** \brief RMON Counters Mode for different Elements.
|
||||
This structure takes RMON Counter Element Name and mode config */
|
||||
typedef struct {
|
||||
/** RMON Counters Type */
|
||||
mxl862xx_rmon_type_t rmon_type;
|
||||
/** RMON Counters Mode */
|
||||
mxl862xx_rmon_count_mode_t count_mode;
|
||||
} mxl862xx_rmon_mode_t;
|
||||
|
||||
/**
|
||||
\brief RMON Counters for Meter - Type (GSWIP-3.0 only).
|
||||
This structure contains the RMON counters of one Meter Instance.
|
||||
Used by \ref MXL862XX_RMON_METER_GET. */
|
||||
typedef struct {
|
||||
/** Meter Instance number (zero-based counting). The valid range is hardware
|
||||
dependent. An error code is delivered if the selected meter is not
|
||||
available. This parameter specifies for which Meter Id the RMON-1
|
||||
counter is read. It has to be set by the application before
|
||||
calling \ref MXL862XX_RMON_METER_GET. */
|
||||
u8 meter_id;
|
||||
/** Metered Green colored packets or bytes (depending upon mode) count. */
|
||||
u32 green_count;
|
||||
/** Metered Yellow colored packets or bytes (depending upon mode) count. */
|
||||
u32 yellow_count;
|
||||
/** Metered Red colored packets or bytes (depending upon mode) count. */
|
||||
u32 red_count;
|
||||
/** Metered Reserved (Future Use) packets or bytes (depending upon mode) count. */
|
||||
u32 res_count;
|
||||
} mxl862xx_rmon_meter_cnt_t;
|
||||
|
||||
/** \brief RMON Counters Data Structure for clearance of values.
|
||||
Used by \ref MXL862XX_RMON_CLEAR. */
|
||||
typedef struct {
|
||||
/** RMON Counters Type */
|
||||
mxl862xx_rmon_type_t rmon_type;
|
||||
/** RMON Counters Identifier - Meter, Port, If, Route, etc. */
|
||||
u8 rmon_id;
|
||||
} mxl862xx_rmon_clear_t;
|
||||
|
||||
/**
|
||||
\brief Hardware platform TFLOW counter mode.
|
||||
Supported modes include, Global (default), Logical, CTP, Bridge port mode.
|
||||
The number of counters that can be assigned varies based these mode type.
|
||||
Used by \ref MXL862XX_TFLOW_COUNT_MODE_SET and MXL862XX_TFLOW_COUNT_MODE_GET. */
|
||||
typedef struct {
|
||||
//Counter type. PCE Rx/Tx/Bp-Tx.
|
||||
mxl862xx_tflow_count_conf_type_t count_type;
|
||||
//Counter mode. Global/Logical/CTP/br_p.
|
||||
mxl862xx_tflow_cmode_type_t count_mode;
|
||||
//The below params are valid only for CTP/br_p types.
|
||||
//A group of ports matching MS (9-n) bits. n is n_ctp_lsb or n_brp_lsb.
|
||||
u16 port_msb;
|
||||
//Number of valid bits in CTP port counter mode.
|
||||
mxl862xx_tflow_ctp_val_bits_t ctp_lsb;
|
||||
//Number of valid bits in bridge port counter mode.
|
||||
mxl862xx_tflow_brp_val_bits_t brp_lsb;
|
||||
} mxl862xx_tflow_cmode_conf_t;
|
||||
|
||||
/**
|
||||
\brief Hardware platform extended RMON Counters. GSWIP-3.1 only.
|
||||
This structure contains additional RMON counters. These counters can be
|
||||
used by the packet classification engine and can be freely assigned to
|
||||
dedicated packet rules and flows.
|
||||
Used by \ref MXL862XX_RMON_FLOW_GET. */
|
||||
typedef struct {
|
||||
/** If TRUE, use \ref MXL862XX_RMON_flow_get_t::n_index to access the Flow Counter,
|
||||
otherwise, use \ref MXL862XX_TFLOW_COUNT_MODE_GET to determine mode and use
|
||||
\ref MXL862XX_RMON_flow_get_t::port_id and \ref MXL862XX_RMON_flow_get_t::flow_id
|
||||
to calculate index of the Flow Counter. */
|
||||
bool use_index;
|
||||
/** Absolute index of Flow Counter. */
|
||||
u16 index;
|
||||
/** Port ID. This could be Logical Port, CTP or Bridge Port. It depends
|
||||
on the mode set by \ref MXL862XX_TFLOW_COUNT_MODE_SET. */
|
||||
u16 port_id;
|
||||
/** \ref MXL862XX_PCE_action_t::flow_id. The range depends on the mode set
|
||||
by \ref MXL862XX_TFLOW_COUNT_MODE_SET. */
|
||||
u16 flow_id;
|
||||
|
||||
/** Rx Packet Counter */
|
||||
u32 rx_pkts;
|
||||
/** Tx Packet Counter (non-PCE-Bypass) */
|
||||
u32 tx_pkts;
|
||||
/** Tx Packet Counter (PCE-Bypass) */
|
||||
u32 tx_pce_bypass_pkts;
|
||||
} mxl862xx_rmon_flow_get_t;
|
||||
|
||||
/** \brief For debugging Purpose only.
|
||||
Used for GSWIP 3.1. */
|
||||
|
||||
typedef struct {
|
||||
/** Ethernet Port number (zero-based counting). The valid range is hardware
|
||||
dependent. An error code is delivered if the selected port is not
|
||||
available. This parameter specifies for which MAC port the RMON
|
||||
counter is read. It has to be set by the application before
|
||||
calling \ref MXL862XX_RMON_PORT_GET. */
|
||||
u16 port_id;
|
||||
/**Table address selection based on port type
|
||||
Applicable only for GSWIP 3.1
|
||||
\ref MXL862XX_RMON_port_type_t**/
|
||||
mxl862xx_rmon_port_type_t port_type;
|
||||
/*Applicable only for GSWIP 3.1*/
|
||||
u32 rx_extended_vlan_discard_pkts;
|
||||
/*Applicable only for GSWIP 3.1*/
|
||||
u32 mtu_exceed_discard_pkts;
|
||||
/*Applicable only for GSWIP 3.1*/
|
||||
u32 tx_under_size_good_pkts;
|
||||
/*Applicable only for GSWIP 3.1*/
|
||||
u32 tx_oversize_good_pkts;
|
||||
/** Receive Packet Count (only packets that are accepted and not discarded). */
|
||||
u32 rx_good_pkts;
|
||||
/** Receive Unicast Packet Count. */
|
||||
u32 rx_unicast_pkts;
|
||||
/** Receive Broadcast Packet Count. */
|
||||
u32 rx_broadcast_pkts;
|
||||
/** Receive Multicast Packet Count. */
|
||||
u32 rx_multicast_pkts;
|
||||
/** Receive FCS Error Packet Count. */
|
||||
u32 rx_fcserror_pkts;
|
||||
/** Receive Undersize Good Packet Count. */
|
||||
u32 rx_under_size_good_pkts;
|
||||
/** Receive Oversize Good Packet Count. */
|
||||
u32 rx_oversize_good_pkts;
|
||||
/** Receive Undersize Error Packet Count. */
|
||||
u32 rx_under_size_error_pkts;
|
||||
/** Receive Good Pause Packet Count. */
|
||||
u32 rx_good_pause_pkts;
|
||||
/** Receive Oversize Error Packet Count. */
|
||||
u32 rx_oversize_error_pkts;
|
||||
/** Receive Align Error Packet Count. */
|
||||
u32 rx_align_error_pkts;
|
||||
/** Filtered Packet Count. */
|
||||
u32 rx_filtered_pkts;
|
||||
/** Receive Size 64 Bytes Packet Count. */
|
||||
u32 rx64byte_pkts;
|
||||
/** Receive Size 65-127 Bytes Packet Count. */
|
||||
u32 rx127byte_pkts;
|
||||
/** Receive Size 128-255 Bytes Packet Count. */
|
||||
u32 rx255byte_pkts;
|
||||
/** Receive Size 256-511 Bytes Packet Count. */
|
||||
u32 rx511byte_pkts;
|
||||
/** Receive Size 512-1023 Bytes Packet Count. */
|
||||
u32 rx1023byte_pkts;
|
||||
/** Receive Size 1024-1522 Bytes (or more, if configured) Packet Count. */
|
||||
u32 rx_max_byte_pkts;
|
||||
/** Overall Transmit Good Packets Count. */
|
||||
u32 tx_good_pkts;
|
||||
/** Transmit Unicast Packet Count. */
|
||||
u32 tx_unicast_pkts;
|
||||
/** Transmit Broadcast Packet Count. */
|
||||
u32 tx_broadcast_pkts;
|
||||
/** Transmit Multicast Packet Count. */
|
||||
u32 tx_multicast_pkts;
|
||||
/** Transmit Single Collision Count. */
|
||||
u32 tx_single_coll_count;
|
||||
/** Transmit Multiple Collision Count. */
|
||||
u32 tx_mult_coll_count;
|
||||
/** Transmit Late Collision Count. */
|
||||
u32 tx_late_coll_count;
|
||||
/** Transmit Excessive Collision Count. */
|
||||
u32 tx_excess_coll_count;
|
||||
/** Transmit Collision Count. */
|
||||
u32 tx_coll_count;
|
||||
/** Transmit Pause Packet Count. */
|
||||
u32 tx_pause_count;
|
||||
/** Transmit Size 64 Bytes Packet Count. */
|
||||
u32 tx64byte_pkts;
|
||||
/** Transmit Size 65-127 Bytes Packet Count. */
|
||||
u32 tx127byte_pkts;
|
||||
/** Transmit Size 128-255 Bytes Packet Count. */
|
||||
u32 tx255byte_pkts;
|
||||
/** Transmit Size 256-511 Bytes Packet Count. */
|
||||
u32 tx511byte_pkts;
|
||||
/** Transmit Size 512-1023 Bytes Packet Count. */
|
||||
u32 tx1023byte_pkts;
|
||||
/** Transmit Size 1024-1522 Bytes (or more, if configured) Packet Count. */
|
||||
u32 tx_max_byte_pkts;
|
||||
/** Transmit Drop Packet Count. */
|
||||
u32 tx_dropped_pkts;
|
||||
/** Transmit Dropped Packet Count, based on Congestion Management. */
|
||||
u32 tx_acm_dropped_pkts;
|
||||
/** Receive Dropped Packet Count. */
|
||||
u32 rx_dropped_pkts;
|
||||
/** Receive Good Byte Count (64 bit). */
|
||||
u64 rx_good_bytes;
|
||||
/** Receive Bad Byte Count (64 bit). */
|
||||
u64 rx_bad_bytes;
|
||||
/** Transmit Good Byte Count (64 bit). */
|
||||
u64 tx_good_bytes;
|
||||
/**For GSWIP V32 only **/
|
||||
/** Receive Unicast Packet Count for Yellow & Red packet. */
|
||||
u32 rx_unicast_pkts_yellow_red;
|
||||
/** Receive Broadcast Packet Count for Yellow & Red packet. */
|
||||
u32 rx_broadcast_pkts_yellow_red;
|
||||
/** Receive Multicast Packet Count for Yellow & Red packet. */
|
||||
u32 rx_multicast_pkts_yellow_red;
|
||||
/** Receive Good Byte Count (64 bit) for Yellow & Red packet. */
|
||||
u64 rx_good_bytes_yellow_red;
|
||||
/** Receive Packet Count for Yellow & Red packet. */
|
||||
u32 rx_good_pkts_yellow_red;
|
||||
/** Transmit Unicast Packet Count for Yellow & Red packet. */
|
||||
u32 tx_unicast_pkts_yellow_red;
|
||||
/** Transmit Broadcast Packet Count for Yellow & Red packet. */
|
||||
u32 tx_broadcast_pkts_yellow_red;
|
||||
/** Transmit Multicast Packet Count for Yellow & Red packet. */
|
||||
u32 tx_multicast_pkts_yellow_red;
|
||||
/** Transmit Good Byte Count (64 bit) for Yellow & Red packet. */
|
||||
u64 tx_good_bytes_yellow_red;
|
||||
/** Transmit Packet Count for Yellow & Red packet. */
|
||||
u32 tx_good_pkts_yellow_red;
|
||||
} mxl862xx_debug_rmon_port_cnt_t;
|
||||
|
||||
#pragma scalar_storage_order default
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif /* _MXL862XX_RMON_H_ */
|
||||
@@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/net/dsa/host_api/mxl862xx_types.h - DSA Driver for MaxLinear Mxl862xx switch chips family
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MXL862XX_TYPES_H_
|
||||
#define _MXL862XX_TYPES_H_
|
||||
|
||||
#include <linux/phy.h>
|
||||
|
||||
/** \brief This is the unsigned 64-bit datatype. */
|
||||
typedef uint64_t u64;
|
||||
/** \brief This is the unsigned 32-bit datatype. */
|
||||
typedef uint32_t u32;
|
||||
/** \brief This is the unsigned 16-bit datatype. */
|
||||
typedef uint16_t u16;
|
||||
/** \brief This is the unsigned 8-bit datatype. */
|
||||
typedef uint8_t u8;
|
||||
/** \brief This is the signed 64-bit datatype. */
|
||||
typedef int64_t i64;
|
||||
/** \brief This is the signed 32-bit datatype. */
|
||||
typedef int32_t i32;
|
||||
/** \brief This is the signed 16-bit datatype. */
|
||||
typedef int16_t i16;
|
||||
/** \brief This is the signed 8-bit datatype. */
|
||||
typedef int8_t i8;
|
||||
/** \brief This is the signed 8-bit datatype. */
|
||||
typedef int32_t s32;
|
||||
/** \brief This is the signed 8-bit datatype. */
|
||||
typedef int8_t s8;
|
||||
|
||||
|
||||
/** \brief This is a union to describe the IPv4 and IPv6 Address in numeric representation. Used by multiple Structures and APIs. The member selection would be based upon \ref GSW_IP_Select_t */
|
||||
typedef union {
|
||||
/** Describe the IPv4 address.
|
||||
Only used if the IPv4 address should be read or configured.
|
||||
Cannot be used together with the IPv6 address fields. */
|
||||
u32 nIPv4;
|
||||
/** Describe the IPv6 address.
|
||||
Only used if the IPv6 address should be read or configured.
|
||||
Cannot be used together with the IPv4 address fields. */
|
||||
u16 nIPv6[8];
|
||||
} mxl862xx_ip_t;
|
||||
|
||||
/** \brief Selection to use IPv4 or IPv6.
|
||||
Used along with \ref GSW_IP_t to denote which union member to be accessed.
|
||||
*/
|
||||
typedef enum {
|
||||
/** IPv4 Type */
|
||||
MXL862XX_IP_SELECT_IPV4 = 0,
|
||||
/** IPv6 Type */
|
||||
MXL862XX_IP_SELECT_IPV6 = 1
|
||||
} mxl862xx_ip_select_t;
|
||||
|
||||
typedef struct {
|
||||
int sw_addr;
|
||||
struct mii_bus *bus;
|
||||
} mxl862xx_device_t;
|
||||
#endif /* _MXL862XX_TYPES_H_ */
|
||||
4587
feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/dsa/mxl862xx/mxl862xx.c
Executable file
4587
feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/dsa/mxl862xx/mxl862xx.c
Executable file
File diff suppressed because it is too large
Load Diff
@@ -4,5 +4,5 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
|
||||
mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o
|
||||
mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o mtk_eth_ptp.o
|
||||
obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtk_hnat/
|
||||
|
||||
1401
feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
Executable file → Normal file
1401
feeds/mediatek-sdk/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,24 @@
|
||||
#define MTK_FE_GDM1_FSM 0x228
|
||||
#define MTK_FE_GDM2_FSM 0x22C
|
||||
#define MTK_FE_GDM3_FSM 0x23C
|
||||
#define MTK_FE_CDM1_DBG1 0x200
|
||||
#define MTK_FE_CDM1_DBG2 0x204
|
||||
#define MTK_FE_CDM2_DBG1 0x208
|
||||
#define MTK_FE_CDM2_DBG2 0x20C
|
||||
#define MTK_FE_CDM3_DBG1 0x230
|
||||
#define MTK_FE_CDM3_DBG2 0x234
|
||||
#define MTK_FE_CDM4_DBG1 0x290
|
||||
#define MTK_FE_CDM4_DBG2 0x294
|
||||
#define MTK_FE_CDM5_DBG1 0x310
|
||||
#define MTK_FE_CDM5_DBG2 0x314
|
||||
#define MTK_FE_CDM6_DBG1 0x320
|
||||
#define MTK_FE_CDM6_DBG2 0x324
|
||||
#define MTK_FE_CDM7_DBG1 0x330
|
||||
#define MTK_FE_CDM7_DBG2 0x334
|
||||
#define MTK_FE_GDM1_DBG1 0x210
|
||||
#define MTK_FE_GDM1_DBG2 0x214
|
||||
#define MTK_FE_GDM2_DBG1 0x218
|
||||
#define MTK_FE_GDM2_DBG2 0x21C
|
||||
#define MTK_FE_PSE_FREE 0x240
|
||||
#define MTK_FE_DROP_FQ 0x244
|
||||
#define MTK_FE_DROP_FC 0x248
|
||||
@@ -42,6 +60,24 @@
|
||||
#define MTK_FE_GDM_FSM(x) (((x) == 2) ? MTK_FE_GDM3_FSM : \
|
||||
((x) == 1) ? MTK_FE_GDM2_FSM : MTK_FE_GDM1_FSM)
|
||||
|
||||
#define MTK_FE_CDM_FSM(x) (((x) == 0) ? MTK_FE_CDM3_FSM : \
|
||||
((x) == 1) ? MTK_FE_CDM4_FSM : MTK_FE_CDM5_FSM)
|
||||
|
||||
#define MTK_FE_WDMA_OQ(x) \
|
||||
(((x) == 0) ? (mtk_r32(eth, MTK_PSE_OQ_STA(4)) & 0x00000FFF) : \
|
||||
(((x) == 1) ? (mtk_r32(eth, MTK_PSE_OQ_STA(4)) & 0x0FFF0000) : \
|
||||
(mtk_r32(eth, MTK_PSE_OQ_STA(6)) & 0x0FFF0000)))
|
||||
|
||||
#define MTK_FE_GDM_IQ(x) \
|
||||
(((x) == 2) ? mtk_r32(eth, MTK_PSE_IQ_STA(7)) & 0x0fff0000 : \
|
||||
((x) == 1) ? mtk_r32(eth, MTK_PSE_IQ_STA(1)) & 0x00000fff : \
|
||||
mtk_r32(eth, MTK_PSE_IQ_STA(0)) & 0x0fff0000)
|
||||
|
||||
#define MTK_FE_GDM_OQ(x) \
|
||||
(((x) == 2) ? mtk_r32(eth, MTK_PSE_OQ_STA(7)) & 0x0fff0000 : \
|
||||
((x) == 1) ? mtk_r32(eth, MTK_PSE_OQ_STA(1)) & 0x00000fff : \
|
||||
mtk_r32(eth, MTK_PSE_OQ_STA(0)) & 0x0fff0000)
|
||||
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
#define MTK_PSE_IQ_STA(x) (0x180 + (x) * 0x4)
|
||||
#define MTK_PSE_OQ_STA(x) (0x1A0 + (x) * 0x4)
|
||||
@@ -59,6 +95,7 @@
|
||||
#define REG_ESW_MAX 0xFC
|
||||
|
||||
#define PROCREG_ESW_CNT "esw_cnt"
|
||||
#define PROCREG_MAC_CNT "mac_cnt"
|
||||
#define PROCREG_XFI_CNT "xfi_cnt"
|
||||
#define PROCREG_TXRING "tx_ring"
|
||||
#define PROCREG_HWTXRING "hwtx_ring"
|
||||
@@ -70,6 +107,40 @@
|
||||
#define PROCREG_HW_LRO_AUTO_TLB "hw_lro_auto_tlb"
|
||||
#define PROCREG_RESET_EVENT "reset_event"
|
||||
|
||||
#define MAX_SWITCH_PORT_NUM (6)
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
#define MAX_PPPQ_QUEUE_NUM (2 * MAX_SWITCH_PORT_NUM + 2)
|
||||
#else
|
||||
#define MAX_PPPQ_QUEUE_NUM (2 * MAX_SWITCH_PORT_NUM)
|
||||
#endif
|
||||
|
||||
/* GMAC MIB Register */
|
||||
#define MTK_MAC_MIB_BASE(x) (0x10400 + (x * 0x60))
|
||||
#define MTK_MAC_RX_UC_PKT_CNT_L 0x00
|
||||
#define MTK_MAC_RX_UC_PKT_CNT_H 0x04
|
||||
#define MTK_MAC_RX_UC_BYTE_CNT_L 0x08
|
||||
#define MTK_MAC_RX_UC_BYTE_CNT_H 0x0C
|
||||
#define MTK_MAC_RX_MC_PKT_CNT_L 0x10
|
||||
#define MTK_MAC_RX_MC_PKT_CNT_H 0x14
|
||||
#define MTK_MAC_RX_MC_BYTE_CNT_L 0x18
|
||||
#define MTK_MAC_RX_MC_BYTE_CNT_H 0x1C
|
||||
#define MTK_MAC_RX_BC_PKT_CNT_L 0x20
|
||||
#define MTK_MAC_RX_BC_PKT_CNT_H 0x24
|
||||
#define MTK_MAC_RX_BC_BYTE_CNT_L 0x28
|
||||
#define MTK_MAC_RX_BC_BYTE_CNT_H 0x2C
|
||||
#define MTK_MAC_TX_UC_PKT_CNT_L 0x30
|
||||
#define MTK_MAC_TX_UC_PKT_CNT_H 0x34
|
||||
#define MTK_MAC_TX_UC_BYTE_CNT_L 0x38
|
||||
#define MTK_MAC_TX_UC_BYTE_CNT_H 0x3C
|
||||
#define MTK_MAC_TX_MC_PKT_CNT_L 0x40
|
||||
#define MTK_MAC_TX_MC_PKT_CNT_H 0x44
|
||||
#define MTK_MAC_TX_MC_BYTE_CNT_L 0x48
|
||||
#define MTK_MAC_TX_MC_BYTE_CNT_H 0x4C
|
||||
#define MTK_MAC_TX_BC_PKT_CNT_L 0x50
|
||||
#define MTK_MAC_TX_BC_PKT_CNT_H 0x54
|
||||
#define MTK_MAC_TX_BC_BYTE_CNT_L 0x58
|
||||
#define MTK_MAC_TX_BC_BYTE_CNT_H 0x5C
|
||||
|
||||
/* XFI MAC MIB Register */
|
||||
#define MTK_XFI_MIB_BASE(x) (MTK_XMAC_MCR(x))
|
||||
#define MTK_XFI_CNT_CTRL 0x100
|
||||
@@ -100,6 +171,18 @@
|
||||
#define MTK_XFI_RX_MC_DROP_CNT 0x208
|
||||
#define MTK_XFI_RX_ALL_DROP_CNT 0x20C
|
||||
|
||||
#define MTK_MT753X_PMCR_P(x) (0x3000 + (x) * 100)
|
||||
|
||||
#define PRINT_FORMATTED_MAC_MIB64(seq, reg) \
|
||||
{ \
|
||||
seq_printf(seq, "| MAC%d_%s : %010llu |\n", \
|
||||
gdm_id, #reg, \
|
||||
mtk_r32(eth, MTK_MAC_MIB_BASE(gdm_id) + \
|
||||
MTK_MAC_##reg##_L) + \
|
||||
((u64)mtk_r32(eth, MTK_MAC_MIB_BASE(gdm_id) +\
|
||||
MTK_MAC_##reg##_H) << 32)); \
|
||||
}
|
||||
|
||||
#define PRINT_FORMATTED_XFI_MIB(seq, reg, mask) \
|
||||
{ \
|
||||
seq_printf(seq, "| XFI%d_%s : %010lu |\n", \
|
||||
@@ -126,55 +209,176 @@
|
||||
#define MTK_HW_LRO_TIMESTAMP_FLUSH (4)
|
||||
#define MTK_HW_LRO_NON_RULE_FLUSH (5)
|
||||
|
||||
#define SET_PDMA_RXRING_MAX_AGG_CNT(eth, x, y) \
|
||||
{ \
|
||||
u32 reg_val1 = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
u32 reg_val2 = mtk_r32(eth, MTK_LRO_CTRL_DW3_CFG(x)); \
|
||||
reg_val1 &= ~MTK_LRO_RING_AGG_CNT_L_MASK; \
|
||||
reg_val2 &= ~MTK_LRO_RING_AGG_CNT_H_MASK; \
|
||||
reg_val1 |= ((y) & 0x3f) << MTK_LRO_RING_AGG_CNT_L_OFFSET; \
|
||||
reg_val2 |= (((y) >> 6) & 0x03) << \
|
||||
MTK_LRO_RING_AGG_CNT_H_OFFSET; \
|
||||
mtk_w32(eth, reg_val1, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
mtk_w32(eth, reg_val2, MTK_LRO_CTRL_DW3_CFG(x)); \
|
||||
#define SET_PDMA_RXRING_MAX_AGG_CNT(eth, x, y) \
|
||||
{ \
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map; \
|
||||
u32 reg_val1, reg_val2; \
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_GLO_MEM_ACCESS)) { \
|
||||
reg_val1 = mtk_r32(eth, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
reg_val2 = mtk_r32(eth, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0xc + (x * 0x40)); \
|
||||
reg_val1 &= ~MTK_LRO_RING_AGG_CNT_L_MASK; \
|
||||
reg_val2 &= ~MTK_LRO_RING_AGG_CNT_H_MASK; \
|
||||
reg_val1 |= ((y) & 0x3f) << MTK_LRO_RING_AGG_CNT_L_OFFSET; \
|
||||
reg_val2 |= (((y) >> 6) & 0x03) << \
|
||||
MTK_LRO_RING_AGG_CNT_H_OFFSET; \
|
||||
mtk_w32(eth, reg_val1, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
mtk_w32(eth, reg_val2, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0xc + (x * 0x40)); \
|
||||
} else { \
|
||||
reg_val1 = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_READ); \
|
||||
mtk_w32(eth, reg_val1, MTK_GLO_MEM_CTRL); \
|
||||
reg_val1 = mtk_r32(eth, MTK_GLO_MEM_DATA(1)); \
|
||||
reg_val1 &= ~MTK_RING_MAX_AGG_CNT; \
|
||||
reg_val1 |= FIELD_PREP(MTK_RING_MAX_AGG_CNT, y); \
|
||||
mtk_w32(eth, reg_val1, MTK_GLO_MEM_DATA(1)); \
|
||||
reg_val1 = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_WRITE); \
|
||||
mtk_w32(eth, reg_val1, MTK_GLO_MEM_CTRL); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SET_PDMA_RXRING_AGG_TIME(eth, x, y) \
|
||||
{ \
|
||||
u32 reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
reg_val &= ~MTK_LRO_RING_AGG_TIME_MASK; \
|
||||
reg_val |= ((y) & 0xffff) << MTK_LRO_RING_AGG_TIME_OFFSET; \
|
||||
mtk_w32(eth, reg_val, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
#define SET_PDMA_RXRING_AGG_TIME(eth, x, y) \
|
||||
{ \
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map; \
|
||||
u32 reg_val; \
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_GLO_MEM_ACCESS)) { \
|
||||
reg_val = mtk_r32(eth, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
reg_val &= ~MTK_LRO_RING_AGG_TIME_MASK; \
|
||||
reg_val |= ((y) & 0xffff) << MTK_LRO_RING_AGG_TIME_OFFSET; \
|
||||
mtk_w32(eth, reg_val, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
} else { \
|
||||
reg_val = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_READ); \
|
||||
mtk_w32(eth, reg_val, MTK_GLO_MEM_CTRL); \
|
||||
reg_val = mtk_r32(eth, MTK_GLO_MEM_DATA(0)); \
|
||||
reg_val &= ~MTK_RING_MAX_AGG_TIME_V2; \
|
||||
reg_val |= FIELD_PREP(MTK_RING_MAX_AGG_TIME_V2, y); \
|
||||
mtk_w32(eth, reg_val, MTK_GLO_MEM_DATA(0)); \
|
||||
reg_val = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_WRITE); \
|
||||
mtk_w32(eth, reg_val, MTK_GLO_MEM_CTRL); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SET_PDMA_RXRING_AGE_TIME(eth, x, y) \
|
||||
{ \
|
||||
u32 reg_val1 = mtk_r32(eth, MTK_LRO_CTRL_DW1_CFG(x)); \
|
||||
u32 reg_val2 = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
reg_val1 &= ~MTK_LRO_RING_AGE_TIME_L_MASK; \
|
||||
reg_val2 &= ~MTK_LRO_RING_AGE_TIME_H_MASK; \
|
||||
reg_val1 |= ((y) & 0x3ff) << MTK_LRO_RING_AGE_TIME_L_OFFSET; \
|
||||
reg_val2 |= (((y) >> 10) & 0x03f) << \
|
||||
MTK_LRO_RING_AGE_TIME_H_OFFSET; \
|
||||
mtk_w32(eth, reg_val1, MTK_LRO_CTRL_DW1_CFG(x)); \
|
||||
mtk_w32(eth, reg_val2, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
#define SET_PDMA_RXRING_AGE_TIME(eth, x, y) \
|
||||
{ \
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map; \
|
||||
u32 reg_val1, reg_val2; \
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_GLO_MEM_ACCESS)) { \
|
||||
reg_val1 = mtk_r32(eth, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x4 + (x * 0x40)); \
|
||||
reg_val2 = mtk_r32(eth, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
reg_val1 &= ~MTK_LRO_RING_AGE_TIME_L_MASK; \
|
||||
reg_val2 &= ~MTK_LRO_RING_AGE_TIME_H_MASK; \
|
||||
reg_val1 |= ((y) & 0x3ff) << MTK_LRO_RING_AGE_TIME_L_OFFSET; \
|
||||
reg_val2 |= (((y) >> 10) & 0x03f) << \
|
||||
MTK_LRO_RING_AGE_TIME_H_OFFSET; \
|
||||
mtk_w32(eth, reg_val1, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x4 + (x * 0x40)); \
|
||||
mtk_w32(eth, reg_val2, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
} else { \
|
||||
reg_val1 = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_READ); \
|
||||
mtk_w32(eth, reg_val1, MTK_GLO_MEM_CTRL); \
|
||||
reg_val1 = mtk_r32(eth, MTK_GLO_MEM_DATA(0)); \
|
||||
reg_val1 &= ~MTK_RING_AGE_TIME; \
|
||||
reg_val1 |= FIELD_PREP(MTK_RING_AGE_TIME, y); \
|
||||
mtk_w32(eth, reg_val1, MTK_GLO_MEM_DATA(0)); \
|
||||
reg_val1 = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val1 |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_WRITE); \
|
||||
mtk_w32(eth, reg_val1, MTK_GLO_MEM_CTRL); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SET_PDMA_LRO_BW_THRESHOLD(eth, x) \
|
||||
{ \
|
||||
u32 reg_val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW2); \
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map; \
|
||||
u32 reg_val = mtk_r32(eth, reg_map->pdma.lro_ctrl_dw0 + 0x8); \
|
||||
reg_val = (x); \
|
||||
mtk_w32(eth, reg_val, MTK_PDMA_LRO_CTRL_DW2); \
|
||||
mtk_w32(eth, reg_val, reg_map->pdma.lro_ctrl_dw0 + 0x8); \
|
||||
}
|
||||
|
||||
#define SET_PDMA_RXRING_VALID(eth, x, y) \
|
||||
{ \
|
||||
u32 reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
reg_val &= ~(0x1 << MTK_RX_PORT_VALID_OFFSET); \
|
||||
reg_val |= ((y) & 0x1) << MTK_RX_PORT_VALID_OFFSET; \
|
||||
mtk_w32(eth, reg_val, MTK_LRO_CTRL_DW2_CFG(x)); \
|
||||
#define SET_PDMA_RXRING_VALID(eth, x, y) \
|
||||
{ \
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map; \
|
||||
u32 reg_val; \
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_GLO_MEM_ACCESS)) { \
|
||||
reg_val = mtk_r32(eth, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
reg_val &= ~(0x1 << MTK_RX_PORT_VALID_OFFSET); \
|
||||
reg_val |= ((y) & 0x1) << MTK_RX_PORT_VALID_OFFSET; \
|
||||
mtk_w32(eth, reg_val, reg_map->pdma.lro_rx_ctrl_dw0 + \
|
||||
0x8 + (x * 0x40)); \
|
||||
} else { \
|
||||
reg_val = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_READ); \
|
||||
mtk_w32(eth, reg_val, MTK_GLO_MEM_CTRL); \
|
||||
reg_val = mtk_r32(eth, MTK_GLO_MEM_DATA(1)); \
|
||||
reg_val &= ~MTK_RING_OPMODE; \
|
||||
reg_val |= FIELD_PREP(MTK_RING_OPMODE, y); \
|
||||
mtk_w32(eth, reg_val, MTK_GLO_MEM_DATA(1)); \
|
||||
reg_val = FIELD_PREP(MTK_GLO_MEM_IDX, MTK_LRO_MEM_IDX); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_ADDR, MTK_LRO_MEM_CFG_BASE + x); \
|
||||
reg_val |= FIELD_PREP(MTK_GLO_MEM_CMD, MTK_GLO_MEM_WRITE); \
|
||||
mtk_w32(eth, reg_val, MTK_GLO_MEM_CTRL); \
|
||||
} \
|
||||
}
|
||||
|
||||
struct mtk_pse_fs_lgc_info_v2 {
|
||||
u32 rev3 : 14;
|
||||
u32 ppe_crsn: 5;
|
||||
u32 sport : 4;
|
||||
u32 is_l4f: 1;
|
||||
u32 is_l4vld: 1;
|
||||
u32 is_tack : 1;
|
||||
u32 is_ip4f : 1;
|
||||
u32 is_ip4 : 1;
|
||||
u32 is_ip6 : 1;
|
||||
u32 dr_idx : 2;
|
||||
u32 rev2 : 4;
|
||||
u32 l3_pidx : 2;
|
||||
u32 rev : 2;
|
||||
u32 fport : 4;
|
||||
u32 l2_len : 7;
|
||||
u32 l3_len : 14;
|
||||
} __packed;
|
||||
|
||||
struct mtk_pse_fs_lgc_info_v3 {
|
||||
u32 is_snap : 1;
|
||||
u32 vofst : 3;
|
||||
u32 l3_pidx : 2;
|
||||
u32 pse_sport : 4;
|
||||
u32 fport : 4;
|
||||
u32 ppe_crsn: 5;
|
||||
u32 sport : 4;
|
||||
u32 is_l4f: 1;
|
||||
u32 is_l4vld: 1;
|
||||
u32 is_tack : 1;
|
||||
u32 is_ip4f : 1;
|
||||
u32 is_ip4 : 1;
|
||||
u32 is_ip6 : 1;
|
||||
u32 is_err_pkt : 1;
|
||||
u32 err_pkt_action : 2;
|
||||
u32 pl_end : 11;
|
||||
u32 l2_len : 7;
|
||||
u32 l3_len : 14;
|
||||
} __packed;
|
||||
|
||||
struct mtk_lro_alt_v1_info0 {
|
||||
u32 dtp : 16;
|
||||
u32 stp : 16;
|
||||
@@ -313,23 +517,13 @@ struct mtk_mii_ioctl_data {
|
||||
unsigned int val_out;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NET_DSA_MT7530) || defined(CONFIG_MT753X_GSW)
|
||||
static inline bool mt7530_exist(struct mtk_eth *eth)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static inline bool mt7530_exist(struct mtk_eth *eth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg);
|
||||
extern u32 _mtk_mdio_write(struct mtk_eth *eth, int phy_addr,
|
||||
int phy_reg, u16 write_data);
|
||||
|
||||
extern atomic_t force;
|
||||
extern atomic_t reset_lock;
|
||||
extern int eth_debug_level;
|
||||
|
||||
int debug_proc_init(struct mtk_eth *eth);
|
||||
void debug_proc_exit(void);
|
||||
@@ -339,5 +533,6 @@ void mtketh_debugfs_exit(struct mtk_eth *eth);
|
||||
int mtk_do_priv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||
void hw_lro_stats_update(u32 ring_no, struct mtk_rx_dma_v2 *rxd);
|
||||
void hw_lro_flush_stats_update(u32 ring_no, struct mtk_rx_dma_v2 *rxd);
|
||||
void mt753x_set_port_link_state(bool up);
|
||||
|
||||
#endif /* MTK_ETH_DBG_H */
|
||||
|
||||
@@ -31,8 +31,8 @@ static const char *mtk_eth_path_name(u64 path)
|
||||
return "gmac2_rgmii";
|
||||
case MTK_ETH_PATH_GMAC2_SGMII:
|
||||
return "gmac2_sgmii";
|
||||
case MTK_ETH_PATH_GMAC2_XGMII:
|
||||
return "gmac2_xgmii";
|
||||
case MTK_ETH_PATH_GMAC2_2P5GPHY:
|
||||
return "gmac2_2p5gphy";
|
||||
case MTK_ETH_PATH_GMAC2_GEPHY:
|
||||
return "gmac2_gephy";
|
||||
case MTK_ETH_PATH_GMAC3_SGMII:
|
||||
@@ -104,13 +104,14 @@ static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
|
||||
static int set_mux_u3_gmac23_to_qphy(struct mtk_eth *eth, u64 path)
|
||||
{
|
||||
unsigned int val = 0,mask=0,reg=0;
|
||||
bool updated = true;
|
||||
|
||||
switch (path) {
|
||||
case MTK_ETH_PATH_GMAC2_SGMII:
|
||||
case MTK_ETH_PATH_GMAC3_SGMII:
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
|
||||
reg = USB_PHY_SWITCH_REG;
|
||||
val = SGMII_QPHY_SEL;
|
||||
@@ -135,7 +136,7 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_mux_gmac2_to_xgmii(struct mtk_eth *eth, u64 path)
|
||||
static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
bool updated = true;
|
||||
@@ -149,7 +150,7 @@ static int set_mux_gmac2_to_xgmii(struct mtk_eth *eth, u64 path)
|
||||
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
|
||||
|
||||
switch (path) {
|
||||
case MTK_ETH_PATH_GMAC2_XGMII:
|
||||
case MTK_ETH_PATH_GMAC2_2P5GPHY:
|
||||
val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
|
||||
mac_id = MTK_GMAC2_ID;
|
||||
break;
|
||||
@@ -311,13 +312,13 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = {
|
||||
.cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
|
||||
.set_path = set_mux_gmac2_gmac0_to_gephy,
|
||||
}, {
|
||||
.name = "mux_u3_gmac2_to_qphy",
|
||||
.cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
|
||||
.set_path = set_mux_u3_gmac2_to_qphy,
|
||||
.name = "mux_u3_gmac23_to_qphy",
|
||||
.cap_bit = MTK_ETH_MUX_U3_GMAC23_TO_QPHY,
|
||||
.set_path = set_mux_u3_gmac23_to_qphy,
|
||||
}, {
|
||||
.name = "mux_gmac2_to_xgmii",
|
||||
.cap_bit = MTK_ETH_MUX_GMAC2_TO_XGMII,
|
||||
.set_path = set_mux_gmac2_to_xgmii,
|
||||
.name = "mux_gmac2_to_2p5gphy",
|
||||
.cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY,
|
||||
.set_path = set_mux_gmac2_to_2p5gphy,
|
||||
}, {
|
||||
.name = "mux_gmac1_gmac2_to_sgmii_rgmii",
|
||||
.cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
|
||||
@@ -403,13 +404,13 @@ int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtk_gmac_xgmii_path_setup(struct mtk_eth *eth, int mac_id)
|
||||
int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id)
|
||||
{
|
||||
int err;
|
||||
u64 path = 0;
|
||||
|
||||
if (mac_id == 1)
|
||||
path = MTK_ETH_PATH_GMAC2_XGMII;
|
||||
if (mac_id == MTK_GMAC2_ID)
|
||||
path = MTK_ETH_PATH_GMAC2_2P5GPHY;
|
||||
|
||||
if (!path)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -0,0 +1,497 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* IEEE1588v2 PTP support for MediaTek ETH device.
|
||||
*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Authors: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/ptp_classify.h>
|
||||
|
||||
#include "mtk_eth_soc.h"
|
||||
|
||||
/* Values for the messageType field */
|
||||
#define SYNC 0x0
|
||||
#define DELAY_REQ 0x1
|
||||
#define PDELAY_REQ 0x2
|
||||
#define PDELAY_RESP 0x3
|
||||
#define FOLLOW_UP 0x8
|
||||
#define DELAY_RESP 0x9
|
||||
#define PDELAY_RESP_FOLLOW_UP 0xA
|
||||
#define ANNOUNCE 0xB
|
||||
|
||||
static int mtk_ptp_hwtstamp_enable(struct net_device *dev, int hwtstamp)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
|
||||
mtk_m32(eth, CSR_HW_TS_EN(mac->id),
|
||||
hwtstamp ? CSR_HW_TS_EN(mac->id) : 0, MAC_TS_MAC_CFG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_hwtstamp_get_t1(struct mtk_mac *mac, u16 seqid, struct timespec64 *ts)
|
||||
{
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
u32 sid[2], dw[4];
|
||||
int i;
|
||||
|
||||
sid[0] = mtk_r32(eth, MAC_TS_T1_SID1(mac->id));
|
||||
for (i = 0; i < 4; i++)
|
||||
dw[i] = mtk_r32(eth, MAC_TS_T1_DW(mac->id) + i * 4);
|
||||
sid[1] = mtk_r32(eth, MAC_TS_T1_SID2(mac->id));
|
||||
|
||||
if (seqid != sid[0] || sid[0] != sid[1]) {
|
||||
dev_warn(eth->dev, "invalid t1 hwtstamp(%d, %d, %d)!\n",
|
||||
seqid, sid[0], sid[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ts->tv_sec = dw[2] | ((u64)dw[3] << 32);
|
||||
ts->tv_nsec = dw[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_hwtstamp_get_t2(struct mtk_mac *mac, u16 seqid, struct timespec64 *ts)
|
||||
{
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
u32 sid[2], dw[4];
|
||||
int i;
|
||||
|
||||
sid[0] = mtk_r32(eth, MAC_TS_T2_SID1(mac->id));
|
||||
for (i = 0; i < 4; i++)
|
||||
dw[i] = mtk_r32(eth, MAC_TS_T2_DW(mac->id) + i * 4);
|
||||
sid[1] = mtk_r32(eth, MAC_TS_T2_SID2(mac->id));
|
||||
|
||||
if (seqid != sid[0] || sid[0] != sid[1]) {
|
||||
dev_warn(eth->dev, "invalid t2 hwtstamp(%d, %d, %d)!\n",
|
||||
seqid, sid[0], sid[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ts->tv_sec = dw[2] | ((u64)dw[3] << 32);
|
||||
ts->tv_nsec = dw[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_hwtstamp_get_t3(struct mtk_mac *mac, u16 seqid, struct timespec64 *ts)
|
||||
{
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
u32 sid[2], dw[4];
|
||||
int i;
|
||||
|
||||
sid[0] = mtk_r32(eth, MAC_TS_T3_SID1(mac->id));
|
||||
for (i = 0; i < 4; i++)
|
||||
dw[i] = mtk_r32(eth, MAC_TS_T3_DW(mac->id) + i * 4);
|
||||
sid[1] = mtk_r32(eth, MAC_TS_T3_SID2(mac->id));
|
||||
|
||||
if (seqid != sid[0] || sid[0] != sid[1]) {
|
||||
dev_warn(eth->dev, "invalid t3 hwtstamp(%d, %d, %d)!\n",
|
||||
seqid, sid[0], sid[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ts->tv_sec = dw[2] | ((u64)dw[3] << 32);
|
||||
ts->tv_nsec = dw[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_hwtstamp_get_t4(struct mtk_mac *mac, u16 seqid, struct timespec64 *ts)
|
||||
{
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
u32 sid[2], dw[4];
|
||||
int i;
|
||||
|
||||
sid[0] = mtk_r32(eth, MAC_TS_T4_SID1(mac->id));
|
||||
for (i = 0; i < 4; i++)
|
||||
dw[i] = mtk_r32(eth, MAC_TS_T4_DW(mac->id) + i * 4);
|
||||
sid[1] = mtk_r32(eth, MAC_TS_T4_SID2(mac->id));
|
||||
|
||||
if (seqid != sid[0] || sid[0] != sid[1]) {
|
||||
dev_warn(eth->dev, "invalid t4 hwtstamp(%d, %d, %d)!\n",
|
||||
seqid, sid[0], sid[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ts->tv_sec = dw[2] | ((u64)dw[3] << 32);
|
||||
ts->tv_nsec = dw[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_ptp_hwtstamp_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct mtk_mac *mac = container_of(work, struct mtk_mac, ptp_tx_work);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
struct sk_buff *skb = mac->ptp_tx_skb;
|
||||
struct skb_shared_hwtstamps shhwtstamps;
|
||||
struct timespec64 ts;
|
||||
unsigned int ptp_class, offset = 0;
|
||||
u8 *data, msgtype;
|
||||
u16 seqid;
|
||||
int ret;
|
||||
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
ptp_class = mac->ptp_tx_class;
|
||||
if (ptp_class & PTP_CLASS_VLAN)
|
||||
offset += VLAN_HLEN;
|
||||
|
||||
if ((ptp_class & PTP_CLASS_PMASK) == PTP_CLASS_L2)
|
||||
offset += ETH_HLEN;
|
||||
|
||||
data = skb_mac_header(skb);
|
||||
seqid = get_unaligned_be16(data + offset + OFF_PTP_SEQUENCE_ID);
|
||||
msgtype = data[offset] & 0x0f;
|
||||
switch (msgtype) {
|
||||
case SYNC:
|
||||
case PDELAY_REQ:
|
||||
ret = mtk_ptp_hwtstamp_get_t1(mac, seqid, &ts);
|
||||
break;
|
||||
case DELAY_REQ:
|
||||
case PDELAY_RESP:
|
||||
ret = mtk_ptp_hwtstamp_get_t3(mac, seqid, &ts);
|
||||
break;
|
||||
default:
|
||||
dev_warn(eth->dev, "unrecognized hwtstamp msgtype (%d)!", msgtype);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (time_is_before_jiffies(mac->ptp_tx_start +
|
||||
msecs_to_jiffies(500))) {
|
||||
dev_warn(eth->dev, "detect %s hwtstamp timeout!",
|
||||
(msgtype == SYNC || msgtype == PDELAY_REQ) ? "t1" : "t3");
|
||||
goto out;
|
||||
} else {
|
||||
schedule_work(&mac->ptp_tx_work);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
|
||||
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
|
||||
shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
|
||||
skb_tstamp_tx(skb, &shhwtstamps);
|
||||
|
||||
out:
|
||||
dev_kfree_skb_any(skb);
|
||||
mac->ptp_tx_skb = NULL;
|
||||
mac->ptp_tx_class = 0;
|
||||
mac->ptp_tx_start = 0;
|
||||
}
|
||||
|
||||
int mtk_ptp_hwtstamp_process_tx(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
unsigned int ptp_class, offset = 0;
|
||||
|
||||
ptp_class = ptp_classify_raw(skb);
|
||||
if (ptp_class == PTP_CLASS_NONE)
|
||||
return 0;
|
||||
|
||||
if (ptp_class & PTP_CLASS_VLAN)
|
||||
offset += VLAN_HLEN;
|
||||
|
||||
if ((ptp_class & PTP_CLASS_PMASK) == PTP_CLASS_L2)
|
||||
offset += ETH_HLEN;
|
||||
else
|
||||
return 0;
|
||||
|
||||
mac->ptp_tx_skb = skb_get(skb);
|
||||
mac->ptp_tx_class = ptp_class;
|
||||
mac->ptp_tx_start = jiffies;
|
||||
schedule_work(&mac->ptp_tx_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtk_ptp_hwtstamp_process_rx(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
|
||||
struct timespec64 ts;
|
||||
unsigned int ptp_class, offset = 0;
|
||||
int ret;
|
||||
u8 *data, msgtype;
|
||||
u16 seqid;
|
||||
|
||||
ptp_class = ptp_classify_raw(skb);
|
||||
if (ptp_class == PTP_CLASS_NONE)
|
||||
return 0;
|
||||
|
||||
if (ptp_class & PTP_CLASS_VLAN)
|
||||
offset += VLAN_HLEN;
|
||||
|
||||
if ((ptp_class & PTP_CLASS_PMASK) == PTP_CLASS_L2)
|
||||
offset += ETH_HLEN;
|
||||
else
|
||||
return 0;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
data = skb_mac_header(skb);
|
||||
seqid = get_unaligned_be16(data + offset + OFF_PTP_SEQUENCE_ID);
|
||||
msgtype = data[offset] & 0x0f;
|
||||
switch (msgtype) {
|
||||
case SYNC:
|
||||
case PDELAY_REQ:
|
||||
ret = mtk_ptp_hwtstamp_get_t2(mac, seqid, &ts);
|
||||
break;
|
||||
case DELAY_REQ:
|
||||
case PDELAY_RESP:
|
||||
ret = mtk_ptp_hwtstamp_get_t4(mac, seqid, &ts);
|
||||
break;
|
||||
default:
|
||||
dev_warn(eth->dev, "unrecognized hwtstamp msgtype (%d)!", msgtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
|
||||
shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtk_ptp_hwtstamp_set_config(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
struct hwtstamp_config cfg;
|
||||
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_HWTSTAMP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
||||
return -EFAULT;
|
||||
|
||||
/* reserved for future extensions */
|
||||
if (cfg.flags)
|
||||
return -EINVAL;
|
||||
|
||||
if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON &&
|
||||
cfg.tx_type != HWTSTAMP_TX_ONESTEP_SYNC)
|
||||
return -ERANGE;
|
||||
|
||||
switch (cfg.rx_filter) {
|
||||
case HWTSTAMP_FILTER_NONE:
|
||||
eth->rx_ts_enabled = 0;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
|
||||
eth->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
eth->tx_ts_enabled = cfg.tx_type;
|
||||
|
||||
mtk_ptp_hwtstamp_enable(dev, eth->tx_ts_enabled);
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
int mtk_ptp_hwtstamp_get_config(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
struct hwtstamp_config cfg;
|
||||
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_HWTSTAMP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cfg.flags = 0;
|
||||
cfg.tx_type = eth->tx_ts_enabled;
|
||||
cfg.rx_filter = eth->rx_ts_enabled;
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
struct mtk_eth *eth = container_of(ptp, struct mtk_eth, ptp_info);
|
||||
u64 base, adj;
|
||||
u16 data16;
|
||||
bool negative;
|
||||
|
||||
if (scaled_ppm) {
|
||||
base = 0x4 << 16;
|
||||
negative = diff_by_scaled_ppm(base, scaled_ppm, &adj);
|
||||
data16 = (u16)adj;
|
||||
|
||||
if (negative)
|
||||
mtk_w32(eth,
|
||||
FIELD_PREP(CSR_TICK_NANOSECOND, 0x3) |
|
||||
FIELD_PREP(CSR_TICK_SUB_NANOSECOND, 0xFFFF - data16),
|
||||
MAC_TS_TICK_SUBSECOND);
|
||||
else
|
||||
mtk_w32(eth,
|
||||
FIELD_PREP(CSR_TICK_NANOSECOND, 0x4) |
|
||||
FIELD_PREP(CSR_TICK_SUB_NANOSECOND, data16),
|
||||
MAC_TS_TICK_SUBSECOND);
|
||||
|
||||
// update tick configuration
|
||||
mtk_m32(eth, CSR_TICK_UPDATE, CSR_TICK_UPDATE, MAC_TS_TICK_CTRL);
|
||||
mtk_m32(eth, CSR_TICK_UPDATE, 0, MAC_TS_TICK_CTRL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct mtk_eth *eth = container_of(ptp, struct mtk_eth, ptp_info);
|
||||
struct timespec64 ts = ns_to_timespec64(delta);
|
||||
|
||||
mtk_w32(eth, (ts.tv_nsec >> 0) & 0xFFFFFFFF, MAC_TS_SUBSECOND_FIELD1);
|
||||
mtk_w32(eth, (ts.tv_sec >> 0) & 0xFFFFFFFF, MAC_TS_SECOND_FIELD0);
|
||||
mtk_w32(eth, (ts.tv_sec >> 32) & 0x0000FFFF, MAC_TS_SECOND_FIELD1);
|
||||
|
||||
// adjust timestamp
|
||||
mtk_m32(eth, CSR_TS_ADJUST, CSR_TS_ADJUST, MAC_TS_TIMESTAMP_CTRL);
|
||||
mtk_m32(eth, CSR_TS_ADJUST, 0, MAC_TS_TIMESTAMP_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_gettime64(struct ptp_clock_info *ptp,
|
||||
struct timespec64 *ts)
|
||||
{
|
||||
struct mtk_eth *eth = container_of(ptp, struct mtk_eth, ptp_info);
|
||||
unsigned long t_start = jiffies;
|
||||
u32 val[4];
|
||||
int i;
|
||||
|
||||
mtk_w32(eth, CPU_TRIG, MAC_TS_CPU_TRIG);
|
||||
|
||||
while (1) {
|
||||
if (!(mtk_r32(eth, MAC_TS_CPU_TRIG) & CPU_TS_VALID))
|
||||
break;
|
||||
if (time_after(jiffies, t_start + jiffies_to_msecs(1000))) {
|
||||
pr_warn("cpu trigger timeout!");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
val[i] = mtk_r32(eth, MAC_TS_CPU_TS_DW(i));
|
||||
|
||||
ts->tv_sec = val[2] | ((u64)val[3] << 32);
|
||||
ts->tv_nsec = val[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_settime64(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts)
|
||||
{
|
||||
struct mtk_eth *eth = container_of(ptp, struct mtk_eth, ptp_info);
|
||||
|
||||
mtk_w32(eth, (ts->tv_nsec >> 0) & 0xFFFFFFFF, MAC_TS_SUBSECOND_FIELD1);
|
||||
mtk_w32(eth, (ts->tv_sec >> 0) & 0xFFFFFFFF, MAC_TS_SECOND_FIELD0);
|
||||
mtk_w32(eth, (ts->tv_sec >> 32) & 0x0000FFFF, MAC_TS_SECOND_FIELD1);
|
||||
|
||||
// update timestamp
|
||||
mtk_m32(eth, CSR_TS_UPDATE, CSR_TS_UPDATE, MAC_TS_TIMESTAMP_CTRL);
|
||||
mtk_m32(eth, CSR_TS_UPDATE, 0, MAC_TS_TIMESTAMP_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_ptp_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *request, int on)
|
||||
{
|
||||
struct mtk_eth *eth = container_of(ptp, struct mtk_eth, ptp_info);
|
||||
|
||||
// enable rx T1/T3 timestamp mask
|
||||
mtk_w32(eth, 0x00000077, MAC_TS_RSV);
|
||||
// update tick configuration
|
||||
mtk_m32(eth, CSR_TICK_UPDATE, CSR_TICK_UPDATE, MAC_TS_TICK_CTRL);
|
||||
mtk_m32(eth, CSR_TICK_UPDATE, 0, MAC_TS_TICK_CTRL);
|
||||
// enable tick
|
||||
mtk_m32(eth, CSR_TICK_RUN, on, MAC_TS_TICK_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ptp_clock_info mtk_ptp_caps = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mtk_ptp",
|
||||
.max_adj = 24999999,
|
||||
.n_alarm = 0,
|
||||
.n_ext_ts = 0,
|
||||
.n_per_out = 1,
|
||||
.n_pins = 0,
|
||||
.pps = 0,
|
||||
.adjfine = mtk_ptp_adjfine,
|
||||
.adjtime = mtk_ptp_adjtime,
|
||||
.gettime64 = mtk_ptp_gettime64,
|
||||
.settime64 = mtk_ptp_settime64,
|
||||
.enable = mtk_ptp_enable,
|
||||
};
|
||||
|
||||
int mtk_ptp_clock_init(struct mtk_eth *eth)
|
||||
{
|
||||
struct mtk_mac *mac;
|
||||
int i;
|
||||
|
||||
eth->ptp_info = mtk_ptp_caps;
|
||||
eth->ptp_clock = ptp_clock_register(ð->ptp_info,
|
||||
eth->dev);
|
||||
if (IS_ERR(eth->ptp_clock)) {
|
||||
eth->ptp_clock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < MTK_MAX_DEVS; i++) {
|
||||
mac = eth->mac[i];
|
||||
if (!mac)
|
||||
continue;
|
||||
|
||||
INIT_WORK(&mac->ptp_tx_work, mtk_ptp_hwtstamp_tx_work);
|
||||
}
|
||||
|
||||
mtk_ptp_enable(ð->ptp_info, NULL, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtk_ptp_clock_deinit(struct mtk_eth *eth)
|
||||
{
|
||||
struct mtk_mac *mac;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MTK_MAX_DEVS; i++) {
|
||||
mac = eth->mac[i];
|
||||
if (!mac)
|
||||
continue;
|
||||
|
||||
cancel_work_sync(&mac->ptp_tx_work);
|
||||
dev_kfree_skb_any(mac->ptp_tx_skb);
|
||||
mac->ptp_tx_skb = NULL;
|
||||
mac->ptp_tx_class = 0;
|
||||
mac->ptp_tx_start = 0;
|
||||
}
|
||||
|
||||
mtk_ptp_enable(ð->ptp_info, NULL, 0);
|
||||
|
||||
ptp_clock_unregister(eth->ptp_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,18 +7,23 @@
|
||||
#ifndef MTK_ETH_RESET_H
|
||||
#define MTK_ETH_RESET_H
|
||||
|
||||
#define MTK_ETH_RESET_VERSION "v1.1.0"
|
||||
|
||||
/* Frame Engine Reset FSM */
|
||||
#define MTK_FE_START_RESET 0x2000
|
||||
#define MTK_FE_RESET_DONE 0x2001
|
||||
#define MTK_WIFI_RESET_DONE 0x2002
|
||||
#define MTK_WIFI_CHIP_ONLINE 0x2003
|
||||
#define MTK_WIFI_CHIP_OFFLINE 0x2004
|
||||
#define MTK_TOPS_DUMP_DONE 0x3001
|
||||
#define MTK_FE_RESET_NAT_DONE 0x4001
|
||||
|
||||
#define MTK_FE_STOP_TRAFFIC (0x2005)
|
||||
#define MTK_FE_STOP_TRAFFIC_DONE (0x2006)
|
||||
#define MTK_FE_START_TRAFFIC (0x2007)
|
||||
#define MTK_FE_STOP_TRAFFIC_DONE_FAIL (0x2008)
|
||||
#define MTK_FE_START_RESET_INIT (0x2009)
|
||||
#define MTK_WIFI_L1SER_DONE (0x200a)
|
||||
|
||||
/*FE GDM Counter */
|
||||
#define MTK_GDM_RX_FC (0x24)
|
||||
@@ -42,12 +47,10 @@
|
||||
#define MTK_PPE_BUSY BIT(31)
|
||||
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
#define MTK_WDMA_CNT (0x3)
|
||||
#define MTK_GDM_RX_BASE (0x8)
|
||||
#define MTK_GDM_CNT_OFFSET (0x80)
|
||||
#define MTK_GDM_TX_BASE (0x48)
|
||||
#else
|
||||
#define MTK_WDMA_CNT (0x2)
|
||||
#define MTK_GDM_RX_BASE (0x8)
|
||||
#define MTK_GDM_CNT_OFFSET (0x40)
|
||||
#define MTK_GDM_TX_BASE (0x38)
|
||||
@@ -71,12 +74,14 @@ enum mtk_reset_event_id {
|
||||
MTK_EVENT_RFIFO_UF = 19,
|
||||
};
|
||||
|
||||
extern struct notifier_block mtk_eth_netdevice_nb __read_mostly;
|
||||
int mtk_eth_netdevice_event(struct notifier_block *n, unsigned long event, void *ptr);
|
||||
extern struct completion wait_ser_done;
|
||||
extern struct completion wait_ack_done;
|
||||
extern struct completion wait_tops_done;
|
||||
extern char* mtk_reset_event_name[32];
|
||||
extern atomic_t reset_lock;
|
||||
extern struct completion wait_nat_done;
|
||||
extern u32 mtk_reset_flag;
|
||||
extern int mtk_wifi_num;
|
||||
extern bool mtk_stop_fail;
|
||||
|
||||
irqreturn_t mtk_handle_fe_irq(int irq, void *_eth);
|
||||
@@ -85,8 +90,11 @@ int mtk_eth_cold_reset(struct mtk_eth *eth);
|
||||
int mtk_eth_warm_reset(struct mtk_eth *eth);
|
||||
void mtk_reset_event_update(struct mtk_eth *eth, u32 id);
|
||||
void mtk_dump_netsys_info(void *_eth);
|
||||
void mtk_dma_monitor(struct timer_list *t);
|
||||
void mtk_prepare_reset_fe(struct mtk_eth *eth);
|
||||
void mtk_dump_netsys_info_brief(void *_eth);
|
||||
void mtk_hw_reset_monitor(struct mtk_eth *eth);
|
||||
void mtk_save_qdma_cfg(struct mtk_eth *eth);
|
||||
void mtk_restore_qdma_cfg(struct mtk_eth *eth);
|
||||
void mtk_prepare_reset_ppe(struct mtk_eth *eth, u32 ppe_id);
|
||||
|
||||
void mtk_pse_set_port_link(struct mtk_eth *eth, u32 port, bool enable);
|
||||
#endif /* MTK_ETH_RESET_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,12 +10,16 @@
|
||||
* Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
|
||||
* Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
#ifndef NF_HNAT_H
|
||||
#define NF_HNAT_H
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <net/dsa.h>
|
||||
#include <net/netevent.h>
|
||||
#include <net/netfilter/nf_conntrack_zones.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include "hnat_mcast.h"
|
||||
#include "nf_hnat_mtk.h"
|
||||
@@ -76,8 +80,8 @@
|
||||
#define PPE_MCAST_H_E 0xE0
|
||||
#define PPE_MCAST_L_F 0x100
|
||||
#define PPE_MCAST_H_F 0x104
|
||||
#define PPE_MCAST_L_10 0xC00
|
||||
#define PPE_MCAST_H_10 0xC04
|
||||
#define PPE_MCAST_L_10 (-0x200)
|
||||
#define PPE_MCAST_H_10 (-0x200 + 0x4)
|
||||
#define PPE_MTU_DRP 0x108
|
||||
#define PPE_MTU_VLYR_0 0x10C
|
||||
#define PPE_MTU_VLYR_1 0x110
|
||||
@@ -103,32 +107,14 @@
|
||||
#define PPE_MIB_CAH_RDATA 0X160
|
||||
#define PPE_SB_FIFO_DBG 0x170
|
||||
#define PPE_SBW_CTRL 0x174
|
||||
#define PPE_SB_WED0_CNT 0x18C
|
||||
#define PPE_CAH_DBG 0x190
|
||||
#define PPE_FLOW_CHK_STATUS 0x1B0
|
||||
|
||||
#define GDMA1_FWD_CFG 0x500
|
||||
#define GDMA2_FWD_CFG 0x1500
|
||||
#define GDMA3_FWD_CFG 0x540
|
||||
|
||||
/* QDMA Tx queue configuration */
|
||||
#define QTX_CFG(x) (QDMA_BASE + ((x) * 0x10))
|
||||
#define QTX_CFG_HW_RESV_CNT_OFFSET (8)
|
||||
#define QTX_CFG_SW_RESV_CNT_OFFSET (0)
|
||||
|
||||
#define QTX_SCH(x) (QDMA_BASE + 0x4 + ((x) * 0x10))
|
||||
#define QTX_SCH_MIN_RATE_EN BIT(27)
|
||||
#define QTX_SCH_MAX_RATE_EN BIT(11)
|
||||
#define QTX_SCH_MIN_RATE_MAN_OFFSET (20)
|
||||
#define QTX_SCH_MIN_RATE_EXP_OFFSET (16)
|
||||
#define QTX_SCH_MAX_RATE_WGHT_OFFSET (12)
|
||||
#define QTX_SCH_MAX_RATE_MAN_OFFSET (4)
|
||||
#define QTX_SCH_MAX_RATE_EXP_OFFSET (0)
|
||||
|
||||
/* QDMA Tx scheduler configuration */
|
||||
#define QDMA_PAGE (QDMA_BASE + 0x1f0)
|
||||
#define QDMA_TX_2SCH_BASE (QDMA_BASE + 0x214)
|
||||
#define QTX_MIB_IF (QDMA_BASE + 0x2bc)
|
||||
#define QDMA_TX_4SCH_BASE(x) (QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
|
||||
#define QDMA_TX_SCH_WFQ_EN BIT(15)
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Register Mask*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -145,13 +131,29 @@
|
||||
#define HASH_MODE (0x3 << 14) /* RW */
|
||||
#define SCAN_MODE (0x3 << 16) /* RW */
|
||||
#define XMODE (0x3 << 18) /* RW */
|
||||
#define HASH_DBG (0x3 << 21) /* RW */
|
||||
#define TICK_SEL (0x1 << 24) /* RW */
|
||||
#define DSCP_TRFC_ECN_EN (0x1 << 25) /* RW */
|
||||
|
||||
|
||||
/*PPE_CAH_CTRL mask*/
|
||||
#define CAH_EN (0x1 << 0) /* RW */
|
||||
#define CAH_REQ (0x1 << 8) /* RW */
|
||||
#define CAH_X_MODE (0x1 << 9) /* RW */
|
||||
#define CAH_CMD (0x3 << 12) /* RW */
|
||||
#define CAH_DATA_SEL (0x3 << 18) /* RW */
|
||||
|
||||
/*PPE_CAH_LINE_RW mask*/
|
||||
#define LINE_RW (0xffff << 0) /* RW */
|
||||
#define OFFSET_RW (0xff << 16) /* RW */
|
||||
|
||||
/*PPE_CAH_TAG_SRH mask*/
|
||||
#define TAG_SRH (0xffff << 0) /* RW */
|
||||
#define SRH_LNUM (0x7fff << 16) /* RW */
|
||||
#define SRH_HIT (0x1 << 31) /* RW */
|
||||
|
||||
/*PPE_MIB_SER_CR mask*/
|
||||
#define BIT_MIB_BUSY (1 << 16) /* RW */
|
||||
|
||||
/*PPE_UNB_AGE mask*/
|
||||
#define UNB_DLTA (0xff << 0) /* RW */
|
||||
@@ -188,8 +190,10 @@
|
||||
#define TTL0_DRP (0x1 << 4) /* RW */
|
||||
#define MCAST_TB_EN (0x1 << 7) /* RW */
|
||||
#define MCAST_HASH (0x3 << 12) /* RW */
|
||||
#define NEW_IPV4_ID_INC_EN (0x1 << 20) /* RW */
|
||||
#define SP_CMP_EN (0x1 << 25) /* RW */
|
||||
|
||||
#define MC_P4_PPSE (0xf << 16) /* RW */
|
||||
#define MC_P3_PPSE (0xf << 12) /* RW */
|
||||
#define MC_P2_PPSE (0xf << 8) /* RW */
|
||||
#define MC_P1_PPSE (0xf << 4) /* RW */
|
||||
@@ -207,16 +211,12 @@
|
||||
#define GDM_ALL_FRC_MASK \
|
||||
(GDM_UFRC_MASK | GDM_BFRC_MASK | GDM_MFRC_MASK | GDM_OFRC_MASK)
|
||||
|
||||
/*QDMA_PAGE mask*/
|
||||
#define QTX_CFG_PAGE (0xf << 0) /* RW */
|
||||
|
||||
/*QTX_MIB_IF mask*/
|
||||
#define MIB_ON_QTX_CFG (0x1 << 31) /* RW */
|
||||
#define VQTX_MIB_EN (0x1 << 28) /* RW */
|
||||
|
||||
/* PPE Side Band FIFO Debug Mask */
|
||||
#define SB_MED_FULL_DRP_EN (0x1 << 11)
|
||||
|
||||
/* PPE Cache Debug status Mask */
|
||||
#define CAH_DBG_BUSY (0xf << 0)
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Descriptor Structure */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -359,6 +359,48 @@ struct hnat_info_blk2_whnat {
|
||||
u32 dscp : 8; /* DSCP value */
|
||||
} __packed;
|
||||
|
||||
struct hnat_l2_bridge {
|
||||
union {
|
||||
struct hnat_bind_info_blk bfib1;
|
||||
struct hnat_unbind_info_blk udib1;
|
||||
u32 info_blk1;
|
||||
};
|
||||
u32 dmac_hi;
|
||||
u16 smac_lo;
|
||||
u16 dmac_lo;
|
||||
u32 smac_hi;
|
||||
u16 etype;
|
||||
u16 hph; /* hash placeholder */
|
||||
u16 vlan1;
|
||||
u16 vlan2;
|
||||
u32 resv1;
|
||||
u32 resv2;
|
||||
union {
|
||||
struct hnat_info_blk2 iblk2;
|
||||
struct hnat_info_blk2_whnat iblk2w;
|
||||
u32 info_blk2;
|
||||
};
|
||||
u32 resv3;
|
||||
u32 resv4 : 24;
|
||||
u32 act_dp : 8; /* UDF */
|
||||
u16 new_vlan1;
|
||||
u16 sp_tag;
|
||||
u32 new_dmac_hi;
|
||||
u16 new_vlan2;
|
||||
u16 new_dmac_lo;
|
||||
u32 new_smac_hi;
|
||||
u16 resv5;
|
||||
u16 new_smac_lo;
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
u32 resv6;
|
||||
struct hnat_winfo winfo;
|
||||
struct hnat_winfo_pao winfo_pao;
|
||||
#elif defined(CONFIG_MEDIATEK_NETSYS_V2)
|
||||
u16 minfo;
|
||||
struct hnat_winfo winfo;
|
||||
#endif
|
||||
} __packed;
|
||||
|
||||
struct hnat_ipv4_hnapt {
|
||||
union {
|
||||
struct hnat_bind_info_blk bfib1;
|
||||
@@ -385,13 +427,13 @@ struct hnat_ipv4_hnapt {
|
||||
u32 resv3_1 : 9;
|
||||
u32 eg_keep_ecn : 1;
|
||||
u32 eg_keep_dscp : 1;
|
||||
u32 resv3_2:13;
|
||||
u32 resv3_2 : 13;
|
||||
#else
|
||||
u32 resv3:24;
|
||||
u32 resv3 : 24;
|
||||
#endif
|
||||
u32 act_dp : 8; /* UDF */
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
union {
|
||||
#if !defined(CONFIG_MEDIATEK_NETSYS_V2) && !defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
@@ -444,12 +486,12 @@ struct hnat_ipv4_dslite {
|
||||
u8 priority; /* in order to consist with Linux kernel (should be 8bits) */
|
||||
u32 hop_limit : 8;
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
u32 resv2_1 : 1;
|
||||
u32 eg_keep_ecn : 1;
|
||||
u32 eg_keep_cls : 1;
|
||||
u32 resv2_2 : 13;
|
||||
u32 resv2_1 : 1;
|
||||
u32 eg_keep_ecn : 1;
|
||||
u32 eg_keep_cls : 1;
|
||||
u32 resv2_2 : 13;
|
||||
#else
|
||||
u32 resv2 : 16;
|
||||
u32 resv2 : 16;
|
||||
#endif
|
||||
u32 act_dp : 8; /* UDF */
|
||||
|
||||
@@ -460,7 +502,7 @@ struct hnat_ipv4_dslite {
|
||||
};
|
||||
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
union {
|
||||
#if !defined(CONFIG_MEDIATEK_NETSYS_V2) && !defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
@@ -529,7 +571,7 @@ struct hnat_ipv4_mape {
|
||||
};
|
||||
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
union {
|
||||
#if !defined(CONFIG_MEDIATEK_NETSYS_V2) && !defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
@@ -601,7 +643,7 @@ struct hnat_ipv6_3t_route {
|
||||
u32 info_blk2;
|
||||
};
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
union {
|
||||
#if !defined(CONFIG_MEDIATEK_NETSYS_V2) && !defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
@@ -666,7 +708,7 @@ struct hnat_ipv6_5t_route {
|
||||
};
|
||||
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
union {
|
||||
#if !defined(CONFIG_MEDIATEK_NETSYS_V2) && !defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
@@ -739,7 +781,7 @@ struct hnat_ipv6_6rd {
|
||||
};
|
||||
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
union {
|
||||
#if !defined(CONFIG_MEDIATEK_NETSYS_V2) && !defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
@@ -801,7 +843,7 @@ struct hnat_ipv6_hnapt {
|
||||
};
|
||||
|
||||
u16 vlan1;
|
||||
u16 etype;
|
||||
u16 sp_tag;
|
||||
u32 dmac_hi;
|
||||
u16 vlan2;
|
||||
u16 dmac_lo;
|
||||
@@ -837,6 +879,7 @@ struct foe_entry {
|
||||
union {
|
||||
struct hnat_unbind_info_blk udib1;
|
||||
struct hnat_bind_info_blk bfib1;
|
||||
struct hnat_l2_bridge l2_bridge;
|
||||
struct hnat_ipv4_hnapt ipv4_hnapt;
|
||||
struct hnat_ipv4_dslite ipv4_dslite;
|
||||
struct hnat_ipv4_mape ipv4_mape;
|
||||
@@ -868,6 +911,12 @@ struct foe_entry {
|
||||
#endif
|
||||
#define CFG_PPE_NUM (hnat_priv->ppe_num)
|
||||
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
#define MAX_PPE_CACHE_NUM (128)
|
||||
#else
|
||||
#define MAX_PPE_CACHE_NUM (32)
|
||||
#endif
|
||||
|
||||
/* If the user wants to set skb->mark to prevent hardware acceleration
|
||||
* for the packet flow.
|
||||
*/
|
||||
@@ -885,6 +934,8 @@ struct mib_entry {
|
||||
struct hnat_accounting {
|
||||
u64 bytes;
|
||||
u64 packets;
|
||||
struct nf_conntrack_zone zone;
|
||||
u8 dir;
|
||||
};
|
||||
|
||||
enum mtk_hnat_version {
|
||||
@@ -957,7 +1008,19 @@ struct mtk_hnat {
|
||||
struct timer_list hnat_mcast_check_timer;
|
||||
bool nf_stat_en;
|
||||
struct xlat_conf xlat;
|
||||
spinlock_t cah_lock;
|
||||
spinlock_t entry_lock;
|
||||
spinlock_t flow_entry_lock;
|
||||
struct hlist_head *foe_flow[MAX_PPE_NUM];
|
||||
int fe_irq2;
|
||||
};
|
||||
|
||||
struct hnat_flow_entry {
|
||||
struct hlist_node list;
|
||||
struct foe_entry data;
|
||||
unsigned long last_update;
|
||||
u16 ppe_index;
|
||||
u16 hash;
|
||||
};
|
||||
|
||||
struct extdev_entry {
|
||||
@@ -970,11 +1033,28 @@ struct tcpudphdr {
|
||||
__be16 dst;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
struct ppe_flow_chk_status {
|
||||
u32 entry : 15;
|
||||
u32 sta : 1;
|
||||
u32 state : 2;
|
||||
u32 sp : 4;
|
||||
u32 fp : 4;
|
||||
u32 cah : 1;
|
||||
u32 rmt : 1;
|
||||
u32 psn : 1;
|
||||
u32 dram : 1;
|
||||
u32 resv : 1;
|
||||
u32 valid : 1;
|
||||
};
|
||||
#endif
|
||||
|
||||
enum FoeEntryState { INVALID = 0, UNBIND = 1, BIND = 2, FIN = 3 };
|
||||
|
||||
enum FoeIpAct {
|
||||
IPV4_HNAPT = 0,
|
||||
IPV4_HNAT = 1,
|
||||
L2_BRIDGE = 2,
|
||||
IPV4_DSLITE = 3,
|
||||
IPV6_3T_ROUTE = 4,
|
||||
IPV6_5T_ROUTE = 5,
|
||||
@@ -1012,9 +1092,11 @@ enum FoeIpAct {
|
||||
#define HASH_MODE_3 3
|
||||
|
||||
/*PPE_FLOW_CFG*/
|
||||
#define BIT_FUC_FOE BIT(2)
|
||||
#define BIT_FMC_FOE BIT(1)
|
||||
#define BIT_FBC_FOE BIT(0)
|
||||
#define BIT_ALERT_TCP_FIN_RST_SYN BIT(0)
|
||||
#define BIT_MD_TOAP_BYP_CRSN0 BIT(1)
|
||||
#define BIT_MD_TOAP_BYP_CRSN1 BIT(2)
|
||||
#define BIT_MD_TOAP_BYP_CRSN2 BIT(3)
|
||||
#define BIT_TCP_IP4F_NAT_EN BIT(6) /*Enable IPv4 fragment + TCP packet NAT*/
|
||||
#define BIT_UDP_IP4F_NAT_EN BIT(7) /*Enable IPv4 fragment + UDP packet NAT*/
|
||||
#define BIT_IPV6_3T_ROUTE_EN BIT(8)
|
||||
#define BIT_IPV6_5T_ROUTE_EN BIT(9)
|
||||
@@ -1023,7 +1105,8 @@ enum FoeIpAct {
|
||||
#define BIT_IPV4_NAT_EN BIT(12)
|
||||
#define BIT_IPV4_NAPT_EN BIT(13)
|
||||
#define BIT_IPV4_DSL_EN BIT(14)
|
||||
#define BIT_MIB_BUSY BIT(16)
|
||||
#define BIT_L2_BRG_EN BIT(15)
|
||||
#define BIT_IP_PROT_CHK_BLIST BIT(16)
|
||||
#define BIT_IPV4_NAT_FRAG_EN BIT(17)
|
||||
#define BIT_IPV4_HASH_GREK BIT(19)
|
||||
#define BIT_IPV6_HASH_GREK BIT(20)
|
||||
@@ -1032,6 +1115,9 @@ enum FoeIpAct {
|
||||
#define BIT_IPV6_NAT_EN BIT(23)
|
||||
#define BIT_IPV6_NAPT_EN BIT(24)
|
||||
#define BIT_CS0_RM_ALL_IP6_IP_EN BIT(25)
|
||||
#define BIT_L2_HASH_ETH BIT(29)
|
||||
#define BIT_L2_HASH_VID BIT(30)
|
||||
#define BIT_L2_LRN_EN BIT(31)
|
||||
|
||||
/*GDMA_FWD_CFG value*/
|
||||
#define BITS_GDM_UFRC_P_PPE (NR_PPE0_PORT << 12)
|
||||
@@ -1058,6 +1144,14 @@ enum FoeIpAct {
|
||||
(BITS_GDM_UFRC_P_PPE2 | BITS_GDM_BFRC_P_PPE2 | \
|
||||
BITS_GDM_MFRC_P_PPE2 | BITS_GDM_OFRC_P_PPE2)
|
||||
|
||||
#define BITS_GDM_UFRC_P_TDMA (NR_TDMA_PORT << 12)
|
||||
#define BITS_GDM_BFRC_P_TDMA (NR_TDMA_PORT << 8)
|
||||
#define BITS_GDM_MFRC_P_TDMA (NR_TDMA_PORT << 4)
|
||||
#define BITS_GDM_OFRC_P_TDMA (NR_TDMA_PORT << 0)
|
||||
#define BITS_GDM_ALL_FRC_P_TDMA \
|
||||
(BITS_GDM_UFRC_P_TDMA | BITS_GDM_BFRC_P_TDMA | \
|
||||
BITS_GDM_MFRC_P_TDMA | BITS_GDM_OFRC_P_TDMA)
|
||||
|
||||
#define BITS_GDM_UFRC_P_CPU_PDMA (NR_PDMA_PORT << 12)
|
||||
#define BITS_GDM_BFRC_P_CPU_PDMA (NR_PDMA_PORT << 8)
|
||||
#define BITS_GDM_MFRC_P_CPU_PDMA (NR_PDMA_PORT << 4)
|
||||
@@ -1144,22 +1238,36 @@ enum FoeIpAct {
|
||||
#define NR_DISCARD 7
|
||||
#define NR_WDMA0_PORT 8
|
||||
#define NR_WDMA1_PORT 9
|
||||
#define NR_TDMA_PORT 10
|
||||
#define NR_WDMA2_PORT 13
|
||||
#define NR_GMAC3_PORT 15
|
||||
#define NR_QDMA_TPORT 1
|
||||
#define NR_EIP197_TPORT 2
|
||||
#define NR_EIP197_QDMA_TPORT 3
|
||||
#define NR_TDMA_TPORT 4
|
||||
#define NR_TDMA_QDMA_TPORT 5
|
||||
#define NR_TDMA_EIP197_TPORT 8
|
||||
#define NR_TDMA_EIP197_QDMA_TPORT 9
|
||||
#define WAN_DEV_NAME hnat_priv->wan
|
||||
#define LAN_DEV_NAME hnat_priv->lan
|
||||
#define LAN2_DEV_NAME hnat_priv->lan2
|
||||
#define IS_WAN(dev) \
|
||||
(!strncmp((dev)->name, hnat_priv->wan, strlen(hnat_priv->wan)))
|
||||
#define IS_ETH_GRP(dev) (IS_LAN_GRP(dev) || IS_WAN(dev))
|
||||
#define IS_WAN(dev) (!strncmp((dev)->name, WAN_DEV_NAME, strlen(WAN_DEV_NAME)))
|
||||
#define IS_LAN_GRP(dev) (IS_LAN(dev) | IS_LAN2(dev))
|
||||
#define IS_LAN(dev) (!strncmp(dev->name, LAN_DEV_NAME, strlen(LAN_DEV_NAME)))
|
||||
#define IS_LAN2(dev) (!strncmp(dev->name, LAN2_DEV_NAME, \
|
||||
strlen(LAN2_DEV_NAME)))
|
||||
#define IS_LAN(dev) \
|
||||
(!strncmp(dev->name, LAN_DEV_NAME, strlen(LAN_DEV_NAME)) || \
|
||||
IS_BOND(dev))
|
||||
#define IS_LAN2(dev) \
|
||||
(!strncmp(dev->name, LAN2_DEV_NAME, strlen(LAN2_DEV_NAME)) || \
|
||||
IS_BOND(dev))
|
||||
#define IS_BR(dev) (!strncmp(dev->name, "br", 2))
|
||||
#define IS_BOND(dev) (!strncmp(dev->name, "bond", 4))
|
||||
#define IS_WHNAT(dev) \
|
||||
((hnat_priv->data->whnat && \
|
||||
(get_wifi_hook_if_index_from_dev(dev) != 0)) ? 1 : 0)
|
||||
#define IS_EXT(dev) ((get_index_from_dev(dev) != 0) ? 1 : 0)
|
||||
#define IS_PPD(dev) (!strcmp(dev->name, hnat_priv->ppd))
|
||||
#define IS_L2_BRIDGE(x) (((x)->bfib1.pkt_type == L2_BRIDGE) ? 1 : 0)
|
||||
#define IS_IPV4_HNAPT(x) (((x)->bfib1.pkt_type == IPV4_HNAPT) ? 1 : 0)
|
||||
#define IS_IPV4_HNAT(x) (((x)->bfib1.pkt_type == IPV4_HNAT) ? 1 : 0)
|
||||
#define IS_IPV4_GRP(x) (IS_IPV4_HNAPT(x) | IS_IPV4_HNAT(x))
|
||||
@@ -1175,16 +1283,25 @@ enum FoeIpAct {
|
||||
(IS_IPV6_3T_ROUTE(x) | IS_IPV6_5T_ROUTE(x) | IS_IPV6_6RD(x) | \
|
||||
IS_IPV4_DSLITE(x) | IS_IPV4_MAPE(x) | IS_IPV4_MAPT(x) | \
|
||||
IS_IPV6_HNAPT(x) | IS_IPV6_HNAT(x))
|
||||
#define IS_BOND_MODE (!strncmp(LAN_DEV_NAME, "bond", 4))
|
||||
#define IS_GMAC1_MODE ((hnat_priv->gmac_num == 1) ? 1 : 0)
|
||||
#define IS_HQOS_MODE (qos_toggle == 1)
|
||||
#define IS_PPPQ_MODE (qos_toggle == 2) /* Per Port Per Queue */
|
||||
#define IS_PPPQ_PATH(dev, skb) \
|
||||
((IS_DSA_1G_LAN(dev) || IS_DSA_WAN(dev)) || \
|
||||
(FROM_WED(skb) && IS_DSA_LAN(dev)))
|
||||
#define IS_HQOS_DL_MODE (IS_HQOS_MODE && qos_dl_toggle)
|
||||
#define IS_HQOS_UL_MODE (IS_HQOS_MODE && qos_ul_toggle)
|
||||
#define MAX_PPPQ_PORT_NUM 6
|
||||
#define MAX_SWITCH_PORT_NUM (6)
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
#define MAX_PPPQ_QUEUE_NUM (2 * MAX_SWITCH_PORT_NUM + 2)
|
||||
#define IS_PPPQ_PATH(dev, skb) \
|
||||
((IS_DSA_1G_LAN(dev) || IS_DSA_WAN(dev)) || \
|
||||
(IS_ETH_GRP(dev) && is_eth_dev_speed_under(dev, SPEED_1000)) ||\
|
||||
(FROM_WED(skb) && (IS_DSA_LAN(dev) || \
|
||||
is_eth_dev_speed_under(dev, SPEED_2500))))
|
||||
#else
|
||||
#define MAX_PPPQ_QUEUE_NUM (2 * MAX_SWITCH_PORT_NUM)
|
||||
#define IS_PPPQ_PATH(dev, skb) \
|
||||
((IS_DSA_1G_LAN(dev) || IS_DSA_WAN(dev)) || \
|
||||
(FROM_WED(skb) && IS_DSA_LAN(dev)))
|
||||
#endif
|
||||
|
||||
#define es(entry) (entry_state[entry->bfib1.state])
|
||||
#define ei(entry, end) (hnat_priv->foe_etry_num - (int)(end - entry))
|
||||
@@ -1212,68 +1329,51 @@ enum FoeIpAct {
|
||||
#define IS_DSA_1G_LAN(dev) (!strncmp(dev->name, "lan", 3) && \
|
||||
strcmp(dev->name, "lan5"))
|
||||
#define IS_DSA_WAN(dev) (!strncmp(dev->name, "wan", 3))
|
||||
#define IS_DSA_TAG_PROTO_MXL862_8021Q(dp) \
|
||||
(dp->cpu_dp->tag_ops->proto == DSA_TAG_PROTO_MXL862_8021Q)
|
||||
#define NONE_DSA_PORT 0xff
|
||||
#define MAX_CRSN_NUM 32
|
||||
#define IPV6_HDR_LEN 40
|
||||
#define IPV6_SNAT 0
|
||||
#define IPV6_DNAT 1
|
||||
|
||||
/*QDMA_PAGE value*/
|
||||
#define NUM_OF_Q_PER_PAGE 16
|
||||
|
||||
/*IPv6 Header*/
|
||||
#ifndef NEXTHDR_IPIP
|
||||
#define NEXTHDR_IPIP 4
|
||||
#endif
|
||||
|
||||
#define UDF_PINGPONG_IFIDX GENMASK(6, 0)
|
||||
#define UDF_HNAT_PRE_FILLED BIT(7)
|
||||
|
||||
#define HQOS_FLAG(dev, skb, qid) \
|
||||
((IS_HQOS_UL_MODE && IS_WAN(dev)) || \
|
||||
(IS_HQOS_DL_MODE && IS_LAN_GRP(dev)) || \
|
||||
(IS_PPPQ_MODE && (IS_PPPQ_PATH(dev, skb) || \
|
||||
qid >= MAX_PPPQ_PORT_NUM)))
|
||||
#define HQOS_FLAG(dev, skb, qid) \
|
||||
((IS_HQOS_UL_MODE && IS_WAN(dev)) || \
|
||||
(IS_HQOS_DL_MODE && IS_LAN_GRP(dev)) || \
|
||||
(IS_PPPQ_MODE && (IS_PPPQ_PATH(dev, skb) || \
|
||||
qid >= MAX_PPPQ_QUEUE_NUM)))
|
||||
|
||||
#define HNAT_GMAC_FP(mac_id) \
|
||||
((IS_GMAC1_MODE || mac_id == MTK_GMAC1_ID) ? NR_GMAC1_PORT : \
|
||||
(mac_id == MTK_GMAC2_ID) ? NR_GMAC2_PORT : \
|
||||
(mac_id == MTK_GMAC3_ID) ? NR_GMAC3_PORT : \
|
||||
-EINVAL)
|
||||
|
||||
extern const struct of_device_id of_hnat_match[];
|
||||
extern struct mtk_hnat *hnat_priv;
|
||||
|
||||
static inline int is_hnat_pre_filled(struct foe_entry *entry)
|
||||
{
|
||||
u32 udf = 0;
|
||||
|
||||
if (IS_IPV4_GRP(entry))
|
||||
udf = entry->ipv4_hnapt.act_dp;
|
||||
else
|
||||
udf = entry->ipv6_5t_route.act_dp;
|
||||
|
||||
return !!(udf & UDF_HNAT_PRE_FILLED);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_DSA_MT7530)
|
||||
u32 hnat_dsa_fill_stag(const struct net_device *netdev,
|
||||
int hnat_dsa_fill_stag(const struct net_device *netdev,
|
||||
struct foe_entry *entry,
|
||||
struct flow_offload_hw_path *hw_path,
|
||||
u16 eth_proto, int mape);
|
||||
|
||||
int hnat_dsa_get_port(struct net_device **dev);
|
||||
static inline bool hnat_dsa_is_enable(struct mtk_hnat *priv)
|
||||
{
|
||||
#if defined(CONFIG_NET_DSA)
|
||||
return (priv->wan_dsa_port != NONE_DSA_PORT);
|
||||
}
|
||||
#else
|
||||
static inline u32 hnat_dsa_fill_stag(const struct net_device *netdev,
|
||||
struct foe_entry *entry,
|
||||
struct flow_offload_hw_path *hw_path,
|
||||
u16 eth_proto, int mape)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool hnat_dsa_is_enable(struct mtk_hnat *priv)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index);
|
||||
|
||||
void hnat_deinit_debugfs(struct mtk_hnat *h);
|
||||
int hnat_init_debugfs(struct mtk_hnat *h);
|
||||
@@ -1282,8 +1382,14 @@ void hnat_unregister_nf_hooks(void);
|
||||
int whnat_adjust_nf_hooks(void);
|
||||
int mtk_hqos_ptype_cb(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *unused);
|
||||
int hnat_search_cache_line(u32 ppe_id, u32 tag);
|
||||
int hnat_write_cache_line(u32 ppe_id, int line, u32 tag, u32 state, u32 *data);
|
||||
int hnat_dump_cache_entry(u32 ppe_id, int hash);
|
||||
int hnat_dump_ppe_entry(u32 ppe_id, u32 hash);
|
||||
bool is_eth_dev_speed_under(const struct net_device *dev, u32 speed);
|
||||
extern int dbg_cpu_reason;
|
||||
extern int debug_level;
|
||||
extern int mcast_mode;
|
||||
extern int xlat_toggle;
|
||||
extern struct hnat_desc headroom[DEF_ETRY_NUM];
|
||||
extern int qos_dl_toggle;
|
||||
@@ -1291,9 +1397,21 @@ extern int qos_ul_toggle;
|
||||
extern int hook_toggle;
|
||||
extern int mape_toggle;
|
||||
extern int qos_toggle;
|
||||
|
||||
extern int l2br_toggle;
|
||||
extern int l4s_toggle;
|
||||
extern int tnl_toggle;
|
||||
extern int (*mtk_tnl_encap_offload)(struct sk_buff *skb, struct ethhdr *eth);
|
||||
extern int (*mtk_tnl_decap_offload)(struct sk_buff *skb);
|
||||
extern bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb);
|
||||
extern bool (*mtk_crypto_offloadable)(struct sk_buff *skb);
|
||||
extern int hnat_bind_crypto_entry(struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
int fill_inner_info);
|
||||
extern void foe_clear_crypto_entry(struct xfrm_selector sel);
|
||||
int ext_if_add(struct extdev_entry *ext_entry);
|
||||
int ext_if_del(struct extdev_entry *ext_entry);
|
||||
void cr_set_bits(void __iomem *reg, u32 bs);
|
||||
void cr_clr_bits(void __iomem *reg, u32 bs);
|
||||
void cr_set_field(void __iomem *reg, u32 field, u32 val);
|
||||
int mtk_sw_nat_hook_tx(struct sk_buff *skb, int gmac_no);
|
||||
int mtk_sw_nat_hook_rx(struct sk_buff *skb);
|
||||
@@ -1309,21 +1427,41 @@ uint32_t hnat_cpu_reason_cnt(struct sk_buff *skb);
|
||||
int hnat_enable_hook(void);
|
||||
int hnat_disable_hook(void);
|
||||
void hnat_cache_ebl(int enable);
|
||||
void __hnat_cache_ebl(u32 ppe_id, int enable);
|
||||
void hnat_cache_clr(u32 ppe_id);
|
||||
void __hnat_cache_clr(u32 ppe_id);
|
||||
void hnat_qos_shaper_ebl(u32 id, u32 enable);
|
||||
void exclude_boundary_entry(struct foe_entry *foe_table_cpu);
|
||||
void set_gmac_ppe_fwd(int gmac_no, int enable);
|
||||
int entry_detail(u32 ppe_id, int index);
|
||||
int entry_delete_by_mac(u8 *mac);
|
||||
int entry_delete_by_ip(bool is_ipv4, void *addr);
|
||||
int entry_delete(u32 ppe_id, int index);
|
||||
void __entry_delete(struct foe_entry *entry);
|
||||
int hnat_warm_init(void);
|
||||
u32 hnat_get_ppe_hash(struct foe_entry *entry);
|
||||
int mtk_ppe_get_xlat_v4_by_v6(struct in6_addr *ipv6, u32 *ipv4);
|
||||
int mtk_ppe_get_xlat_v6_by_v4(u32 *ipv4, struct in6_addr *ipv6,
|
||||
struct in6_addr *prefix);
|
||||
bool hnat_flow_entry_match(struct foe_entry *entry, struct foe_entry *data);
|
||||
void hnat_flow_entry_delete(struct hnat_flow_entry *flow_entry);
|
||||
|
||||
struct hnat_accounting *hnat_get_count(struct mtk_hnat *h, u32 ppe_id,
|
||||
u32 index, struct hnat_accounting *diff);
|
||||
|
||||
static inline u16 foe_timestamp(struct mtk_hnat *h)
|
||||
int mtk_hnat_skb_headroom_copy(struct sk_buff *new, struct sk_buff *old);
|
||||
static inline u16 foe_timestamp(struct mtk_hnat *h, bool mcast)
|
||||
{
|
||||
return (readl(hnat_priv->fe_base + 0x0010)) & 0xffff;
|
||||
u16 time_stamp;
|
||||
|
||||
if (mcast)
|
||||
time_stamp = (readl(h->fe_base + 0x0010)) & 0xffff;
|
||||
else if (h->data->version == MTK_HNAT_V2 || h->data->version == MTK_HNAT_V3)
|
||||
time_stamp = readl(h->fe_base + 0x0010) & (0xFF);
|
||||
else
|
||||
time_stamp = readl(h->fe_base + 0x0010) & (0x7FFF);
|
||||
|
||||
return time_stamp;
|
||||
}
|
||||
|
||||
#endif /* NF_HNAT_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,8 @@
|
||||
*
|
||||
* Copyright (C) 2014-2016 Zhiqiang Yang <zhiqiang.yang@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <net/netfilter/nf_flow_table.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
@@ -19,20 +21,21 @@
|
||||
* mcast_entry_get - Returns the index of an unused entry
|
||||
* or an already existed entry in mtbl
|
||||
*/
|
||||
static int mcast_entry_get(u16 vlan_id, u32 dst_mac)
|
||||
static int mcast_entry_get(u16 vlan_id, u8 *dmac)
|
||||
{
|
||||
int index = -1;
|
||||
u8 i;
|
||||
struct ppe_mcast_group *p = hnat_priv->pmcast->mtbl;
|
||||
int index = -1;
|
||||
u8 max = hnat_priv->pmcast->max_entry;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if ((index == -1) && (!p->valid)) {
|
||||
if (p->valid) {
|
||||
if ((p->vid == vlan_id) && !memcmp(p->dmac, dmac, ETH_ALEN)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
} else if (index == -1) {
|
||||
index = i; /*get the first unused entry index*/
|
||||
continue;
|
||||
}
|
||||
if ((p->vid == vlan_id) && (p->mac_hi == dst_mac)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
@@ -43,21 +46,37 @@ static int mcast_entry_get(u16 vlan_id, u32 dst_mac)
|
||||
return index;
|
||||
}
|
||||
|
||||
static void get_mac_from_mdb_entry(struct br_mdb_entry *entry,
|
||||
u32 *mac_hi, u16 *mac_lo)
|
||||
static int get_mac_from_mdb_entry(struct br_mdb_entry *entry, u8 *mac)
|
||||
{
|
||||
u32 ip;
|
||||
|
||||
switch (ntohs(entry->addr.proto)) {
|
||||
case ETH_P_IP:
|
||||
*mac_lo = 0x0100;
|
||||
*mac_hi = swab32((entry->addr.u.ip4 & 0xfffffe00) + 0x5e);
|
||||
ip = be32_to_cpu(entry->addr.u.ip4);
|
||||
mac[0] = 0x01;
|
||||
mac[1] = 0x00;
|
||||
mac[2] = 0x5e;
|
||||
mac[3] = (ip >> 16) & 0x7F;
|
||||
mac[4] = (ip >> 8) & 0xFF;
|
||||
mac[5] = ip & 0xFF;
|
||||
break;
|
||||
case ETH_P_IPV6:
|
||||
*mac_lo = 0x3333;
|
||||
*mac_hi = swab32(entry->addr.u.ip6.s6_addr32[3]);
|
||||
ip = be32_to_cpu(entry->addr.u.ip6.s6_addr32[3]);
|
||||
mac[0] = 0x33;
|
||||
mac[1] = 0x33;
|
||||
mac[2] = (ip >> 24) & 0xFF;
|
||||
mac[3] = (ip >> 16) & 0xFF;
|
||||
mac[4] = (ip >> 8) & 0xFF;
|
||||
mac[5] = ip & 0xFF;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
trace_printk("%s:group mac_h=0x%08x, mac_l=0x%04x\n",
|
||||
__func__, *mac_hi, *mac_lo);
|
||||
|
||||
if (debug_level >= 7)
|
||||
pr_info("%s:group mac=%pM\n", __func__, mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*set_hnat_mtbl - set ppe multicast register*/
|
||||
@@ -65,8 +84,8 @@ static int set_hnat_mtbl(struct ppe_mcast_group *group, u32 ppe_id, int index)
|
||||
{
|
||||
struct ppe_mcast_h mcast_h;
|
||||
struct ppe_mcast_l mcast_l;
|
||||
u16 mac_lo = group->mac_lo;
|
||||
u32 mac_hi = group->mac_hi;
|
||||
u16 mac_hi = DMAC_TO_HI16(group->dmac);
|
||||
u32 mac_lo = DMAC_TO_LO32(group->dmac);
|
||||
u8 mc_port = group->mc_port;
|
||||
void __iomem *reg;
|
||||
|
||||
@@ -75,16 +94,20 @@ static int set_hnat_mtbl(struct ppe_mcast_group *group, u32 ppe_id, int index)
|
||||
|
||||
mcast_h.u.value = 0;
|
||||
mcast_l.addr = 0;
|
||||
if (mac_lo == 0x0100)
|
||||
if (mac_hi == 0x0100)
|
||||
mcast_h.u.info.mc_mpre_sel = 0;
|
||||
else if (mac_lo == 0x3333)
|
||||
else if (mac_hi == 0x3333)
|
||||
mcast_h.u.info.mc_mpre_sel = 1;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
mcast_h.u.info.mc_px_en = mc_port;
|
||||
mcast_l.addr = mac_hi;
|
||||
mcast_h.u.info.valid = group->valid;
|
||||
trace_printk("%s:index=%d,group info=0x%x,addr=0x%x\n",
|
||||
__func__, index, mcast_h.u.value, mcast_l.addr);
|
||||
mcast_l.addr = mac_lo;
|
||||
|
||||
if (debug_level >= 7)
|
||||
trace_printk("%s:index=%d,group info=0x%x,addr=0x%x\n",
|
||||
__func__, index, mcast_h.u.value, mcast_l.addr);
|
||||
|
||||
if (index < 0x10) {
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_H_0 + ((index) * 8);
|
||||
writel(mcast_h.u.value, reg);
|
||||
@@ -92,31 +115,55 @@ static int set_hnat_mtbl(struct ppe_mcast_group *group, u32 ppe_id, int index)
|
||||
writel(mcast_l.addr, reg);
|
||||
} else {
|
||||
index = index - 0x10;
|
||||
reg = hnat_priv->fe_base + PPE_MCAST_H_10 + ((index) * 8);
|
||||
writel(mcast_h.u.value, reg);
|
||||
reg = hnat_priv->fe_base + PPE_MCAST_L_10 + ((index) * 8);
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_H_10 + ((index) * 8);
|
||||
writel(mcast_h.u.value, reg);
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_L_10 + ((index) * 8);
|
||||
writel(mcast_l.addr, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*clr_hnat_mtbl - clear ppe multicast register*/
|
||||
static void clr_hnat_mtbl(struct ppe_mcast_group *group, u32 ppe_id, int index)
|
||||
{
|
||||
void __iomem *reg;
|
||||
|
||||
if (ppe_id >= CFG_PPE_NUM)
|
||||
return;
|
||||
|
||||
if (index < 0x10) {
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_H_0 + ((index) * 8);
|
||||
writel(0, reg);
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_L_0 + ((index) * 8);
|
||||
writel(0, reg);
|
||||
} else {
|
||||
index = index - 0x10;
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_H_10 + ((index) * 8);
|
||||
writel(0, reg);
|
||||
reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_L_10 + ((index) * 8);
|
||||
writel(0, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hnat_mcast_table_update -
|
||||
* 1.get a valid group entry
|
||||
* 2.update group info
|
||||
* a.update eif&oif count
|
||||
* b.eif ==0 & oif == 0,delete it from group table
|
||||
* c.oif != 0,set mc forward port to cpu,else do not forward to cpu
|
||||
* a.update if_num count
|
||||
* b.if_num[i] port refer to ppe_mcast_port in hnat_mcash.h
|
||||
* c.if_num[i] = 0 for i, delete it from group table
|
||||
* 3.set the group info to ppe register
|
||||
*/
|
||||
static int hnat_mcast_table_update(int type, struct br_mdb_entry *entry)
|
||||
{
|
||||
struct net_device *dev;
|
||||
u32 mac_hi = 0;
|
||||
u16 mac_lo = 0;
|
||||
int i, index;
|
||||
struct flow_offload_hw_path hw_path = { 0 };
|
||||
struct ppe_mcast_group *group;
|
||||
struct net_device *dev;
|
||||
struct mtk_mac *mac;
|
||||
int i, index, port;
|
||||
int ret;
|
||||
u8 dmac[ETH_ALEN];
|
||||
|
||||
rcu_read_lock();
|
||||
dev = dev_get_by_index_rcu(&init_net, entry->ifindex);
|
||||
@@ -126,55 +173,242 @@ static int hnat_mcast_table_update(int type, struct br_mdb_entry *entry)
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
get_mac_from_mdb_entry(entry, &mac_hi, &mac_lo);
|
||||
index = mcast_entry_get(entry->vid, mac_hi);
|
||||
ret = get_mac_from_mdb_entry(entry, dmac);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
index = mcast_entry_get(entry->vid, dmac);
|
||||
if (index == -1)
|
||||
return -1;
|
||||
|
||||
group = &hnat_priv->pmcast->mtbl[index];
|
||||
group->mac_hi = mac_hi;
|
||||
group->mac_lo = mac_lo;
|
||||
memcpy(group->dmac, dmac, ETH_ALEN);
|
||||
|
||||
if (IS_ETH_GRP(dev) && !IS_DSA_LAN(dev)) {
|
||||
if (dev->netdev_ops->ndo_flow_offload_check) {
|
||||
hw_path.dev = dev;
|
||||
hw_path.virt_dev = dev;
|
||||
dev->netdev_ops->ndo_flow_offload_check(&hw_path);
|
||||
dev = hw_path.dev;
|
||||
}
|
||||
mac = netdev_priv(dev);
|
||||
port = (mac->id == MTK_GMAC1_ID) ? MCAST_TO_GDMA1 :
|
||||
(mac->id == MTK_GMAC2_ID) ? MCAST_TO_GDMA2 :
|
||||
(mac->id == MTK_GMAC3_ID) ? MCAST_TO_GDMA3 :
|
||||
-EINVAL;
|
||||
if (port < 0)
|
||||
return -1;
|
||||
} else {
|
||||
port = MCAST_TO_PDMA; /* to PDMA */
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWMDB:
|
||||
if (IS_LAN(dev) || IS_WAN(dev))
|
||||
group->eif++;
|
||||
else
|
||||
group->oif++;
|
||||
group->if_num[port]++;
|
||||
group->vid = entry->vid;
|
||||
group->valid = true;
|
||||
break;
|
||||
case RTM_DELMDB:
|
||||
if (group->valid) {
|
||||
if (IS_LAN(dev) || IS_WAN(dev))
|
||||
group->eif--;
|
||||
else
|
||||
group->oif--;
|
||||
}
|
||||
if (group->valid)
|
||||
group->if_num[port]--;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
trace_printk("%s:devname=%s,eif=%d,oif=%d\n", __func__,
|
||||
dev->name, group->eif, group->oif);
|
||||
if (group->valid) {
|
||||
if (group->oif && group->eif)
|
||||
/*eth&wifi both in group,forward to cpu&GDMA1*/
|
||||
group->mc_port = (MCAST_TO_PDMA || MCAST_TO_GDMA1);
|
||||
else if (group->oif)
|
||||
/*only wifi in group,forward to cpu only*/
|
||||
group->mc_port = MCAST_TO_PDMA;
|
||||
else
|
||||
/*only eth in group,forward to GDMA1 only*/
|
||||
group->mc_port = MCAST_TO_GDMA1;
|
||||
if (!group->oif && !group->eif)
|
||||
/*nobody in this group,clear the entry*/
|
||||
memset(group, 0, sizeof(struct ppe_mcast_group));
|
||||
if (debug_level >= 7)
|
||||
trace_printk("%s:devname=%s,if_num=%d|%d|%d|%d|%d\n", __func__,
|
||||
dev->name, group->if_num[4], group->if_num[3],
|
||||
group->if_num[2], group->if_num[1], group->if_num[0]);
|
||||
|
||||
for (i = 0; i < CFG_PPE_NUM; i++)
|
||||
set_hnat_mtbl(group, i, index);
|
||||
if (group->valid) {
|
||||
group->mc_port = 0;
|
||||
for (i = 0; i < MAX_MCAST_PORT; i++) {
|
||||
if (group->if_num[i] > 0)
|
||||
group->mc_port |= (0x1 << i);
|
||||
}
|
||||
|
||||
if (group->mc_port == 0) {
|
||||
for (i = 0; i < CFG_PPE_NUM; i++)
|
||||
clr_hnat_mtbl(group, i, index);
|
||||
/* nobody in this group, clear the entry */
|
||||
memset(group, 0, sizeof(struct ppe_mcast_group));
|
||||
} else {
|
||||
for (i = 0; i < CFG_PPE_NUM; i++)
|
||||
set_hnat_mtbl(group, i, index);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get mc_port value for read-only access */
|
||||
static bool hnat_mcast_get_mc_port(u8 *dmac, u16 vlan_id, u8 *mc_port)
|
||||
{
|
||||
struct ppe_mcast_list *entry;
|
||||
struct list_head *head;
|
||||
bool found = false;
|
||||
|
||||
if (!hnat_priv->pmcast)
|
||||
return false;
|
||||
|
||||
head = &hnat_priv->pmcast->mlist;
|
||||
|
||||
read_lock(&hnat_priv->pmcast->mcast_lock);
|
||||
list_for_each_entry(entry, head, list) {
|
||||
if (!memcmp(entry->dmac, dmac, ETH_ALEN) && (entry->vid == vlan_id)) {
|
||||
*mc_port = entry->mc_port;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&hnat_priv->pmcast->mcast_lock);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Find node for update access - must be called with mcast_lock held */
|
||||
static struct ppe_mcast_list *hnat_mcast_list_find(u8 *dmac, u16 vlan_id)
|
||||
{
|
||||
struct ppe_mcast_list *entry;
|
||||
struct list_head *head;
|
||||
|
||||
if (!hnat_priv->pmcast)
|
||||
return NULL;
|
||||
|
||||
head = &hnat_priv->pmcast->mlist;
|
||||
|
||||
/* Regular list traversal since we hold the lock */
|
||||
list_for_each_entry(entry, head, list) {
|
||||
if (!memcmp(entry->dmac, dmac, ETH_ALEN) && (entry->vid == vlan_id))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hnat_mcast_list_del_all(void)
|
||||
{
|
||||
struct ppe_mcast_list *entry, *tmp;
|
||||
struct list_head *head;
|
||||
|
||||
if (!hnat_priv->pmcast)
|
||||
return;
|
||||
|
||||
head = &hnat_priv->pmcast->mlist;
|
||||
|
||||
write_lock(&hnat_priv->pmcast->mcast_lock);
|
||||
list_for_each_entry_safe(entry, tmp, head, list) {
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
write_unlock(&hnat_priv->pmcast->mcast_lock);
|
||||
}
|
||||
|
||||
bool hnat_is_mcast_uni(struct sk_buff *skb)
|
||||
{
|
||||
u8 mc_port;
|
||||
u16 vid;
|
||||
|
||||
if (!skb)
|
||||
return false;
|
||||
|
||||
vid = skb_vlan_tagged(skb) ? skb->vlan_tci & VLAN_VID_MASK : 0;
|
||||
|
||||
if (!hnat_mcast_get_mc_port(eth_hdr(skb)->h_dest, vid, &mc_port))
|
||||
return false;
|
||||
|
||||
/* only allows packets destined to single GDMA ports */
|
||||
return IS_MCAST_PORT_GDM(mc_port);
|
||||
}
|
||||
|
||||
static int hnat_mcast_list_update(int type, struct br_mdb_entry *entry)
|
||||
{
|
||||
struct flow_offload_hw_path hw_path = { 0 };
|
||||
struct ppe_mcast_list *pmcast_list;
|
||||
struct net_device *dev;
|
||||
struct mtk_mac *mac;
|
||||
int port, ret;
|
||||
u8 dmac[ETH_ALEN];
|
||||
|
||||
rcu_read_lock();
|
||||
dev = dev_get_by_index_rcu(&init_net, entry->ifindex);
|
||||
if (!dev) {
|
||||
rcu_read_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = get_mac_from_mdb_entry(entry, dmac);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (IS_ETH_GRP(dev) && !IS_DSA_LAN(dev)) {
|
||||
if (dev->netdev_ops->ndo_flow_offload_check) {
|
||||
hw_path.dev = dev;
|
||||
hw_path.virt_dev = dev;
|
||||
dev->netdev_ops->ndo_flow_offload_check(&hw_path);
|
||||
dev = hw_path.dev;
|
||||
}
|
||||
mac = netdev_priv(dev);
|
||||
port = (mac->id == MTK_GMAC1_ID) ? MCAST_TO_GDMA1 :
|
||||
(mac->id == MTK_GMAC2_ID) ? MCAST_TO_GDMA2 :
|
||||
(mac->id == MTK_GMAC3_ID) ? MCAST_TO_GDMA3 :
|
||||
-EINVAL;
|
||||
if (port < 0)
|
||||
return -1;
|
||||
} else {
|
||||
port = MCAST_TO_PDMA; /* to PDMA */
|
||||
}
|
||||
|
||||
write_lock(&hnat_priv->pmcast->mcast_lock);
|
||||
|
||||
pmcast_list = hnat_mcast_list_find(dmac, entry->vid);
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWMDB:
|
||||
if (!pmcast_list) {
|
||||
pmcast_list = kmalloc(sizeof(struct ppe_mcast_list), GFP_KERNEL);
|
||||
if (!pmcast_list) {
|
||||
write_unlock(&hnat_priv->pmcast->mcast_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_LIST_HEAD(&pmcast_list->list);
|
||||
memcpy(pmcast_list->dmac, dmac, ETH_ALEN);
|
||||
pmcast_list->vid = entry->vid;
|
||||
pmcast_list->mc_port = (1 << port);
|
||||
list_add_tail(&pmcast_list->list, &hnat_priv->pmcast->mlist);
|
||||
} else {
|
||||
pmcast_list->mc_port |= (1 << port);
|
||||
}
|
||||
break;
|
||||
case RTM_DELMDB:
|
||||
if (pmcast_list) {
|
||||
pmcast_list->mc_port &= ~(1 << port);
|
||||
if (pmcast_list->mc_port == 0) {
|
||||
list_del(&pmcast_list->list);
|
||||
kfree(pmcast_list);
|
||||
pmcast_list = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
write_unlock(&hnat_priv->pmcast->mcast_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_unlock(&hnat_priv->pmcast->mcast_lock);
|
||||
|
||||
entry_delete_by_mac(dmac);
|
||||
|
||||
if (debug_level >= 7)
|
||||
pr_info("%s_%s:devname=%s,mcast_port=%x, mac:%pM\n",
|
||||
__func__,
|
||||
(type == RTM_NEWMDB) ? "NEW" : "DEL", dev->name,
|
||||
(pmcast_list) ? pmcast_list->mc_port : 0, dmac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hnat_mcast_nlmsg_handler(struct work_struct *work)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
@@ -209,13 +443,19 @@ static void hnat_mcast_nlmsg_handler(struct work_struct *work)
|
||||
}
|
||||
|
||||
entry = (struct br_mdb_entry *)nla_data(info);
|
||||
trace_printk("%s:cmd=0x%2x,ifindex=0x%x,state=0x%x",
|
||||
__func__, nlh->nlmsg_type,
|
||||
entry->ifindex, entry->state);
|
||||
trace_printk("vid=0x%x,ip=0x%x,proto=0x%x\n",
|
||||
entry->vid, entry->addr.u.ip4,
|
||||
entry->addr.proto);
|
||||
hnat_mcast_table_update(nlh->nlmsg_type, entry);
|
||||
if (debug_level >= 7) {
|
||||
trace_printk("%s:cmd=0x%2x,ifindex=0x%x,state=0x%x",
|
||||
__func__, nlh->nlmsg_type,
|
||||
entry->ifindex, entry->state);
|
||||
trace_printk("vid=0x%x,ip=0x%x,proto=0x%x\n",
|
||||
entry->vid, entry->addr.u.ip4,
|
||||
entry->addr.proto);
|
||||
}
|
||||
|
||||
if (IS_MCAST_MULTI_MODE)
|
||||
hnat_mcast_table_update(nlh->nlmsg_type, entry);
|
||||
|
||||
hnat_mcast_list_update(nlh->nlmsg_type, entry);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
}
|
||||
@@ -267,7 +507,7 @@ static void hnat_mcast_check_timestamp(struct timer_list *t)
|
||||
entry = hnat_priv->foe_table_cpu[i] + hash_index;
|
||||
if (entry->bfib1.sta == 1) {
|
||||
e_ts = (entry->ipv4_hnapt.m_timestamp) & 0xffff;
|
||||
foe_ts = foe_timestamp(hnat_priv);
|
||||
foe_ts = foe_timestamp(hnat_priv, true);
|
||||
if ((foe_ts - e_ts) > 0x3000)
|
||||
foe_ts = (~(foe_ts)) & 0xffff;
|
||||
if (abs(foe_ts - e_ts) > 20)
|
||||
@@ -285,44 +525,54 @@ int hnat_mcast_enable(u32 ppe_id)
|
||||
if (ppe_id >= CFG_PPE_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
pmcast = kzalloc(sizeof(*pmcast), GFP_KERNEL);
|
||||
if (!pmcast)
|
||||
return -1;
|
||||
if (!hnat_priv->pmcast) {
|
||||
pmcast = kzalloc(sizeof(*pmcast), GFP_KERNEL);
|
||||
if (!pmcast)
|
||||
return -1;
|
||||
|
||||
if (hnat_priv->data->version == MTK_HNAT_V1_1)
|
||||
pmcast->max_entry = 0x10;
|
||||
else
|
||||
pmcast->max_entry = MAX_MCAST_ENTRY;
|
||||
memset(pmcast->mtbl, 0, sizeof(struct ppe_mcast_group) * MAX_MCAST_ENTRY);
|
||||
|
||||
INIT_WORK(&pmcast->work, hnat_mcast_nlmsg_handler);
|
||||
pmcast->queue = create_singlethread_workqueue("ppe_mcast");
|
||||
if (!pmcast->queue)
|
||||
goto err1;
|
||||
/* Initialize multicast list for unicast mode */
|
||||
INIT_LIST_HEAD(&pmcast->mlist);
|
||||
rwlock_init(&pmcast->mcast_lock);
|
||||
|
||||
pmcast->msock = hnat_mcast_netlink_open(&init_net);
|
||||
if (!pmcast->msock)
|
||||
goto err2;
|
||||
if (hnat_priv->data->version == MTK_HNAT_V1_1)
|
||||
pmcast->max_entry = 0x10;
|
||||
else
|
||||
pmcast->max_entry = MAX_MCAST_ENTRY;
|
||||
|
||||
hnat_priv->pmcast = pmcast;
|
||||
INIT_WORK(&pmcast->work, hnat_mcast_nlmsg_handler);
|
||||
pmcast->queue = create_singlethread_workqueue("ppe_mcast");
|
||||
if (!pmcast->queue)
|
||||
goto err1;
|
||||
|
||||
/* mt7629 should checkout mcast entry life time manualy */
|
||||
if (hnat_priv->data->version == MTK_HNAT_V1_3) {
|
||||
timer_setup(&hnat_priv->hnat_mcast_check_timer,
|
||||
hnat_mcast_check_timestamp, 0);
|
||||
hnat_priv->hnat_mcast_check_timer.expires = jiffies;
|
||||
add_timer(&hnat_priv->hnat_mcast_check_timer);
|
||||
pmcast->msock = hnat_mcast_netlink_open(&init_net);
|
||||
if (!pmcast->msock)
|
||||
goto err2;
|
||||
|
||||
hnat_priv->pmcast = pmcast;
|
||||
|
||||
/* mt7629 should checkout mcast entry life time manualy */
|
||||
if (hnat_priv->data->version == MTK_HNAT_V1_3) {
|
||||
timer_setup(&hnat_priv->hnat_mcast_check_timer,
|
||||
hnat_mcast_check_timestamp, 0);
|
||||
hnat_priv->hnat_mcast_check_timer.expires = jiffies;
|
||||
add_timer(&hnat_priv->hnat_mcast_check_timer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable multicast table lookup */
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, MCAST_TB_EN, 1);
|
||||
/* multicast port0 map to PDMA */
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P0_PPSE, 0);
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P0_PPSE, NR_PDMA_PORT);
|
||||
/* multicast port1 map to GMAC1 */
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P1_PPSE, 1);
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P1_PPSE, NR_GMAC1_PORT);
|
||||
/* multicast port2 map to GMAC2 */
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P2_PPSE, 2);
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P2_PPSE, NR_GMAC2_PORT);
|
||||
/* multicast port3 map to QDMA */
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P3_PPSE, 5);
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P3_PPSE, NR_QDMA_PORT);
|
||||
/* multicast port4 map to GMAC3 */
|
||||
cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P4_PPSE, NR_GMAC3_PORT);
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
@@ -337,6 +587,7 @@ err1:
|
||||
int hnat_mcast_disable(void)
|
||||
{
|
||||
struct ppe_mcast_table *pmcast = hnat_priv->pmcast;
|
||||
int i;
|
||||
|
||||
if (!pmcast)
|
||||
return -EINVAL;
|
||||
@@ -344,10 +595,16 @@ int hnat_mcast_disable(void)
|
||||
if (hnat_priv->data->version == MTK_HNAT_V1_3)
|
||||
del_timer_sync(&hnat_priv->hnat_mcast_check_timer);
|
||||
|
||||
/* Disable multicast table lookup */
|
||||
for (i = 0; i < CFG_PPE_NUM; i++)
|
||||
cr_set_field(hnat_priv->ppe_base[i] + PPE_GLO_CFG, MCAST_TB_EN, 0);
|
||||
|
||||
flush_work(&pmcast->work);
|
||||
destroy_workqueue(pmcast->queue);
|
||||
sock_release(pmcast->msock);
|
||||
hnat_mcast_list_del_all();
|
||||
kfree(pmcast);
|
||||
hnat_priv->pmcast = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,18 +17,20 @@
|
||||
#define RTMGRP_MDB 0x2000000
|
||||
|
||||
#define MAX_MCAST_ENTRY 64
|
||||
#define MAX_MCAST_PORT 5
|
||||
|
||||
#define MCAST_TO_PDMA (0x1 << 0)
|
||||
#define MCAST_TO_GDMA1 (0x1 << 1)
|
||||
#define MCAST_TO_GDMA2 (0x1 << 2)
|
||||
struct ppe_mcast_list {
|
||||
struct list_head list; /* Protected by rwlock */
|
||||
u16 vid; /* vlan id */
|
||||
u8 dmac[ETH_ALEN]; /* multicast mac addr */
|
||||
u8 mc_port; /* multicast port */
|
||||
};
|
||||
|
||||
struct ppe_mcast_group {
|
||||
u32 mac_hi; /*multicast mac addr*/
|
||||
u16 mac_lo; /*multicast mac addr*/
|
||||
u16 vid;
|
||||
u8 mc_port; /*1:forward to cpu,2:forward to GDMA1,4:forward to GDMA2*/
|
||||
u8 eif; /*num of eth if added to multi group. */
|
||||
u8 oif; /* num of other if added to multi group ,ex wifi.*/
|
||||
u8 dmac[ETH_ALEN]; /* multicast mac addr */
|
||||
u8 if_num[MAX_MCAST_PORT]; /* num of if added to multi group. */
|
||||
u8 mc_port; /* 1:forward to cpu,2:forward to GDMA1,3:forward to GDMA2 */
|
||||
bool valid;
|
||||
};
|
||||
|
||||
@@ -37,24 +39,22 @@ struct ppe_mcast_table {
|
||||
struct work_struct work;
|
||||
struct socket *msock;
|
||||
struct ppe_mcast_group mtbl[MAX_MCAST_ENTRY];
|
||||
struct list_head mlist;
|
||||
u8 max_entry;
|
||||
rwlock_t mcast_lock; /* Protect list and mc_port field */
|
||||
};
|
||||
|
||||
struct ppe_mcast_h {
|
||||
union {
|
||||
u32 value;
|
||||
struct {
|
||||
u32 mc_vid:12;
|
||||
u32 mc_qos_qid54:2; /* mt7622 only */
|
||||
u32 valid:1;
|
||||
u32 rev1:1;
|
||||
/*0:forward to cpu,1:forward to GDMA1*/
|
||||
u32 mc_px_en:4;
|
||||
u32 mc_mpre_sel:2; /* 0=01:00, 2=33:33 */
|
||||
u32 mc_vid_cmp:1;
|
||||
u32 rev2:1;
|
||||
u32 mc_px_qos_en:4;
|
||||
u32 mc_qos_qid:4;
|
||||
u32 mc_vid : 12;
|
||||
u32 mc_qos_qid64 : 3;
|
||||
u32 mc_px_en : 5;
|
||||
u32 mc_mpre_sel : 2; /* 0=01:00, 1=33:33 */
|
||||
u32 mc_vid_cmp: 1;
|
||||
u32 mc_px_qos_en : 5;
|
||||
u32 mc_qos_qid : 4;
|
||||
} info;
|
||||
} u;
|
||||
};
|
||||
@@ -63,7 +63,29 @@ struct ppe_mcast_l {
|
||||
u32 addr;
|
||||
};
|
||||
|
||||
enum ppe_mcast_port {
|
||||
MCAST_TO_GDMA3,
|
||||
MCAST_TO_PDMA,
|
||||
MCAST_TO_GDMA1,
|
||||
MCAST_TO_GDMA2,
|
||||
MCAST_TO_QDMA,
|
||||
};
|
||||
|
||||
enum hnat_mcast_mode {
|
||||
HNAT_MCAST_MODE_MULTI = 0,
|
||||
HNAT_MCAST_MODE_UNI,
|
||||
};
|
||||
|
||||
#define IS_MCAST_MULTI_MODE (hnat_priv->data->mcast && mcast_mode == HNAT_MCAST_MODE_MULTI)
|
||||
#define IS_MCAST_UNI_MODE (hnat_priv->data->mcast && mcast_mode == HNAT_MCAST_MODE_UNI)
|
||||
#define IS_MCAST_PORT_GDM(port) \
|
||||
(port == (1 << MCAST_TO_GDMA1) || port == (1 << MCAST_TO_GDMA2) || \
|
||||
port == (1 << MCAST_TO_GDMA3))
|
||||
#define DMAC_TO_HI16(dmac) ((dmac[0] << 8) | dmac[1])
|
||||
#define DMAC_TO_LO32(dmac) ((dmac[2] << 24) | (dmac[3] << 16) | (dmac[4] << 8) | dmac[5])
|
||||
|
||||
int hnat_mcast_enable(u32 ppe_id);
|
||||
int hnat_mcast_disable(void);
|
||||
bool hnat_is_mcast_uni(struct sk_buff *skb);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,58 +6,110 @@
|
||||
|
||||
#include <linux/of_device.h>
|
||||
#include <net/netfilter/nf_flow_table.h>
|
||||
|
||||
#include "hnat.h"
|
||||
|
||||
u32 hnat_dsa_fill_stag(const struct net_device *netdev,
|
||||
int hnat_dsa_get_port(struct net_device **dev)
|
||||
{
|
||||
#if defined(CONFIG_NET_DSA)
|
||||
struct dsa_port *dp;
|
||||
|
||||
dp = dsa_port_from_netdev(*dev);
|
||||
if (IS_ERR(dp))
|
||||
return -ENODEV;
|
||||
|
||||
*dev = dp->cpu_dp->master;
|
||||
|
||||
return dp->index;
|
||||
#else
|
||||
return -ENODEV;
|
||||
#endif
|
||||
}
|
||||
|
||||
int hnat_dsa_fill_stag(const struct net_device *netdev,
|
||||
struct foe_entry *entry,
|
||||
struct flow_offload_hw_path *hw_path,
|
||||
u16 eth_proto,
|
||||
int mape)
|
||||
{
|
||||
const struct net_device *ndev;
|
||||
#if defined(CONFIG_NET_DSA)
|
||||
const unsigned int *port_reg;
|
||||
const struct dsa_port *dp;
|
||||
struct net_device *ndev;
|
||||
int port_index;
|
||||
u16 sp_tag;
|
||||
u16 dsa_tag;
|
||||
|
||||
if (hw_path->flags & FLOW_OFFLOAD_PATH_VLAN)
|
||||
if (hw_path->flags & BIT(DEV_PATH_VLAN))
|
||||
ndev = hw_path->dev;
|
||||
else
|
||||
ndev = netdev;
|
||||
ndev = (struct net_device *)netdev;
|
||||
|
||||
port_reg = of_get_property(ndev->dev.of_node, "reg", NULL);
|
||||
if (unlikely(!port_reg))
|
||||
return -EINVAL;
|
||||
|
||||
port_index = be32_to_cpup(port_reg);
|
||||
sp_tag = BIT(port_index);
|
||||
|
||||
if (!entry->bfib1.vlan_layer)
|
||||
entry->bfib1.vlan_layer = 1;
|
||||
else
|
||||
/* VLAN existence indicator */
|
||||
sp_tag |= BIT(8);
|
||||
entry->bfib1.vpm = 0;
|
||||
/* In the case MAPE LAN --> WAN, binding entry is to CPU.
|
||||
* Do not add special tag.
|
||||
*/
|
||||
if (IS_WAN(ndev) && mape)
|
||||
return port_index;
|
||||
|
||||
switch (eth_proto) {
|
||||
case ETH_P_IP:
|
||||
if (entry->ipv4_hnapt.bfib1.pkt_type == IPV4_DSLITE
|
||||
|| (entry->ipv4_hnapt.bfib1.pkt_type == IPV4_MAP_E))
|
||||
entry->ipv4_dslite.etype = sp_tag;
|
||||
dp = dsa_port_from_netdev(ndev);
|
||||
if (IS_ERR(dp))
|
||||
return -ENODEV;
|
||||
|
||||
if (IS_DSA_TAG_PROTO_MXL862_8021Q(dp)) {
|
||||
dsa_tag = port_index + BIT(11);
|
||||
|
||||
if (IS_IPV4_GRP(entry)) {
|
||||
/* PPE can only be filled up to 2 VLAN layers,
|
||||
* outer VLAN(vlan1) is preserved for stag.
|
||||
*/
|
||||
if (unlikely(entry->ipv4_hnapt.vlan2))
|
||||
return -EINVAL;
|
||||
else if (entry->ipv4_hnapt.vlan1)
|
||||
/* Move to inner VLAN if it's already set */
|
||||
entry->ipv4_hnapt.vlan2 = entry->ipv4_hnapt.vlan1;
|
||||
entry->ipv4_hnapt.vlan1 = dsa_tag;
|
||||
|
||||
entry->bfib1.vlan_layer = (entry->ipv4_hnapt.vlan1 != 0) +
|
||||
(entry->ipv4_hnapt.vlan2 != 0);
|
||||
} else {
|
||||
if (unlikely(entry->ipv6_5t_route.vlan2))
|
||||
return -EINVAL;
|
||||
else if (entry->ipv6_5t_route.vlan1)
|
||||
/* Move to inner VLAN if it's already set */
|
||||
entry->ipv6_5t_route.vlan2 = entry->ipv6_5t_route.vlan1;
|
||||
entry->ipv6_5t_route.vlan1 = dsa_tag;
|
||||
|
||||
entry->bfib1.vlan_layer = (entry->ipv6_5t_route.vlan1 != 0) +
|
||||
(entry->ipv6_5t_route.vlan2 != 0);
|
||||
}
|
||||
|
||||
entry->bfib1.vpm = 1;
|
||||
} else {
|
||||
dsa_tag = BIT(port_index);
|
||||
|
||||
if (!entry->bfib1.vlan_layer)
|
||||
entry->bfib1.vlan_layer = 1;
|
||||
else
|
||||
entry->ipv4_hnapt.etype = sp_tag;
|
||||
break;
|
||||
case ETH_P_IPV6:
|
||||
/* In the case MAPE LAN --> WAN, binding entry is to CPU.
|
||||
* Do not add special tag.
|
||||
*/
|
||||
if (!mape)
|
||||
/* etype offset of ipv6 entries are the same. */
|
||||
entry->ipv6_5t_route.etype = sp_tag;
|
||||
/* VLAN existence indicator */
|
||||
dsa_tag |= BIT(8);
|
||||
|
||||
break;
|
||||
default:
|
||||
pr_info("DSA + HNAT unsupport protocol\n");
|
||||
if (IS_IPV4_GRP(entry))
|
||||
entry->ipv4_hnapt.sp_tag = dsa_tag;
|
||||
else if (IS_IPV6_GRP(entry))
|
||||
entry->ipv6_5t_route.sp_tag = dsa_tag;
|
||||
else if (IS_L2_BRIDGE(entry))
|
||||
entry->l2_bridge.sp_tag = dsa_tag;
|
||||
|
||||
entry->bfib1.vpm = 0;
|
||||
}
|
||||
|
||||
return port_index;
|
||||
#else
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -44,7 +44,11 @@ struct hnat_desc {
|
||||
u32 is_sp : 1;
|
||||
u32 hf : 1;
|
||||
u32 amsdu : 1;
|
||||
u32 resv3 : 19;
|
||||
u32 tops : 6;
|
||||
u32 is_decap : 1;
|
||||
u32 cdrt : 8;
|
||||
u32 is_decrypt : 1;
|
||||
u32 resv3 : 3;
|
||||
u32 magic_tag_protect : 16;
|
||||
} __packed;
|
||||
#elif defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
|
||||
@@ -85,12 +89,36 @@ struct hnat_desc {
|
||||
#define HAS_HQOS_MAGIC_TAG(skb) (qos_toggle && skb->protocol == HQOS_MAGIC_TAG)
|
||||
|
||||
#define HNAT_MAGIC_TAG 0x6789
|
||||
#define HNAT_INFO_FILLED 0x7
|
||||
#define WIFI_INFO_LEN 6
|
||||
#define FOE_INFO_LEN (10 + WIFI_INFO_LEN)
|
||||
#define IS_SPACE_AVAILABLE_HEAD(skb) \
|
||||
((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))
|
||||
|
||||
#define skb_hnat_info(skb) ((struct hnat_desc *)(skb->head))
|
||||
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
|
||||
#define skb_hnat_tops(skb) (((struct hnat_desc *)((skb)->head))->tops)
|
||||
#define skb_hnat_is_decap(skb) (((struct hnat_desc *)((skb)->head))->is_decap)
|
||||
#define skb_hnat_is_encap(skb) (!skb_hnat_is_decap(skb))
|
||||
#define skb_hnat_set_tops(skb, tops) ((skb_hnat_tops(skb)) = (tops))
|
||||
#define skb_hnat_set_is_decap(skb, is_decap) ((skb_hnat_is_decap(skb)) = (is_decap))
|
||||
#define skb_hnat_cdrt(skb) (((struct hnat_desc *)((skb)->head))->cdrt)
|
||||
#define skb_hnat_is_decrypt(skb) (((struct hnat_desc *)((skb)->head))->is_decrypt)
|
||||
#define skb_hnat_is_encrypt(skb) (!skb_hnat_is_decrypt(skb))
|
||||
#define skb_hnat_set_cdrt(skb, cdrt) ((skb_hnat_cdrt(skb)) = (cdrt))
|
||||
#define skb_hnat_set_is_decrypt(skb, is_dec) ((skb_hnat_is_decrypt(skb)) = is_dec)
|
||||
#else /* !defined(CONFIG_MEDIATEK_NETSYS_V3) */
|
||||
#define skb_hnat_tops(skb) (0)
|
||||
#define skb_hnat_is_decap(skb) (0)
|
||||
#define skb_hnat_is_encap(skb) (0)
|
||||
#define skb_hnat_set_tops(skb, tops)
|
||||
#define skb_hnat_set_is_decap(skb, is_decap)
|
||||
#define skb_hnat_cdrt(skb) (0)
|
||||
#define skb_hnat_is_decrypt(skb) (0)
|
||||
#define skb_hnat_is_encrypt(skb) (0)
|
||||
#define skb_hnat_set_cdrt(skb, cdrt)
|
||||
#define skb_hnat_set_is_decrypt(skb, is_dec)
|
||||
#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
|
||||
#define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic)
|
||||
#define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)
|
||||
#define skb_hnat_entry(skb) (((struct hnat_desc *)(skb->head))->entry)
|
||||
@@ -134,6 +162,7 @@ struct hnat_desc {
|
||||
#define set_to_ppe(skb) (HNAT_SKB_CB2(skb)->magic = 0x78681415)
|
||||
#define is_from_extge(skb) (HNAT_SKB_CB2(skb)->magic == 0x78786688)
|
||||
#define is_magic_tag_valid(skb) (skb_hnat_magic_tag(skb) == HNAT_MAGIC_TAG)
|
||||
#define is_hnat_info_filled(skb) (skb_hnat_filled(skb) == HNAT_INFO_FILLED)
|
||||
#define set_from_mape(skb) (HNAT_SKB_CB2(skb)->magic = 0x78787788)
|
||||
#define is_from_mape(skb) (HNAT_SKB_CB2(skb)->magic == 0x78787788)
|
||||
#define is_unreserved_port(hdr) \
|
||||
@@ -164,6 +193,8 @@ struct hnat_desc {
|
||||
#define HIT_PRE_BIND 0x1A
|
||||
#define HIT_BIND_PACKET_SAMPLING 0x1B
|
||||
#define HIT_BIND_EXCEED_MTU 0x1C
|
||||
#define IPVERSION_V4 0x04
|
||||
#define IPVERSION_V6 0x06
|
||||
|
||||
#define TPORT_ID(x) ((x) & GENMASK(3, 0))
|
||||
#define TOPS_ENTRY(x) ((x) & GENMASK(5, 0))
|
||||
|
||||
@@ -45,7 +45,7 @@ static int mtk_sgmii_xfi_pll_init(struct mtk_sgmii *ss, struct device_node *r)
|
||||
|
||||
np = of_parse_phandle(r, "mediatek,xfi_pll", 0);
|
||||
if (!np)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
ss->pll = syscon_node_to_regmap(np);
|
||||
if (IS_ERR(ss->pll))
|
||||
@@ -77,96 +77,142 @@ int mtk_sgmii_link_status(struct mtk_sgmii_pcs *mpcs)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
|
||||
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
|
||||
return FIELD_GET(SGMII_LINK_STATYS, val);
|
||||
}
|
||||
|
||||
void mtk_sgmii_reset(struct mtk_eth *eth, int id)
|
||||
static void mtk_sgmii_get_state(struct mtk_sgmii_pcs *mpcs)
|
||||
{
|
||||
struct phylink_link_state *state = &mpcs->state;
|
||||
unsigned int bm, adv, rgc3, sgm_mode;
|
||||
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
state->interface = mpcs->interface;
|
||||
|
||||
regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
|
||||
if (bm & SGMII_AN_ENABLE) {
|
||||
regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
|
||||
|
||||
phylink_mii_c22_pcs_decode_state(state,
|
||||
FIELD_GET(SGMII_BMSR, bm),
|
||||
FIELD_GET(SGMII_LPA, adv));
|
||||
} else {
|
||||
state->link = !!(bm & SGMII_LINK_STATYS);
|
||||
|
||||
regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &sgm_mode);
|
||||
|
||||
switch (sgm_mode & SGMII_SPEED_MASK) {
|
||||
case SGMII_SPEED_10:
|
||||
state->speed = SPEED_10;
|
||||
break;
|
||||
case SGMII_SPEED_100:
|
||||
state->speed = SPEED_100;
|
||||
break;
|
||||
case SGMII_SPEED_1000:
|
||||
regmap_read(mpcs->regmap, mpcs->ana_rgc3, &rgc3);
|
||||
rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, rgc3);
|
||||
state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sgm_mode & SGMII_DUPLEX_HALF)
|
||||
state->duplex = DUPLEX_HALF;
|
||||
else
|
||||
state->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
}
|
||||
|
||||
void mtk_sgmii_reset(struct mtk_sgmii_pcs *mpcs)
|
||||
{
|
||||
struct mtk_eth *eth = mpcs->eth;
|
||||
int id = mpcs->id;
|
||||
u32 val = 0;
|
||||
|
||||
if (!eth->toprgu)
|
||||
if (id >= MTK_MAX_DEVS || !eth->toprgu)
|
||||
return;
|
||||
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
/* Enable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val |= SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_SGMII0_GRST;
|
||||
val |= SWSYSRST_SGMII0_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val |= SWSYSRST_XFI_PEXPT0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
|
||||
/* Assert SGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
|
||||
SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_SGMII0_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val |= SWSYSRST_XFI_PEXPT0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
|
||||
/* De-assert SGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_SGMII0_GRST);
|
||||
val &= ~SWSYSRST_SGMII0_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val &= ~SWSYSRST_XFI_PEXPT0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
/* Disable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_SGMII0_GRST);
|
||||
val &= ~SWSYSRST_SGMII0_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val &= ~SWSYSRST_XFI_PEXPT0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
break;
|
||||
case 1:
|
||||
/* Enable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val |= SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_SGMII1_GRST;
|
||||
val |= SWSYSRST_SGMII1_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val |= SWSYSRST_XFI_PEXPT1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
|
||||
/* Assert SGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
|
||||
SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_SGMII1_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val |= SWSYSRST_XFI_PEXPT1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
|
||||
/* De-assert SGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_SGMII1_GRST);
|
||||
val &= ~SWSYSRST_SGMII1_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val &= ~SWSYSRST_XFI_PEXPT1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
/* Disable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_SGMII1_GRST);
|
||||
val &= ~SWSYSRST_SGMII1_GRST;
|
||||
if (mpcs->regmap_pextp)
|
||||
val &= ~SWSYSRST_XFI_PEXPT1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
break;
|
||||
}
|
||||
|
||||
mdelay(1);
|
||||
}
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
|
||||
int mtk_sgmii_need_powerdown(struct mtk_sgmii_pcs *mpcs, unsigned int bmcr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* need to power down sgmii if link down */
|
||||
regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
|
||||
if (!(val & SGMII_LINK_STATYS))
|
||||
return true;
|
||||
|
||||
/* need to power down sgmii if autoneg change */
|
||||
if ((val & SGMII_AN_ENABLE) != bmcr)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
|
||||
@@ -226,7 +272,7 @@ void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
|
||||
/* Force AEQ on */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x02002800);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x20000000);
|
||||
/* Setup DA default value */
|
||||
@@ -257,28 +303,28 @@ void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
|
||||
/* Release reset */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200E800);
|
||||
udelay(150);
|
||||
usleep_range(150, 500);
|
||||
/* Switch to P0 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C101);
|
||||
udelay(15);
|
||||
usleep_range(15, 50);
|
||||
/* Switch to Gen2 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0201C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0201C101);
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
|
||||
0x00000030);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
|
||||
0x80201F01);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x30000000);
|
||||
udelay(400);
|
||||
usleep_range(400, 1000);
|
||||
}
|
||||
|
||||
void mtk_sgmii_setup_phya_gen2(struct mtk_sgmii_pcs *mpcs)
|
||||
@@ -338,7 +384,7 @@ void mtk_sgmii_setup_phya_gen2(struct mtk_sgmii_pcs *mpcs)
|
||||
/* Force AEQ on */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x02002800);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x20000000);
|
||||
/* Setup DA default value */
|
||||
@@ -367,28 +413,28 @@ void mtk_sgmii_setup_phya_gen2(struct mtk_sgmii_pcs *mpcs)
|
||||
/* Release reset */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200E800);
|
||||
udelay(150);
|
||||
usleep_range(150, 500);
|
||||
/* Switch to P0 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C101);
|
||||
udelay(15);
|
||||
usleep_range(15, 50);
|
||||
/* Switch to Gen2 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0201C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0201C101);
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
|
||||
0x00000030);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
|
||||
0x80201F01);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x30000000);
|
||||
udelay(400);
|
||||
usleep_range(400, 1000);
|
||||
}
|
||||
|
||||
static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
@@ -407,8 +453,6 @@ static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
if (advertise < 0)
|
||||
return advertise;
|
||||
|
||||
spin_lock(&mpcs->regmap_lock);
|
||||
|
||||
/* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
|
||||
* we assume that fixes it's speed at bitrate = line rate (in
|
||||
* other words, 1000Mbps or 2500Mbps).
|
||||
@@ -432,55 +476,63 @@ static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
speed = SGMII_SPEED_1000;
|
||||
}
|
||||
|
||||
if (mpcs->interface != interface ||
|
||||
mtk_sgmii_need_powerdown(mpcs, bmcr)) {
|
||||
link_timer = phylink_get_link_timer_ns(interface);
|
||||
if (link_timer < 0) {
|
||||
spin_unlock(&mpcs->regmap_lock);
|
||||
return link_timer;
|
||||
}
|
||||
link_timer = phylink_get_link_timer_ns(interface);
|
||||
if (link_timer < 0)
|
||||
return link_timer;
|
||||
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
|
||||
mtk_sgmii_xfi_pll_enable(eth->sgmii);
|
||||
mtk_sgmii_reset(eth, mpcs->id);
|
||||
}
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
|
||||
mtk_sgmii_xfi_pll_enable(eth->sgmii);
|
||||
mtk_sgmii_reset(mpcs);
|
||||
}
|
||||
|
||||
/* PHYA power down */
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
|
||||
SGMII_PHYA_PWD, SGMII_PHYA_PWD);
|
||||
|
||||
/* Reset SGMII PCS state */
|
||||
regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
|
||||
SGMII_SW_RESET, SGMII_SW_RESET);
|
||||
|
||||
/* Configure the interface polarity */
|
||||
if (MTK_HAS_FLAGS(mpcs->flags, MTK_SGMII_PN_SWAP))
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
|
||||
SGMII_PN_SWAP_MASK,
|
||||
SGMII_PN_SWAP_TX_RX);
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_2500BASEX)
|
||||
rgc3 = RG_PHY_SPEED_3_125G;
|
||||
else
|
||||
rgc3 = 0;
|
||||
|
||||
/* Configure the underlying interface speed */
|
||||
regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
|
||||
RG_PHY_SPEED_3_125G, rgc3);
|
||||
|
||||
/* Setup the link timer */
|
||||
regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
|
||||
link_timer / 2 / 8);
|
||||
mutex_lock(&mpcs->regmap_lock);
|
||||
|
||||
if (mode <= MLO_AN_INBAND && mpcs->interface != interface) {
|
||||
mpcs->interface = interface;
|
||||
mpcs->mode = mode;
|
||||
linkmode_copy(mpcs->advertising, advertising);
|
||||
mode_changed = true;
|
||||
}
|
||||
|
||||
/* PHYA power down */
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
|
||||
SGMII_PHYA_PWD, SGMII_PHYA_PWD);
|
||||
|
||||
/* Reset SGMII PCS state */
|
||||
regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
|
||||
SGMII_SW_RESET, SGMII_SW_RESET);
|
||||
|
||||
/* Configure the interface polarity */
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
|
||||
SGMII_PN_SWAP_MASK, mpcs->polarity);
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_2500BASEX)
|
||||
rgc3 = RG_PHY_SPEED_3_125G;
|
||||
else
|
||||
rgc3 = 0;
|
||||
|
||||
/* Configure the underlying interface speed */
|
||||
regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
|
||||
RG_PHY_SPEED_3_125G, rgc3);
|
||||
|
||||
/* Setup the link timer */
|
||||
regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
|
||||
link_timer / 2 / 8);
|
||||
|
||||
/* Update the advertisement, noting whether it has changed */
|
||||
regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
|
||||
SGMII_ADVERTISE, advertise, &changed);
|
||||
|
||||
if (eth->soc->caps == MT7987_CAPS) {
|
||||
/* Change the sgmsys clock source from PHYA */
|
||||
bmcr |= SGMII_PCS_REF_CK_SEL;
|
||||
|
||||
/* Change the sgmsys tx/rx buffer threshold */
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
|
||||
SGMII_TRX_BUF_THR_MASK,
|
||||
FIELD_PREP(SGMII_TRX_BUF_THR_MASK, 0x2111));
|
||||
}
|
||||
|
||||
/* Update the sgmsys mode register */
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
|
||||
SGMII_REMOTE_FAULT_DIS | SGMII_DUPLEX_HALF |
|
||||
@@ -489,74 +541,94 @@ static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
|
||||
/* Update the BMCR */
|
||||
regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
|
||||
SGMII_AN_ENABLE, bmcr);
|
||||
SGMII_AN_ENABLE | SGMII_PCS_REF_CK_SEL, bmcr);
|
||||
|
||||
/* Release PHYA power down state */
|
||||
usleep_range(50, 100);
|
||||
regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
|
||||
|
||||
if (mode_changed) {
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
|
||||
if (interface == PHY_INTERFACE_MODE_2500BASEX)
|
||||
mtk_sgmii_setup_phya_gen2(mpcs);
|
||||
else
|
||||
mtk_sgmii_setup_phya_gen1(mpcs);
|
||||
}
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
|
||||
if (interface == PHY_INTERFACE_MODE_2500BASEX)
|
||||
mtk_sgmii_setup_phya_gen2(mpcs);
|
||||
else
|
||||
mtk_sgmii_setup_phya_gen1(mpcs);
|
||||
}
|
||||
|
||||
spin_unlock(&mpcs->regmap_lock);
|
||||
mutex_unlock(&mpcs->regmap_lock);
|
||||
|
||||
return changed || mode_changed;
|
||||
}
|
||||
|
||||
static void mtk_sgmii_pcs_link_poll(struct work_struct *work)
|
||||
{
|
||||
struct mtk_sgmii_pcs *mpcs = container_of(work, struct mtk_sgmii_pcs,
|
||||
link_poll.work);
|
||||
|
||||
if ((mpcs->interface != PHY_INTERFACE_MODE_SGMII &&
|
||||
mpcs->interface != PHY_INTERFACE_MODE_1000BASEX &&
|
||||
mpcs->interface != PHY_INTERFACE_MODE_2500BASEX) ||
|
||||
(mpcs->link_poll_enable == false))
|
||||
goto exit;
|
||||
|
||||
if (!mtk_sgmii_link_status(mpcs))
|
||||
mtk_sgmii_pcs_config(&mpcs->pcs, UINT_MAX, mpcs->interface,
|
||||
mpcs->advertising, false);
|
||||
|
||||
exit:
|
||||
if (mpcs->mode == MLO_AN_INBAND)
|
||||
mtk_sgmii_get_state(mpcs);
|
||||
else if (!delayed_work_pending(&mpcs->link_poll))
|
||||
schedule_delayed_work(&mpcs->link_poll, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static int mtk_sgmii_pcs_enable(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
|
||||
|
||||
if (!delayed_work_pending(&mpcs->link_poll))
|
||||
schedule_delayed_work(&mpcs->link_poll, msecs_to_jiffies(1000));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_sgmii_pcs_disable(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
|
||||
|
||||
cancel_delayed_work_sync(&mpcs->link_poll);
|
||||
|
||||
if (mpcs->mode == MLO_AN_INBAND)
|
||||
mtk_sgmii_get_state(mpcs);
|
||||
}
|
||||
|
||||
static void mtk_sgmii_pcs_get_state(struct phylink_pcs *pcs,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
|
||||
unsigned int bm, adv, rgc3, sgm_mode;
|
||||
static unsigned long t_start;
|
||||
|
||||
state->interface = mpcs->interface;
|
||||
/* Passing the advertising and lp_advertising parameters to
|
||||
* phylink_mii_c22_pcs_decode_state()in mtk_sgmii_get_state().
|
||||
*/
|
||||
linkmode_copy(mpcs->state.advertising, state->advertising);
|
||||
linkmode_copy(mpcs->state.lp_advertising, state->lp_advertising);
|
||||
|
||||
regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
|
||||
if (bm & SGMII_AN_ENABLE) {
|
||||
regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
|
||||
|
||||
phylink_mii_c22_pcs_decode_state(state,
|
||||
FIELD_GET(SGMII_BMSR, bm),
|
||||
FIELD_GET(SGMII_LPA, adv));
|
||||
} else {
|
||||
state->link = !!(bm & SGMII_LINK_STATYS);
|
||||
|
||||
regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &sgm_mode);
|
||||
|
||||
switch (sgm_mode & SGMII_SPEED_MASK) {
|
||||
case SGMII_SPEED_10:
|
||||
state->speed = SPEED_10;
|
||||
break;
|
||||
case SGMII_SPEED_100:
|
||||
state->speed = SPEED_100;
|
||||
break;
|
||||
case SGMII_SPEED_1000:
|
||||
regmap_read(mpcs->regmap, mpcs->ana_rgc3, &rgc3);
|
||||
rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, rgc3);
|
||||
state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sgm_mode & SGMII_DUPLEX_HALF)
|
||||
state->duplex = DUPLEX_HALF;
|
||||
else
|
||||
state->duplex = DUPLEX_FULL;
|
||||
}
|
||||
/* When the interface of the mpcs is not initialized,
|
||||
* we should avoid overriding the state interface.
|
||||
*/
|
||||
if (mpcs->state.interface != PHY_INTERFACE_MODE_NA)
|
||||
state->interface = mpcs->state.interface;
|
||||
state->speed = mpcs->state.speed;
|
||||
state->duplex = mpcs->state.duplex;
|
||||
state->link = mpcs->state.link;
|
||||
|
||||
/* Reconfiguring SGMII every second to ensure that PCS can
|
||||
* link up with the Link Partner when a module is inserted.
|
||||
*/
|
||||
if (state->link == 0 && time_after(jiffies, t_start + HZ)) {
|
||||
t_start = jiffies;
|
||||
mtk_sgmii_pcs_config(pcs, MLO_AN_INBAND,
|
||||
state->interface, mpcs->advertising, false);
|
||||
if (time_after(jiffies, mpcs->link_poll_expire) &&
|
||||
!delayed_work_pending(&mpcs->link_poll)) {
|
||||
mpcs->link_poll_expire = jiffies + HZ;
|
||||
mpcs->state.an_enabled = state->an_enabled;
|
||||
schedule_delayed_work(&mpcs->link_poll, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,21 +650,20 @@ static void mtk_sgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
|
||||
int speed, int duplex)
|
||||
{
|
||||
struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
|
||||
struct device *dev = mpcs->eth->dev;
|
||||
unsigned int sgm_mode, val;
|
||||
unsigned long t_start = jiffies;
|
||||
|
||||
do {
|
||||
msleep(1000);
|
||||
msleep(100);
|
||||
|
||||
if (mtk_sgmii_link_status(mpcs))
|
||||
goto exit;
|
||||
|
||||
if (mode != MLO_AN_INBAND)
|
||||
mtk_sgmii_pcs_config(&mpcs->pcs, mode,
|
||||
interface, mpcs->advertising, false);
|
||||
} while (time_before(jiffies, t_start + msecs_to_jiffies(3000)));
|
||||
|
||||
pr_warn("%s wait link up timeout!\n", __func__);
|
||||
dev_warn(dev, "sgmii%d: wait link up timeout!\n", mpcs->id);
|
||||
return;
|
||||
|
||||
exit:
|
||||
/* If autoneg is enabled, the force speed and duplex
|
||||
@@ -620,6 +691,8 @@ exit:
|
||||
|
||||
static const struct phylink_pcs_ops mtk_sgmii_pcs_ops = {
|
||||
.pcs_config = mtk_sgmii_pcs_config,
|
||||
.pcs_enable = mtk_sgmii_pcs_enable,
|
||||
.pcs_disable = mtk_sgmii_pcs_disable,
|
||||
.pcs_get_state = mtk_sgmii_pcs_get_state,
|
||||
.pcs_an_restart = mtk_sgmii_pcs_restart_an,
|
||||
.pcs_link_up = mtk_sgmii_pcs_link_up,
|
||||
@@ -644,15 +717,27 @@ int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *r, u32 ana_rgc3)
|
||||
if (IS_ERR(ss->pcs[i].regmap))
|
||||
return PTR_ERR(ss->pcs[i].regmap);
|
||||
|
||||
ss->pcs[i].flags &= ~(MTK_SGMII_PN_SWAP);
|
||||
ss->pcs[i].polarity = 0;
|
||||
if (of_property_read_bool(np, "pn_swap"))
|
||||
ss->pcs[i].flags |= MTK_SGMII_PN_SWAP;
|
||||
ss->pcs[i].polarity |= SGMII_PN_SWAP_TX | SGMII_PN_SWAP_RX;
|
||||
else if (of_property_read_bool(np, "pn_swap_tx"))
|
||||
ss->pcs[i].polarity |= SGMII_PN_SWAP_TX;
|
||||
else if (of_property_read_bool(np, "pn_swap_rx"))
|
||||
ss->pcs[i].polarity |= SGMII_PN_SWAP_RX;
|
||||
|
||||
ss->pcs[i].pcs.ops = &mtk_sgmii_pcs_ops;
|
||||
ss->pcs[i].pcs.poll = true;
|
||||
ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
|
||||
|
||||
spin_lock_init(&ss->pcs[i].regmap_lock);
|
||||
ss->pcs[i].state.link = 0;
|
||||
ss->pcs[i].state.duplex = DUPLEX_FULL;
|
||||
ss->pcs[i].state.speed = SPEED_1000;
|
||||
|
||||
ss->pcs[i].link_poll_enable = true;
|
||||
INIT_DELAYED_WORK(&ss->pcs[i].link_poll, mtk_sgmii_pcs_link_poll);
|
||||
|
||||
mutex_init(&ss->pcs[i].regmap_lock);
|
||||
mutex_init(&ss->pcs[i].reset_lock);
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
@@ -670,9 +755,9 @@ int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *r, u32 ana_rgc3)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
|
||||
struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, unsigned int id)
|
||||
{
|
||||
if (!ss->pcs[id].regmap)
|
||||
if (id >= MTK_MAX_DEVS || !ss->pcs[id].regmap)
|
||||
return NULL;
|
||||
|
||||
return &ss->pcs[id].pcs;
|
||||
|
||||
@@ -41,7 +41,7 @@ int mtk_usxgmii_xfi_pll_init(struct mtk_usxgmii *ss, struct device_node *r)
|
||||
|
||||
np = of_parse_phandle(r, "mediatek,xfi_pll", 0);
|
||||
if (!np)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < MTK_MAX_DEVS; i++) {
|
||||
ss->pll = syscon_node_to_regmap(np);
|
||||
@@ -60,7 +60,7 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r)
|
||||
|
||||
np = of_parse_phandle(r, "mediatek,toprgu", 0);
|
||||
if (!np)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
eth->toprgu = syscon_node_to_regmap(np);
|
||||
if (IS_ERR(eth->toprgu))
|
||||
@@ -91,17 +91,32 @@ int mtk_mac2xgmii_id(struct mtk_eth *eth, int mac_id)
|
||||
u32 xgmii_id = mac_id;
|
||||
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
|
||||
switch (mac_id) {
|
||||
case MTK_GMAC1_ID:
|
||||
case MTK_GMAC2_ID:
|
||||
xgmii_id = 1;
|
||||
break;
|
||||
case MTK_GMAC3_ID:
|
||||
xgmii_id = 0;
|
||||
break;
|
||||
default:
|
||||
pr_info("[%s] Warning: get illegal mac_id=%d !=!!!\n",
|
||||
__func__, mac_id);
|
||||
if (eth->soc->caps == MT7988_CAPS) {
|
||||
switch (mac_id) {
|
||||
case MTK_GMAC1_ID:
|
||||
case MTK_GMAC2_ID:
|
||||
xgmii_id = 1;
|
||||
break;
|
||||
case MTK_GMAC3_ID:
|
||||
xgmii_id = 0;
|
||||
break;
|
||||
default:
|
||||
pr_info("[%s] Warning: get illegal mac_id=%d !=!!!\n",
|
||||
__func__, mac_id);
|
||||
}
|
||||
} else {
|
||||
switch (mac_id) {
|
||||
case MTK_GMAC1_ID:
|
||||
xgmii_id = 0;
|
||||
break;
|
||||
case MTK_GMAC2_ID:
|
||||
case MTK_GMAC3_ID:
|
||||
xgmii_id = 1;
|
||||
break;
|
||||
default:
|
||||
pr_info("[%s] Warning: get illegal mac_id=%d !=!!!\n",
|
||||
__func__, mac_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,16 +128,30 @@ int mtk_xgmii2mac_id(struct mtk_eth *eth, int xgmii_id)
|
||||
u32 mac_id = xgmii_id;
|
||||
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
|
||||
switch (xgmii_id) {
|
||||
case 0:
|
||||
mac_id = 2;
|
||||
break;
|
||||
case 1:
|
||||
mac_id = 1;
|
||||
break;
|
||||
default:
|
||||
pr_info("[%s] Warning: get illegal xgmii_id=%d !=!!!\n",
|
||||
__func__, xgmii_id);
|
||||
if (eth->soc->caps == MT7988_CAPS) {
|
||||
switch (xgmii_id) {
|
||||
case 0:
|
||||
mac_id = 2;
|
||||
break;
|
||||
case 1:
|
||||
mac_id = 1;
|
||||
break;
|
||||
default:
|
||||
pr_info("[%s] Warning: get illegal xgmii_id=%d !=!!!\n",
|
||||
__func__, xgmii_id);
|
||||
}
|
||||
} else {
|
||||
switch (xgmii_id) {
|
||||
case 0:
|
||||
mac_id = 0;
|
||||
break;
|
||||
case 1:
|
||||
mac_id = 2;
|
||||
break;
|
||||
default:
|
||||
pr_info("[%s] Warning: get illegal xgmii_id=%d !=!!!\n",
|
||||
__func__, xgmii_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +215,7 @@ void mtk_usxgmii_setup_phya_usxgmii(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Force AEQ on */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x02002800);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x20000000);
|
||||
/* Setup DA default value */
|
||||
@@ -219,28 +248,28 @@ void mtk_usxgmii_setup_phya_usxgmii(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Release reset */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200E800);
|
||||
udelay(150);
|
||||
usleep_range(150, 500);
|
||||
/* Switch to P0 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C101);
|
||||
udelay(15);
|
||||
usleep_range(15, 50);
|
||||
/* Switch to Gen3 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0202C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0202C101);
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
|
||||
0x00000030);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
|
||||
0x80201F00);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x30000000);
|
||||
udelay(400);
|
||||
usleep_range(400, 1000);
|
||||
}
|
||||
|
||||
void mtk_usxgmii_setup_phya_5gbaser(struct mtk_usxgmii_pcs *mpcs)
|
||||
@@ -300,7 +329,7 @@ void mtk_usxgmii_setup_phya_5gbaser(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Force AEQ on */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x02002800);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x20000000);
|
||||
/* Setup DA default value */
|
||||
@@ -333,28 +362,28 @@ void mtk_usxgmii_setup_phya_5gbaser(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Release reset */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200E800);
|
||||
udelay(150);
|
||||
usleep_range(150, 500);
|
||||
/* Switch to P0 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C101);
|
||||
udelay(15);
|
||||
usleep_range(15, 50);
|
||||
/* Switch to Gen3 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0202C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0202C101);
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
|
||||
0x00000030);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
|
||||
0x80201F00);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x30000000);
|
||||
udelay(400);
|
||||
usleep_range(400, 1000);
|
||||
}
|
||||
|
||||
void mtk_usxgmii_setup_phya_10gbaser(struct mtk_usxgmii_pcs *mpcs)
|
||||
@@ -414,7 +443,7 @@ void mtk_usxgmii_setup_phya_10gbaser(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Force AEQ on */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x02002800);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x20000000);
|
||||
/* Setup DA default value */
|
||||
@@ -450,34 +479,36 @@ void mtk_usxgmii_setup_phya_10gbaser(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Release reset */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200E800);
|
||||
udelay(150);
|
||||
usleep_range(150, 500);
|
||||
/* Switch to P0 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0200C101);
|
||||
udelay(15);
|
||||
usleep_range(15, 50);
|
||||
/* Switch to Gen3 */
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0202C111);
|
||||
ndelay(1020);
|
||||
usleep_range(1, 5);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
|
||||
0x0202C101);
|
||||
udelay(100);
|
||||
usleep_range(100, 500);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
|
||||
0x00000030);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
|
||||
0x80201F00);
|
||||
regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
|
||||
0x30000000);
|
||||
udelay(400);
|
||||
usleep_range(400, 1000);
|
||||
}
|
||||
|
||||
int mtk_usxgmii_link_status(struct mtk_usxgmii_pcs *mpcs)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
/* Refresh USXGMII link status by toggling RG_PCS_RX_STATUS_UPDATE */
|
||||
regmap_read(mpcs->regmap, RG_PCS_RX_STATUS0, &val);
|
||||
val |= RG_PCS_RX_STATUS_UPDATE;
|
||||
@@ -490,196 +521,39 @@ int mtk_usxgmii_link_status(struct mtk_usxgmii_pcs *mpcs)
|
||||
/* Read USXGMII link status */
|
||||
regmap_read(mpcs->regmap, RG_PCS_RX_STATUS0, &val);
|
||||
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
|
||||
return FIELD_GET(RG_PCS_RX_LINK_STATUS, val);
|
||||
}
|
||||
|
||||
void mtk_usxgmii_reset(struct mtk_eth *eth, int id)
|
||||
bool mtk_usxgmii_is_valid_ctle(struct mtk_usxgmii_pcs *mpcs)
|
||||
{
|
||||
u32 val = 0;
|
||||
unsigned int val, ctle;
|
||||
|
||||
if (id >= MTK_MAX_DEVS || !eth->toprgu)
|
||||
return;
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
/* Enable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val |= SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
regmap_write(mpcs->regmap_pextp, 0x00, 0x00000404);
|
||||
regmap_write(mpcs->regmap_pextp, 0x10, 0x00d600d5);
|
||||
regmap_read(mpcs->regmap_pextp, 0xd0, &val);
|
||||
|
||||
/* Assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
|
||||
SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
|
||||
udelay(100);
|
||||
ctle = FIELD_GET(GENMASK(12, 8), val);
|
||||
if (ctle > 10)
|
||||
return false;
|
||||
|
||||
/* De-assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
/* Disable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
break;
|
||||
case 1:
|
||||
/* Enable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val |= SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
|
||||
/* Assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
|
||||
SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
udelay(100);
|
||||
|
||||
/* De-assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
/* Disable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
break;
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
bool permit_pause_to_mac)
|
||||
static void mtk_usxgmii_get_state(struct mtk_usxgmii_pcs *mpcs)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
struct mtk_eth *eth = mpcs->eth;
|
||||
unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0;
|
||||
bool mode_changed = false;
|
||||
|
||||
spin_lock(&mpcs->regmap_lock);
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII) {
|
||||
an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) |
|
||||
USXGMII_AN_ENABLE;
|
||||
link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
|
||||
xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_10G) |
|
||||
FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_10G);
|
||||
} else if (interface == PHY_INTERFACE_MODE_10GKR) {
|
||||
an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF);
|
||||
link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
|
||||
xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_10G) |
|
||||
FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_10G);
|
||||
adapt_mode = USXGMII_RATE_UPDATE_MODE;
|
||||
} else if (interface == PHY_INTERFACE_MODE_5GBASER) {
|
||||
an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF);
|
||||
link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D);
|
||||
xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_5G) |
|
||||
FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_5G);
|
||||
adapt_mode = USXGMII_RATE_UPDATE_MODE;
|
||||
} else {
|
||||
spin_unlock(&mpcs->regmap_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1);
|
||||
|
||||
if (mpcs->interface != interface) {
|
||||
mpcs->interface = interface;
|
||||
mpcs->mode = mode;
|
||||
mode_changed = true;
|
||||
}
|
||||
|
||||
mtk_usxgmii_xfi_pll_enable(eth->usxgmii);
|
||||
mtk_usxgmii_reset(eth, mpcs->id);
|
||||
|
||||
/* Setup USXGMII AN ctrl */
|
||||
regmap_update_bits(mpcs->regmap, RG_PCS_AN_CTRL0,
|
||||
USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE,
|
||||
an_ctrl);
|
||||
|
||||
regmap_update_bits(mpcs->regmap, RG_PCS_AN_CTRL2,
|
||||
USXGMII_LINK_TIMER_IDLE_DETECT |
|
||||
USXGMII_LINK_TIMER_COMP_ACK_DETECT |
|
||||
USXGMII_LINK_TIMER_AN_RESTART,
|
||||
link_timer);
|
||||
|
||||
/* Gated MAC CK */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED);
|
||||
|
||||
/* Enable interface force mode */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN);
|
||||
|
||||
/* Setup USXGMII adapt mode */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE,
|
||||
adapt_mode);
|
||||
|
||||
/* Setup USXGMII speed */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE,
|
||||
xfi_mode);
|
||||
|
||||
udelay(1);
|
||||
|
||||
/* Un-gated MAC CK */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_MAC_CK_GATED, 0);
|
||||
|
||||
udelay(1);
|
||||
|
||||
/* Disable interface force mode for the AN mode */
|
||||
if (an_ctrl & USXGMII_AN_ENABLE)
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_IF_FORCE_EN, 0);
|
||||
|
||||
/* Setup USXGMIISYS with the determined property */
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII)
|
||||
mtk_usxgmii_setup_phya_usxgmii(mpcs);
|
||||
else if (interface == PHY_INTERFACE_MODE_10GKR)
|
||||
mtk_usxgmii_setup_phya_10gbaser(mpcs);
|
||||
else if (interface == PHY_INTERFACE_MODE_5GBASER)
|
||||
mtk_usxgmii_setup_phya_5gbaser(mpcs);
|
||||
|
||||
spin_unlock(&mpcs->regmap_lock);
|
||||
|
||||
return mode_changed;
|
||||
}
|
||||
|
||||
static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
struct phylink_link_state *state = &mpcs->state;
|
||||
struct mtk_eth *eth = mpcs->eth;
|
||||
struct mtk_mac *mac = eth->mac[mtk_xgmii2mac_id(eth, mpcs->id)];
|
||||
static unsigned long t_start;
|
||||
u32 val = 0;
|
||||
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
|
||||
if (FIELD_GET(USXGMII_AN_ENABLE, val)) {
|
||||
/* Refresh LPA by inverting LPA_LATCH */
|
||||
@@ -740,13 +614,257 @@ static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
|
||||
state->duplex = DUPLEX_FULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
}
|
||||
|
||||
void mtk_usxgmii_reset(struct mtk_usxgmii_pcs *mpcs)
|
||||
{
|
||||
struct mtk_eth *eth = mpcs->eth;
|
||||
int id = mpcs->id;
|
||||
u32 val = 0;
|
||||
|
||||
if (id >= MTK_MAX_DEVS || !eth->toprgu)
|
||||
return;
|
||||
|
||||
mutex_lock(&mpcs->reset_lock);
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
/* Enable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val |= SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
|
||||
/* Assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
|
||||
SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
usleep_range(100, 500);
|
||||
|
||||
/* De-assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
/* Disable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
|
||||
SWSYSRST_XFI0_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
break;
|
||||
case 1:
|
||||
/* Enable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val |= SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
|
||||
/* Assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
|
||||
SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST;
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
usleep_range(100, 500);
|
||||
|
||||
/* De-assert USXGMII reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
|
||||
val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
|
||||
|
||||
/* Disable software reset */
|
||||
regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
|
||||
val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
|
||||
SWSYSRST_XFI1_GRST);
|
||||
regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&mpcs->reset_lock);
|
||||
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
bool permit_pause_to_mac)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
struct mtk_eth *eth = mpcs->eth;
|
||||
unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0;
|
||||
bool mode_changed = false;
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII) {
|
||||
an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) |
|
||||
USXGMII_AN_ENABLE;
|
||||
link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
|
||||
xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_10G) |
|
||||
FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_10G);
|
||||
} else if (interface == PHY_INTERFACE_MODE_10GKR) {
|
||||
an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF);
|
||||
link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
|
||||
xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_10G) |
|
||||
FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_10G);
|
||||
adapt_mode = USXGMII_RATE_UPDATE_MODE;
|
||||
} else if (interface == PHY_INTERFACE_MODE_5GBASER) {
|
||||
an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF);
|
||||
link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) |
|
||||
FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D);
|
||||
xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_5G) |
|
||||
FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_5G);
|
||||
adapt_mode = USXGMII_RATE_UPDATE_MODE;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1);
|
||||
|
||||
mtk_usxgmii_xfi_pll_enable(eth->usxgmii);
|
||||
mtk_usxgmii_reset(mpcs);
|
||||
|
||||
mutex_lock(&mpcs->regmap_lock);
|
||||
|
||||
if (mode <= MLO_AN_INBAND && mpcs->interface != interface) {
|
||||
mpcs->interface = interface;
|
||||
mpcs->mode = mode;
|
||||
mode_changed = true;
|
||||
}
|
||||
|
||||
/* Configure the interface polarity */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_CTRL0,
|
||||
USXGMII_PN_SWAP_MASK, mpcs->polarity);
|
||||
|
||||
/* Setup USXGMII AN ctrl */
|
||||
regmap_update_bits(mpcs->regmap, RG_PCS_AN_CTRL0,
|
||||
USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE,
|
||||
an_ctrl);
|
||||
|
||||
regmap_update_bits(mpcs->regmap, RG_PCS_AN_CTRL2,
|
||||
USXGMII_LINK_TIMER_IDLE_DETECT |
|
||||
USXGMII_LINK_TIMER_COMP_ACK_DETECT |
|
||||
USXGMII_LINK_TIMER_AN_RESTART,
|
||||
link_timer);
|
||||
|
||||
/* Gated MAC CK */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED);
|
||||
|
||||
/* Enable interface force mode */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN);
|
||||
|
||||
/* Setup USXGMII adapt mode */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE,
|
||||
adapt_mode);
|
||||
|
||||
/* Setup USXGMII speed */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE,
|
||||
xfi_mode);
|
||||
|
||||
usleep_range(1, 5);
|
||||
|
||||
/* Un-gated MAC CK */
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_MAC_CK_GATED, 0);
|
||||
|
||||
usleep_range(1, 5);
|
||||
|
||||
/* Disable interface force mode for the AN mode */
|
||||
if (an_ctrl & USXGMII_AN_ENABLE)
|
||||
regmap_update_bits(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1,
|
||||
USXGMII_IF_FORCE_EN, 0);
|
||||
|
||||
/* Setup USXGMIISYS with the determined property */
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII)
|
||||
mtk_usxgmii_setup_phya_usxgmii(mpcs);
|
||||
else if (interface == PHY_INTERFACE_MODE_10GKR)
|
||||
mtk_usxgmii_setup_phya_10gbaser(mpcs);
|
||||
else if (interface == PHY_INTERFACE_MODE_5GBASER)
|
||||
mtk_usxgmii_setup_phya_5gbaser(mpcs);
|
||||
|
||||
mutex_unlock(&mpcs->regmap_lock);
|
||||
|
||||
return mode_changed;
|
||||
}
|
||||
|
||||
static void mtk_usxgmii_pcs_link_poll(struct work_struct *work)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = container_of(work, struct mtk_usxgmii_pcs,
|
||||
link_poll.work);
|
||||
|
||||
if ((mpcs->interface != PHY_INTERFACE_MODE_5GBASER &&
|
||||
mpcs->interface != PHY_INTERFACE_MODE_10GKR &&
|
||||
mpcs->interface != PHY_INTERFACE_MODE_USXGMII) ||
|
||||
(mpcs->link_poll_enable == false))
|
||||
goto exit;
|
||||
|
||||
if (!mtk_usxgmii_link_status(mpcs) || !mtk_usxgmii_is_valid_ctle(mpcs))
|
||||
mtk_usxgmii_pcs_config(&mpcs->pcs, UINT_MAX,
|
||||
mpcs->interface, NULL, false);
|
||||
|
||||
exit:
|
||||
if (mpcs->mode == MLO_AN_INBAND)
|
||||
mtk_usxgmii_get_state(mpcs);
|
||||
else if (!delayed_work_pending(&mpcs->link_poll))
|
||||
schedule_delayed_work(&mpcs->link_poll, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static int mtk_usxgmii_pcs_enable(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
|
||||
if (!delayed_work_pending(&mpcs->link_poll))
|
||||
schedule_delayed_work(&mpcs->link_poll, msecs_to_jiffies(1000));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
|
||||
cancel_delayed_work_sync(&mpcs->link_poll);
|
||||
|
||||
if (mpcs->mode == MLO_AN_INBAND)
|
||||
mtk_usxgmii_get_state(mpcs);
|
||||
}
|
||||
|
||||
static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
|
||||
if (mpcs->state.interface != PHY_INTERFACE_MODE_NA)
|
||||
state->interface = mpcs->state.interface;
|
||||
state->speed = mpcs->state.speed;
|
||||
state->duplex = mpcs->state.duplex;
|
||||
state->link = mpcs->state.link;
|
||||
|
||||
/* Reconfiguring USXGMII every second to ensure that PCS can
|
||||
* link up with the Link Partner when a module is inserted.
|
||||
*/
|
||||
if (state->link == 0 && time_after(jiffies, t_start + HZ)) {
|
||||
t_start = jiffies;
|
||||
mtk_usxgmii_pcs_config(pcs, MLO_AN_INBAND,
|
||||
state->interface, NULL, false);
|
||||
if (time_after(jiffies, mpcs->link_poll_expire) &&
|
||||
!delayed_work_pending(&mpcs->link_poll)) {
|
||||
mpcs->link_poll_expire = jiffies + HZ;
|
||||
mpcs->state.an_enabled = state->an_enabled;
|
||||
schedule_delayed_work(&mpcs->link_poll, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,35 +886,24 @@ static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
|
||||
int speed, int duplex)
|
||||
{
|
||||
struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
|
||||
struct device *dev = mpcs->eth->dev;
|
||||
unsigned long t_start = jiffies;
|
||||
unsigned int mpcs_mode;
|
||||
|
||||
/* Reconfiguring USXGMII to ensure the quality of the RX signal
|
||||
* after the line side link up.
|
||||
*/
|
||||
mtk_usxgmii_pcs_config(pcs, mode,
|
||||
interface, NULL, false);
|
||||
|
||||
do {
|
||||
msleep(1000);
|
||||
msleep(100);
|
||||
|
||||
if (mtk_usxgmii_link_status(mpcs))
|
||||
return;
|
||||
|
||||
spin_lock(&mpcs->regmap_lock);
|
||||
mpcs_mode = mpcs->mode;
|
||||
spin_unlock(&mpcs->regmap_lock);
|
||||
|
||||
if (mpcs_mode != MLO_AN_INBAND)
|
||||
mtk_usxgmii_pcs_config(&mpcs->pcs, mode,
|
||||
interface, NULL, false);
|
||||
} while (time_before(jiffies, t_start + msecs_to_jiffies(3000)));
|
||||
|
||||
pr_warn("%s wait link up timeout!\n", __func__);
|
||||
dev_warn(dev, "usxgmii%d: wait link up timeout!\n", mpcs->id);
|
||||
}
|
||||
|
||||
static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
|
||||
.pcs_config = mtk_usxgmii_pcs_config,
|
||||
.pcs_enable = mtk_usxgmii_pcs_enable,
|
||||
.pcs_disable = mtk_usxgmii_pcs_disable,
|
||||
.pcs_get_state = mtk_usxgmii_pcs_get_state,
|
||||
.pcs_an_restart = mtk_usxgmii_pcs_restart_an,
|
||||
.pcs_link_up = mtk_usxgmii_pcs_link_up,
|
||||
@@ -820,11 +927,27 @@ int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r)
|
||||
if (IS_ERR(ss->pcs[i].regmap))
|
||||
return PTR_ERR(ss->pcs[i].regmap);
|
||||
|
||||
ss->pcs[i].polarity = 0;
|
||||
if (of_property_read_bool(np, "pn_swap"))
|
||||
ss->pcs[i].polarity |= USXGMII_PN_SWAP_TX | USXGMII_PN_SWAP_RX;
|
||||
else if (of_property_read_bool(np, "pn_swap_tx"))
|
||||
ss->pcs[i].polarity |= USXGMII_PN_SWAP_TX;
|
||||
else if (of_property_read_bool(np, "pn_swap_rx"))
|
||||
ss->pcs[i].polarity |= USXGMII_PN_SWAP_RX;
|
||||
|
||||
ss->pcs[i].pcs.ops = &mtk_usxgmii_pcs_ops;
|
||||
ss->pcs[i].pcs.poll = true;
|
||||
ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
|
||||
|
||||
spin_lock_init(&ss->pcs[i].regmap_lock);
|
||||
ss->pcs[i].state.link = 0;
|
||||
ss->pcs[i].state.duplex = DUPLEX_FULL;
|
||||
ss->pcs[i].state.speed = SPEED_10000;
|
||||
|
||||
ss->pcs[i].link_poll_enable = true;
|
||||
INIT_DELAYED_WORK(&ss->pcs[i].link_poll, mtk_usxgmii_pcs_link_poll);
|
||||
|
||||
mutex_init(&ss->pcs[i].regmap_lock);
|
||||
mutex_init(&ss->pcs[i].reset_lock);
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
@@ -840,9 +963,9 @@ int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id)
|
||||
struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, unsigned int id)
|
||||
{
|
||||
if (!ss->pcs[id].regmap)
|
||||
if (id >= MTK_MAX_DEVS || !ss->pcs[id].regmap)
|
||||
return NULL;
|
||||
|
||||
return &ss->pcs[id].pcs;
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
#define EN8811H_MD32_DM "EthMD32.dm.bin"
|
||||
#define EN8811H_MD32_DSP "EthMD32.DSP.bin"
|
||||
#define EN8811H_IVY "ivypram.bin"
|
||||
|
||||
#define EN8811H_PHY_ID1 0x03a2
|
||||
#define EN8811H_PHY_ID2 0xa411
|
||||
#define EN8811H_PHY_ID ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2)
|
||||
#define EN8811H_PHY_READY 0x02
|
||||
#define EN8811H_PHY_IVY_READY 0xABC
|
||||
#define MAX_RETRY 25
|
||||
|
||||
#define EN8811H_TX_POL_NORMAL 0x1
|
||||
@@ -46,7 +48,7 @@
|
||||
#define MII_MMD_ADDR_DATA_REG 0x0e
|
||||
#define MMD_OP_MODE_DATA BIT(14)
|
||||
|
||||
#define EN8811H_DRIVER_VERSION "v1.2.5"
|
||||
#define EN8811H_DRIVER_VERSION "v1.3.0"
|
||||
|
||||
#define LED_ON_CTRL(i) (0x024 + ((i)*2))
|
||||
#define LED_ON_EN (1 << 15)
|
||||
@@ -86,20 +88,64 @@
|
||||
#define LED_BLK_DUR (0x023)
|
||||
#define LED_BLK_DUR_MASK (0xffff)
|
||||
|
||||
#define UNIT_LED_BLINK_DURATION 1024
|
||||
#define UNIT_LED_BLINK_DURATION 780
|
||||
|
||||
#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit)
|
||||
|
||||
#define INVALID_DATA 0xffff
|
||||
#define PBUS_INVALID_DATA 0xffffffff
|
||||
|
||||
/* MII Registers */
|
||||
#define AIR_AUX_CTRL_STATUS 0x1d
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
|
||||
|
||||
/* Registers on BUCKPBUS */
|
||||
#define EN8811H_2P5G_LPA 0x3b30
|
||||
#define EN8811H_2P5G_LPA_2P5G BIT(0)
|
||||
|
||||
#define EN8811H_FW_CTRL_1 0x0f0018
|
||||
#define EN8811H_FW_CTRL_1_START 0x0
|
||||
#define EN8811H_FW_CTRL_1_FINISH 0x1
|
||||
#define EN8811H_FW_CTRL_2 0x800000
|
||||
#define EN8811H_FW_CTRL_2_LOADING BIT(11)
|
||||
#define EN8811H_LOOP 0x800
|
||||
|
||||
#define NUM_ASI_REGS 5
|
||||
struct air_cable_test_rsl {
|
||||
int status[4];
|
||||
unsigned int length[4];
|
||||
};
|
||||
|
||||
struct en8811h_priv {
|
||||
struct dentry *debugfs_root;
|
||||
unsigned int dm_crc32;
|
||||
unsigned int dsp_crc32;
|
||||
char buf[512];
|
||||
unsigned int ivy_crc32;
|
||||
int pol;
|
||||
int surge;
|
||||
int cko;
|
||||
struct kobject *cable_kobj;
|
||||
int running_status;
|
||||
int pair[4];
|
||||
int an;
|
||||
int link;
|
||||
int speed;
|
||||
int duplex;
|
||||
int pause;
|
||||
int asym_pause;
|
||||
u16 on_crtl[3];
|
||||
u16 blk_crtl[3];
|
||||
u32 firmware_version;
|
||||
bool mcu_needs_restart;
|
||||
bool mcu_load;
|
||||
int debug;
|
||||
int phy_handle;
|
||||
int init_stage;
|
||||
int need_an;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct air_base_t_led_cfg {
|
||||
@@ -109,6 +155,18 @@ struct air_base_t_led_cfg {
|
||||
u16 on_cfg;
|
||||
u16 blk_cfg;
|
||||
};
|
||||
|
||||
enum air_init_stage {
|
||||
AIR_INIT_START,
|
||||
AIR_INIT_CONFIG,
|
||||
AIR_INIT_FW_LOADING,
|
||||
AIR_INIT_FW_READY,
|
||||
AIR_INIT_SUCESS,
|
||||
AIR_INIT_FW_FAIL,
|
||||
AIR_INIT_FAIL,
|
||||
AIR_INIT_LAST
|
||||
};
|
||||
|
||||
enum air_led_gpio {
|
||||
AIR_LED2_GPIO3 = 3,
|
||||
AIR_LED1_GPIO4,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,10 +15,12 @@
|
||||
#define phydev_mdio_bus(_dev) (_dev->bus)
|
||||
#define phydev_addr(_dev) (_dev->addr)
|
||||
#define phydev_dev(_dev) (&_dev->dev)
|
||||
#define phydev_kobj(_dev) (&_dev->dev.kobj)
|
||||
#else
|
||||
#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
|
||||
#define phydev_addr(_dev) (_dev->mdio.addr)
|
||||
#define phydev_dev(_dev) (&_dev->mdio.dev)
|
||||
#define phydev_kobj(_dev) (&_dev->mdio.dev.kobj)
|
||||
#endif
|
||||
|
||||
#define DEBUGFS_COUNTER "counter"
|
||||
@@ -31,8 +33,42 @@
|
||||
#define DEBUGFS_DBG_REG_SHOW "dbg_regs_show"
|
||||
#define DEBUGFS_TEMPERATURE "temp"
|
||||
#define DEBUGFS_LP_SPEED "lp_speed"
|
||||
#define DEBUGFS_MII_CL22_OP "cl22_op"
|
||||
#define DEBUGFS_MII_CL45_OP "cl45_op"
|
||||
#define DEBUGFS_MII_CL22_OP "cl22_op"
|
||||
#define DEBUGFS_MII_CL45_OP "cl45_op"
|
||||
#define DEBUGFS_CABLE_DIAG "cable_diag"
|
||||
#define DEBUGFS_LED_MODE "led_mode"
|
||||
#define DEBUGFS_TX_COMP "tx_comp"
|
||||
|
||||
#define CMD_MAX_LENGTH 128
|
||||
|
||||
/* bits range: for example AIR_BITS_RANGE(16, 4) = 0x0F0000 */
|
||||
#ifndef AIR_BITS_RANGE
|
||||
#define AIR_BITS_RANGE(offset, range) GENMASK((offset) + (range) - 1U, (offset))
|
||||
#endif /* End of AIR_BITS_RANGE */
|
||||
|
||||
/* bits offset right: for example AIR_BITS_OFF_R(0x1234, 8, 4) = 0x2 */
|
||||
#ifndef AIR_BITS_OFF_R
|
||||
#define AIR_BITS_OFF_R(val, offset, range) (((val) >> (offset)) & GENMASK((range) - 1U, 0))
|
||||
#endif /* End of AIR_BITS_OFF_R */
|
||||
|
||||
/* bits offset left: for example AIR_BITS_OFF_L(0x1234, 8, 4) = 0x400 */
|
||||
#ifndef AIR_BITS_OFF_L
|
||||
#define AIR_BITS_OFF_L(val, offset, range) (((val) & GENMASK((range) - 1U, 0)) << (offset))
|
||||
#endif /* End of AIR_BITS_OFF_L */
|
||||
|
||||
#define AIR_EN8811H_SET_VALUE(__out__, __val__, __offset__, __length__) \
|
||||
{ \
|
||||
(__out__) &= ~AIR_BITS_RANGE((__offset__), (__length__)); \
|
||||
(__out__) |= AIR_BITS_OFF_L((__val__), (__offset__), (__length__)); \
|
||||
}
|
||||
|
||||
#define CTL1000_PORT_TYPE (0x0400)
|
||||
#define CTL1000_TEST_NORMAL (0x0000)
|
||||
#define CTL1000_TEST_TM1 (0x2000)
|
||||
#define CTL1000_TEST_TM2 (0x4000)
|
||||
#define CTL1000_TEST_TM3 (0x6000)
|
||||
#define CTL1000_TEST_TM4 (0x8000)
|
||||
#define MMD_DEV_VSPEC1 (0x1e)
|
||||
|
||||
enum air_port_mode {
|
||||
AIR_PORT_MODE_FORCE_100,
|
||||
@@ -64,6 +100,104 @@ enum air_link_mode_bit {
|
||||
AIR_LINK_MODE_2500baseT_Full_BIT = 5,
|
||||
};
|
||||
|
||||
enum air_led_force {
|
||||
AIR_LED_NORMAL = 0,
|
||||
AIR_LED_FORCE_OFF,
|
||||
AIR_LED_FORCE_ON,
|
||||
AIR_LED_FORCE_LAST = 0xff,
|
||||
};
|
||||
|
||||
enum air_para {
|
||||
AIR_PARA_PRIV,
|
||||
AIR_PARA_PHYDEV,
|
||||
AIR_PARA_LAST = 0xff
|
||||
};
|
||||
|
||||
enum air_port_cable_status {
|
||||
AIR_PORT_CABLE_STATUS_ERROR,
|
||||
AIR_PORT_CABLE_STATUS_OPEN,
|
||||
AIR_PORT_CABLE_STATUS_SHORT,
|
||||
AIR_PORT_CABLE_STATUS_NORMAL,
|
||||
AIR_PORT_CABLE_STATUS_LAST = 0xff
|
||||
};
|
||||
|
||||
enum air_surge {
|
||||
AIR_SURGE_0R,
|
||||
AIR_SURGE_5R,
|
||||
AIR_SURGE_LAST = 0xff
|
||||
};
|
||||
|
||||
enum air_port_cable_test_pair {
|
||||
AIR_PORT_CABLE_TEST_PAIR_A,
|
||||
AIR_PORT_CABLE_TEST_PAIR_B,
|
||||
AIR_PORT_CABLE_TEST_PAIR_C,
|
||||
AIR_PORT_CABLE_TEST_PAIR_D,
|
||||
AIR_PORT_CABLE_TEST_PAIR_ALL,
|
||||
AIR_PORT_CABLE_TEST_PAIR_LAST
|
||||
};
|
||||
|
||||
enum air_cko {
|
||||
AIR_CKO_DIS,
|
||||
AIR_CKO_EN,
|
||||
AIR_CKO_LAST = 0xff
|
||||
};
|
||||
|
||||
enum air_tx_comp_mode {
|
||||
AIR_TX_COMP_MODE_100M_PAIR_A,
|
||||
AIR_TX_COMP_MODE_100M_PAIR_B,
|
||||
AIR_TX_COMP_MODE_100M_PAIR_A_DISCRETE,
|
||||
AIR_TX_COMP_MODE_100M_PAIR_B_DISCRETE,
|
||||
AIR_TX_COMP_MODE_1000M_TM1,
|
||||
AIR_TX_COMP_MODE_1000M_TM2,
|
||||
AIR_TX_COMP_MODE_1000M_TM3,
|
||||
AIR_TX_COMP_MODE_1000M_TM4_TD,
|
||||
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_A,
|
||||
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_B,
|
||||
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_C,
|
||||
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_D,
|
||||
AIR_TX_COMP_MODE_2500M_TM1,
|
||||
AIR_TX_COMP_MODE_2500M_TM2,
|
||||
AIR_TX_COMP_MODE_2500M_TM3,
|
||||
AIR_TX_COMP_MODE_2500M_TM4_TONE_1,
|
||||
AIR_TX_COMP_MODE_2500M_TM4_TONE_2,
|
||||
AIR_TX_COMP_MODE_2500M_TM4_TONE_3,
|
||||
AIR_TX_COMP_MODE_2500M_TM4_TONE_4,
|
||||
AIR_TX_COMP_MODE_2500M_TM4_TONE_5,
|
||||
AIR_TX_COMP_MODE_2500M_TM5,
|
||||
AIR_TX_COMP_MODE_2500M_TM6,
|
||||
AIR_TX_COMP_MODE_LAST = 0xFF,
|
||||
};
|
||||
|
||||
struct trrg_param_s {
|
||||
unsigned int TrRG_LSB :5;
|
||||
unsigned int Reserved_21 :3;
|
||||
unsigned int TrRG_MSB :5;
|
||||
unsigned int Reserved_29 :3;
|
||||
unsigned int Reserved_0 :1;
|
||||
unsigned int DATA_ADDR :6;
|
||||
unsigned int NODE_ADDR :4;
|
||||
unsigned int CH_ADDR :2;
|
||||
unsigned int WR_RD_CTRL :1;
|
||||
unsigned int Reserved_14 :1;
|
||||
unsigned int PKT_XMT_STA :1;
|
||||
};
|
||||
|
||||
union trrgdesc_s {
|
||||
struct trrg_param_s param;
|
||||
unsigned short Raw[2];
|
||||
unsigned int DescVal;
|
||||
};
|
||||
|
||||
struct trrg_s {
|
||||
union trrgdesc_s TrRGDesc;
|
||||
unsigned int RgMask;
|
||||
};
|
||||
|
||||
struct hal_tr_data_s {
|
||||
unsigned short data_lo;
|
||||
unsigned char data_hi;
|
||||
};
|
||||
|
||||
#ifndef unlikely
|
||||
# define unlikely(x) (x)
|
||||
#endif
|
||||
@@ -84,7 +218,10 @@ unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
|
||||
int air_buckpbus_reg_write(struct phy_device *phydev,
|
||||
unsigned int pbus_address, unsigned int pbus_data);
|
||||
int en8811h_of_init(struct phy_device *phydev);
|
||||
int air_surge_5ohm_config(struct phy_device *phydev);
|
||||
int air_surge_protect_cfg(struct phy_device *phydev);
|
||||
int air_ref_clk_speed(struct phy_device *phydev, int para);
|
||||
int air_cko_cfg(struct phy_device *phydev);
|
||||
int airoha_control_flag(struct phy_device *phydev, int mask, int val);
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
int airphy_debugfs_init(struct phy_device *phydev);
|
||||
void airphy_debugfs_remove(struct phy_device *phydev);
|
||||
|
||||
@@ -35,7 +35,11 @@ MODULE_LICENSE("GPL");
|
||||
* GPIO3 <-> BASE_T_LED2,
|
||||
**************************/
|
||||
/* User-defined.B */
|
||||
/*#define AIR_MD32_FW_CHECK*/
|
||||
/* #define AIR_MD32_FW_CHECK */
|
||||
/* #define AIR_IVY_LOAD */
|
||||
#ifdef AIR_IVY_LOAD
|
||||
/* #define AIR_IVY_CHECK */
|
||||
#endif
|
||||
#define AIR_LED_SUPPORT
|
||||
#ifdef AIR_LED_SUPPORT
|
||||
static const struct air_base_t_led_cfg led_cfg[3] = {
|
||||
@@ -53,17 +57,20 @@ static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
|
||||
/***********************************************************
|
||||
* F U N C T I O N S
|
||||
***********************************************************/
|
||||
#ifdef AIR_MD32_FW_CHECK
|
||||
static void air_mdio_read_buf(struct phy_device *phydev, unsigned long address,
|
||||
const struct firmware *fw, unsigned int *crc32)
|
||||
{
|
||||
unsigned int write_data, offset;
|
||||
int ret = 0, len = 0;
|
||||
unsigned int offset;
|
||||
int ret = 0;
|
||||
unsigned int pbus_data_low, pbus_data_high;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int addr = phydev_addr(phydev);
|
||||
char *buf = kmalloc(fw->size, GFP_KERNEL);
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
memset(buf, '\0', fw->size);
|
||||
/* page 4 */
|
||||
ret |= air_mii_cl22_write(mbus, addr, 0x1F, 4);
|
||||
@@ -90,7 +97,7 @@ static void air_mdio_read_buf(struct phy_device *phydev, unsigned long address,
|
||||
__func__, address, ret);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
static int air_mdio_write_buf(struct phy_device *phydev,
|
||||
unsigned long address, const struct firmware *fw)
|
||||
{
|
||||
@@ -144,7 +151,113 @@ static int air_mdio_write_buf(struct phy_device *phydev,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#ifdef AIR_IVY_LOAD
|
||||
static int modify_reg_bits(struct phy_device *phydev,
|
||||
unsigned int reg, unsigned int mask, unsigned int set)
|
||||
{
|
||||
unsigned int write_data;
|
||||
int ret;
|
||||
|
||||
write_data = air_buckpbus_reg_read(phydev, reg);
|
||||
write_data &= ~mask;
|
||||
write_data |= set;
|
||||
ret = air_buckpbus_reg_write(phydev, reg, write_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int air_mdio_load_ivy(struct phy_device *phydev,
|
||||
unsigned long address, const struct firmware *fw)
|
||||
{
|
||||
unsigned int write_data = 0, offset, read_data;
|
||||
int ret = 0, retry;
|
||||
#ifdef AIR_IVY_CHECK
|
||||
int error = 0;
|
||||
#endif
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev,
|
||||
0xcf924, 0x12);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
write_data = air_buckpbus_reg_read(phydev, 0xcfa28);
|
||||
write_data |= BIT(0);
|
||||
ret = air_buckpbus_reg_write(phydev,
|
||||
0xcfa28, write_data);
|
||||
write_data = air_buckpbus_reg_read(phydev, 0xcfa28);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(100);
|
||||
for (offset = 0; offset < fw->size; offset += 4) {
|
||||
write_data = (fw->data[offset + 3] << 24) | (fw->data[offset + 2] << 16);
|
||||
write_data |= ((fw->data[offset + 1] << 8) | fw->data[offset]);
|
||||
ret = air_buckpbus_reg_write(phydev,
|
||||
address, write_data);
|
||||
#ifdef AIR_IVY_CHECK
|
||||
read_data = air_buckpbus_reg_read(phydev, address);
|
||||
if (write_data != read_data) {
|
||||
dev_info(dev, "%x: write_data(0x%x) != read_data(0x%x)\n",
|
||||
address, write_data, read_data);
|
||||
error++;
|
||||
}
|
||||
#endif
|
||||
address += 1;
|
||||
}
|
||||
#ifdef AIR_IVY_CHECK
|
||||
if (error)
|
||||
dev_err(dev, "Check ivy Fail(%d)\n", error);
|
||||
else
|
||||
dev_err(dev, "Check ivy Pass\n");
|
||||
#endif
|
||||
ret = modify_reg_bits(phydev, 0xCFA28, BIT(0), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = modify_reg_bits(phydev, 0xCFA28, 0, BIT(16));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret |= air_buckpbus_reg_write(phydev,
|
||||
0xDC065, 0x80);
|
||||
ret |= air_buckpbus_reg_write(phydev,
|
||||
0xDC064, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
retry = 5;
|
||||
do {
|
||||
msleep(300);
|
||||
ret = air_buckpbus_reg_write(phydev,
|
||||
0xDC064, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
write_data = air_buckpbus_reg_read(phydev, 0xDC065);
|
||||
if (write_data == 0x80)
|
||||
break;
|
||||
if (!retry)
|
||||
dev_err(dev, "0xDC065 is not ready.(0x%x)\n", write_data);
|
||||
} while (retry--);
|
||||
|
||||
ret = modify_reg_bits(phydev, 0xCFA28, BIT(16), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = modify_reg_bits(phydev, 0xCFA28, 0, BIT(24));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
retry = 10;
|
||||
do {
|
||||
msleep(300);
|
||||
write_data = air_buckpbus_reg_read(phydev, 0xCFA38);
|
||||
if (write_data == EN8811H_PHY_IVY_READY) {
|
||||
dev_info(dev, "IVY ready!\n");
|
||||
break;
|
||||
}
|
||||
if (!retry)
|
||||
dev_err(dev, "IVY is not ready.(0x%x)\n", write_data);
|
||||
} while (retry--);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static int en8811h_load_firmware(struct phy_device *phydev)
|
||||
{
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
@@ -158,6 +271,27 @@ static int en8811h_load_firmware(struct phy_device *phydev)
|
||||
#endif
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
|
||||
priv->init_stage = AIR_INIT_FW_LOADING;
|
||||
#ifdef AIR_IVY_LOAD
|
||||
firmware = EN8811H_IVY;
|
||||
ret = request_firmware_direct(&fw, firmware, dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"failed to load firmware %s, ret: %d\n", firmware, ret);
|
||||
return ret;
|
||||
}
|
||||
priv->ivy_crc32 = ~crc32(~0, fw->data, fw->size);
|
||||
dev_info(dev, "%s: crc32=0x%x\n",
|
||||
firmware, ~crc32(~0, fw->data, fw->size));
|
||||
/* Download ivy */
|
||||
ret = air_mdio_load_ivy(phydev, 0xd4000, fw);
|
||||
release_firmware(fw);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"air_mdio_write_buf 0xd4000 fail, ret: %d\n", ret);
|
||||
goto release;
|
||||
}
|
||||
#endif
|
||||
ret = air_buckpbus_reg_write(phydev,
|
||||
0x0f0018, 0x0);
|
||||
if (ret < 0)
|
||||
@@ -228,13 +362,13 @@ static int en8811h_load_firmware(struct phy_device *phydev)
|
||||
return ret;
|
||||
msleep(100);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x0f0018);
|
||||
retry--;
|
||||
if (retry == 0) {
|
||||
dev_err(dev,
|
||||
"Release Software Reset fail , ret: %d\n",
|
||||
pbus_value);
|
||||
break;
|
||||
goto release;
|
||||
}
|
||||
retry--;
|
||||
} while (pbus_value != 0x1);
|
||||
dev_info(dev,
|
||||
"Release Software Reset successful.\n");
|
||||
@@ -250,6 +384,41 @@ release:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int en8811h_init_up(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0, retry, reg_value;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
unsigned int pbus_value;
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
|
||||
dev_info(dev, "%s start\n", __func__);
|
||||
ret = en8811h_load_firmware(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "EN8811H load firmware fail.\n");
|
||||
return ret;
|
||||
}
|
||||
retry = MAX_RETRY;
|
||||
do {
|
||||
mdelay(300);
|
||||
reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
|
||||
if (reg_value == EN8811H_PHY_READY) {
|
||||
dev_info(dev, "EN8811H PHY ready!\n");
|
||||
priv->init_stage = AIR_INIT_FW_READY;
|
||||
break;
|
||||
}
|
||||
if (retry == 0) {
|
||||
dev_err(dev, "MD32 FW is not ready.(Status 0x%x)\n", reg_value);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_err(dev,
|
||||
"Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
|
||||
dev_err(dev,
|
||||
"%s fail!\n", __func__);
|
||||
priv->init_stage = AIR_INIT_FW_FAIL;
|
||||
}
|
||||
} while (retry--);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef AIR_LED_SUPPORT
|
||||
static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity,
|
||||
int polar, u16 on_evt, u16 blk_evt)
|
||||
@@ -322,6 +491,7 @@ static int en8811h_led_init(struct phy_device *phydev)
|
||||
u16 cl45_data = led_dur;
|
||||
int ret = 0, id;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
|
||||
ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
|
||||
if (ret < 0)
|
||||
@@ -357,6 +527,10 @@ static int en8811h_led_init(struct phy_device *phydev)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
priv->on_crtl[id] = air_mii_cl45_read(phydev, 0x1f,
|
||||
LED_ON_CTRL(id));
|
||||
priv->blk_crtl[id] = air_mii_cl45_read(phydev, 0x1f,
|
||||
LED_BLK_CTRL(id));
|
||||
}
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0xcf8b8) | led_gpio;
|
||||
ret = air_buckpbus_reg_write(phydev, 0xcf8b8, reg_value);
|
||||
@@ -366,6 +540,7 @@ static int en8811h_led_init(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
#endif /* AIR_LED_SUPPORT */
|
||||
|
||||
#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
|
||||
static int en8811h_get_features(struct phy_device *phydev)
|
||||
{
|
||||
@@ -386,11 +561,13 @@ static int en8811h_get_features(struct phy_device *phydev)
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
return 0;
|
||||
}
|
||||
@@ -399,12 +576,11 @@ static int en8811h_get_features(struct phy_device *phydev)
|
||||
static int en8811h_probe(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
int reg_value, pid1 = 0, pid2 = 0;
|
||||
u32 retry, pbus_value = 0;
|
||||
int pid1 = 0, pid2 = 0;
|
||||
u32 pbus_value = 0;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int addr = phydev_addr(phydev);
|
||||
|
||||
struct en8811h_priv *priv;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
@@ -414,23 +590,30 @@ static int en8811h_probe(struct phy_device *phydev)
|
||||
ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
|
||||
pid1 = air_mii_cl22_read(mbus, addr, MII_PHYSID1);
|
||||
pid2 = air_mii_cl22_read(mbus, addr, MII_PHYSID2);
|
||||
dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
|
||||
if ((pid1 != EN8811H_PHY_ID1) || (pid2 != EN8811H_PHY_ID2)) {
|
||||
dev_err(dev, "EN8811H dose not exist!!\n");
|
||||
kfree(priv);
|
||||
return -ENODEV;
|
||||
goto priv_free;
|
||||
}
|
||||
|
||||
priv->init_stage = AIR_INIT_START;
|
||||
ret = air_buckpbus_reg_write(phydev, 0x1e00d0, 0xf);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1e0228, 0xf0);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
|
||||
priv->mcu_needs_restart = false;
|
||||
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xcf914);
|
||||
dev_info(dev, "Bootmode: %s\n",
|
||||
(GET_BIT(pbus_value, 24) ? "Flash" : "Download Code"));
|
||||
|
||||
ret = en8811h_load_firmware(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "EN8811H load firmware fail.\n");
|
||||
ret = en8811h_of_init(phydev);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
ret = airphy_debugfs_init(phydev);
|
||||
if (ret < 0) {
|
||||
@@ -439,69 +622,68 @@ static int en8811h_probe(struct phy_device *phydev)
|
||||
goto priv_free;
|
||||
}
|
||||
#endif /* CONFIG_AIROHA_EN8811H_PHY_DEBUGFS */
|
||||
retry = MAX_RETRY;
|
||||
do {
|
||||
mdelay(300);
|
||||
reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
|
||||
if (reg_value == EN8811H_PHY_READY) {
|
||||
dev_info(dev, "EN8811H PHY ready!\n");
|
||||
break;
|
||||
}
|
||||
retry--;
|
||||
} while (retry);
|
||||
if (retry == 0) {
|
||||
dev_err(dev, "MD32 FW is not ready.(Status 0x%x)\n", reg_value);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_err(dev,
|
||||
"Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
|
||||
dev_err(dev,
|
||||
"EN8811H initialize fail!\n");
|
||||
goto priv_free;
|
||||
}
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
/* Serdes polarity */
|
||||
ret = en8811h_of_init(phydev);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
pbus_value &= ~0x3;
|
||||
#if defined(CONFIG_OF)
|
||||
pbus_value |= priv->pol;
|
||||
#else
|
||||
pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
|
||||
#endif
|
||||
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_info(dev, "MD32 FW Version : %08x\n", pbus_value);
|
||||
if (priv->surge) {
|
||||
ret = air_surge_5ohm_config(phydev);
|
||||
|
||||
if (priv->phy_handle) {
|
||||
dev_info(dev, "EN8811H Probe OK! (%s)\n", EN8811H_DRIVER_VERSION);
|
||||
} else {
|
||||
ret = en8811h_init_up(phydev);
|
||||
if (ret < 0)
|
||||
dev_err(dev,
|
||||
"air_surge_5ohm_config fail. (ret=%d)\n", ret);
|
||||
} else
|
||||
dev_info(dev, "Surge Protection Mode - 0R\n");
|
||||
#if defined(AIR_LED_SUPPORT)
|
||||
ret = en8811h_led_init(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
goto priv_free;
|
||||
|
||||
priv->init_stage = AIR_INIT_CONFIG;
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
pbus_value &= ~0x3;
|
||||
#if defined(CONFIG_OF)
|
||||
pbus_value |= priv->pol;
|
||||
#else
|
||||
pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
|
||||
#endif
|
||||
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
|
||||
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
|
||||
priv->firmware_version = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_info(dev, "MD32 FW Version : %08x\n", priv->firmware_version);
|
||||
ret = air_surge_protect_cfg(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"air_surge_protect_cfg fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
|
||||
ret = air_cko_cfg(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"air_cko_cfg fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
|
||||
#if defined(AIR_LED_SUPPORT)
|
||||
ret = en8811h_led_init(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
#endif
|
||||
|
||||
priv->init_stage = AIR_INIT_SUCESS;
|
||||
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
|
||||
}
|
||||
return 0;
|
||||
priv_free:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void en8811h_remove(struct phy_device *phydev)
|
||||
{
|
||||
|
||||
@@ -518,6 +700,229 @@ void en8811h_remove(struct phy_device *phydev)
|
||||
}
|
||||
}
|
||||
|
||||
static int en8811h_restart_up(struct phy_device *phydev)
|
||||
{
|
||||
int ret, retry, reg_value;
|
||||
u32 pbus_value;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
|
||||
dev_info(dev, "%s start\n", __func__);
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x8009, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
|
||||
EN8811H_FW_CTRL_1_START);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
|
||||
EN8811H_FW_CTRL_1_FINISH);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
retry = MAX_RETRY;
|
||||
do {
|
||||
mdelay(300);
|
||||
reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
|
||||
if (reg_value == EN8811H_PHY_READY) {
|
||||
priv->init_stage = AIR_INIT_FW_READY;
|
||||
dev_info(dev, "EN8811H PHY ready!\n");
|
||||
break;
|
||||
}
|
||||
if (retry == 0) {
|
||||
dev_err(dev, "MD32 FW is not ready.(Status 0x%x)\n", reg_value);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_err(dev,
|
||||
"Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
|
||||
dev_err(dev,
|
||||
"%s fail!\n", __func__);
|
||||
priv->init_stage = AIR_INIT_FW_FAIL;
|
||||
}
|
||||
} while (retry--);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en8811h_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 pbus_value = 0;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, 0x1e00d0, 0xf);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1e0228, 0xf0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* If restart happened in .probe(), no need to restart now */
|
||||
if (priv->mcu_needs_restart) {
|
||||
ret = en8811h_restart_up(phydev);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
} else {
|
||||
ret = en8811h_init_up(phydev);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
/* Next calls to .config_init() mcu needs to restart */
|
||||
priv->mcu_needs_restart = true;
|
||||
}
|
||||
|
||||
priv->init_stage = AIR_INIT_CONFIG;
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
|
||||
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
|
||||
/* Serdes polarity */
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
pbus_value &= ~0x3;
|
||||
#if defined(CONFIG_OF)
|
||||
pbus_value |= priv->pol;
|
||||
#else
|
||||
pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
|
||||
#endif
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
|
||||
if (ret < 0)
|
||||
goto priv_free;
|
||||
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
|
||||
priv->firmware_version = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_info(dev, "MD32 FW Version : %08x\n", priv->firmware_version);
|
||||
|
||||
ret = air_surge_protect_cfg(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"air_surge_protect_cfg fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
|
||||
ret = air_cko_cfg(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"air_cko_cfg fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
|
||||
#if defined(AIR_LED_SUPPORT)
|
||||
ret = en8811h_led_init(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
|
||||
goto priv_free;
|
||||
}
|
||||
#endif
|
||||
|
||||
priv->init_stage = AIR_INIT_SUCESS;
|
||||
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
|
||||
return 0;
|
||||
|
||||
priv_free:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
static int en8811h_get_rate_matching(struct phy_device *phydev,
|
||||
phy_interface_t iface)
|
||||
{
|
||||
return RATE_MATCH_PAUSE;
|
||||
}
|
||||
|
||||
static int en8811h_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
bool changed = false;
|
||||
int err, val;
|
||||
|
||||
val = 0;
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
phydev->advertising))
|
||||
val |= MDIO_AN_10GBT_CTRL_ADV2_5G;
|
||||
err = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
|
||||
MDIO_AN_10GBT_CTRL_ADV2_5G, val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err > 0)
|
||||
changed = true;
|
||||
|
||||
return __genphy_config_aneg(phydev, changed);
|
||||
}
|
||||
|
||||
static int en8811h_update_link(struct phy_device *phydev)
|
||||
{
|
||||
int status = 0, bmcr;
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int addr = phydev_addr(phydev);
|
||||
|
||||
bmcr = air_mii_cl22_read(mbus, addr, MII_BMCR);
|
||||
if (bmcr < 0)
|
||||
return bmcr;
|
||||
/* Autoneg is being started, therefore disregard BMSR value and
|
||||
* report link as down.
|
||||
*/
|
||||
if (bmcr & BMCR_ANRESTART)
|
||||
goto done;
|
||||
status = air_mii_cl22_read(mbus, addr, MII_BMSR);
|
||||
if (status < 0)
|
||||
return status;
|
||||
done:
|
||||
phydev->link = status & BMSR_LSTATUS ? 1 : 0;
|
||||
phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en8811h_read_status(struct phy_device *phydev)
|
||||
{
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
u32 pbus_value;
|
||||
int old_link = phydev->link, ret;
|
||||
|
||||
ret = en8811h_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* why bother the PHY if nothing can have changed */
|
||||
if (old_link && phydev->link)
|
||||
return 0;
|
||||
phydev->speed = SPEED_UNKNOWN;
|
||||
phydev->duplex = DUPLEX_UNKNOWN;
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
phydev->rate_matching = RATE_MATCH_PAUSE;
|
||||
|
||||
ret = genphy_read_lpa(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Get link partner 2.5GBASE-T ability from vendor register */
|
||||
pbus_value = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
phydev->lp_advertising,
|
||||
pbus_value & EN8811H_2P5G_LPA_2P5G);
|
||||
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
if (phydev->autoneg_complete)
|
||||
phy_resolve_aneg_pause(phydev);
|
||||
|
||||
if (!phydev->link)
|
||||
return 0;
|
||||
|
||||
ret = air_ref_clk_speed(phydev, AIR_PARA_PHYDEV);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Firmware before version 24011202 has no vendor register 2P5G_LPA.
|
||||
* Assume link partner advertised it if connected at 2500Mbps.
|
||||
*/
|
||||
if (priv->firmware_version < 0x24011202) {
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
phydev->lp_advertising,
|
||||
phydev->speed == SPEED_2500);
|
||||
}
|
||||
if (phydev->speed <= SPEED_1000)
|
||||
phydev->pause = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver en8811h_driver[] = {
|
||||
{
|
||||
.phy_id = EN8811H_PHY_ID,
|
||||
@@ -530,6 +935,12 @@ static struct phy_driver en8811h_driver[] = {
|
||||
.read_mmd = __air_mii_cl45_read,
|
||||
.write_mmd = __air_mii_cl45_write,
|
||||
#endif
|
||||
.config_init = en8811h_config_init,
|
||||
.read_status = en8811h_read_status,
|
||||
.get_rate_matching = en8811h_get_rate_matching,
|
||||
.config_aneg = en8811h_config_aneg,
|
||||
.resume = genphy_resume,
|
||||
.suspend = genphy_suspend,
|
||||
} };
|
||||
|
||||
int __init en8811h_phy_driver_register(void)
|
||||
|
||||
@@ -18,6 +18,16 @@
|
||||
/* AN8855 registers */
|
||||
#define SCU_BASE 0x10000000
|
||||
#define RG_RGMII_TXCK_C (SCU_BASE + 0x1d0)
|
||||
#define RG_GPIO_LED_MODE (SCU_BASE + 0x0054)
|
||||
#define RG_GPIO_LED_SEL(i) (SCU_BASE + (0x0058 + ((i) * 4)))
|
||||
#define RG_INTB_MODE (SCU_BASE + 0x0080)
|
||||
#define RG_GDMP_RAM (SCU_BASE + 0x10000)
|
||||
|
||||
#define RG_GPIO_L_INV (SCU_BASE + 0x0010)
|
||||
#define RG_GPIO_CTRL (SCU_BASE + 0xa300)
|
||||
#define RG_GPIO_DATA (SCU_BASE + 0xa304)
|
||||
#define RG_GPIO_OE (SCU_BASE + 0xa314)
|
||||
|
||||
|
||||
#define HSGMII_AN_CSR_BASE 0x10220000
|
||||
#define SGMII_REG_AN0 (HSGMII_AN_CSR_BASE + 0x000)
|
||||
@@ -61,6 +71,8 @@
|
||||
#define SS_LCPLL_TDC_PCW_1 (QP_PMA_TOP_BASE + 0x248)
|
||||
#define INTF_CTRL_8 (QP_PMA_TOP_BASE + 0x320)
|
||||
#define INTF_CTRL_9 (QP_PMA_TOP_BASE + 0x324)
|
||||
#define INTF_CTRL_10 (QP_PMA_TOP_BASE + 0x328)
|
||||
#define INTF_CTRL_11 (QP_PMA_TOP_BASE + 0x32c)
|
||||
#define PLL_CTRL_0 (QP_PMA_TOP_BASE + 0x400)
|
||||
#define PLL_CTRL_2 (QP_PMA_TOP_BASE + 0x408)
|
||||
#define PLL_CTRL_3 (QP_PMA_TOP_BASE + 0x40c)
|
||||
@@ -78,6 +90,7 @@
|
||||
#define QP_ANA_CSR_BASE 0x1022f000
|
||||
#define RG_QP_RX_DAC_EN (QP_ANA_CSR_BASE + 0x00)
|
||||
#define RG_QP_RXAFE_RESERVE (QP_ANA_CSR_BASE + 0x04)
|
||||
#define RG_QP_CDR_LPF_BOT_LIM (QP_ANA_CSR_BASE + 0x08)
|
||||
#define RG_QP_CDR_LPF_MJV_LIM (QP_ANA_CSR_BASE + 0x0c)
|
||||
#define RG_QP_CDR_LPF_SETVALUE (QP_ANA_CSR_BASE + 0x14)
|
||||
#define RG_QP_CDR_PR_CKREF_DIV1 (QP_ANA_CSR_BASE + 0x18)
|
||||
@@ -106,9 +119,72 @@
|
||||
/* Fields of PHY_EXT_REG_14 */
|
||||
#define PHY_EN_DOWN_SHFIT BIT(4)
|
||||
|
||||
/* PHY dev address 0x1E */
|
||||
#define PHY_DEV1E 0x1e
|
||||
|
||||
/* PHY TX PAIR DELAY SELECT Register */
|
||||
#define PHY_TX_PAIR_DLY_SEL_GBE 0x013
|
||||
/* PHY ADC Register */
|
||||
#define PHY_RXADC_CTRL 0x0d8
|
||||
#define PHY_RXADC_REV_0 0x0d9
|
||||
#define PHY_RXADC_REV_1 0x0da
|
||||
|
||||
/* PHY LED Register bitmap of define */
|
||||
#define PHY_LED_CTRL_SELECT 0x3e8
|
||||
#define PHY_SINGLE_LED_ON_CTRL(i) (0x3e0 + ((i) * 2))
|
||||
#define PHY_SINGLE_LED_BLK_CTRL(i) (0x3e1 + ((i) * 2))
|
||||
#define PHY_SINGLE_LED_ON_DUR(i) (0x3e9 + ((i) * 2))
|
||||
#define PHY_SINGLE_LED_BLK_DUR(i) (0x3ea + ((i) * 2))
|
||||
|
||||
#define PHY_PMA_CTRL (0x340)
|
||||
|
||||
/* PHY dev address 0x1F */
|
||||
#define PHY_DEV1F 0x1f
|
||||
#define PHY_LED_ON_CTRL(i) (0x24 + ((i) * 2))
|
||||
#define LED_ON_EN (1 << 15)
|
||||
#define LED_ON_POL (1 << 14)
|
||||
#define LED_ON_EVT_MASK (0x7f)
|
||||
/* LED ON Event */
|
||||
#define LED_ON_EVT_FORCE (1 << 6)
|
||||
#define LED_ON_EVT_LINK_HD (1 << 5)
|
||||
#define LED_ON_EVT_LINK_FD (1 << 4)
|
||||
#define LED_ON_EVT_LINK_DOWN (1 << 3)
|
||||
#define LED_ON_EVT_LINK_10M (1 << 2)
|
||||
#define LED_ON_EVT_LINK_100M (1 << 1)
|
||||
#define LED_ON_EVT_LINK_1000M (1 << 0)
|
||||
|
||||
#define PHY_LED_BLK_CTRL(i) (0x25 + ((i) * 2))
|
||||
#define LED_BLK_EVT_MASK (0x3ff)
|
||||
/* LED Blinking Event */
|
||||
#define LED_BLK_EVT_FORCE (1 << 9)
|
||||
#define LED_BLK_EVT_10M_RX_ACT (1 << 5)
|
||||
#define LED_BLK_EVT_10M_TX_ACT (1 << 4)
|
||||
#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
|
||||
#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
|
||||
#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
|
||||
#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
|
||||
|
||||
#define PHY_LED_BCR (0x21)
|
||||
#define LED_BCR_EXT_CTRL (1 << 15)
|
||||
#define LED_BCR_CLK_EN (1 << 3)
|
||||
#define LED_BCR_TIME_TEST (1 << 2)
|
||||
#define LED_BCR_MODE_MASK (3)
|
||||
#define LED_BCR_MODE_DISABLE (0)
|
||||
|
||||
#define PHY_LED_ON_DUR (0x22)
|
||||
#define LED_ON_DUR_MASK (0xffff)
|
||||
|
||||
#define PHY_LED_BLK_DUR (0x23)
|
||||
#define LED_BLK_DUR_MASK (0xffff)
|
||||
|
||||
#define PHY_LED_BLINK_DUR_CTRL (0x720)
|
||||
|
||||
/* Unique fields of PMCR for AN8855 */
|
||||
#define FORCE_TX_FC BIT(4)
|
||||
#define FORCE_RX_FC BIT(5)
|
||||
#define FORCE_EEE100 BIT(6)
|
||||
#define FORCE_EEE1G BIT(7)
|
||||
#define FORCE_EEE2P5G BIT(8)
|
||||
#define FORCE_DPX BIT(25)
|
||||
#define FORCE_SPD BITS(28, 30)
|
||||
#define FORCE_LNK BIT(24)
|
||||
@@ -117,10 +193,114 @@
|
||||
#define CHIP_ID 0x10005000
|
||||
#define CHIP_REV 0x10005004
|
||||
|
||||
#define AN8855_EFUSE_DATA0 0x1000a500
|
||||
|
||||
const u8 r50ohm_table[] = {
|
||||
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 126, 122, 117,
|
||||
112, 109, 104, 101, 97, 94, 90, 88, 84, 80,
|
||||
78, 74, 72, 68, 66, 64, 61, 58, 56, 53,
|
||||
51, 48, 47, 44, 42, 40, 38, 36, 34, 32,
|
||||
31, 28, 27, 24, 24, 22, 20, 18, 16, 16,
|
||||
14, 12, 11, 9
|
||||
};
|
||||
|
||||
static u8 shift_check(u8 base)
|
||||
{
|
||||
u8 i;
|
||||
u32 sz = sizeof(r50ohm_table)/sizeof(u8);
|
||||
|
||||
for (i = 0; i < sz; ++i)
|
||||
if (r50ohm_table[i] == base)
|
||||
break;
|
||||
|
||||
if (i < 8 || i >= sz)
|
||||
return 25; /* index of 94 */
|
||||
|
||||
return (i - 8);
|
||||
}
|
||||
|
||||
static u8 get_shift_val(u8 idx)
|
||||
{
|
||||
return r50ohm_table[idx];
|
||||
}
|
||||
|
||||
/* T830 AN8855 Reference Board */
|
||||
static const struct an8855_led_cfg led_cfg[] = {
|
||||
/*************************************************************************
|
||||
* Enable, LED idx, LED Polarity, LED ON event, LED Blink event LED Freq
|
||||
*************************************************************************
|
||||
*/
|
||||
/* GPIO0 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO1 */
|
||||
{1, P0_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO2 */
|
||||
{1, P1_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO3 */
|
||||
{1, P2_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO4 */
|
||||
{1, P3_LED1, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO5 */
|
||||
{1, P4_LED1, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO6 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO7 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO8 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO9 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO10 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO11 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO12 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO13 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO14 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO15 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO16 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO17 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO18 */
|
||||
{0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO19 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
/* GPIO20 */
|
||||
{0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
|
||||
};
|
||||
|
||||
static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
/* TX FIR - improve TX EYE */
|
||||
val = an8855_reg_read(gsw, INTF_CTRL_10);
|
||||
val &= ~(0x3f << 16);
|
||||
val |= BIT(21);
|
||||
val &= ~(0x1f << 24);
|
||||
val |= (0x4 << 24);
|
||||
val |= BIT(29);
|
||||
an8855_reg_write(gsw, INTF_CTRL_10, val);
|
||||
|
||||
val = an8855_reg_read(gsw, INTF_CTRL_11);
|
||||
val &= ~(0x3f);
|
||||
val |= BIT(6);
|
||||
an8855_reg_write(gsw, INTF_CTRL_11, val);
|
||||
|
||||
/* RX CDR - improve RX Jitter Tolerance */
|
||||
val = an8855_reg_read(gsw, RG_QP_CDR_LPF_BOT_LIM);
|
||||
val &= ~(0x7 << 24);
|
||||
val |= (0x5 << 24);
|
||||
val &= ~(0x7 << 20);
|
||||
val |= (0x5 << 20);
|
||||
an8855_reg_write(gsw, RG_QP_CDR_LPF_BOT_LIM, val);
|
||||
|
||||
/* PLL */
|
||||
val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_1);
|
||||
val &= ~(0x3 << 2);
|
||||
@@ -250,7 +430,7 @@ static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
|
||||
val &= ~(0xf << 25);
|
||||
val |= (0x1 << 25);
|
||||
val &= ~(0x7 << 29);
|
||||
val |= (0x3 << 29);
|
||||
val |= (0x6 << 29);
|
||||
an8855_reg_write(gsw, RG_QP_CDR_LPF_SETVALUE, val);
|
||||
|
||||
val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
|
||||
@@ -281,12 +461,10 @@ static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
|
||||
val |= (0x4 << 24);
|
||||
an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
|
||||
|
||||
val = an8855_reg_read(gsw, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_reg_write(gsw, PLL_CTRL_0, val);
|
||||
|
||||
/* PMA (For HW Mode) */
|
||||
val = an8855_reg_read(gsw, RX_CTRL_26);
|
||||
val &= ~BIT(23);
|
||||
val |= BIT(23);
|
||||
val &= ~BIT(24);
|
||||
val |= BIT(26);
|
||||
an8855_reg_write(gsw, RX_CTRL_26, val);
|
||||
|
||||
@@ -314,8 +492,8 @@ static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
|
||||
val = an8855_reg_read(gsw, RX_CTRL_8);
|
||||
val &= ~(0xfff << 16);
|
||||
val |= (0x200 << 16);
|
||||
val &= ~(0x7fff << 14);
|
||||
val |= (0xfff << 14);
|
||||
val &= ~(0x7fff << 0);
|
||||
val |= (0xfff << 0);
|
||||
an8855_reg_write(gsw, RX_CTRL_8, val);
|
||||
|
||||
/* Frequency memter */
|
||||
@@ -334,6 +512,10 @@ static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
|
||||
val |= (0x2710 << 0);
|
||||
an8855_reg_write(gsw, RX_CTRL_7, val);
|
||||
|
||||
val = an8855_reg_read(gsw, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_reg_write(gsw, PLL_CTRL_0, val);
|
||||
|
||||
/* PCS Init */
|
||||
val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
|
||||
val &= ~BIT(30);
|
||||
@@ -372,6 +554,28 @@ static int an8855_sgmii_setup(struct gsw_an8855 *gsw, int mode)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
/* TX FIR - improve TX EYE */
|
||||
val = an8855_reg_read(gsw, INTF_CTRL_10);
|
||||
val &= ~(0x3f << 16);
|
||||
val |= BIT(21);
|
||||
val &= ~(0x1f << 24);
|
||||
val |= BIT(29);
|
||||
an8855_reg_write(gsw, INTF_CTRL_10, val);
|
||||
|
||||
val = an8855_reg_read(gsw, INTF_CTRL_11);
|
||||
val &= ~(0x3f);
|
||||
val |= (0xd << 0);
|
||||
val |= BIT(6);
|
||||
an8855_reg_write(gsw, INTF_CTRL_11, val);
|
||||
|
||||
/* RX CDR - improve RX Jitter Tolerance */
|
||||
val = an8855_reg_read(gsw, RG_QP_CDR_LPF_BOT_LIM);
|
||||
val &= ~(0x7 << 24);
|
||||
val |= (0x6 << 24);
|
||||
val &= ~(0x7 << 20);
|
||||
val |= (0x6 << 20);
|
||||
an8855_reg_write(gsw, RG_QP_CDR_LPF_BOT_LIM, val);
|
||||
|
||||
/* PMA Init */
|
||||
/* PLL */
|
||||
val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_1);
|
||||
@@ -531,13 +735,10 @@ static int an8855_sgmii_setup(struct gsw_an8855 *gsw, int mode)
|
||||
val |= (0x4 << 24);
|
||||
an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
|
||||
|
||||
val = an8855_reg_read(gsw, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_reg_write(gsw, PLL_CTRL_0, val);
|
||||
|
||||
/* PMA (For HW Mode) */
|
||||
val = an8855_reg_read(gsw, RX_CTRL_26);
|
||||
val &= ~BIT(23);
|
||||
if (mode == SGMII_MODE_AN)
|
||||
val |= BIT(23);
|
||||
val &= ~BIT(24);
|
||||
val |= BIT(26);
|
||||
|
||||
an8855_reg_write(gsw, RX_CTRL_26, val);
|
||||
@@ -586,6 +787,10 @@ static int an8855_sgmii_setup(struct gsw_an8855 *gsw, int mode)
|
||||
val |= (0x2710 << 0);
|
||||
an8855_reg_write(gsw, RX_CTRL_7, val);
|
||||
|
||||
val = an8855_reg_read(gsw, PLL_CTRL_0);
|
||||
val |= BIT(0);
|
||||
an8855_reg_write(gsw, PLL_CTRL_0, val);
|
||||
|
||||
if (mode == SGMII_MODE_FORCE) {
|
||||
/* PCS Init */
|
||||
val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_0);
|
||||
@@ -670,7 +875,6 @@ static int an8855_sgmii_setup(struct gsw_an8855 *gsw, int mode)
|
||||
/* Restart AN */
|
||||
val = an8855_reg_read(gsw, SGMII_REG_AN0);
|
||||
val |= BIT(9);
|
||||
val |= BIT(15);
|
||||
an8855_reg_write(gsw, SGMII_REG_AN0, val);
|
||||
}
|
||||
|
||||
@@ -745,6 +949,9 @@ static int an8855_mac_port_setup(struct gsw_an8855 *gsw, u32 port,
|
||||
phy_modes(port_cfg->phy_mode), port);
|
||||
}
|
||||
|
||||
/* disable eee on cpu port */
|
||||
pmcr &= ~(FORCE_EEE100 | FORCE_EEE1G | FORCE_EEE2P5G);
|
||||
|
||||
if (port_cfg->force_link)
|
||||
an8855_reg_write(gsw, PMCR(port), pmcr);
|
||||
}
|
||||
@@ -772,7 +979,10 @@ static int an8855_sw_detect(struct gsw_an8855 *gsw, struct chip_rev *crev)
|
||||
|
||||
static void an8855_phy_setting(struct gsw_an8855 *gsw)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
u8 shift_sel = 0, rsel_tx_a = 0, rsel_tx_b = 0;
|
||||
u8 rsel_tx_c = 0, rsel_tx_d = 0;
|
||||
u16 cl45_data = 0;
|
||||
u32 val;
|
||||
|
||||
/* Release power down */
|
||||
@@ -791,40 +1001,44 @@ static void an8855_phy_setting(struct gsw_an8855 *gsw)
|
||||
val |= ADVERTISE_PAUSE_ASYM;
|
||||
gsw->mii_write(gsw, i, MII_ADVERTISE, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void an8855_low_power_setting(struct gsw_an8855 *gsw)
|
||||
{
|
||||
int port, addr;
|
||||
if (gsw->extSurge) {
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++) {
|
||||
/* Read data */
|
||||
for (j = 0; j < AN8855_WORD_SIZE; j++) {
|
||||
val = an8855_reg_read(gsw, AN8855_EFUSE_DATA0 +
|
||||
(AN8855_WORD_SIZE * (3 + j + (4 * i))));
|
||||
|
||||
for (port = 0; port < AN8855_NUM_PHYS; port++) {
|
||||
gsw->mmd_write(gsw, port, 0x1e, 0x11, 0x0f00);
|
||||
gsw->mmd_write(gsw, port, 0x1e, 0x3c, 0x0000);
|
||||
gsw->mmd_write(gsw, port, 0x1e, 0x3d, 0x0000);
|
||||
gsw->mmd_write(gsw, port, 0x1e, 0x3e, 0x0000);
|
||||
gsw->mmd_write(gsw, port, 0x1e, 0xc6, 0x53aa);
|
||||
shift_sel = shift_check((val & 0x7f000000) >> 24);
|
||||
switch (j) {
|
||||
case 0:
|
||||
rsel_tx_a = get_shift_val(shift_sel);
|
||||
break;
|
||||
case 1:
|
||||
rsel_tx_b = get_shift_val(shift_sel);
|
||||
break;
|
||||
case 2:
|
||||
rsel_tx_c = get_shift_val(shift_sel);
|
||||
break;
|
||||
case 3:
|
||||
rsel_tx_d = get_shift_val(shift_sel);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cl45_data = gsw->mmd_read(gsw, i, PHY_DEV1E, 0x174);
|
||||
cl45_data &= ~(0x7f7f);
|
||||
cl45_data |= (rsel_tx_a << 8);
|
||||
cl45_data |= rsel_tx_b;
|
||||
gsw->mmd_write(gsw, i, PHY_DEV1E, 0x174, cl45_data);
|
||||
cl45_data = gsw->mmd_read(gsw, i, PHY_DEV1E, 0x175);
|
||||
cl45_data &= ~(0x7f7f);
|
||||
cl45_data |= (rsel_tx_c << 8);
|
||||
cl45_data |= rsel_tx_d;
|
||||
gsw->mmd_write(gsw, i, PHY_DEV1E, 0x175, cl45_data);
|
||||
}
|
||||
}
|
||||
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x268, 0x07f1);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x269, 0x2111);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x26a, 0x0000);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x26b, 0x0074);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x26e, 0x00f6);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x26f, 0x6666);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x271, 0x2c02);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x272, 0x0c22);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x700, 0x0001);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x701, 0x0803);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x702, 0x01b6);
|
||||
gsw->mmd_write(gsw, 0, 0x1f, 0x703, 0x2111);
|
||||
|
||||
gsw->mmd_write(gsw, 1, 0x1f, 0x700, 0x0001);
|
||||
|
||||
for (addr = 0x200; addr <= 0x230; addr += 2)
|
||||
gsw->mmd_write(gsw, 0, 0x1f, addr, 0x2020);
|
||||
|
||||
for (addr = 0x201; addr <= 0x231; addr += 2)
|
||||
gsw->mmd_write(gsw, 0, 0x1f, addr, 0x0020);
|
||||
}
|
||||
|
||||
static void an8855_eee_setting(struct gsw_an8855 *gsw, u32 port)
|
||||
@@ -833,10 +1047,216 @@ static void an8855_eee_setting(struct gsw_an8855 *gsw, u32 port)
|
||||
gsw->mmd_write(gsw, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
|
||||
}
|
||||
|
||||
static int an8855_led_set_usr_def(struct gsw_an8855 *gsw, u8 entity,
|
||||
int polar, u16 on_evt, u16 blk_evt, u8 led_freq)
|
||||
{
|
||||
u32 cl45_data = 0;
|
||||
|
||||
if (polar == LED_HIGH)
|
||||
on_evt |= LED_ON_POL;
|
||||
else
|
||||
on_evt &= ~LED_ON_POL;
|
||||
|
||||
/* LED on event */
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_ON_CTRL(entity % 4), on_evt | LED_ON_EN);
|
||||
|
||||
/* LED blink event */
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_BLK_CTRL(entity % 4), blk_evt);
|
||||
|
||||
/* LED freq */
|
||||
switch (led_freq) {
|
||||
case AIR_LED_BLK_DUR_32M:
|
||||
cl45_data = 0x30e;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_64M:
|
||||
cl45_data = 0x61a;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_128M:
|
||||
cl45_data = 0xc35;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_256M:
|
||||
cl45_data = 0x186a;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_512M:
|
||||
cl45_data = 0x30d4;
|
||||
break;
|
||||
case AIR_LED_BLK_DUR_1024M:
|
||||
cl45_data = 0x61a8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_BLK_DUR(entity % 4), cl45_data);
|
||||
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_ON_DUR(entity % 4), (cl45_data >> 1));
|
||||
|
||||
/* Disable DATA & BAD_SSD for port LED blink behavior */
|
||||
cl45_data = gsw->mmd_read(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_PMA_CTRL);
|
||||
cl45_data &= ~BIT(0);
|
||||
cl45_data &= ~BIT(15);
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_PMA_CTRL, cl45_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_set_mode(struct gsw_an8855 *gsw, u8 mode)
|
||||
{
|
||||
u16 cl45_data;
|
||||
|
||||
cl45_data = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_LED_BCR);
|
||||
switch (mode) {
|
||||
case AN8855_LED_MODE_DISABLE:
|
||||
cl45_data &= ~LED_BCR_EXT_CTRL;
|
||||
cl45_data &= ~LED_BCR_MODE_MASK;
|
||||
cl45_data |= LED_BCR_MODE_DISABLE;
|
||||
break;
|
||||
case AN8855_LED_MODE_USER_DEFINE:
|
||||
cl45_data |= LED_BCR_EXT_CTRL;
|
||||
cl45_data |= LED_BCR_CLK_EN;
|
||||
break;
|
||||
default:
|
||||
dev_info(gsw->dev, "LED mode%d is not supported!\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_LED_BCR, cl45_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_set_state(struct gsw_an8855 *gsw, u8 entity, u8 state)
|
||||
{
|
||||
u16 cl45_data = 0;
|
||||
|
||||
/* Change to per port contorl */
|
||||
cl45_data = gsw->mmd_read(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_LED_CTRL_SELECT);
|
||||
|
||||
if (state == 1)
|
||||
cl45_data |= (1 << (entity % 4));
|
||||
else
|
||||
cl45_data &= ~(1 << (entity % 4));
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_LED_CTRL_SELECT, cl45_data);
|
||||
|
||||
/* LED enable setting */
|
||||
cl45_data = gsw->mmd_read(gsw, (entity / 4),
|
||||
PHY_DEV1E, PHY_SINGLE_LED_ON_CTRL(entity % 4));
|
||||
|
||||
if (state == 1)
|
||||
cl45_data |= LED_ON_EN;
|
||||
else
|
||||
cl45_data &= ~LED_ON_EN;
|
||||
|
||||
gsw->mmd_write(gsw, (entity / 4), PHY_DEV1E,
|
||||
PHY_SINGLE_LED_ON_CTRL(entity % 4), cl45_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_led_init(struct gsw_an8855 *gsw)
|
||||
{
|
||||
u32 val, led_count = ARRAY_SIZE(led_cfg);
|
||||
int ret = 0, id;
|
||||
u32 tmp_val = 0;
|
||||
u32 tmp_id = 0;
|
||||
|
||||
ret = an8855_led_set_mode(gsw, AN8855_LED_MODE_USER_DEFINE);
|
||||
if (ret != 0) {
|
||||
dev_info(gsw->dev, "led_set_mode fail(ret:%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (id = 0; id < led_count; id++) {
|
||||
ret = an8855_led_set_state(gsw,
|
||||
led_cfg[id].phy_led_idx, led_cfg[id].en);
|
||||
if (ret != 0) {
|
||||
dev_info(gsw->dev, "led_set_state fail(ret:%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (led_cfg[id].en == 1) {
|
||||
ret = an8855_led_set_usr_def(gsw,
|
||||
led_cfg[id].phy_led_idx,
|
||||
led_cfg[id].pol, led_cfg[id].on_cfg,
|
||||
led_cfg[id].blk_cfg,
|
||||
led_cfg[id].led_freq);
|
||||
if (ret != 0) {
|
||||
dev_info(gsw->dev, "led_set_usr_def fail!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Setting for System LED & Loop LED */
|
||||
an8855_reg_write(gsw, RG_GPIO_OE, 0x0);
|
||||
an8855_reg_write(gsw, RG_GPIO_CTRL, 0x0);
|
||||
val = 0;
|
||||
an8855_reg_write(gsw, RG_GPIO_L_INV, val);
|
||||
|
||||
val = 0x1001;
|
||||
an8855_reg_write(gsw, RG_GPIO_CTRL, val);
|
||||
val = an8855_reg_read(gsw, RG_GPIO_DATA);
|
||||
val |= BITS(1, 3);
|
||||
val &= ~(BIT(0));
|
||||
val &= ~(BIT(6));
|
||||
|
||||
an8855_reg_write(gsw, RG_GPIO_DATA, val);
|
||||
val = an8855_reg_read(gsw, RG_GPIO_OE);
|
||||
val |= 0x41;
|
||||
an8855_reg_write(gsw, RG_GPIO_OE, val);
|
||||
|
||||
/* Mapping between GPIO & LED */
|
||||
val = 0;
|
||||
for (id = 0; id < led_count; id++) {
|
||||
/* Skip GPIO6, due to GPIO6 does not support PORT LED */
|
||||
if (id == 6)
|
||||
continue;
|
||||
|
||||
if (led_cfg[id].en == 1) {
|
||||
if (id < 7)
|
||||
val |= led_cfg[id].phy_led_idx << ((id % 4) * 8);
|
||||
else
|
||||
val |= led_cfg[id].phy_led_idx << (((id - 1) % 4) * 8);
|
||||
}
|
||||
|
||||
if (id < 7)
|
||||
tmp_id = id;
|
||||
else
|
||||
tmp_id = id - 1;
|
||||
|
||||
if ((tmp_id % 4) == 0x3) {
|
||||
an8855_reg_write(gsw, RG_GPIO_LED_SEL(tmp_id / 4), val);
|
||||
tmp_val = an8855_reg_read(gsw, RG_GPIO_LED_SEL(tmp_id / 4));
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn on LAN LED mode */
|
||||
val = 0;
|
||||
for (id = 0; id < led_count; id++) {
|
||||
if (led_cfg[id].en == 1)
|
||||
val |= 0x1 << id;
|
||||
}
|
||||
an8855_reg_write(gsw, RG_GPIO_LED_MODE, val);
|
||||
|
||||
/* Force clear blink pulse for per port LED */
|
||||
gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_LED_BLINK_DUR_CTRL, 0x1f);
|
||||
usleep_range(1000, 5000);
|
||||
gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_LED_BLINK_DUR_CTRL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_sw_init(struct gsw_an8855 *gsw)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
int i, ret = 0;
|
||||
u32 val, led_count = ARRAY_SIZE(led_cfg);
|
||||
int id;
|
||||
|
||||
gsw->phy_base = gsw->smi_addr & AN8855_SMI_ADDR_MASK;
|
||||
|
||||
@@ -852,7 +1272,7 @@ static int an8855_sw_init(struct gsw_an8855 *gsw)
|
||||
an8855_reg_write(gsw, SYS_CTRL, SW_SYS_RST);
|
||||
usleep_range(100000, 110000);
|
||||
|
||||
/* change gphy smi address */
|
||||
/* Change gphy smi address */
|
||||
if (gsw->new_smi_addr != gsw->smi_addr) {
|
||||
an8855_reg_write(gsw, RG_GPHY_SMI_ADDR, gsw->new_smi_addr);
|
||||
gsw->smi_addr = gsw->new_smi_addr;
|
||||
@@ -865,6 +1285,59 @@ static int an8855_sw_init(struct gsw_an8855 *gsw)
|
||||
gsw->mii_write(gsw, i, MII_BMCR, val);
|
||||
}
|
||||
|
||||
/* AN8855H need to setup before switch init */
|
||||
val = an8855_reg_read(gsw, PKG_SEL);
|
||||
if ((val & 0x7) == PAG_SEL_AN8855H) {
|
||||
|
||||
/* Invert for LED activity change */
|
||||
val = an8855_reg_read(gsw, RG_GPIO_L_INV);
|
||||
for (id = 0; id < led_count; id++) {
|
||||
if ((led_cfg[id].pol == LED_HIGH) &&
|
||||
(led_cfg[id].en == 1))
|
||||
val |= 0x1 << id;
|
||||
}
|
||||
an8855_reg_write(gsw, RG_GPIO_L_INV, (val | 0x1));
|
||||
|
||||
/* MCU NOP CMD */
|
||||
an8855_reg_write(gsw, RG_GDMP_RAM, 0x846);
|
||||
an8855_reg_write(gsw, RG_GDMP_RAM + 4, 0x4a);
|
||||
|
||||
/* Enable MCU */
|
||||
val = an8855_reg_read(gsw, RG_CLK_CPU_ICG);
|
||||
an8855_reg_write(gsw, RG_CLK_CPU_ICG, val | MCU_ENABLE);
|
||||
usleep_range(1000, 5000);
|
||||
|
||||
/* Disable MCU watchdog */
|
||||
val = an8855_reg_read(gsw, RG_TIMER_CTL);
|
||||
an8855_reg_write(gsw, RG_TIMER_CTL, (val & (~WDOG_ENABLE)));
|
||||
|
||||
/* Configure interrupt */
|
||||
an8855_reg_write(gsw, RG_INTB_MODE, (0x1 << gsw->intr_pin));
|
||||
|
||||
/* LED settings for T830 reference board */
|
||||
ret = an8855_led_init(gsw);
|
||||
if (ret < 0) {
|
||||
dev_info(gsw->dev, "an8855_led_init fail. (ret=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust to reduce noise */
|
||||
for (i = 0; i < AN8855_NUM_PHYS; i++) {
|
||||
gsw->mmd_write(gsw, i, PHY_DEV1E,
|
||||
PHY_TX_PAIR_DLY_SEL_GBE, 0x4040);
|
||||
|
||||
gsw->mmd_write(gsw, i, PHY_DEV1E,
|
||||
PHY_RXADC_CTRL, 0x1010);
|
||||
|
||||
gsw->mmd_write(gsw, i, PHY_DEV1E,
|
||||
PHY_RXADC_REV_0, 0x100);
|
||||
|
||||
gsw->mmd_write(gsw, i, PHY_DEV1E,
|
||||
PHY_RXADC_REV_1, 0x100);
|
||||
}
|
||||
|
||||
/* Setup SERDES port 5 */
|
||||
an8855_mac_port_setup(gsw, 5, &gsw->port5_cfg);
|
||||
|
||||
/* Global mac control settings */
|
||||
@@ -875,6 +1348,7 @@ static int an8855_sw_init(struct gsw_an8855 *gsw)
|
||||
val = an8855_reg_read(gsw, CKGCR);
|
||||
val &= ~(CKG_LNKDN_GLB_STOP | CKG_LNKDN_PORT_STOP);
|
||||
an8855_reg_write(gsw, CKGCR, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,24 @@
|
||||
|
||||
#define AN8855_DFL_CPU_PORT 5
|
||||
#define AN8855_NUM_PHYS 5
|
||||
#define AN8855_WORD_SIZE 4
|
||||
#define AN8855_DFL_SMI_ADDR 0x1
|
||||
#define AN8855_SMI_ADDR_MASK 0x1f
|
||||
#define AN8855_DFL_INTR_ID 0xd
|
||||
#define AN8855_DFL_EXT_SURGE 0x0
|
||||
|
||||
#define LED_ON_EVENT (LED_ON_EVT_LINK_1000M | \
|
||||
LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M |\
|
||||
LED_ON_EVT_LINK_HD | LED_ON_EVT_LINK_FD)
|
||||
|
||||
#define LED_BLK_EVENT (LED_BLK_EVT_1000M_TX_ACT | \
|
||||
LED_BLK_EVT_1000M_RX_ACT | \
|
||||
LED_BLK_EVT_100M_TX_ACT | \
|
||||
LED_BLK_EVT_100M_RX_ACT | \
|
||||
LED_BLK_EVT_10M_TX_ACT | \
|
||||
LED_BLK_EVT_10M_RX_ACT)
|
||||
|
||||
#define LED_FREQ AIR_LED_BLK_DUR_64M
|
||||
|
||||
struct gsw_an8855;
|
||||
|
||||
@@ -37,6 +53,60 @@ enum sgmii_mode {
|
||||
SGMII_MODE_FORCE,
|
||||
};
|
||||
|
||||
enum phy_led_idx {
|
||||
P0_LED0,
|
||||
P0_LED1,
|
||||
P0_LED2,
|
||||
P0_LED3,
|
||||
P1_LED0,
|
||||
P1_LED1,
|
||||
P1_LED2,
|
||||
P1_LED3,
|
||||
P2_LED0,
|
||||
P2_LED1,
|
||||
P2_LED2,
|
||||
P2_LED3,
|
||||
P3_LED0,
|
||||
P3_LED1,
|
||||
P3_LED2,
|
||||
P3_LED3,
|
||||
P4_LED0,
|
||||
P4_LED1,
|
||||
P4_LED2,
|
||||
P4_LED3,
|
||||
PHY_LED_MAX
|
||||
};
|
||||
|
||||
/* TBD */
|
||||
enum an8855_led_blk_dur {
|
||||
AIR_LED_BLK_DUR_32M,
|
||||
AIR_LED_BLK_DUR_64M,
|
||||
AIR_LED_BLK_DUR_128M,
|
||||
AIR_LED_BLK_DUR_256M,
|
||||
AIR_LED_BLK_DUR_512M,
|
||||
AIR_LED_BLK_DUR_1024M,
|
||||
AIR_LED_BLK_DUR_LAST
|
||||
};
|
||||
|
||||
enum an8855_led_polarity {
|
||||
LED_LOW,
|
||||
LED_HIGH,
|
||||
};
|
||||
enum an8855_led_mode {
|
||||
AN8855_LED_MODE_DISABLE,
|
||||
AN8855_LED_MODE_USER_DEFINE,
|
||||
AN8855_LED_MODE_LAST
|
||||
};
|
||||
|
||||
struct an8855_led_cfg {
|
||||
u16 en;
|
||||
u8 phy_led_idx;
|
||||
u16 pol;
|
||||
u16 on_cfg;
|
||||
u16 blk_cfg;
|
||||
u8 led_freq;
|
||||
};
|
||||
|
||||
struct an8855_port_cfg {
|
||||
struct device_node *np;
|
||||
phy_interface_t phy_mode;
|
||||
@@ -55,6 +125,8 @@ struct gsw_an8855 {
|
||||
u32 smi_addr;
|
||||
u32 new_smi_addr;
|
||||
u32 phy_base;
|
||||
u32 intr_pin;
|
||||
u32 extSurge;
|
||||
|
||||
enum an8855_model model;
|
||||
const char *name;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifian8855_gsw_ider: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2023 Airoha Inc.
|
||||
* Author: Min Yao <min.yao@airoha.com>
|
||||
@@ -18,6 +18,9 @@
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include "an8855.h"
|
||||
#include "an8855_swconfig.h"
|
||||
@@ -25,11 +28,15 @@
|
||||
#include "an8855_nl.h"
|
||||
|
||||
/* AN8855 driver version */
|
||||
#define ARHT_AN8855_SWCFG_DRIVER_VER "1.0.1-L5.4"
|
||||
#define ARHT_AN8855_SWCFG_DRIVER_VER "1.0.6"
|
||||
#define ARHT_CHIP_NAME "an8855"
|
||||
#define ARHT_PROC_DIR "air_sw"
|
||||
#define ARHT_PROC_NODE_DEVICE "device"
|
||||
|
||||
static u32 an8855_gsw_id;
|
||||
struct list_head an8855_devs;
|
||||
static DEFINE_MUTEX(an8855_devs_lock);
|
||||
struct proc_dir_entry *proc_an8855_gsw_dir;
|
||||
|
||||
static struct an8855_sw_id *an8855_sw_ids[] = {
|
||||
&an8855_id,
|
||||
@@ -53,7 +60,6 @@ u32 an8855_reg_read(struct gsw_an8855 *gsw, u32 reg)
|
||||
high = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x17);
|
||||
|
||||
gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, 0x0);
|
||||
gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, 0x0);
|
||||
|
||||
mutex_unlock(&gsw->host_bus->mdio_lock);
|
||||
|
||||
@@ -78,7 +84,6 @@ void an8855_reg_write(struct gsw_an8855 *gsw, u32 reg, u32 val)
|
||||
(val & 0xFFFF));
|
||||
|
||||
gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f, 0x0);
|
||||
gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, 0x0);
|
||||
|
||||
mutex_unlock(&gsw->host_bus->mdio_lock);
|
||||
}
|
||||
@@ -110,13 +115,17 @@ void an8855_mii_write(struct gsw_an8855 *gsw, int phy, int reg, u16 val)
|
||||
int an8855_mmd_read(struct gsw_an8855 *gsw, int addr, int devad, u16 reg)
|
||||
{
|
||||
int val;
|
||||
u32 regnum = MII_ADDR_C45 | (devad << 16) | reg;
|
||||
|
||||
if (addr < AN8855_NUM_PHYS)
|
||||
addr = (gsw->phy_base + addr) & AN8855_SMI_ADDR_MASK;
|
||||
|
||||
mutex_lock(&gsw->host_bus->mdio_lock);
|
||||
val = gsw->host_bus->read(gsw->host_bus, addr, regnum);
|
||||
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0d, devad);
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0e, reg);
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0d, devad | (0x4000));
|
||||
val = gsw->host_bus->read(gsw->host_bus, addr, 0xe);
|
||||
|
||||
mutex_unlock(&gsw->host_bus->mdio_lock);
|
||||
|
||||
return val;
|
||||
@@ -125,13 +134,16 @@ int an8855_mmd_read(struct gsw_an8855 *gsw, int addr, int devad, u16 reg)
|
||||
void an8855_mmd_write(struct gsw_an8855 *gsw, int addr, int devad, u16 reg,
|
||||
u16 val)
|
||||
{
|
||||
u32 regnum = MII_ADDR_C45 | (devad << 16) | reg;
|
||||
|
||||
if (addr < AN8855_NUM_PHYS)
|
||||
addr = (gsw->phy_base + addr) & AN8855_SMI_ADDR_MASK;
|
||||
|
||||
mutex_lock(&gsw->host_bus->mdio_lock);
|
||||
gsw->host_bus->write(gsw->host_bus, addr, regnum, val);
|
||||
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0d, devad);
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0e, reg);
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0d, devad | (0x4000));
|
||||
gsw->host_bus->write(gsw->host_bus, addr, 0x0e, val);
|
||||
|
||||
mutex_unlock(&gsw->host_bus->mdio_lock);
|
||||
}
|
||||
|
||||
@@ -146,6 +158,10 @@ static void an8855_load_port_cfg(struct gsw_an8855 *gsw)
|
||||
struct device_node *fixed_link_node;
|
||||
struct an8855_port_cfg *port_cfg;
|
||||
u32 port;
|
||||
#if (KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE)
|
||||
int ret;
|
||||
|
||||
#endif
|
||||
|
||||
for_each_child_of_node(gsw->dev->of_node, port_np) {
|
||||
if (!of_device_is_compatible(port_np, "airoha,an8855-port"))
|
||||
@@ -172,9 +188,13 @@ static void an8855_load_port_cfg(struct gsw_an8855 *gsw)
|
||||
}
|
||||
|
||||
port_cfg->np = port_np;
|
||||
|
||||
#if (KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE)
|
||||
ret = of_get_phy_mode(port_np, &port_cfg->phy_mode);
|
||||
if (ret < 0) {
|
||||
#else
|
||||
port_cfg->phy_mode = of_get_phy_mode(port_np);
|
||||
if (port_cfg->phy_mode < 0) {
|
||||
#endif
|
||||
dev_info(gsw->dev, "incorrect phy-mode %d\n", port);
|
||||
continue;
|
||||
}
|
||||
@@ -296,6 +316,7 @@ static int an8855_hw_reset(struct gsw_an8855 *gsw)
|
||||
}
|
||||
|
||||
gpio_direction_output(gsw->reset_pin, 0);
|
||||
gpio_set_value(gsw->reset_pin, 0);
|
||||
usleep_range(100000, 150000);
|
||||
gpio_set_value(gsw->reset_pin, 1);
|
||||
usleep_range(100000, 150000);
|
||||
@@ -314,6 +335,51 @@ static irqreturn_t an8855_irq_handler(int irq, void *dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int an8855_proc_device_read(struct seq_file *seq, void *v)
|
||||
{
|
||||
seq_printf(seq, "%s\n", ARHT_CHIP_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8855_proc_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, an8855_proc_device_read, 0);
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE)
|
||||
static const struct proc_ops an8855_proc_device_fops = {
|
||||
.proc_open = an8855_proc_device_open,
|
||||
.proc_read = seq_read,
|
||||
.proc_lseek = seq_lseek,
|
||||
.proc_release = single_release,
|
||||
};
|
||||
#else
|
||||
static const struct file_operations an8855_proc_device_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = an8855_proc_device_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int an8855_proc_device_init(struct gsw_an8855 *gsw)
|
||||
{
|
||||
if (!proc_an8855_gsw_dir)
|
||||
proc_an8855_gsw_dir = proc_mkdir(ARHT_PROC_DIR, 0);
|
||||
|
||||
proc_create(ARHT_PROC_NODE_DEVICE, 0400, proc_an8855_gsw_dir,
|
||||
&an8855_proc_device_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void an8855_proc_device_exit(void)
|
||||
{
|
||||
remove_proc_entry(ARHT_PROC_NODE_DEVICE, 0);
|
||||
}
|
||||
|
||||
static int an8855_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gsw_an8855 *gsw;
|
||||
@@ -355,6 +421,14 @@ static int an8855_probe(struct platform_device *pdev)
|
||||
if (of_property_read_u32(np, "airoha,smi-addr", &gsw->new_smi_addr))
|
||||
gsw->new_smi_addr = AN8855_DFL_SMI_ADDR;
|
||||
|
||||
/* Assign AN8855 interrupt pin */
|
||||
if (of_property_read_u32(np, "airoha,intr", &gsw->intr_pin))
|
||||
gsw->intr_pin = AN8855_DFL_INTR_ID;
|
||||
|
||||
/* AN8855 surge enhancement */
|
||||
if (of_property_read_u32(np, "airoha,extSurge", &gsw->extSurge))
|
||||
gsw->extSurge = AN8855_DFL_EXT_SURGE;
|
||||
|
||||
/* Get LAN/WAN port mapping */
|
||||
map = an8855_find_mapping(np);
|
||||
if (map) {
|
||||
@@ -394,6 +468,8 @@ static int an8855_probe(struct platform_device *pdev)
|
||||
|
||||
gsw->irq = platform_get_irq(pdev, 0);
|
||||
if (gsw->irq >= 0) {
|
||||
INIT_WORK(&gsw->irq_worker, an8855_irq_worker);
|
||||
|
||||
ret = devm_request_irq(gsw->dev, gsw->irq, an8855_irq_handler,
|
||||
0, dev_name(gsw->dev), gsw);
|
||||
if (ret) {
|
||||
@@ -401,8 +477,6 @@ static int an8855_probe(struct platform_device *pdev)
|
||||
gsw->irq);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
INIT_WORK(&gsw->irq_worker, an8855_irq_worker);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gsw);
|
||||
@@ -411,6 +485,8 @@ static int an8855_probe(struct platform_device *pdev)
|
||||
|
||||
an8855_gsw_nl_init();
|
||||
|
||||
an8855_proc_device_init(gsw);
|
||||
|
||||
an8855_swconfig_init(gsw);
|
||||
|
||||
if (sw->post_init)
|
||||
@@ -441,6 +517,8 @@ static int an8855_remove(struct platform_device *pdev)
|
||||
an8855_swconfig_destroy(gsw);
|
||||
#endif
|
||||
|
||||
an8855_proc_device_exit();
|
||||
|
||||
an8855_gsw_nl_exit();
|
||||
|
||||
an8855_remove_gsw(gsw);
|
||||
|
||||
@@ -26,8 +26,8 @@ static int an8855_nl_response(struct sk_buff *skb, struct genl_info *info);
|
||||
static const struct nla_policy an8855_nl_cmd_policy[] = {
|
||||
[AN8855_ATTR_TYPE_MESG] = { .type = NLA_STRING },
|
||||
[AN8855_ATTR_TYPE_PHY] = { .type = NLA_S32 },
|
||||
[AN8855_ATTR_TYPE_REG] = { .type = NLA_S32 },
|
||||
[AN8855_ATTR_TYPE_VAL] = { .type = NLA_S32 },
|
||||
[AN8855_ATTR_TYPE_REG] = { .type = NLA_U32 },
|
||||
[AN8855_ATTR_TYPE_VAL] = { .type = NLA_U32 },
|
||||
[AN8855_ATTR_TYPE_DEV_NAME] = { .type = NLA_S32 },
|
||||
[AN8855_ATTR_TYPE_DEV_ID] = { .type = NLA_S32 },
|
||||
[AN8855_ATTR_TYPE_DEVAD] = { .type = NLA_S32 },
|
||||
@@ -202,15 +202,15 @@ err:
|
||||
static int an8855_nl_reply_read(struct genl_info *info, struct gsw_an8855 *gsw)
|
||||
{
|
||||
struct sk_buff *rep_skb = NULL;
|
||||
s32 phy, devad, reg;
|
||||
int value;
|
||||
s32 phy, devad;
|
||||
u32 reg = 0;
|
||||
int value = 0;
|
||||
int ret = 0;
|
||||
|
||||
phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
|
||||
devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
|
||||
reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
|
||||
|
||||
if (reg < 0)
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_REG, ®))
|
||||
goto err;
|
||||
|
||||
ret = an8855_nl_prepare_reply(info, AN8855_CMD_READ, &rep_skb);
|
||||
@@ -226,11 +226,11 @@ static int an8855_nl_reply_read(struct genl_info *info, struct gsw_an8855 *gsw)
|
||||
value = an8855_reg_read(gsw, reg);
|
||||
}
|
||||
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@@ -246,18 +246,16 @@ err:
|
||||
static int an8855_nl_reply_write(struct genl_info *info, struct gsw_an8855 *gsw)
|
||||
{
|
||||
struct sk_buff *rep_skb = NULL;
|
||||
s32 phy, devad, reg;
|
||||
u32 value;
|
||||
s32 phy, devad;
|
||||
u32 value = 0, reg = 0;
|
||||
int ret = 0;
|
||||
|
||||
phy = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_PHY, -1);
|
||||
devad = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_DEVAD, -1);
|
||||
reg = an8855_nl_get_s32(info, AN8855_ATTR_TYPE_REG, -1);
|
||||
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_VAL, &value))
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_REG, ®))
|
||||
goto err;
|
||||
|
||||
if (reg < 0)
|
||||
if (an8855_nl_get_u32(info, AN8855_ATTR_TYPE_VAL, &value))
|
||||
goto err;
|
||||
|
||||
ret = an8855_nl_prepare_reply(info, AN8855_CMD_WRITE, &rep_skb);
|
||||
@@ -273,11 +271,11 @@ static int an8855_nl_reply_write(struct genl_info *info, struct gsw_an8855 *gsw)
|
||||
an8855_reg_write(gsw, reg, value);
|
||||
}
|
||||
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_REG, reg);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = nla_put_s32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
ret = nla_put_u32(rep_skb, AN8855_ATTR_TYPE_VAL, value);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
|
||||
@@ -85,10 +85,10 @@
|
||||
#define PMCR(p) PORT_MAC_CTRL_REG(p, 0x00)
|
||||
#define PMSR(p) PORT_MAC_CTRL_REG(p, 0x10)
|
||||
|
||||
#define GMACCR (PORT_MAC_CTRL_BASE + 0x30e0)
|
||||
#define GMACCR (PORT_MAC_CTRL_BASE + 0x3e00)
|
||||
|
||||
#define MAX_RX_JUMBO_S 2
|
||||
#define MAX_RX_JUMBO_M 0x3c
|
||||
#define MAX_RX_JUMBO_S 4
|
||||
#define MAX_RX_JUMBO_M 0xf0
|
||||
#define MAX_RX_PKT_LEN_S 0
|
||||
#define MAX_RX_PKT_LEN_M 0x3
|
||||
|
||||
@@ -172,6 +172,12 @@
|
||||
#define STATS_RSFTPC 0xF8
|
||||
#define STATS_RXCDPC 0xFC
|
||||
|
||||
#define RG_CLK_CPU_ICG 0x10005034
|
||||
#define MCU_ENABLE BIT(3)
|
||||
|
||||
#define RG_TIMER_CTL 0x1000a100
|
||||
#define WDOG_ENABLE BIT(25)
|
||||
|
||||
#define SYS_CTRL 0x100050C0
|
||||
#define SW_SYS_RST BIT(31)
|
||||
|
||||
@@ -182,7 +188,10 @@
|
||||
#define SYS_INT_STS 0x1021C014
|
||||
#define PHY_LC_INT(p) BIT(p)
|
||||
|
||||
#define CKGCR (0x10213E1C)
|
||||
#define CKG_LNKDN_GLB_STOP (0x01)
|
||||
#define CKG_LNKDN_PORT_STOP (0x02)
|
||||
#define CKGCR 0x10213E1C
|
||||
#define CKG_LNKDN_GLB_STOP 0x01
|
||||
#define CKG_LNKDN_PORT_STOP 0x02
|
||||
|
||||
#define PKG_SEL 0x10000094
|
||||
#define PAG_SEL_AN8855H 0x2
|
||||
#endif /* _AN8855_REGS_H_ */
|
||||
|
||||
@@ -125,7 +125,7 @@ static int an8855_get_port_pvid(struct switch_dev *dev, int port, int *val)
|
||||
{
|
||||
struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
|
||||
|
||||
if (port >= AN8855_NUM_PORTS)
|
||||
if (port < 0 || port >= AN8855_NUM_PORTS)
|
||||
return -EINVAL;
|
||||
|
||||
*val = an8855_reg_read(gsw, PVID(port));
|
||||
@@ -138,7 +138,7 @@ static int an8855_set_port_pvid(struct switch_dev *dev, int port, int pvid)
|
||||
{
|
||||
struct gsw_an8855 *gsw = container_of(dev, struct gsw_an8855, swdev);
|
||||
|
||||
if (port >= AN8855_NUM_PORTS)
|
||||
if (port < 0 || port >= AN8855_NUM_PORTS)
|
||||
return -EINVAL;
|
||||
|
||||
if (pvid < AN8855_MIN_VID || pvid > AN8855_MAX_VID)
|
||||
@@ -300,18 +300,20 @@ static int an8855_set_port_link(struct switch_dev *dev, int port,
|
||||
static u64 get_mib_counter(struct gsw_an8855 *gsw, int i, int port)
|
||||
{
|
||||
unsigned int offset;
|
||||
u64 lo, hi, hi2;
|
||||
u64 lo = 0, hi = 0, hi2 = 0;
|
||||
|
||||
offset = an8855_mibs[i].offset;
|
||||
if (i >= 0) {
|
||||
offset = an8855_mibs[i].offset;
|
||||
|
||||
if (an8855_mibs[i].size == 1)
|
||||
return an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset));
|
||||
if (an8855_mibs[i].size == 1)
|
||||
return an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset));
|
||||
|
||||
do {
|
||||
hi = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
|
||||
lo = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset));
|
||||
hi2 = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
|
||||
} while (hi2 != hi);
|
||||
do {
|
||||
hi = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
|
||||
lo = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset));
|
||||
hi2 = an8855_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
|
||||
} while (hi2 != hi);
|
||||
}
|
||||
|
||||
return (hi << 32) | lo;
|
||||
}
|
||||
@@ -370,7 +372,7 @@ static void an8855_port_isolation(struct gsw_an8855 *gsw)
|
||||
an8855_reg_write(gsw, PORTMATRIX(gsw->cpu_port), PORT_MATRIX_M);
|
||||
|
||||
for (i = 0; i < AN8855_NUM_PORTS; i++) {
|
||||
u32 pvc_mode = 0x8100 << STAG_VPID_S;
|
||||
u32 pvc_mode = 0x9100 << STAG_VPID_S;
|
||||
|
||||
if (gsw->port5_cfg.stag_on && i == 5)
|
||||
pvc_mode |= PVC_PORT_STAG | PVC_STAG_REPLACE;
|
||||
|
||||
@@ -11,19 +11,19 @@ struct an8855_mapping an8855_def_mapping[] = {
|
||||
.name = "llllw",
|
||||
.pvids = { 1, 1, 1, 1, 2, 1 },
|
||||
.members = { 0, 0x2f, 0x30 },
|
||||
.etags = { 0, 0, 0x20 },
|
||||
.etags = { 0, 0, 0 },
|
||||
.vids = { 0, 1, 2 },
|
||||
}, {
|
||||
.name = "wllll",
|
||||
.pvids = { 2, 1, 1, 1, 1, 1 },
|
||||
.members = { 0, 0x3e, 0x21 },
|
||||
.etags = { 0, 0, 0x20 },
|
||||
.etags = { 0, 0, 0 },
|
||||
.vids = { 0, 1, 2 },
|
||||
}, {
|
||||
.name = "lwlll",
|
||||
.pvids = { 1, 2, 1, 1, 1, 1 },
|
||||
.members = { 0, 0x3d, 0x22 },
|
||||
.etags = { 0, 0, 0x20 },
|
||||
.etags = { 0, 0, 0 },
|
||||
.vids = { 0, 1, 2 },
|
||||
}, {
|
||||
.name = "lllll",
|
||||
@@ -124,14 +124,14 @@ void an8855_apply_vlan_config(struct gsw_an8855 *gsw)
|
||||
|
||||
/* set all untag-only ports as transparent and the rest as user port */
|
||||
for (i = 0; i < AN8855_NUM_PORTS; i++) {
|
||||
u32 pvc_mode = 0x8100 << STAG_VPID_S;
|
||||
u32 pvc_mode = 0x9100 << STAG_VPID_S;
|
||||
|
||||
if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
|
||||
pvc_mode = (0x8100 << STAG_VPID_S) |
|
||||
pvc_mode = (0x9100 << STAG_VPID_S) |
|
||||
(VA_TRANSPARENT_PORT << VLAN_ATTR_S);
|
||||
|
||||
if (gsw->port5_cfg.stag_on && i == 5)
|
||||
pvc_mode = (u32)((0x8100 << STAG_VPID_S) | PVC_PORT_STAG
|
||||
pvc_mode = (u32)((0x9100 << STAG_VPID_S) | PVC_PORT_STAG
|
||||
| PVC_STAG_REPLACE);
|
||||
|
||||
an8855_reg_write(gsw, PVC(i), pvc_mode);
|
||||
@@ -159,7 +159,8 @@ void an8855_apply_vlan_config(struct gsw_an8855 *gsw)
|
||||
u16 pvid = 0;
|
||||
u32 val;
|
||||
|
||||
if (vlan < AN8855_NUM_VLANS && gsw->vlan_entries[vlan].member)
|
||||
if ((vlan >= 0) && (vlan < AN8855_NUM_VLANS)
|
||||
&& (gsw->vlan_entries[vlan].member))
|
||||
pvid = gsw->vlan_entries[vlan].vid;
|
||||
|
||||
val = an8855_reg_read(gsw, PVID(i));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*SPDX-License-Identifier: GPL-2.0*/
|
||||
/*FILE NAME: an8801.c
|
||||
*PURPOSE:
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*PURPOSE:
|
||||
*Airoha phy driver for Linux
|
||||
*NOTES:
|
||||
*
|
||||
@@ -635,6 +634,23 @@ static int an8801sb_of_init(struct phy_device *phydev)
|
||||
} else
|
||||
priv->surge = AIR_SURGE_0R;
|
||||
|
||||
if (of_find_property(of_node, "airoha,sgmii-mode", NULL)) {
|
||||
if (of_property_read_u32(of_node, "airoha,sgmii-mode",
|
||||
&val) != 0) {
|
||||
dev_err(phydev_dev(phydev), "airoha,sgmii-mode value is invalid.");
|
||||
return -1;
|
||||
}
|
||||
if (val < AIR_SGMII_AN ||
|
||||
val > AIR_SGMII_FORCE) {
|
||||
dev_err(phydev_dev(phydev),
|
||||
"airoha,sgmii-mode value %u out of range.",
|
||||
val);
|
||||
return -1;
|
||||
}
|
||||
priv->sgmii_mode = val;
|
||||
} else
|
||||
priv->sgmii_mode = AIR_SGMII_AN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@@ -732,27 +748,43 @@ static int an8801sb_config_init(struct phy_device *phydev)
|
||||
u32 pbus_value = 0;
|
||||
u32 reg_value = 0;
|
||||
|
||||
reg_value = phy_read(phydev, MII_BMSR);
|
||||
if ((reg_value & MCS_LINK_STATUS_MASK) != 0) {
|
||||
ret = air_buckpbus_reg_write(phydev, 0x10220010, 0x1801);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220010);
|
||||
dev_dbg(phydev_dev(phydev),
|
||||
"air_buckpbus_reg_read(0x10220010,0x%x).\n", reg_value);
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, 0x10220000, 0x9140);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
|
||||
dev_dbg(phydev_dev(phydev),
|
||||
"air_buckpbus_reg_read(0x10220000,0x%x).\n", reg_value);
|
||||
mdelay(80);
|
||||
}
|
||||
|
||||
ret = an8801sb_of_init(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (priv->sgmii_mode == AIR_SGMII_AN) {
|
||||
dev_info(phydev_dev(phydev), "sgmii mode - AN\n");
|
||||
reg_value = phy_read(phydev, MII_BMSR);
|
||||
if ((reg_value & MCS_LINK_STATUS_MASK) != 0) {
|
||||
ret = air_buckpbus_reg_write(phydev, 0x10220010, 0x1801);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220010);
|
||||
dev_dbg(phydev_dev(phydev),
|
||||
"air_buckpbus_reg_read(0x10220010,0x%x).\n", reg_value);
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, 0x10220000, 0x9140);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
|
||||
dev_dbg(phydev_dev(phydev),
|
||||
"air_buckpbus_reg_read(0x10220000,0x%x).\n", reg_value);
|
||||
mdelay(80);
|
||||
}
|
||||
} else { /* SGMII force mode */
|
||||
dev_info(phydev_dev(phydev), "sgmii mode - Force\n");
|
||||
ret = air_buckpbus_reg_write(phydev, 0x102260E4, 0xFF11);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224004, 0x0700);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224018, 0x0);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022450C, 0x0700);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022A140, 0x5);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10226100, 0xF0000000);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10226300, 0x0);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022A078, 0x10050);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10220034, 0x31120009);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10220000, 0x140);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
#ifdef CONFIG_OF
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x1022a0f8);
|
||||
pbus_value &= ~0x3;
|
||||
@@ -1347,6 +1379,7 @@ static void an8801_phy_remove(struct phy_device *phydev)
|
||||
static int an8801sb_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret, prespeed = phydev->speed;
|
||||
struct an8801_priv *priv = phydev->priv;
|
||||
u32 reg_value = 0;
|
||||
u32 an_retry = MAX_SGMII_AN_RETRY;
|
||||
|
||||
@@ -1357,14 +1390,16 @@ static int an8801sb_read_status(struct phy_device *phydev)
|
||||
ret |= phy_write_mmd(
|
||||
phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
|
||||
|
||||
mdelay(10); /* delay 10 ms */
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220010);
|
||||
reg_value &= 0x7fff;
|
||||
air_buckpbus_reg_write(phydev, 0x10220010, reg_value);
|
||||
if (priv->sgmii_mode == AIR_SGMII_AN) {
|
||||
mdelay(10); /* delay 10 ms */
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220010);
|
||||
reg_value &= 0x7fff;
|
||||
air_buckpbus_reg_write(phydev, 0x10220010, reg_value);
|
||||
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
|
||||
reg_value |= AN8801SB_SGMII_AN0_ANRESTART;
|
||||
air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
|
||||
reg_value |= AN8801SB_SGMII_AN0_ANRESTART;
|
||||
air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (prespeed != phydev->speed && phydev->link == LINK_UP) {
|
||||
@@ -1372,31 +1407,59 @@ static int an8801sb_read_status(struct phy_device *phydev)
|
||||
ret |= phy_write_mmd(
|
||||
phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
|
||||
dev_info(phydev_dev(phydev), "AN8801SB SPEED %d\n", prespeed);
|
||||
while (an_retry > 0) {
|
||||
mdelay(1); /* delay 1 ms */
|
||||
reg_value = air_buckpbus_reg_read(
|
||||
phydev, 0x10220b04);
|
||||
if (reg_value & AN8801SB_SGMII_AN0_AN_DONE)
|
||||
break;
|
||||
an_retry--;
|
||||
if (priv->sgmii_mode == AIR_SGMII_AN) {
|
||||
while (an_retry > 0) {
|
||||
mdelay(1); /* delay 1 ms */
|
||||
reg_value = air_buckpbus_reg_read(
|
||||
phydev, 0x10220b04);
|
||||
if (reg_value & AN8801SB_SGMII_AN0_AN_DONE)
|
||||
break;
|
||||
an_retry--;
|
||||
}
|
||||
mdelay(10); /* delay 10 ms */
|
||||
|
||||
|
||||
if (prespeed == SPEED_1000) {
|
||||
air_buckpbus_reg_write(
|
||||
phydev, 0x10220010, 0xd801);
|
||||
} else if (prespeed == SPEED_100) {
|
||||
air_buckpbus_reg_write(
|
||||
phydev, 0x10220010, 0xd401);
|
||||
} else {
|
||||
air_buckpbus_reg_write(
|
||||
phydev, 0x10220010, 0xd001);
|
||||
}
|
||||
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
|
||||
reg_value |= (AN8801SB_SGMII_AN0_RESET | AN8801SB_SGMII_AN0_ANRESTART);
|
||||
air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
|
||||
} else { /* SGMII force mode */
|
||||
if (prespeed == SPEED_1000) {
|
||||
ret = air_buckpbus_reg_write(phydev, 0x102260E4, 0xFF11);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224004, 0x0700);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224018, 0x0);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022450C, 0x0700);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022A140, 0x5);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10226100, 0xF0000000);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10270100, 0xF);
|
||||
} else if (prespeed == SPEED_100) {
|
||||
ret = air_buckpbus_reg_write(phydev, 0x102260E4, 0xFF11);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224004, 0x0755);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224018, 0x14);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022450C, 0x0755);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022A140, 0x10);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10226100, 0xF000000C);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10270100, 0xC);
|
||||
} else {
|
||||
ret = air_buckpbus_reg_write(phydev, 0x102260E4, 0xFFAA);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224004, 0x07AA);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10224018, 0x4);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022450C, 0x07AA);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x1022A140, 0x20);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10226100, 0xF000000F);
|
||||
ret |= air_buckpbus_reg_write(phydev, 0x10270100, 0xC);
|
||||
}
|
||||
}
|
||||
mdelay(10); /* delay 10 ms */
|
||||
|
||||
|
||||
if (prespeed == SPEED_1000) {
|
||||
air_buckpbus_reg_write(
|
||||
phydev, 0x10220010, 0xd801);
|
||||
} else if (prespeed == SPEED_100) {
|
||||
air_buckpbus_reg_write(
|
||||
phydev, 0x10220010, 0xd401);
|
||||
} else {
|
||||
air_buckpbus_reg_write(
|
||||
phydev, 0x10220010, 0xd001);
|
||||
}
|
||||
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
|
||||
reg_value |= (AN8801SB_SGMII_AN0_RESET | AN8801SB_SGMII_AN0_ANRESTART);
|
||||
air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*SPDX-License-Identifier: GPL-2.0*/
|
||||
/*FILE NAME: an8801.h
|
||||
*PURPOSE:
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*PURPOSE:
|
||||
*Define Airoha phy driver function
|
||||
*
|
||||
*NOTES:
|
||||
@@ -12,7 +11,7 @@
|
||||
|
||||
/* NAMING DECLARATIONS
|
||||
*/
|
||||
#define AN8801_DRIVER_VERSION "1.1.6"
|
||||
#define AN8801_DRIVER_VERSION "1.1.7"
|
||||
|
||||
#define DEBUGFS_COUNTER "counter"
|
||||
#define DEBUGFS_INFO "driver_info"
|
||||
@@ -90,7 +89,7 @@
|
||||
|
||||
#define UNIT_LED_BLINK_DURATION 780
|
||||
|
||||
/* Serdes auto negotation restart */
|
||||
/* Serdes auto negotiation restart */
|
||||
#define AN8801SB_SGMII_AN0_ANRESTART (0x0200)
|
||||
#define AN8801SB_SGMII_AN0_AN_DONE (0x0001)
|
||||
#define AN8801SB_SGMII_AN0_RESET (0x8000)
|
||||
@@ -109,8 +108,8 @@
|
||||
#define AN8801_RG_PKG_SEL_MSB BIT(5)
|
||||
|
||||
/*
|
||||
For reference only
|
||||
*/
|
||||
*For reference only
|
||||
*/
|
||||
/* User-defined.B */
|
||||
/* Link on(1G/100M/10M), no activity */
|
||||
#define AIR_LED0_ON \
|
||||
@@ -209,6 +208,7 @@ struct an8801_priv {
|
||||
#endif
|
||||
int pol;
|
||||
int surge;
|
||||
int sgmii_mode;
|
||||
};
|
||||
|
||||
enum an8801_polarity {
|
||||
@@ -224,4 +224,10 @@ enum air_surge {
|
||||
AIR_SURGE_LAST = 0xff
|
||||
};
|
||||
|
||||
enum air_sgmii_mode {
|
||||
AIR_SGMII_AN,
|
||||
AIR_SGMII_FORCE,
|
||||
AIR_SGMII_LAST = 0xff
|
||||
};
|
||||
|
||||
#endif /* End of __AN8801_H */
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
@@ -61,7 +62,7 @@ enum {
|
||||
PHY_STATE_PROCESS = 2,
|
||||
PHY_STATE_FAIL = 3,
|
||||
};
|
||||
|
||||
#define CONFIG_EN8801S_DEBUGFS
|
||||
struct en8801s_priv {
|
||||
bool first_init;
|
||||
u16 count;
|
||||
@@ -69,6 +70,9 @@ struct en8801s_priv {
|
||||
#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
|
||||
struct gpio_desc *hw_reset;
|
||||
#endif
|
||||
#ifdef CONFIG_EN8801S_DEBUGFS
|
||||
struct dentry *debugfs_root;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -101,11 +105,48 @@ static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
|
||||
#endif
|
||||
|
||||
/* User-defined.E */
|
||||
#ifdef CONFIG_EN8801S_DEBUGFS
|
||||
#define EN8801S_DEBUGFS_POLARITY_HELP_STRING \
|
||||
"\nUsage: echo [tx_polarity] [rx_polarity] > /sys/" \
|
||||
"kernel/debug/mdio-bus\':[phy_addr]/polarity" \
|
||||
"\npolarity: tx_normal, tx_reverse, rx_normal, rx_reverse" \
|
||||
"\ntx_normal is tx polarity is normal." \
|
||||
"\ntx_reverse is tx polarity need to be swapped." \
|
||||
"\nrx_normal is rx polarity is normal." \
|
||||
"\nrx_reverse is rx polarity need to be swapped." \
|
||||
"\nFor example tx polarity need to be swapped. " \
|
||||
"But rx polarity is normal." \
|
||||
"\necho tx_reverse rx_normal > /sys/" \
|
||||
"kernel/debug/mdio-bus\':[phy_addr]/polarity" \
|
||||
"\n"
|
||||
#define EN8801S_DEBUGFS_RX_ERROR_STRING \
|
||||
"\nRx param is not correct." \
|
||||
"\nrx_normal: rx polarity is normal." \
|
||||
"rx_reverse: rx polarity is reverse.\n"
|
||||
#define EN8801S_DEBUGFS_TX_ERROR_STRING \
|
||||
"\nTx param is not correct." \
|
||||
"\ntx_normal: tx polarity is normal." \
|
||||
"tx_reverse: tx polarity is reverse.\n"
|
||||
#define EN8801S_DEBUGFS_PBUS_HELP_STRING \
|
||||
"\nUsage: echo w [pbus_addr] [pbus_reg] [value] > /sys/" \
|
||||
"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
|
||||
"\n echo r [pbus_addr] [pbus_reg] > /sys/" \
|
||||
"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
|
||||
"\nRead example: PBUS addr 0x19, Register 0x19a4" \
|
||||
"\necho r 0x19 0x19a4 > /sys/" \
|
||||
"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
|
||||
"\nWrite example: PBUS addr 0x19, Register 0xcf8 0x1a01503" \
|
||||
"\necho w 0x19 0xcf8 0x1a01503> /sys/" \
|
||||
"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
|
||||
"\n"
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* F U N C T I O N S
|
||||
************************************************************************/
|
||||
static int en8801s_phase2_init(struct phy_device *phydev);
|
||||
static void air_debugfs_remove(struct phy_device *phydev);
|
||||
static int en8801s_debugfs_init(struct phy_device *phydev);
|
||||
static unsigned int airoha_cl22_read(struct mii_bus *ebus, int phy_addr,
|
||||
unsigned int phy_register, unsigned int *read_data)
|
||||
{
|
||||
@@ -530,20 +571,19 @@ static int en8801s_phase1_init(struct phy_device *phydev)
|
||||
mdelay(500);
|
||||
if (priv->pro_version == 4) {
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900);
|
||||
dev_dbg(dev, "Before 0x1900 0x%x\n", pbus_data);
|
||||
dev_dbg(dev, "Before 0x1900 0x%lx\n", pbus_data);
|
||||
ret = airoha_pbus_write(mbus, pbus_addr, 0x1900, 0x101009f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900);
|
||||
dev_dbg(dev, "After 0x1900 0x%x\n", pbus_data);
|
||||
dev_dbg(dev, "After 0x1900 0x%lx\n", pbus_data);
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8);
|
||||
dev_dbg(dev, "Before 19a8 0x%x\n", pbus_data);
|
||||
ret = airoha_pbus_write(mbus, pbus_addr,
|
||||
0x19a8, pbus_data & ~BIT(16));
|
||||
dev_dbg(dev, "Before 19a8 0x%lx\n", pbus_data);
|
||||
ret = airoha_pbus_write(mbus, pbus_addr, 0x19a8, pbus_data & ~BIT(16));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8);
|
||||
dev_dbg(dev, "After 19a8 0x%x\n", pbus_data);
|
||||
dev_dbg(dev, "After 19a8 0x%lx\n", pbus_data);
|
||||
}
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr,
|
||||
EN8801S_RG_SMI_ADDR); /* SMI ADDR */
|
||||
@@ -587,7 +627,7 @@ static int en8801s_phase1_init(struct phy_device *phydev)
|
||||
|
||||
phydev->dev_flags = PHY_STATE_INIT;
|
||||
|
||||
dev_info(dev, "Phase1 initialize OK ! (%s) 10Te TP_IDL fixed.\n", EN8801S_DRIVER_VERSION);
|
||||
dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION);
|
||||
if (priv->pro_version == 4) {
|
||||
ret = en8801s_phase2_init(phydev);
|
||||
if (ret != 0) {
|
||||
@@ -811,7 +851,14 @@ static int en8801s_phase2_init(struct phy_device *phydev)
|
||||
retry--;
|
||||
}
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */
|
||||
ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, 0xA018);
|
||||
ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
GPHY_RG_1E_012.DATA = cl45_value;
|
||||
GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt =
|
||||
(u16)(pbus_data & 0x03f);
|
||||
ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12,
|
||||
GPHY_RG_1E_012.DATA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value);
|
||||
@@ -886,17 +933,6 @@ static int en8801s_phase2_init(struct phy_device *phydev)
|
||||
}
|
||||
}
|
||||
|
||||
//Fix 10Te TP_IDL
|
||||
ret = airoha_cl45_read(mbus, phy_addr, 0x1E,
|
||||
0x1A3, &cl45_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cl45_value &= ~0xf0;
|
||||
ret = airoha_cl45_write(mbus, phy_addr, 0x1E,
|
||||
0x1A3, cl45_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->first_init = false;
|
||||
dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n");
|
||||
return 0;
|
||||
@@ -1055,6 +1091,7 @@ static int en8801s_probe(struct phy_device *phydev)
|
||||
unsigned long phy_addr = phydev_phy_addr(phydev);
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
struct device *dev = &mbus->dev;
|
||||
int ret = 0;
|
||||
#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
|
||||
struct gpio_desc *en8801s_reset;
|
||||
int err = 0;
|
||||
@@ -1068,7 +1105,15 @@ static int en8801s_probe(struct phy_device *phydev)
|
||||
|
||||
priv->count = 0;
|
||||
priv->first_init = true;
|
||||
|
||||
phydev->priv = priv;
|
||||
#ifdef CONFIG_EN8801S_DEBUGFS
|
||||
ret = en8801s_debugfs_init(phydev);
|
||||
if (ret < 0) {
|
||||
air_debugfs_remove(phydev);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
|
||||
/* Assert the optional reset signal */
|
||||
en8801s_reset = gpiod_get_optional(&phydev->dev,
|
||||
@@ -1099,6 +1144,276 @@ static int en8801s_probe(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const tx_rx_string[32] = {
|
||||
"Tx Normal, Rx Reverse",
|
||||
"Tx Reverse, Rx Reverse",
|
||||
"Tx Normal, Rx Normal",
|
||||
"Tx Reverse, Rx Normal",
|
||||
};
|
||||
|
||||
static int en8801s_counter_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct phy_device *phydev = seq->private;
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int ret = 0;
|
||||
u32 pkt_cnt = 0;
|
||||
int pbus_addr = phydev_pbus_addr(phydev);
|
||||
|
||||
seq_puts(seq, "==========AIR PHY COUNTER==========\n");
|
||||
seq_puts(seq, "|\t<<FCM COUNTER>>\n");
|
||||
seq_puts(seq, "| Rx from Line side_S :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1490);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Rx from Line side_T :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1494);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Tx to System side_S :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x149c);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Tx to System side_T :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x14a0);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Rx from System side_S :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1478);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Rx from System side_T :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x147c);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Tx to Line side_S :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1484);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Tx to Line side_T :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1488);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Rx from Line side_PAUSE :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1498);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Tx to System side_PAUSE :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x14a4);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Rx from System side_PAUSE :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x1480);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
seq_puts(seq, "| Tx to Line side_PAUSE :");
|
||||
pkt_cnt = airoha_pbus_read(mbus, pbus_addr, 0x148c);
|
||||
seq_printf(seq, "%010u |\n", pkt_cnt);
|
||||
|
||||
|
||||
ret = airoha_pbus_write(mbus, pbus_addr, 0x1474, 0x3);
|
||||
if (ret < 0)
|
||||
seq_puts(seq, "\nClear Counter fail\n");
|
||||
else
|
||||
seq_puts(seq, "\nClear Counter!!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int en8801s_counter_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, en8801s_counter_show, inode->i_private);
|
||||
}
|
||||
|
||||
int en8801s_info_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct phy_device *phydev = seq->private;
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int pbus_addr = phydev_pbus_addr(phydev);
|
||||
unsigned int tx_rx =
|
||||
(airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_LTR_CTL) & 0x3);
|
||||
unsigned long pbus_data = 0;
|
||||
|
||||
seq_puts(seq, "<<AIR EN8801S Driver Info>>\n");
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_PROD_VER);
|
||||
pbus_data &= 0xf;
|
||||
seq_printf(seq, "| Product Version : E%ld\n", pbus_data);
|
||||
seq_printf(seq, "| Driver Version : %s\n", EN8801S_DRIVER_VERSION);
|
||||
pbus_data = airoha_pbus_read(mbus, pbus_addr, 0xb04);
|
||||
seq_printf(seq, "| Serdes Status : Rx_Sync(%01ld), AN_Done(%01ld)\n",
|
||||
GET_BIT(pbus_data, 4), GET_BIT(pbus_data, 0));
|
||||
seq_printf(seq, "| Tx, Rx Polarity : %s(%02d)\n",
|
||||
tx_rx_string[tx_rx], tx_rx);
|
||||
|
||||
seq_puts(seq, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en8801s_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, en8801s_info_show, inode->i_private);
|
||||
}
|
||||
|
||||
|
||||
static int en8801s_debugfs_pbus_help(void)
|
||||
{
|
||||
pr_notice(EN8801S_DEBUGFS_PBUS_HELP_STRING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t en8801s_debugfs_pbus(struct file *file,
|
||||
const char __user *buffer, size_t count,
|
||||
loff_t *data)
|
||||
{
|
||||
struct phy_device *phydev = file->private_data;
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
char buf[64];
|
||||
int ret = 0;
|
||||
unsigned int reg, addr;
|
||||
unsigned long val;
|
||||
|
||||
memset(buf, 0, 64);
|
||||
|
||||
if (copy_from_user(buf, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
if (buf[0] == 'w') {
|
||||
if (sscanf(buf, "w %x %x %lx", &addr, ®, &val) == -1)
|
||||
return -EFAULT;
|
||||
if (addr > 0 && addr < 32) {
|
||||
pr_notice("\nphy=0x%x, reg=0x%x, val=0x%lx\n",
|
||||
addr, reg, val);
|
||||
|
||||
ret = airoha_pbus_write(mbus, addr, reg, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pr_notice("\nphy=%d, reg=0x%x, val=0x%lx confirm..\n",
|
||||
addr, reg,
|
||||
airoha_pbus_read(mbus, addr, reg));
|
||||
} else {
|
||||
pr_notice("addr is out of range(1~32)\n");
|
||||
}
|
||||
} else if (buf[0] == 'r') {
|
||||
if (sscanf(buf, "r %x %x", &addr, ®) == -1)
|
||||
return -EFAULT;
|
||||
if (addr > 0 && addr < 32) {
|
||||
pr_notice("\nphy=0x%x, reg=0x%x, val=0x%lx\n",
|
||||
addr, reg,
|
||||
airoha_pbus_read(mbus, addr, reg));
|
||||
} else {
|
||||
pr_notice("addr is out of range(1~32)\n");
|
||||
}
|
||||
} else if (buf[0] == 'h') {
|
||||
en8801s_debugfs_pbus_help();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int dbg_regs_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct phy_device *phydev = seq->private;
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int pbus_addr = phydev_pbus_addr(phydev), reg;
|
||||
|
||||
seq_puts(seq, "\t<<DEBUG REG DUMP>>\n");
|
||||
for (reg = MII_BMCR; reg <= MII_STAT1000; reg++) {
|
||||
if ((reg <= MII_LPA) || (reg >= MII_CTRL1000))
|
||||
seq_printf(seq, "| RG_MII 0x%02x : 0x%08x\n",
|
||||
reg, phy_read(phydev, reg));
|
||||
}
|
||||
seq_printf(seq, "| RG_SERDES_1 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0x600));
|
||||
seq_printf(seq, "| RG_SERDES_2 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0x10));
|
||||
seq_printf(seq, "| RG_SERDES_3 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0x0));
|
||||
seq_printf(seq, "| RG_SERDES_4 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0xa14));
|
||||
seq_printf(seq, "| RG_SERDES_5 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0x1404));
|
||||
seq_printf(seq, "| RG_SERDES_6 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0x140c));
|
||||
seq_printf(seq, "| RG_SERDES_7 : 0x%08lx |\n",
|
||||
airoha_pbus_read(mbus, pbus_addr, 0x1694));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airphy_dbg_regs_show_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_regs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations airphy_dbg_reg_show_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = airphy_dbg_regs_show_open,
|
||||
.read = seq_read,
|
||||
.llseek = noop_llseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct file_operations en8801s_debugfs_pbus_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.write = en8801s_debugfs_pbus,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations en8801s_info_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = en8801s_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = noop_llseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct file_operations en8801s_counter_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = en8801s_counter_open,
|
||||
.read = seq_read,
|
||||
.llseek = noop_llseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int en8801s_debugfs_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct en8801s_priv *priv = phydev->priv;
|
||||
|
||||
dev_info(phydev_dev(phydev), "Debugfs init start\n");
|
||||
priv->debugfs_root =
|
||||
debugfs_create_dir(dev_name(phydev_dev(phydev)), NULL);
|
||||
if (!priv->debugfs_root) {
|
||||
dev_err(phydev_dev(phydev), "Debugfs init err\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
debugfs_create_file(DEBUGFS_DRIVER_INFO, 0444,
|
||||
priv->debugfs_root, phydev,
|
||||
&en8801s_info_fops);
|
||||
debugfs_create_file(DEBUGFS_COUNTER, 0644,
|
||||
priv->debugfs_root, phydev,
|
||||
&en8801s_counter_fops);
|
||||
debugfs_create_file(DEBUGFS_PBUS_OP, S_IFREG | 0200,
|
||||
priv->debugfs_root, phydev,
|
||||
&en8801s_debugfs_pbus_fops);
|
||||
debugfs_create_file(DEBUGFS_DBG_REG_SHOW, S_IFREG | 0444,
|
||||
priv->debugfs_root, phydev,
|
||||
&airphy_dbg_reg_show_fops);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void air_debugfs_remove(struct phy_device *phydev)
|
||||
{
|
||||
struct en8801s_priv *priv = phydev->priv;
|
||||
|
||||
if (priv->debugfs_root != NULL) {
|
||||
debugfs_remove_recursive(priv->debugfs_root);
|
||||
priv->debugfs_root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void en8801s_phy_remove(struct phy_device *phydev)
|
||||
{
|
||||
struct en8801s_priv *priv = (struct en8801s_priv *)phydev->priv;
|
||||
|
||||
if (priv) {
|
||||
#ifdef CONFIG_EN8801S_DEBUGFS
|
||||
air_debugfs_remove(phydev);
|
||||
#endif
|
||||
kfree(priv);
|
||||
dev_info(phydev_dev(phydev), "EN8801S remove OK!\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
|
||||
static int airoha_mmd_read(struct phy_device *phydev,
|
||||
int devad, u16 reg)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/* NAMING DECLARATIONS
|
||||
*/
|
||||
#define EN8801S_DRIVER_VERSION "1.1.8_Generic"
|
||||
#define EN8801S_DRIVER_VERSION "1.1.9_Generic"
|
||||
#define EN8801S_PBUS_DEFAULT_ADDR 0x1e
|
||||
#define EN8801S_PHY_DEFAULT_ADDR 0x1d
|
||||
#define EN8801S_RG_ETHER_PHY_OUI 0x19a4
|
||||
@@ -26,6 +26,12 @@
|
||||
#define EN8801S_PHY_ID2 0x9461
|
||||
#define EN8801SC_PHY_ID 0x03a29471
|
||||
|
||||
#define DEBUGFS_COUNTER "counter"
|
||||
#define DEBUGFS_DRIVER_INFO "driver_info"
|
||||
#define DEBUGFS_PBUS_OP "pbus_op"
|
||||
#define DEBUGFS_POLARITY "polarity"
|
||||
#define DEBUGFS_DBG_REG_SHOW "dbg_regs_show"
|
||||
|
||||
#define LED_ON_CTRL(i) (0x024 + ((i)*2))
|
||||
#define LED_ON_EN (1 << 15)
|
||||
#define LED_ON_POL (1 << 14)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config MTK_NET_PHYLIB
|
||||
tristate
|
||||
|
||||
config MEDIATEK_GE_PHY
|
||||
tristate "MediaTek Gigabit Ethernet PHYs"
|
||||
select MTK_NET_PHYLIB
|
||||
help
|
||||
Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
|
||||
|
||||
Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
|
||||
You may find mt7530 inside mt7621. This driver shares some
|
||||
common operations with MediaTek SoC built-in Gigabit
|
||||
Ethernet PHYs.
|
||||
|
||||
config MEDIATEK_GE_SOC_PHY
|
||||
tristate "MediaTek SoC Ethernet PHYs"
|
||||
depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
|
||||
select NVMEM_MTK_EFUSE
|
||||
select MTK_NET_PHYLIB
|
||||
help
|
||||
Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
|
||||
|
||||
Include support for built-in Ethernet PHYs which are present in
|
||||
the MT7981 and MT7988 SoCs. These PHYs need calibration data
|
||||
present in the SoCs efuse and will dynamically calibrate VCM
|
||||
(common-mode voltage) during startup.
|
||||
|
||||
config MEDIATEK_2P5GE_PHY
|
||||
tristate "MediaTek 2.5Gb Ethernet PHYs"
|
||||
depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
|
||||
select MTK_NET_PHYLIB
|
||||
help
|
||||
Supports MediaTek SoC built-in 2.5Gb Ethernet PHYs.
|
||||
|
||||
This will load necessary firmware and add appropriate time delay.
|
||||
Accelerate this procedure through internal pbus instead of MDIO
|
||||
bus. Certain link-up issues will also be fixed here.
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
|
||||
obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
|
||||
obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
|
||||
obj-$(CONFIG_MEDIATEK_2P5GE_PHY) += mtk-2p5ge.o
|
||||
@@ -0,0 +1,730 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "mtk.h"
|
||||
|
||||
#define MTK_2P5GPHY_ID_MT7987 (0x00339c91)
|
||||
#define MTK_2P5GPHY_ID_MT7988 (0x00339c11)
|
||||
|
||||
#define MT7987_2P5GE_PMB_FW "mediatek/mt7987/i2p5ge-phy-pmb.bin"
|
||||
#define MT7987_2P5GE_PMB_FW_SIZE (0x18000)
|
||||
#define MT7987_2P5GE_DSPBITTB \
|
||||
"mediatek/mt7987/i2p5ge-phy-DSPBitTb.bin"
|
||||
#define MT7987_2P5GE_DSPBITTB_SIZE (0x7000)
|
||||
|
||||
#define MT7988_2P5GE_PMB_FW "mediatek/mt7988/i2p5ge-phy-pmb.bin"
|
||||
#define MT7988_2P5GE_PMB_FW_SIZE (0x20000)
|
||||
#define MT7988_2P5GE_PMB_FW_BASE (0x0f100000)
|
||||
#define MT7988_2P5GE_PMB_FW_LEN (0x20000)
|
||||
|
||||
#define MTK_2P5GPHY_PMD_REG_BASE (0x0f010000)
|
||||
#define MTK_2P5GPHY_PMD_REG_LEN (0x210)
|
||||
#define DO_NOT_RESET (0x28)
|
||||
#define DO_NOT_RESET_XBZ BIT(0)
|
||||
#define DO_NOT_RESET_PMA BIT(3)
|
||||
#define DO_NOT_RESET_RX BIT(5)
|
||||
#define FNPLL_PWR_CTRL1 (0x208)
|
||||
#define RG_SPEED_MASK GENMASK(3, 0)
|
||||
#define RG_SPEED_2500 BIT(3)
|
||||
#define RG_SPEED_100 BIT(0)
|
||||
#define FNPLL_PWR_CTRL_STATUS (0x20c)
|
||||
#define RG_STABLE_MASK GENMASK(3, 0)
|
||||
#define RG_SPEED_2500_STABLE BIT(3)
|
||||
#define RG_SPEED_100_STABLE BIT(0)
|
||||
|
||||
#define MTK_2P5GPHY_XBZ_PCS_REG_BASE (0x0f030000)
|
||||
#define MTK_2P5GPHY_XBZ_PCS_REG_LEN (0x844)
|
||||
#define PHY_CTRL_CONFIG (0x200)
|
||||
#define PMU_WP (0x800)
|
||||
#define WRITE_PROTECT_KEY (0xCAFEF00D)
|
||||
#define PMU_PMA_AUTO_CFG (0x820)
|
||||
#define POWER_ON_AUTO_MODE BIT(16)
|
||||
#define PMU_AUTO_MODE_EN BIT(0)
|
||||
#define PMU_PMA_STATUS (0x840)
|
||||
#define CLK_IS_DISABLED BIT(3)
|
||||
|
||||
#define MTK_2P5GPHY_XBZ_PMA_RX_BASE (0x0f080000)
|
||||
#define MTK_2P5GPHY_XBZ_PMA_RX_LEN (0x5228)
|
||||
#define SMEM_WDAT0 (0x5000)
|
||||
#define SMEM_WDAT1 (0x5004)
|
||||
#define SMEM_WDAT2 (0x5008)
|
||||
#define SMEM_WDAT3 (0x500c)
|
||||
#define SMEM_CTRL (0x5024)
|
||||
#define SMEM_HW_RDATA_ZERO BIT(24)
|
||||
#define SMEM_ADDR_REF_ADDR (0x502c)
|
||||
#define CM_CTRL_P01 (0x5100)
|
||||
#define CM_CTRL_P23 (0x5124)
|
||||
#define DM_CTRL_P01 (0x5200)
|
||||
#define DM_CTRL_P23 (0x5224)
|
||||
|
||||
#define MTK_2P5GPHY_CHIP_SCU_BASE (0x0f0cf800)
|
||||
#define MTK_2P5GPHY_CHIP_SCU_LEN (0x12c)
|
||||
#define SYS_SW_RESET (0x128)
|
||||
#define RESET_RST_CNT BIT(0)
|
||||
|
||||
#define MTK_2P5GPHY_MCU_CSR_BASE (0x0f0f0000)
|
||||
#define MTK_2P5GPHY_MCU_CSR_LEN (0x20)
|
||||
#define MD32_EN_CFG (0x18)
|
||||
#define MD32_EN BIT(0)
|
||||
|
||||
#define MTK_2P5GPHY_PMB_FW_BASE (0x0f100000)
|
||||
//#define MTK_2P5GPHY_PMB_FW_LEN MT7988_2P5GE_PMB_FW_SIZE
|
||||
|
||||
#define MTK_2P5GPHY_APB_BASE (0x11c30000)
|
||||
#define MTK_2P5GPHY_APB_LEN (0x9c)
|
||||
#define SW_RESET (0x94)
|
||||
#define MD32_RESTART_EN_CLEAR BIT(9)
|
||||
|
||||
#define BASE100T_STATUS_EXTEND (0x10)
|
||||
#define BASE1000T_STATUS_EXTEND (0x11)
|
||||
#define EXTEND_CTRL_AND_STATUS (0x16)
|
||||
|
||||
#define PHY_AUX_CTRL_STATUS (0x1d)
|
||||
#define PHY_AUX_DPX_MASK GENMASK(5, 5)
|
||||
#define PHY_AUX_SPEED_MASK GENMASK(4, 2)
|
||||
|
||||
/* Registers on MDIO_MMD_VEND1 */
|
||||
#define MTK_PHY_LINK_STATUS_RELATED (0x147)
|
||||
#define MTK_PHY_BYPASS_LINK_STATUS_OK BIT(4)
|
||||
#define MTK_PHY_FORCE_LINK_STATUS_HCD BIT(3)
|
||||
|
||||
#define MTK_PHY_PMA_PMD_SPPED_ABILITY 0x300
|
||||
|
||||
#define MTK_PHY_AN_FORCE_SPEED_REG (0x313)
|
||||
#define MTK_PHY_MASTER_FORCE_SPEED_SEL_EN BIT(7)
|
||||
#define MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK GENMASK(6, 0)
|
||||
|
||||
#define MTK_PHY_LPI_PCS_DSP_CTRL (0x121)
|
||||
#define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8)
|
||||
|
||||
/* Registers on Token Ring debug nodes */
|
||||
/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
|
||||
#define AUTO_NP_10XEN BIT(6)
|
||||
|
||||
struct mtk_i2p5ge_phy_priv {
|
||||
bool fw_loaded;
|
||||
int pd_en;
|
||||
};
|
||||
|
||||
enum {
|
||||
PHY_AUX_SPD_10 = 0,
|
||||
PHY_AUX_SPD_100,
|
||||
PHY_AUX_SPD_1000,
|
||||
PHY_AUX_SPD_2500,
|
||||
};
|
||||
|
||||
static int mt7987_2p5ge_phy_load_fw(struct phy_device *phydev)
|
||||
{
|
||||
struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
|
||||
struct device *dev = &phydev->mdio.dev;
|
||||
void __iomem *xbz_pcs_reg_base;
|
||||
void __iomem *xbz_pma_rx_base;
|
||||
void __iomem *chip_scu_base;
|
||||
void __iomem *pmd_reg_base;
|
||||
void __iomem *mcu_csr_base;
|
||||
const struct firmware *fw;
|
||||
void __iomem *apb_base;
|
||||
void __iomem *pmb_addr;
|
||||
int ret, i;
|
||||
u32 reg;
|
||||
|
||||
if (priv->fw_loaded)
|
||||
return 0;
|
||||
|
||||
apb_base = ioremap(MTK_2P5GPHY_APB_BASE,
|
||||
MTK_2P5GPHY_APB_LEN);
|
||||
if (!apb_base)
|
||||
return -ENOMEM;
|
||||
|
||||
pmd_reg_base = ioremap(MTK_2P5GPHY_PMD_REG_BASE,
|
||||
MTK_2P5GPHY_PMD_REG_LEN);
|
||||
if (!pmd_reg_base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_apb;
|
||||
}
|
||||
|
||||
xbz_pcs_reg_base = ioremap(MTK_2P5GPHY_XBZ_PCS_REG_BASE,
|
||||
MTK_2P5GPHY_XBZ_PCS_REG_LEN);
|
||||
if (!xbz_pcs_reg_base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_pmd;
|
||||
}
|
||||
|
||||
xbz_pma_rx_base = ioremap(MTK_2P5GPHY_XBZ_PMA_RX_BASE,
|
||||
MTK_2P5GPHY_XBZ_PMA_RX_LEN);
|
||||
if (!xbz_pma_rx_base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_pcs;
|
||||
}
|
||||
|
||||
chip_scu_base = ioremap(MTK_2P5GPHY_CHIP_SCU_BASE,
|
||||
MTK_2P5GPHY_CHIP_SCU_LEN);
|
||||
if (!chip_scu_base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_pma;
|
||||
}
|
||||
|
||||
mcu_csr_base = ioremap(MTK_2P5GPHY_MCU_CSR_BASE,
|
||||
MTK_2P5GPHY_MCU_CSR_LEN);
|
||||
if (!mcu_csr_base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_chip_scu;
|
||||
}
|
||||
|
||||
pmb_addr = ioremap(MTK_2P5GPHY_PMB_FW_BASE, MT7987_2P5GE_PMB_FW_SIZE);
|
||||
if (!pmb_addr) {
|
||||
return -ENOMEM;
|
||||
goto free_mcu_csr;
|
||||
}
|
||||
|
||||
ret = request_firmware(&fw, MT7987_2P5GE_PMB_FW, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to load firmware: %s, ret: %d\n",
|
||||
MT7987_2P5GE_PMB_FW, ret);
|
||||
goto free_pmb_addr;
|
||||
}
|
||||
|
||||
if (fw->size != MT7987_2P5GE_PMB_FW_SIZE) {
|
||||
dev_err(dev, "PMb firmware size 0x%zx != 0x%x\n",
|
||||
fw->size, MT7987_2P5GE_PMB_FW_SIZE);
|
||||
ret = -EINVAL;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
/* Force 2.5Gphy back to AN state */
|
||||
phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
|
||||
usleep_range(5000, 6000);
|
||||
phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
|
||||
|
||||
reg = readw(apb_base + SW_RESET);
|
||||
writew(reg & ~MD32_RESTART_EN_CLEAR, apb_base + SW_RESET);
|
||||
writew(reg | MD32_RESTART_EN_CLEAR, apb_base + SW_RESET);
|
||||
writew(reg & ~MD32_RESTART_EN_CLEAR, apb_base + SW_RESET);
|
||||
|
||||
reg = readw(mcu_csr_base + MD32_EN_CFG);
|
||||
writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG);
|
||||
|
||||
for (i = 0; i < MT7987_2P5GE_PMB_FW_SIZE - 1; i += 4)
|
||||
writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
|
||||
dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n",
|
||||
be16_to_cpu(*((__be16 *)(fw->data +
|
||||
MT7987_2P5GE_PMB_FW_SIZE - 8))),
|
||||
*(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 6),
|
||||
*(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 5),
|
||||
*(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 2),
|
||||
*(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 1));
|
||||
release_firmware(fw);
|
||||
|
||||
/* Enable 100Mbps module clock. */
|
||||
writel(FIELD_PREP(RG_SPEED_MASK, RG_SPEED_100),
|
||||
pmd_reg_base + FNPLL_PWR_CTRL1);
|
||||
|
||||
/* Check if 100Mbps module clock is ready. */
|
||||
ret = readl_poll_timeout(pmd_reg_base + FNPLL_PWR_CTRL_STATUS, reg,
|
||||
reg & RG_SPEED_100_STABLE, 1, 10000);
|
||||
if (ret)
|
||||
dev_err(dev, "Fail to enable 100Mbps module clock: %d\n", ret);
|
||||
|
||||
/* Enable 2.5Gbps module clock. */
|
||||
writel(FIELD_PREP(RG_SPEED_MASK, RG_SPEED_2500),
|
||||
pmd_reg_base + FNPLL_PWR_CTRL1);
|
||||
|
||||
/* Check if 2.5Gbps module clock is ready. */
|
||||
ret = readl_poll_timeout(pmd_reg_base + FNPLL_PWR_CTRL_STATUS, reg,
|
||||
reg & RG_SPEED_2500_STABLE, 1, 10000);
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "Fail to enable 2.5Gbps module clock: %d\n", ret);
|
||||
|
||||
/* Disable AN */
|
||||
phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE);
|
||||
|
||||
/* Force to run at 2.5G speed */
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_AN_FORCE_SPEED_REG,
|
||||
MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK,
|
||||
MTK_PHY_MASTER_FORCE_SPEED_SEL_EN |
|
||||
FIELD_PREP(MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK, 0x1b));
|
||||
|
||||
phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_RELATED,
|
||||
MTK_PHY_BYPASS_LINK_STATUS_OK |
|
||||
MTK_PHY_FORCE_LINK_STATUS_HCD);
|
||||
|
||||
/* Set xbz, pma and rx as "do not reset" in order to input DSP code. */
|
||||
reg = readl(pmd_reg_base + DO_NOT_RESET);
|
||||
reg |= DO_NOT_RESET_XBZ | DO_NOT_RESET_PMA | DO_NOT_RESET_RX;
|
||||
writel(reg, pmd_reg_base + DO_NOT_RESET);
|
||||
|
||||
reg = readl(chip_scu_base + SYS_SW_RESET);
|
||||
writel(reg & ~RESET_RST_CNT, chip_scu_base + SYS_SW_RESET);
|
||||
|
||||
writel(WRITE_PROTECT_KEY, xbz_pcs_reg_base + PMU_WP);
|
||||
|
||||
reg = readl(xbz_pcs_reg_base + PMU_PMA_AUTO_CFG);
|
||||
reg |= PMU_AUTO_MODE_EN | POWER_ON_AUTO_MODE;
|
||||
writel(reg, xbz_pcs_reg_base + PMU_PMA_AUTO_CFG);
|
||||
|
||||
/* Check if clock in auto mode is disabled. */
|
||||
ret = readl_poll_timeout(xbz_pcs_reg_base + PMU_PMA_STATUS, reg,
|
||||
(reg & CLK_IS_DISABLED) == 0x0, 1, 100000);
|
||||
if (ret)
|
||||
dev_err(dev, "Clock isn't disabled in auto mode: %d\n", ret);
|
||||
|
||||
reg = readl(xbz_pma_rx_base + SMEM_CTRL);
|
||||
writel(reg | SMEM_HW_RDATA_ZERO, xbz_pma_rx_base + SMEM_CTRL);
|
||||
|
||||
reg = readl(xbz_pcs_reg_base + PHY_CTRL_CONFIG);
|
||||
writel(reg | BIT(16), xbz_pcs_reg_base + PHY_CTRL_CONFIG);
|
||||
|
||||
/* Initialize data memory */
|
||||
reg = readl(xbz_pma_rx_base + DM_CTRL_P01);
|
||||
writel(reg | BIT(28), xbz_pma_rx_base + DM_CTRL_P01);
|
||||
reg = readl(xbz_pma_rx_base + DM_CTRL_P23);
|
||||
writel(reg | BIT(28), xbz_pma_rx_base + DM_CTRL_P23);
|
||||
|
||||
/* Initialize coefficient memory */
|
||||
reg = readl(xbz_pma_rx_base + CM_CTRL_P01);
|
||||
writel(reg | BIT(28), xbz_pma_rx_base + CM_CTRL_P01);
|
||||
reg = readl(xbz_pma_rx_base + CM_CTRL_P23);
|
||||
writel(reg | BIT(28), xbz_pma_rx_base + CM_CTRL_P23);
|
||||
|
||||
/* Initilize PM offset */
|
||||
writel(0, xbz_pma_rx_base + SMEM_ADDR_REF_ADDR);
|
||||
|
||||
ret = request_firmware(&fw, MT7987_2P5GE_DSPBITTB, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to load firmware: %s, ret: %d\n",
|
||||
MT7987_2P5GE_DSPBITTB, ret);
|
||||
goto free_pmb_addr;
|
||||
}
|
||||
if (fw->size != MT7987_2P5GE_DSPBITTB_SIZE) {
|
||||
dev_err(dev, "DSPBITTB size 0x%zx != 0x%x\n",
|
||||
fw->size, MT7987_2P5GE_DSPBITTB_SIZE);
|
||||
ret = -EINVAL;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
for (i = 0; i < fw->size - 1; i += 16) {
|
||||
writel(*((uint32_t *)(fw->data + i)),
|
||||
xbz_pma_rx_base + SMEM_WDAT0);
|
||||
writel(*((uint32_t *)(fw->data + i + 0x4)),
|
||||
xbz_pma_rx_base + SMEM_WDAT1);
|
||||
writel(*((uint32_t *)(fw->data + i + 0x8)),
|
||||
xbz_pma_rx_base + SMEM_WDAT2);
|
||||
writel(*((uint32_t *)(fw->data + i + 0xc)),
|
||||
xbz_pma_rx_base + SMEM_WDAT3);
|
||||
}
|
||||
|
||||
reg = readl(xbz_pma_rx_base + DM_CTRL_P01);
|
||||
writel(reg & ~BIT(28), xbz_pma_rx_base + DM_CTRL_P01);
|
||||
|
||||
reg = readl(xbz_pma_rx_base + DM_CTRL_P23);
|
||||
writel(reg & ~BIT(28), xbz_pma_rx_base + DM_CTRL_P23);
|
||||
|
||||
reg = readl(xbz_pma_rx_base + CM_CTRL_P01);
|
||||
writel(reg & ~BIT(28), xbz_pma_rx_base + CM_CTRL_P01);
|
||||
|
||||
reg = readl(xbz_pma_rx_base + CM_CTRL_P23);
|
||||
writel(reg & ~BIT(28), xbz_pma_rx_base + CM_CTRL_P23);
|
||||
|
||||
reg = readw(mcu_csr_base + MD32_EN_CFG);
|
||||
writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG);
|
||||
phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
|
||||
/* We need a delay here to stabilize initialization of MCU */
|
||||
usleep_range(7000, 8000);
|
||||
dev_info(dev, "Firmware loading/trigger ok.\n");
|
||||
|
||||
priv->fw_loaded = true;
|
||||
|
||||
release_fw:
|
||||
release_firmware(fw);
|
||||
free_pmb_addr:
|
||||
iounmap(pmb_addr);
|
||||
free_mcu_csr:
|
||||
iounmap(mcu_csr_base);
|
||||
free_chip_scu:
|
||||
iounmap(chip_scu_base);
|
||||
free_pma:
|
||||
iounmap(xbz_pma_rx_base);
|
||||
free_pcs:
|
||||
iounmap(xbz_pcs_reg_base);
|
||||
free_pmd:
|
||||
iounmap(pmd_reg_base);
|
||||
free_apb:
|
||||
iounmap(apb_base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt7988_2p5ge_phy_load_fw(struct phy_device *phydev)
|
||||
{
|
||||
struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
|
||||
void __iomem *mcu_csr_base, *pmb_addr;
|
||||
struct device *dev = &phydev->mdio.dev;
|
||||
const struct firmware *fw;
|
||||
int ret, i;
|
||||
u32 reg;
|
||||
|
||||
if (priv->fw_loaded)
|
||||
return 0;
|
||||
|
||||
pmb_addr = ioremap(MT7988_2P5GE_PMB_FW_BASE, MT7988_2P5GE_PMB_FW_LEN);
|
||||
if (!pmb_addr)
|
||||
return -ENOMEM;
|
||||
mcu_csr_base = ioremap(MTK_2P5GPHY_MCU_CSR_BASE,
|
||||
MTK_2P5GPHY_MCU_CSR_LEN);
|
||||
if (!mcu_csr_base) {
|
||||
ret = -ENOMEM;
|
||||
goto free_pmb;
|
||||
}
|
||||
|
||||
ret = request_firmware(&fw, MT7988_2P5GE_PMB_FW, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to load firmware: %s, ret: %d\n",
|
||||
MT7988_2P5GE_PMB_FW, ret);
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (fw->size != MT7988_2P5GE_PMB_FW_SIZE) {
|
||||
dev_err(dev, "Firmware size 0x%zx != 0x%x\n",
|
||||
fw->size, MT7988_2P5GE_PMB_FW_SIZE);
|
||||
ret = -EINVAL;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
reg = readw(mcu_csr_base + MD32_EN_CFG);
|
||||
if (reg & MD32_EN) {
|
||||
phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
|
||||
|
||||
/* Write magic number to safely stall MCU */
|
||||
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800e, 0x1100);
|
||||
phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x800f, 0x00df);
|
||||
|
||||
for (i = 0; i < MT7988_2P5GE_PMB_FW_SIZE - 1; i += 4)
|
||||
writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
|
||||
dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n",
|
||||
be16_to_cpu(*((__be16 *)(fw->data +
|
||||
MT7988_2P5GE_PMB_FW_SIZE - 8))),
|
||||
*(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 6),
|
||||
*(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 5),
|
||||
*(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2),
|
||||
*(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1));
|
||||
|
||||
writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG);
|
||||
writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG);
|
||||
phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
|
||||
/* We need a delay here to stabilize initialization of MCU */
|
||||
usleep_range(7000, 8000);
|
||||
dev_info(dev, "Firmware loading/trigger ok.\n");
|
||||
|
||||
priv->fw_loaded = true;
|
||||
|
||||
release_fw:
|
||||
release_firmware(fw);
|
||||
free:
|
||||
iounmap(mcu_csr_base);
|
||||
free_pmb:
|
||||
iounmap(pmb_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct pinctrl *pinctrl;
|
||||
int ret;
|
||||
|
||||
/* Check if PHY interface type is compatible */
|
||||
if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
|
||||
return -ENODEV;
|
||||
|
||||
switch (phydev->drv->phy_id) {
|
||||
case MTK_2P5GPHY_ID_MT7987:
|
||||
ret = mt7987_2p5ge_phy_load_fw(phydev);
|
||||
phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
|
||||
MTK_PHY_LED_ON_POLARITY);
|
||||
break;
|
||||
case MTK_2P5GPHY_ID_MT7988:
|
||||
ret = mt7988_2p5ge_phy_load_fw(phydev);
|
||||
phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
|
||||
MTK_PHY_LED_ON_POLARITY);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Setup LED */
|
||||
phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
|
||||
MTK_PHY_LED_ON_LINK10 | MTK_PHY_LED_ON_LINK100 |
|
||||
MTK_PHY_LED_ON_LINK1000 | MTK_PHY_LED_ON_LINK2500);
|
||||
phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
|
||||
MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX);
|
||||
|
||||
/* Switch pinctrl after setting polarity to avoid bogus blinking */
|
||||
pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led");
|
||||
if (IS_ERR(pinctrl))
|
||||
dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n");
|
||||
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
|
||||
MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
|
||||
|
||||
/* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */
|
||||
mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN,
|
||||
FIELD_PREP(AUTO_NP_10XEN, 0x1));
|
||||
|
||||
/* Enable HW auto downshift */
|
||||
phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
|
||||
MTK_PHY_AUX_CTRL_AND_STATUS,
|
||||
0, MTK_PHY_ENABLE_DOWNSHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
|
||||
bool changed = false;
|
||||
u32 adv;
|
||||
int ret;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_DISABLE)
|
||||
goto out;
|
||||
|
||||
ret = genphy_c45_an_config_aneg(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
/* Clause 45 doesn't define 1000BaseT support. Use Clause 22 instead in
|
||||
* our design.
|
||||
*/
|
||||
adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
|
||||
ret = phy_modify_changed(phydev, MII_CTRL1000, ADVERTISE_1000FULL, adv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
out:
|
||||
if (priv->pd_en) {
|
||||
phy_write_mmd(phydev, MDIO_MMD_VEND1,
|
||||
MTK_PHY_PMA_PMD_SPPED_ABILITY, 0xf7cf);
|
||||
phy_modify_paged(phydev, MTK_PHY_PAGE_STANDARD,
|
||||
MII_ADVERTISE, 0,
|
||||
ADVERTISE_100HALF | ADVERTISE_10HALF);
|
||||
}
|
||||
|
||||
if (phydev->autoneg == AUTONEG_DISABLE)
|
||||
return genphy_c45_pma_setup_forced(phydev);
|
||||
else
|
||||
return genphy_c45_check_and_restart_aneg(phydev, changed);
|
||||
}
|
||||
|
||||
static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_c45_pma_read_abilities(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* This phy can't handle collision, and neither can (XFI)MAC it's
|
||||
* connected to. Although it can do HDX handshake, it doesn't support
|
||||
* CSMA/CD that HDX requires.
|
||||
*/
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* When MDIO_STAT1_LSTATUS is raised genphy_c45_read_link(), this phy
|
||||
* actually hasn't finished AN. So use CL22's link update function
|
||||
* instead.
|
||||
*/
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phydev->speed = SPEED_UNKNOWN;
|
||||
phydev->duplex = DUPLEX_UNKNOWN;
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
|
||||
/* We'll read link speed through vendor specific registers down below.
|
||||
* So remove phy_resolve_aneg_linkmode (AN on) & genphy_c45_read_pma
|
||||
* (AN off).
|
||||
*/
|
||||
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
|
||||
ret = genphy_c45_read_lpa(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Clause 45 doesn't define 1000BaseT support. Read the link
|
||||
* partner's 1G advertisement via Clause 22.
|
||||
*/
|
||||
ret = phy_read(phydev, MII_STAT1000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
|
||||
} else if (phydev->autoneg == AUTONEG_DISABLE) {
|
||||
linkmode_zero(phydev->lp_advertising);
|
||||
}
|
||||
|
||||
if (phydev->link) {
|
||||
ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
|
||||
case PHY_AUX_SPD_10:
|
||||
phydev->speed = SPEED_10;
|
||||
break;
|
||||
case PHY_AUX_SPD_100:
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
case PHY_AUX_SPD_1000:
|
||||
phydev->speed = SPEED_1000;
|
||||
break;
|
||||
case PHY_AUX_SPD_2500:
|
||||
phydev->speed = SPEED_2500;
|
||||
break;
|
||||
}
|
||||
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
/* FIXME:
|
||||
* The current firmware always enables rate adaptation mode.
|
||||
*/
|
||||
phydev->rate_matching = RATE_MATCH_PAUSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
|
||||
phy_interface_t iface)
|
||||
{
|
||||
return RATE_MATCH_PAUSE;
|
||||
}
|
||||
|
||||
static ssize_t pd_en_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct phy_device *phydev = container_of(dev, struct phy_device,
|
||||
mdio.dev);
|
||||
struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
|
||||
|
||||
return sprintf(buf, "%d\n", priv->pd_en);
|
||||
}
|
||||
|
||||
static ssize_t pd_en_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct phy_device *phydev = container_of(dev, struct phy_device,
|
||||
mdio.dev);
|
||||
struct mtk_i2p5ge_phy_priv *priv = phydev->priv;
|
||||
int val;
|
||||
|
||||
if (kstrtoint(buf, 0, &val) == 0)
|
||||
priv->pd_en = !!val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(pd_en);
|
||||
|
||||
static int mt798x_2p5ge_phy_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct mtk_i2p5ge_phy_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&phydev->mdio.dev,
|
||||
sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (phydev->drv->phy_id) {
|
||||
case MTK_2P5GPHY_ID_MT7987:
|
||||
case MTK_2P5GPHY_ID_MT7988:
|
||||
/* The original hardware only sets MDIO_DEVS_PMAPMD */
|
||||
phydev->c45_ids.devices_in_package |= MDIO_DEVS_PCS |
|
||||
MDIO_DEVS_AN |
|
||||
MDIO_DEVS_VEND1 |
|
||||
MDIO_DEVS_VEND2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->fw_loaded = false;
|
||||
phydev->priv = priv;
|
||||
|
||||
priv->pd_en = 1;
|
||||
device_create_file(&phydev->mdio.dev, &dev_attr_pd_en);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver mtk_2p5gephy_driver[] = {
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7987),
|
||||
.name = "MediaTek MT7987 2.5GbE PHY",
|
||||
.probe = mt798x_2p5ge_phy_probe,
|
||||
.config_init = mt798x_2p5ge_phy_config_init,
|
||||
.config_aneg = mt798x_2p5ge_phy_config_aneg,
|
||||
.get_features = mt798x_2p5ge_phy_get_features,
|
||||
.read_status = mt798x_2p5ge_phy_read_status,
|
||||
.get_rate_matching = mt798x_2p5ge_phy_get_rate_matching,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.read_page = mtk_phy_read_page,
|
||||
.write_page = mtk_phy_write_page,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988),
|
||||
.name = "MediaTek MT7988 2.5GbE PHY",
|
||||
.probe = mt798x_2p5ge_phy_probe,
|
||||
.config_init = mt798x_2p5ge_phy_config_init,
|
||||
.config_aneg = mt798x_2p5ge_phy_config_aneg,
|
||||
.get_features = mt798x_2p5ge_phy_get_features,
|
||||
.read_status = mt798x_2p5ge_phy_read_status,
|
||||
.get_rate_matching = mt798x_2p5ge_phy_get_rate_matching,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.read_page = mtk_phy_read_page,
|
||||
.write_page = mtk_phy_write_page,
|
||||
},
|
||||
};
|
||||
|
||||
module_phy_driver(mtk_2p5gephy_driver);
|
||||
|
||||
static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
|
||||
{ PHY_ID_MATCH_VENDOR(0x00339c00) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
|
||||
MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
|
||||
MODULE_FIRMWARE(MT7988_2P5GE_PMB_FW);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#include "mtk.h"
|
||||
|
||||
#define MTK_GPHY_ID_MT7530 0x03a29412
|
||||
#define MTK_GPHY_ID_MT7531 0x03a29441
|
||||
|
||||
#define MTK_PHY_PAGE_EXTENDED_2 0x0002
|
||||
#define MTK_PHY_PAGE_EXTENDED_3 0x0003
|
||||
#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11
|
||||
|
||||
#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
|
||||
|
||||
/* Registers on Token Ring debug nodes */
|
||||
/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
|
||||
#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15)
|
||||
|
||||
/* Registers on MDIO_MMD_VEND1 */
|
||||
#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13
|
||||
#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14
|
||||
#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8)
|
||||
#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0)
|
||||
|
||||
#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6
|
||||
#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8)
|
||||
|
||||
#define MTK_PHY_RXADC_CTRL_RG7 0xc6
|
||||
#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8)
|
||||
|
||||
#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123
|
||||
#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8)
|
||||
#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0)
|
||||
|
||||
static void mtk_gephy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
/* Enable HW auto downshift */
|
||||
phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
|
||||
MTK_PHY_AUX_CTRL_AND_STATUS,
|
||||
0, MTK_PHY_ENABLE_DOWNSHIFT);
|
||||
|
||||
/* Increase SlvDPSready time */
|
||||
mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK,
|
||||
FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e));
|
||||
|
||||
/* Adjust 100_mse_threshold */
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1,
|
||||
MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123,
|
||||
MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK |
|
||||
MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
|
||||
FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK,
|
||||
0xff) |
|
||||
FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK,
|
||||
0xff));
|
||||
|
||||
/* If echo time is narrower than 0x3, it will be regarded as noise */
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1,
|
||||
MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL,
|
||||
MTK_MCC_NEARECHO_OFFSET_MASK,
|
||||
FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
|
||||
}
|
||||
|
||||
static int mt7530_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
mtk_gephy_config_init(phydev);
|
||||
|
||||
/* Increase post_update_timer */
|
||||
phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
|
||||
MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7531_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
mtk_gephy_config_init(phydev);
|
||||
|
||||
/* PHY link down power saving enable */
|
||||
phy_set_bits(phydev, 0x17, BIT(4));
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
|
||||
MTK_PHY_DA_AD_BUF_BIAS_LP_MASK,
|
||||
FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3));
|
||||
|
||||
/* Set TX Pair delay selection */
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL,
|
||||
MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
|
||||
FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
|
||||
FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
|
||||
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL,
|
||||
MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK,
|
||||
FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) |
|
||||
FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver mtk_gephy_driver[] = {
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
|
||||
.name = "MediaTek MT7530 PHY",
|
||||
.config_init = mt7530_phy_config_init,
|
||||
/* Interrupts are handled by the switch, not the PHY
|
||||
* itself.
|
||||
*/
|
||||
.config_intr = genphy_no_config_intr,
|
||||
.handle_interrupt = genphy_no_ack_interrupt,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.read_page = mtk_phy_read_page,
|
||||
.write_page = mtk_phy_write_page,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
|
||||
.name = "MediaTek MT7531 PHY",
|
||||
.config_init = mt7531_phy_config_init,
|
||||
.read_status = mtk_gphy_cl22_read_status,
|
||||
/* Interrupts are handled by the switch, not the PHY
|
||||
* itself.
|
||||
*/
|
||||
.config_intr = genphy_no_config_intr,
|
||||
.handle_interrupt = genphy_no_ack_interrupt,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.read_page = mtk_phy_read_page,
|
||||
.write_page = mtk_phy_write_page,
|
||||
},
|
||||
};
|
||||
|
||||
module_phy_driver(mtk_gephy_driver);
|
||||
|
||||
static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
|
||||
{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
|
||||
{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
|
||||
MODULE_AUTHOR("DENG, Qingfang <dqfext@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
|
||||
@@ -0,0 +1,452 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "mtk.h"
|
||||
|
||||
/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is
|
||||
* mtk_tr* functions: wrapped by page switching operations
|
||||
* __mtk_tr* functions: no page switching operations
|
||||
*/
|
||||
|
||||
static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr,
|
||||
u8 node_addr, u8 data_addr)
|
||||
{
|
||||
u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */
|
||||
|
||||
if (read)
|
||||
tr_cmd |= BIT(13);
|
||||
|
||||
tr_cmd |= (((ch_addr & 0x3) << 11) |
|
||||
((node_addr & 0xf) << 7) |
|
||||
((data_addr & 0x3f) << 1));
|
||||
dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd);
|
||||
__phy_write(phydev, 0x10, tr_cmd);
|
||||
}
|
||||
|
||||
static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u16 *tr_high, u16 *tr_low)
|
||||
{
|
||||
__mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr);
|
||||
*tr_low = __phy_read(phydev, 0x11);
|
||||
*tr_high = __phy_read(phydev, 0x12);
|
||||
dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n",
|
||||
*tr_high, *tr_low);
|
||||
}
|
||||
|
||||
u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr)
|
||||
{
|
||||
u16 tr_high;
|
||||
u16 tr_low;
|
||||
|
||||
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
|
||||
__mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
|
||||
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
|
||||
|
||||
return (tr_high << 16) | tr_low;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_tr_read);
|
||||
|
||||
static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 tr_data)
|
||||
{
|
||||
__phy_write(phydev, 0x11, tr_data & 0xffff);
|
||||
__phy_write(phydev, 0x12, tr_data >> 16);
|
||||
dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n",
|
||||
tr_data >> 16, tr_data & 0xffff);
|
||||
__mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
|
||||
}
|
||||
|
||||
void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 mask, u32 set)
|
||||
{
|
||||
u32 tr_data;
|
||||
u16 tr_high;
|
||||
u16 tr_low;
|
||||
|
||||
__mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low);
|
||||
tr_data = (tr_high << 16) | tr_low;
|
||||
tr_data = (tr_data & ~mask) | set;
|
||||
__mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__mtk_tr_modify);
|
||||
|
||||
void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 mask, u32 set)
|
||||
{
|
||||
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
|
||||
__mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set);
|
||||
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_tr_modify);
|
||||
|
||||
void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 set)
|
||||
{
|
||||
__mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__mtk_tr_set_bits);
|
||||
|
||||
void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 clr)
|
||||
{
|
||||
__mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits);
|
||||
|
||||
int mtk_phy_read_page(struct phy_device *phydev)
|
||||
{
|
||||
return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_read_page);
|
||||
|
||||
int mtk_phy_write_page(struct phy_device *phydev, int page)
|
||||
{
|
||||
return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_write_page);
|
||||
|
||||
/* This function deals with the case that 1G AN starts but isn't completed. We
|
||||
* set AN_NEW_LP_CNT_LIMIT with different values time after time to let our
|
||||
* 1G->100Mbps hardware automatic downshift to fit more partner devices.
|
||||
*/
|
||||
static int extend_an_new_lp_cnt_limit(struct phy_device *phydev)
|
||||
{
|
||||
int mmd_read_ret;
|
||||
u32 reg_val;
|
||||
int timeout;
|
||||
|
||||
/* According to table 28-9 & Figure 28-18 in IEEE 802.3,
|
||||
* link_fail_inhibit_timer of 10/100/1000 Mbps devices ranges from 750
|
||||
* to "1000ms". Once MTK_PHY_FINAL_SPEED_1000 is set, it means that we
|
||||
* enter "FLP LINK GOOD CHECK" state, link_fail_inhibit_timer starts and
|
||||
* this PHY's 1G training starts. If 1G training never starts, we do
|
||||
* nothing but leave.
|
||||
*/
|
||||
timeout = read_poll_timeout(mmd_read_ret = phy_read_mmd, reg_val,
|
||||
(mmd_read_ret < 0) ||
|
||||
reg_val & MTK_PHY_FINAL_SPEED_1000,
|
||||
10000, 1000000, false, phydev,
|
||||
MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC);
|
||||
if (mmd_read_ret < 0)
|
||||
return mmd_read_ret;
|
||||
|
||||
if (!timeout) {
|
||||
/* Once we found MTK_PHY_FINAL_SPEED_1000 is set, no matter 1G
|
||||
* AN is completed or not, we'll set AN_NEW_LP_CNT_LIMIT again
|
||||
* and again.
|
||||
*/
|
||||
mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AN_NEW_LP_CNT_LIMIT_MASK,
|
||||
FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK, 0xf));
|
||||
mdelay(1500);
|
||||
|
||||
timeout = read_poll_timeout(mtk_tr_read, reg_val,
|
||||
(reg_val & AN_STATE_MASK) !=
|
||||
(AN_STATE_TX_DISABLE <<
|
||||
AN_STATE_SHIFT),
|
||||
10000, 1000000, false, phydev,
|
||||
0x0, 0xf, 0x2);
|
||||
if (!timeout) {
|
||||
mdelay(625);
|
||||
mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
|
||||
AN_NEW_LP_CNT_LIMIT_MASK,
|
||||
FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK,
|
||||
0x8));
|
||||
mdelay(500);
|
||||
mtk_tr_modify(phydev, 0x0, 0xf, 0x3c,
|
||||
AN_NEW_LP_CNT_LIMIT_MASK,
|
||||
FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK,
|
||||
0xf));
|
||||
} else {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtk_gphy_cl22_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_read_status(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) {
|
||||
ret = phy_read_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
|
||||
MTK_PHY_AUX_CTRL_AND_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Once LP_DETECTED is set, it means that"ability_match" in
|
||||
* IEEE 802.3 Figure 28-18 is set. This happens after we plug in
|
||||
* cable. Also, LP_DETECTED will be cleared after AN complete.
|
||||
*/
|
||||
if (!FIELD_GET(MTK_PHY_LP_DETECTED_MASK, ret))
|
||||
return 0;
|
||||
|
||||
ret = phy_read(phydev, MII_CTRL1000);
|
||||
if (ret & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) {
|
||||
ret = extend_an_new_lp_cnt_limit(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_gphy_cl22_read_status);
|
||||
|
||||
#if 0
|
||||
int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
|
||||
unsigned long rules,
|
||||
unsigned long supported_triggers)
|
||||
{
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* All combinations of the supported triggers are allowed */
|
||||
if (rules & ~supported_triggers)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
|
||||
|
||||
int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
|
||||
unsigned long *rules, unsigned long *led_state,
|
||||
u16 on_set, u16 rx_blink_set, u16 tx_blink_set)
|
||||
{
|
||||
unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
|
||||
(index ? 16 : 0);
|
||||
unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
|
||||
unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
|
||||
int on, blink;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
|
||||
index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
|
||||
|
||||
if (on < 0)
|
||||
return -EIO;
|
||||
|
||||
blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
|
||||
index ? MTK_PHY_LED1_BLINK_CTRL :
|
||||
MTK_PHY_LED0_BLINK_CTRL);
|
||||
if (blink < 0)
|
||||
return -EIO;
|
||||
|
||||
if ((on & (on_set | MTK_PHY_LED_ON_FDX |
|
||||
MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
|
||||
(blink & (rx_blink_set | tx_blink_set)))
|
||||
set_bit(bit_netdev, led_state);
|
||||
else
|
||||
clear_bit(bit_netdev, led_state);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_FORCE_ON)
|
||||
set_bit(bit_on, led_state);
|
||||
else
|
||||
clear_bit(bit_on, led_state);
|
||||
|
||||
if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
|
||||
set_bit(bit_blink, led_state);
|
||||
else
|
||||
clear_bit(bit_blink, led_state);
|
||||
|
||||
if (!rules)
|
||||
return 0;
|
||||
|
||||
if (on & on_set)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK10)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_10);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK100)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_100);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK1000)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK2500)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_FDX)
|
||||
*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_HDX)
|
||||
*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
|
||||
|
||||
if (blink & rx_blink_set)
|
||||
*rules |= BIT(TRIGGER_NETDEV_RX);
|
||||
|
||||
if (blink & tx_blink_set)
|
||||
*rules |= BIT(TRIGGER_NETDEV_TX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
|
||||
|
||||
int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
|
||||
unsigned long rules, unsigned long *led_state,
|
||||
u16 on_set, u16 rx_blink_set, u16 tx_blink_set)
|
||||
{
|
||||
unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
|
||||
u16 on = 0, blink = 0;
|
||||
int ret;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
|
||||
on |= MTK_PHY_LED_ON_FDX;
|
||||
|
||||
if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
|
||||
on |= MTK_PHY_LED_ON_HDX;
|
||||
|
||||
if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
on |= MTK_PHY_LED_ON_LINK10;
|
||||
|
||||
if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
on |= MTK_PHY_LED_ON_LINK100;
|
||||
|
||||
if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
on |= MTK_PHY_LED_ON_LINK1000;
|
||||
|
||||
if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
on |= MTK_PHY_LED_ON_LINK2500;
|
||||
|
||||
if (rules & BIT(TRIGGER_NETDEV_RX)) {
|
||||
if (on & on_set) {
|
||||
if (on & MTK_PHY_LED_ON_LINK10)
|
||||
blink |= MTK_PHY_LED_BLINK_10RX;
|
||||
if (on & MTK_PHY_LED_ON_LINK100)
|
||||
blink |= MTK_PHY_LED_BLINK_100RX;
|
||||
if (on & MTK_PHY_LED_ON_LINK1000)
|
||||
blink |= MTK_PHY_LED_BLINK_1000RX;
|
||||
if (on & MTK_PHY_LED_ON_LINK2500)
|
||||
blink |= MTK_PHY_LED_BLINK_2500RX;
|
||||
} else {
|
||||
blink |= rx_blink_set;
|
||||
}
|
||||
}
|
||||
|
||||
if (rules & BIT(TRIGGER_NETDEV_TX)) {
|
||||
if (on & on_set) {
|
||||
if (on & MTK_PHY_LED_ON_LINK10)
|
||||
blink |= MTK_PHY_LED_BLINK_10TX;
|
||||
if (on & MTK_PHY_LED_ON_LINK100)
|
||||
blink |= MTK_PHY_LED_BLINK_100TX;
|
||||
if (on & MTK_PHY_LED_ON_LINK1000)
|
||||
blink |= MTK_PHY_LED_BLINK_1000TX;
|
||||
if (on & MTK_PHY_LED_ON_LINK2500)
|
||||
blink |= MTK_PHY_LED_BLINK_2500TX;
|
||||
} else {
|
||||
blink |= tx_blink_set;
|
||||
}
|
||||
}
|
||||
|
||||
if (blink || on)
|
||||
set_bit(bit_netdev, led_state);
|
||||
else
|
||||
clear_bit(bit_netdev, led_state);
|
||||
|
||||
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
|
||||
MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
|
||||
MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
|
||||
on);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
|
||||
MTK_PHY_LED1_BLINK_CTRL :
|
||||
MTK_PHY_LED0_BLINK_CTRL, blink);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
|
||||
|
||||
int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
|
||||
unsigned long *delay_off, bool *blinking)
|
||||
{
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
|
||||
*blinking = true;
|
||||
*delay_on = 50;
|
||||
*delay_off = 50;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
|
||||
|
||||
int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
|
||||
unsigned long *led_state, u16 led_on_mask, bool on)
|
||||
{
|
||||
unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
|
||||
bool changed;
|
||||
|
||||
if (on)
|
||||
changed = !test_and_set_bit(bit_on, led_state);
|
||||
else
|
||||
changed = !!test_and_clear_bit(bit_on, led_state);
|
||||
|
||||
changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
|
||||
(index ? 16 : 0), led_state);
|
||||
if (changed)
|
||||
return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
|
||||
MTK_PHY_LED1_ON_CTRL :
|
||||
MTK_PHY_LED0_ON_CTRL,
|
||||
led_on_mask,
|
||||
on ? MTK_PHY_LED_ON_FORCE_ON : 0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
|
||||
|
||||
int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
|
||||
unsigned long *led_state, bool blinking)
|
||||
{
|
||||
unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
|
||||
(index ? 16 : 0);
|
||||
bool changed;
|
||||
|
||||
if (blinking)
|
||||
changed = !test_and_set_bit(bit_blink, led_state);
|
||||
else
|
||||
changed = !!test_and_clear_bit(bit_blink, led_state);
|
||||
|
||||
changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
|
||||
(index ? 16 : 0), led_state);
|
||||
if (changed)
|
||||
return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
|
||||
MTK_PHY_LED1_BLINK_CTRL :
|
||||
MTK_PHY_LED0_BLINK_CTRL,
|
||||
blinking ?
|
||||
MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
|
||||
|
||||
void mtk_phy_leds_state_init(struct phy_device *phydev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; ++i)
|
||||
phydev->drv->led_hw_control_get(phydev, i, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
|
||||
MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
|
||||
MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,119 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Common definition for Mediatek Ethernet PHYs
|
||||
* Author: SkyLake Huang <SkyLake.Huang@mediatek.com>
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_EPHY_H_
|
||||
#define _MTK_EPHY_H_
|
||||
|
||||
#define MTK_EXT_PAGE_ACCESS 0x1f
|
||||
#define MTK_PHY_PAGE_STANDARD 0x0000
|
||||
#define MTK_PHY_PAGE_EXTENDED_1 0x0001
|
||||
#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14
|
||||
/* suprv_media_select_RefClk */
|
||||
#define MTK_PHY_LP_DETECTED_MASK GENMASK(7, 6)
|
||||
#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4)
|
||||
|
||||
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
|
||||
|
||||
/* Registers on Token Ring debug nodes */
|
||||
/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x2 */
|
||||
#define AN_STATE_MASK GENMASK(22, 19)
|
||||
#define AN_STATE_SHIFT 19
|
||||
#define AN_STATE_TX_DISABLE 1
|
||||
|
||||
/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
|
||||
#define AN_NEW_LP_CNT_LIMIT_MASK GENMASK(23, 20)
|
||||
#define AUTO_NP_10XEN BIT(6)
|
||||
|
||||
/* Registers on MDIO_MMD_VEND1 */
|
||||
#define MTK_PHY_LINK_STATUS_MISC (0xa2)
|
||||
#define MTK_PHY_FINAL_SPEED_1000 BIT(3)
|
||||
|
||||
/* Registers on MDIO_MMD_VEND2 */
|
||||
#define MTK_PHY_LED0_ON_CTRL 0x24
|
||||
#define MTK_PHY_LED1_ON_CTRL 0x26
|
||||
#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0)
|
||||
#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0)
|
||||
#define MTK_PHY_LED_ON_LINK1000 BIT(0)
|
||||
#define MTK_PHY_LED_ON_LINK100 BIT(1)
|
||||
#define MTK_PHY_LED_ON_LINK10 BIT(2)
|
||||
#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
|
||||
#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
|
||||
#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
|
||||
#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
|
||||
#define MTK_PHY_LED_ON_LINK2500 BIT(7)
|
||||
#define MTK_PHY_LED_ON_POLARITY BIT(14)
|
||||
#define MTK_PHY_LED_ON_ENABLE BIT(15)
|
||||
|
||||
#define MTK_PHY_LED0_BLINK_CTRL 0x25
|
||||
#define MTK_PHY_LED1_BLINK_CTRL 0x27
|
||||
#define MTK_PHY_LED_BLINK_1000TX BIT(0)
|
||||
#define MTK_PHY_LED_BLINK_1000RX BIT(1)
|
||||
#define MTK_PHY_LED_BLINK_100TX BIT(2)
|
||||
#define MTK_PHY_LED_BLINK_100RX BIT(3)
|
||||
#define MTK_PHY_LED_BLINK_10TX BIT(4)
|
||||
#define MTK_PHY_LED_BLINK_10RX BIT(5)
|
||||
#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
|
||||
#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
|
||||
#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
|
||||
#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
|
||||
#define MTK_PHY_LED_BLINK_2500TX BIT(10)
|
||||
#define MTK_PHY_LED_BLINK_2500RX BIT(11)
|
||||
|
||||
#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \
|
||||
MTK_PHY_LED_ON_LINK100 | \
|
||||
MTK_PHY_LED_ON_LINK10)
|
||||
#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
|
||||
MTK_PHY_LED_BLINK_100RX | \
|
||||
MTK_PHY_LED_BLINK_10RX)
|
||||
#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
|
||||
MTK_PHY_LED_BLINK_100RX | \
|
||||
MTK_PHY_LED_BLINK_10RX)
|
||||
|
||||
#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \
|
||||
MTK_GPHY_LED_ON_SET)
|
||||
#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
|
||||
MTK_GPHY_LED_RX_BLINK_SET)
|
||||
#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
|
||||
MTK_GPHY_LED_TX_BLINK_SET)
|
||||
|
||||
#define MTK_PHY_LED_STATE_FORCE_ON 0
|
||||
#define MTK_PHY_LED_STATE_FORCE_BLINK 1
|
||||
#define MTK_PHY_LED_STATE_NETDEV 2
|
||||
|
||||
u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr);
|
||||
void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 mask, u32 set);
|
||||
void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 mask, u32 set);
|
||||
void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 set);
|
||||
void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
|
||||
u8 data_addr, u32 clr);
|
||||
|
||||
int mtk_phy_read_page(struct phy_device *phydev);
|
||||
int mtk_phy_write_page(struct phy_device *phydev, int page);
|
||||
|
||||
int mtk_gphy_cl22_read_status(struct phy_device *phydev);
|
||||
/*int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
|
||||
unsigned long rules,
|
||||
unsigned long supported_triggers);
|
||||
int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
|
||||
unsigned long rules, unsigned long *led_state,
|
||||
u16 on_set, u16 rx_blink_set, u16 tx_blink_set);
|
||||
int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
|
||||
unsigned long *rules, unsigned long *led_state,
|
||||
u16 on_set, u16 rx_blink_set, u16 tx_blink_set);
|
||||
int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
|
||||
unsigned long *delay_off, bool *blinking);
|
||||
int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
|
||||
unsigned long *led_state, u16 led_on_mask, bool on);
|
||||
int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
|
||||
unsigned long *led_state, bool blinking);
|
||||
void mtk_phy_leds_state_init(struct phy_device *phydev);*/
|
||||
|
||||
#endif /* _MTK_EPHY_H_ */
|
||||
@@ -491,6 +491,7 @@ static int mt7531_mac_port_setup(struct gsw_mt753x *gsw, u32 port,
|
||||
mt7531_set_port_rgmii(gsw, port);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
if (port_cfg->force_link)
|
||||
mt7531_set_port_sgmii_force_mode(gsw, port, port_cfg);
|
||||
else
|
||||
|
||||
@@ -765,6 +765,8 @@ static int mt753x_probe(struct platform_device *pdev)
|
||||
|
||||
gsw->irq = platform_get_irq(pdev, 0);
|
||||
if (gsw->irq >= 0) {
|
||||
INIT_WORK(&gsw->irq_worker, mt753x_irq_worker);
|
||||
|
||||
ret = devm_request_irq(gsw->dev, gsw->irq, mt753x_irq_handler,
|
||||
0, dev_name(gsw->dev), gsw);
|
||||
if (ret) {
|
||||
@@ -772,8 +774,6 @@ static int mt753x_probe(struct platform_device *pdev)
|
||||
gsw->irq);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
INIT_WORK(&gsw->irq_worker, mt753x_irq_worker);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gsw);
|
||||
|
||||
@@ -196,6 +196,7 @@ struct mtk_pcie_port {
|
||||
struct mtk_msi_set msi_sets[PCIE_MSI_SET_NUM];
|
||||
enum mtk_msi_group_type msi_group_type;
|
||||
struct mutex lock;
|
||||
bool soft_off;
|
||||
DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM);
|
||||
};
|
||||
|
||||
@@ -234,6 +235,11 @@ static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct mtk_pcie_port *port = bus->sysdata;
|
||||
|
||||
if (port->soft_off)
|
||||
return 0;
|
||||
|
||||
mtk_pcie_config_tlp_header(bus, devfn, where, size);
|
||||
|
||||
return pci_generic_config_read32(bus, devfn, where, size, val);
|
||||
@@ -242,6 +248,11 @@ static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
static int mtk_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct mtk_pcie_port *port = bus->sysdata;
|
||||
|
||||
if (port->soft_off)
|
||||
return 0;
|
||||
|
||||
mtk_pcie_config_tlp_header(bus, devfn, where, size);
|
||||
|
||||
if (size <= 2)
|
||||
@@ -1257,6 +1268,95 @@ static int __maybe_unused mtk_pcie_turn_off_link(struct mtk_pcie_port *port)
|
||||
50 * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
int mtk_pcie_soft_off(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_host_bridge *host;
|
||||
struct mtk_pcie_port *port;
|
||||
struct pci_dev *dev;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (!bus) {
|
||||
dev_err(port->dev, "There is no bus, please check the host driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
port = bus->sysdata;
|
||||
if (port->soft_off) {
|
||||
dev_err(port->dev, "The soft_off is true, can't soft off\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
host = pci_host_bridge_from_priv(port);
|
||||
dev = pci_get_slot(host->bus, 0);
|
||||
if (!dev) {
|
||||
dev_err(port->dev, "Failed to get device from bus\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Trigger link to L2 state */
|
||||
ret = mtk_pcie_turn_off_link(port);
|
||||
|
||||
pci_save_state(dev);
|
||||
pci_dev_put(dev);
|
||||
mtk_pcie_irq_save(port);
|
||||
port->soft_off = true;
|
||||
mtk_pcie_power_down(port);
|
||||
|
||||
dev_info(port->dev, "mtk pcie soft off done\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_pcie_soft_off);
|
||||
|
||||
int mtk_pcie_soft_on(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_host_bridge *host;
|
||||
struct mtk_pcie_port *port;
|
||||
struct pci_dev *dev;
|
||||
int ret;
|
||||
|
||||
if (!bus) {
|
||||
dev_err(port->dev, "There is no bus, please check the host driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
port = bus->sysdata;
|
||||
if (!port->soft_off) {
|
||||
dev_err(port->dev, "The soft_off is false, can't soft on\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
host = pci_host_bridge_from_priv(port);
|
||||
dev = pci_get_slot(host->bus, 0);
|
||||
if (!dev) {
|
||||
dev_err(port->dev, "Failed to get device from bus\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = mtk_pcie_power_up(port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "Failed to power up RC\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mtk_pcie_startup_port(port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "Failed to detect EP\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
port->soft_off = false;
|
||||
mtk_pcie_irq_restore(port);
|
||||
pci_restore_state(dev);
|
||||
pci_dev_put(dev);
|
||||
|
||||
dev_info(port->dev, "mtk pcie soft on done\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_pcie_soft_on);
|
||||
|
||||
static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct mtk_pcie_port *port = dev_get_drvdata(dev);
|
||||
|
||||
@@ -0,0 +1,769 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* The MT7987 driver based on Linux generic pinctrl binding.
|
||||
*
|
||||
* Copyright (C) 2020 MediaTek Inc.
|
||||
* Author: Tim.Kuo <Tim.Kuo@mediatek.com>
|
||||
*/
|
||||
|
||||
#include "pinctrl-moore.h"
|
||||
|
||||
enum MT7987_PINCTRL_REG_PAGE {
|
||||
GPIO_BASE,
|
||||
IOCFG_RB_BASE,
|
||||
IOCFG_LB_BASE,
|
||||
IOCFG_RT1_BASE,
|
||||
IOCFG_RT2_BASE,
|
||||
IOCFG_TL_BASE,
|
||||
};
|
||||
|
||||
#define MT7987_PIN(_number, _name) MTK_PIN(_number, _name, 0, _number, DRV_GRP4)
|
||||
|
||||
#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
|
||||
_x_bits) \
|
||||
PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
|
||||
_x_bits, 32, 0)
|
||||
|
||||
#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
|
||||
_x_bits) \
|
||||
PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
|
||||
_x_bits, 32, 0)
|
||||
|
||||
|
||||
#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
|
||||
_x_bits) \
|
||||
PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
|
||||
_x_bits, 32, 1)
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_mode_range[] = {
|
||||
PIN_FIELD(0, 49, 0x300, 0x10, 0, 4),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_dir_range[] = {
|
||||
PIN_FIELD(0, 49, 0x0, 0x10, 0, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_di_range[] = {
|
||||
PIN_FIELD(0, 49, 0x200, 0x10, 0, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_do_range[] = {
|
||||
PIN_FIELD(0, 49, 0x100, 0x10, 0, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_ies_range[] = {
|
||||
PIN_FIELD_BASE(0, 0, IOCFG_RT2_BASE, 0x20, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(1, 1, IOCFG_RT2_BASE, 0x20, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(2, 2, IOCFG_RT2_BASE, 0x20, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(3, 3, IOCFG_TL_BASE, 0x20, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(4, 4, IOCFG_TL_BASE, 0x20, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(5, 5, IOCFG_TL_BASE, 0x20, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(6, 6, IOCFG_TL_BASE, 0x20, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(7, 7, IOCFG_TL_BASE, 0x20, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(8, 8, IOCFG_RB_BASE, 0x10, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(9, 9, IOCFG_RB_BASE, 0x10, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(10, 10, IOCFG_RB_BASE, 0x10, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(11, 11, IOCFG_RB_BASE, 0x10, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(12, 12, IOCFG_RB_BASE, 0x10, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(13, 13, IOCFG_RT1_BASE, 0x20, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(14, 14, IOCFG_RT1_BASE, 0x20, 0x10, 15, 1),
|
||||
PIN_FIELD_BASE(15, 15, IOCFG_RT1_BASE, 0x20, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(16, 16, IOCFG_RT1_BASE, 0x20, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(17, 17, IOCFG_RT1_BASE, 0x20, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(18, 18, IOCFG_RT1_BASE, 0x20, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(19, 19, IOCFG_RT1_BASE, 0x20, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(20, 20, IOCFG_RT1_BASE, 0x20, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(21, 21, IOCFG_RT1_BASE, 0x20, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(22, 22, IOCFG_RT1_BASE, 0x20, 0x10, 12, 1),
|
||||
PIN_FIELD_BASE(23, 23, IOCFG_RT1_BASE, 0x20, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(24, 24, IOCFG_RT1_BASE, 0x20, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(25, 25, IOCFG_RT1_BASE, 0x20, 0x10, 13, 1),
|
||||
PIN_FIELD_BASE(26, 26, IOCFG_RT1_BASE, 0x20, 0x10, 14, 1),
|
||||
PIN_FIELD_BASE(27, 27, IOCFG_RT2_BASE, 0x20, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(28, 28, IOCFG_RT2_BASE, 0x20, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(29, 29, IOCFG_RT2_BASE, 0x20, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(30, 30, IOCFG_RT2_BASE, 0x20, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(31, 31, IOCFG_TL_BASE, 0x20, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(32, 32, IOCFG_TL_BASE, 0x20, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(33, 33, IOCFG_LB_BASE, 0x20, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(34, 34, IOCFG_LB_BASE, 0x20, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(35, 35, IOCFG_LB_BASE, 0x20, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(36, 36, IOCFG_LB_BASE, 0x20, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(37, 37, IOCFG_LB_BASE, 0x20, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(38, 38, IOCFG_LB_BASE, 0x20, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(39, 39, IOCFG_RT1_BASE, 0x20, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(40, 40, IOCFG_RT1_BASE, 0x20, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(41, 41, IOCFG_RT2_BASE, 0x20, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(42, 42, IOCFG_RT2_BASE, 0x20, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(43, 43, IOCFG_RT2_BASE, 0x20, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(44, 44, IOCFG_RT2_BASE, 0x20, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(45, 45, IOCFG_RT2_BASE, 0x20, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(46, 46, IOCFG_TL_BASE, 0x20, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(47, 47, IOCFG_TL_BASE, 0x20, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(48, 48, IOCFG_TL_BASE, 0x20, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(49, 49, IOCFG_TL_BASE, 0x20, 0x10, 8, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_smt_range[] = {
|
||||
PIN_FIELD_BASE(0, 0, IOCFG_RT2_BASE, 0x90, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(1, 1, IOCFG_RT2_BASE, 0x90, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(2, 2, IOCFG_RT2_BASE, 0x90, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(3, 3, IOCFG_TL_BASE, 0x90, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(4, 4, IOCFG_TL_BASE, 0x90, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(5, 5, IOCFG_TL_BASE, 0x90, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(6, 6, IOCFG_TL_BASE, 0x90, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(7, 7, IOCFG_TL_BASE, 0x90, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(8, 8, IOCFG_RB_BASE, 0x70, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(9, 9, IOCFG_RB_BASE, 0x70, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(10, 10, IOCFG_RB_BASE, 0x70, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(11, 11, IOCFG_RB_BASE, 0x70, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(12, 12, IOCFG_RB_BASE, 0x70, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(13, 13, IOCFG_RT1_BASE, 0xA0, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(14, 14, IOCFG_RT1_BASE, 0xA0, 0x10, 15, 1),
|
||||
PIN_FIELD_BASE(15, 15, IOCFG_RT1_BASE, 0xA0, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(16, 16, IOCFG_RT1_BASE, 0xA0, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(17, 17, IOCFG_RT1_BASE, 0xA0, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(18, 18, IOCFG_RT1_BASE, 0xA0, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(19, 19, IOCFG_RT1_BASE, 0xA0, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(20, 20, IOCFG_RT1_BASE, 0xA0, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(21, 21, IOCFG_RT1_BASE, 0xA0, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(22, 22, IOCFG_RT1_BASE, 0xA0, 0x10, 12, 1),
|
||||
PIN_FIELD_BASE(23, 23, IOCFG_RT1_BASE, 0xA0, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(24, 24, IOCFG_RT1_BASE, 0xA0, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(25, 25, IOCFG_RT1_BASE, 0xA0, 0x10, 13, 1),
|
||||
PIN_FIELD_BASE(26, 26, IOCFG_RT1_BASE, 0xA0, 0x10, 14, 1),
|
||||
PIN_FIELD_BASE(27, 27, IOCFG_RT2_BASE, 0x90, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(28, 28, IOCFG_RT2_BASE, 0x90, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(29, 29, IOCFG_RT2_BASE, 0x90, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(30, 30, IOCFG_RT2_BASE, 0x90, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(31, 31, IOCFG_TL_BASE, 0x90, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(32, 32, IOCFG_TL_BASE, 0x90, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(33, 33, IOCFG_LB_BASE, 0x60, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(34, 34, IOCFG_LB_BASE, 0x60, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(35, 35, IOCFG_LB_BASE, 0x60, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(36, 36, IOCFG_LB_BASE, 0x60, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(37, 37, IOCFG_LB_BASE, 0x60, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(38, 38, IOCFG_LB_BASE, 0x60, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(39, 39, IOCFG_RT1_BASE, 0xA0, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(40, 40, IOCFG_RT1_BASE, 0xA0, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(41, 41, IOCFG_RT2_BASE, 0x90, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(42, 42, IOCFG_RT2_BASE, 0x90, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(43, 43, IOCFG_RT2_BASE, 0x90, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(44, 44, IOCFG_RT2_BASE, 0x90, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(45, 45, IOCFG_RT2_BASE, 0x90, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(46, 46, IOCFG_TL_BASE, 0x90, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(47, 47, IOCFG_TL_BASE, 0x90, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(48, 48, IOCFG_TL_BASE, 0x90, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(49, 49, IOCFG_TL_BASE, 0x90, 0x10, 8, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_pu_range[] = {
|
||||
PIN_FIELD_BASE(33, 33, IOCFG_LB_BASE, 0x40, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(34, 34, IOCFG_LB_BASE, 0x40, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(35, 35, IOCFG_LB_BASE, 0x40, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(36, 36, IOCFG_LB_BASE, 0x40, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(37, 37, IOCFG_LB_BASE, 0x40, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(38, 38, IOCFG_LB_BASE, 0x40, 0x10, 5, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_pd_range[] = {
|
||||
PIN_FIELD_BASE(33, 33, IOCFG_LB_BASE, 0x30, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(34, 34, IOCFG_LB_BASE, 0x30, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(35, 35, IOCFG_LB_BASE, 0x30, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(36, 36, IOCFG_LB_BASE, 0x30, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(37, 37, IOCFG_LB_BASE, 0x30, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(38, 38, IOCFG_LB_BASE, 0x30, 0x10, 5, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_drv_range[] = {
|
||||
PIN_FIELD_BASE(0, 0, IOCFG_RT2_BASE, 0x0, 0x10, 9, 3),
|
||||
PIN_FIELD_BASE(1, 1, IOCFG_RT2_BASE, 0x0, 0x10, 6, 3),
|
||||
PIN_FIELD_BASE(2, 2, IOCFG_RT2_BASE, 0x10, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(3, 3, IOCFG_TL_BASE, 0x0, 0x10, 6, 3),
|
||||
PIN_FIELD_BASE(4, 4, IOCFG_TL_BASE, 0x0, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(5, 5, IOCFG_TL_BASE, 0x0, 0x10, 9, 3),
|
||||
PIN_FIELD_BASE(6, 6, IOCFG_TL_BASE, 0x0, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(7, 7, IOCFG_TL_BASE, 0x0, 0x10, 12, 3),
|
||||
PIN_FIELD_BASE(8, 8, IOCFG_RB_BASE, 0x0, 0x10, 6, 3),
|
||||
PIN_FIELD_BASE(9, 9, IOCFG_RB_BASE, 0x0, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(10, 10, IOCFG_RB_BASE, 0x0, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(11, 11, IOCFG_RB_BASE, 0x0, 0x10, 9, 3),
|
||||
PIN_FIELD_BASE(12, 12, IOCFG_RB_BASE, 0x0, 0x10, 12, 3),
|
||||
PIN_FIELD_BASE(13, 13, IOCFG_RT1_BASE, 0x0, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(14, 14, IOCFG_RT1_BASE, 0x10, 0x10, 15, 3),
|
||||
PIN_FIELD_BASE(15, 15, IOCFG_RT1_BASE, 0x0, 0x10, 9, 3),
|
||||
PIN_FIELD_BASE(16, 16, IOCFG_RT1_BASE, 0x0, 0x10, 21, 3),
|
||||
PIN_FIELD_BASE(17, 17, IOCFG_RT1_BASE, 0x0, 0x10, 18, 3),
|
||||
PIN_FIELD_BASE(18, 18, IOCFG_RT1_BASE, 0x0, 0x10, 12, 3),
|
||||
PIN_FIELD_BASE(19, 19, IOCFG_RT1_BASE, 0x0, 0x10, 15, 3),
|
||||
PIN_FIELD_BASE(20, 20, IOCFG_RT1_BASE, 0x0, 0x10, 24, 3),
|
||||
PIN_FIELD_BASE(21, 21, IOCFG_RT1_BASE, 0x0, 0x10, 27, 3),
|
||||
PIN_FIELD_BASE(22, 22, IOCFG_RT1_BASE, 0x10, 0x10, 6, 3),
|
||||
PIN_FIELD_BASE(23, 23, IOCFG_RT1_BASE, 0x10, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(24, 24, IOCFG_RT1_BASE, 0x10, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(25, 25, IOCFG_RT1_BASE, 0x10, 0x10, 9, 3),
|
||||
PIN_FIELD_BASE(26, 26, IOCFG_RT1_BASE, 0x10, 0x10, 12, 3),
|
||||
PIN_FIELD_BASE(27, 27, IOCFG_RT2_BASE, 0x0, 0x10, 27, 3),
|
||||
PIN_FIELD_BASE(28, 28, IOCFG_RT2_BASE, 0x0, 0x10, 21, 3),
|
||||
PIN_FIELD_BASE(29, 29, IOCFG_RT2_BASE, 0x0, 0x10, 24, 3),
|
||||
PIN_FIELD_BASE(30, 30, IOCFG_RT2_BASE, 0x10, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(31, 31, IOCFG_TL_BASE, 0x0, 0x10, 15, 3),
|
||||
PIN_FIELD_BASE(32, 32, IOCFG_TL_BASE, 0x0, 0x10, 18, 3),
|
||||
PIN_FIELD_BASE(33, 33, IOCFG_LB_BASE, 0x0, 0x10, 6, 3),
|
||||
PIN_FIELD_BASE(34, 34, IOCFG_LB_BASE, 0x0, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(35, 35, IOCFG_LB_BASE, 0x0, 0x10, 12, 3),
|
||||
PIN_FIELD_BASE(36, 36, IOCFG_LB_BASE, 0x0, 0x10, 9, 3),
|
||||
PIN_FIELD_BASE(37, 37, IOCFG_LB_BASE, 0x0, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(38, 38, IOCFG_LB_BASE, 0x0, 0x10, 15, 3),
|
||||
PIN_FIELD_BASE(39, 39, IOCFG_RT1_BASE, 0x0, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(40, 40, IOCFG_RT1_BASE, 0x0, 0x10, 6, 3),
|
||||
PIN_FIELD_BASE(41, 41, IOCFG_RT2_BASE, 0x0, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(42, 42, IOCFG_RT2_BASE, 0x0, 0x10, 3, 3),
|
||||
PIN_FIELD_BASE(43, 43, IOCFG_RT2_BASE, 0x0, 0x10, 12, 3),
|
||||
PIN_FIELD_BASE(44, 44, IOCFG_RT2_BASE, 0x0, 0x10, 15, 3),
|
||||
PIN_FIELD_BASE(45, 45, IOCFG_RT2_BASE, 0x0, 0x10, 18, 3),
|
||||
PIN_FIELD_BASE(46, 46, IOCFG_TL_BASE, 0x0, 0x10, 27, 3),
|
||||
PIN_FIELD_BASE(47, 47, IOCFG_TL_BASE, 0x10, 0x10, 0, 3),
|
||||
PIN_FIELD_BASE(48, 48, IOCFG_TL_BASE, 0x0, 0x10, 21, 3),
|
||||
PIN_FIELD_BASE(49, 49, IOCFG_TL_BASE, 0x0, 0x10, 24, 3),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_pupd_range[] = {
|
||||
PIN_FIELD_BASE(0, 0, IOCFG_RT2_BASE, 0x30, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(1, 1, IOCFG_RT2_BASE, 0x30, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(2, 2, IOCFG_RT2_BASE, 0x30, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(3, 3, IOCFG_TL_BASE, 0x30, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(4, 4, IOCFG_TL_BASE, 0x30, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(5, 5, IOCFG_TL_BASE, 0x30, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(6, 6, IOCFG_TL_BASE, 0x30, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(7, 7, IOCFG_TL_BASE, 0x30, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(8, 8, IOCFG_RB_BASE, 0x20, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(9, 9, IOCFG_RB_BASE, 0x20, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(10, 10, IOCFG_RB_BASE, 0x20, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(11, 11, IOCFG_RB_BASE, 0x20, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(12, 12, IOCFG_RB_BASE, 0x20, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(13, 13, IOCFG_RT1_BASE, 0x30, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(14, 14, IOCFG_RT1_BASE, 0x30, 0x10, 15, 1),
|
||||
PIN_FIELD_BASE(15, 15, IOCFG_RT1_BASE, 0x30, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(16, 16, IOCFG_RT1_BASE, 0x30, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(17, 17, IOCFG_RT1_BASE, 0x30, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(18, 18, IOCFG_RT1_BASE, 0x30, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(19, 19, IOCFG_RT1_BASE, 0x30, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(20, 20, IOCFG_RT1_BASE, 0x30, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(21, 21, IOCFG_RT1_BASE, 0x30, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(22, 22, IOCFG_RT1_BASE, 0x30, 0x10, 12, 1),
|
||||
PIN_FIELD_BASE(23, 23, IOCFG_RT1_BASE, 0x30, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(24, 24, IOCFG_RT1_BASE, 0x30, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(25, 25, IOCFG_RT1_BASE, 0x30, 0x10, 13, 1),
|
||||
PIN_FIELD_BASE(26, 26, IOCFG_RT1_BASE, 0x30, 0x10, 14, 1),
|
||||
PIN_FIELD_BASE(27, 27, IOCFG_RT2_BASE, 0x30, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(28, 28, IOCFG_RT2_BASE, 0x30, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(29, 29, IOCFG_RT2_BASE, 0x30, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(30, 30, IOCFG_RT2_BASE, 0x30, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(31, 31, IOCFG_TL_BASE, 0x30, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(32, 32, IOCFG_TL_BASE, 0x30, 0x10, 6, 1),
|
||||
|
||||
PIN_FIELD_BASE(39, 39, IOCFG_RT1_BASE, 0x30, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(40, 40, IOCFG_RT1_BASE, 0x30, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(41, 41, IOCFG_RT2_BASE, 0x30, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(42, 42, IOCFG_RT2_BASE, 0x30, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(43, 43, IOCFG_RT2_BASE, 0x30, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(44, 44, IOCFG_RT2_BASE, 0x30, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(45, 45, IOCFG_RT2_BASE, 0x30, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(46, 46, IOCFG_TL_BASE, 0x30, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(47, 47, IOCFG_TL_BASE, 0x30, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(48, 48, IOCFG_TL_BASE, 0x30, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(49, 49, IOCFG_TL_BASE, 0x30, 0x10, 8, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_r0_range[] = {
|
||||
PIN_FIELD_BASE(0, 0, IOCFG_RT2_BASE, 0x40, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(1, 1, IOCFG_RT2_BASE, 0x40, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(2, 2, IOCFG_RT2_BASE, 0x40, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(3, 3, IOCFG_TL_BASE, 0x40, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(4, 4, IOCFG_TL_BASE, 0x40, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(5, 5, IOCFG_TL_BASE, 0x40, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(6, 6, IOCFG_TL_BASE, 0x40, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(7, 7, IOCFG_TL_BASE, 0x40, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(8, 8, IOCFG_RB_BASE, 0x30, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(9, 9, IOCFG_RB_BASE, 0x30, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(10, 10, IOCFG_RB_BASE, 0x30, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(11, 11, IOCFG_RB_BASE, 0x30, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(12, 12, IOCFG_RB_BASE, 0x30, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(13, 13, IOCFG_RT1_BASE, 0x40, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(14, 14, IOCFG_RT1_BASE, 0x40, 0x10, 15, 1),
|
||||
PIN_FIELD_BASE(15, 15, IOCFG_RT1_BASE, 0x40, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(16, 16, IOCFG_RT1_BASE, 0x40, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(17, 17, IOCFG_RT1_BASE, 0x40, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(18, 18, IOCFG_RT1_BASE, 0x40, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(19, 19, IOCFG_RT1_BASE, 0x40, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(20, 20, IOCFG_RT1_BASE, 0x40, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(21, 21, IOCFG_RT1_BASE, 0x40, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(22, 22, IOCFG_RT1_BASE, 0x40, 0x10, 12, 1),
|
||||
PIN_FIELD_BASE(23, 23, IOCFG_RT1_BASE, 0x40, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(24, 24, IOCFG_RT1_BASE, 0x40, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(25, 25, IOCFG_RT1_BASE, 0x40, 0x10, 13, 1),
|
||||
PIN_FIELD_BASE(26, 26, IOCFG_RT1_BASE, 0x40, 0x10, 14, 1),
|
||||
PIN_FIELD_BASE(27, 27, IOCFG_RT2_BASE, 0x40, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(28, 28, IOCFG_RT2_BASE, 0x40, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(29, 29, IOCFG_RT2_BASE, 0x40, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(30, 30, IOCFG_RT2_BASE, 0x40, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(31, 31, IOCFG_TL_BASE, 0x40, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(32, 32, IOCFG_TL_BASE, 0x40, 0x10, 6, 1),
|
||||
|
||||
PIN_FIELD_BASE(39, 39, IOCFG_RT1_BASE, 0x40, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(40, 40, IOCFG_RT1_BASE, 0x40, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(41, 41, IOCFG_RT2_BASE, 0x40, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(42, 42, IOCFG_RT2_BASE, 0x40, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(43, 43, IOCFG_RT2_BASE, 0x40, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(44, 44, IOCFG_RT2_BASE, 0x40, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(45, 45, IOCFG_RT2_BASE, 0x40, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(46, 46, IOCFG_TL_BASE, 0x40, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(47, 47, IOCFG_TL_BASE, 0x40, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(48, 48, IOCFG_TL_BASE, 0x40, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(49, 49, IOCFG_TL_BASE, 0x40, 0x10, 8, 1),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_field_calc mt7987_pin_r1_range[] = {
|
||||
PIN_FIELD_BASE(0, 0, IOCFG_RT2_BASE, 0x50, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(1, 1, IOCFG_RT2_BASE, 0x50, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(2, 2, IOCFG_RT2_BASE, 0x50, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(3, 3, IOCFG_TL_BASE, 0x50, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(4, 4, IOCFG_TL_BASE, 0x50, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(5, 5, IOCFG_TL_BASE, 0x50, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(6, 6, IOCFG_TL_BASE, 0x50, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(7, 7, IOCFG_TL_BASE, 0x50, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(8, 8, IOCFG_RB_BASE, 0x40, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(9, 9, IOCFG_RB_BASE, 0x40, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(10, 10, IOCFG_RB_BASE, 0x40, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(11, 11, IOCFG_RB_BASE, 0x40, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(12, 12, IOCFG_RB_BASE, 0x40, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(13, 13, IOCFG_RT1_BASE, 0x50, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(14, 14, IOCFG_RT1_BASE, 0x50, 0x10, 15, 1),
|
||||
PIN_FIELD_BASE(15, 15, IOCFG_RT1_BASE, 0x50, 0x10, 3, 1),
|
||||
PIN_FIELD_BASE(16, 16, IOCFG_RT1_BASE, 0x50, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(17, 17, IOCFG_RT1_BASE, 0x50, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(18, 18, IOCFG_RT1_BASE, 0x50, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(19, 19, IOCFG_RT1_BASE, 0x50, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(20, 20, IOCFG_RT1_BASE, 0x50, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(21, 21, IOCFG_RT1_BASE, 0x50, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(22, 22, IOCFG_RT1_BASE, 0x50, 0x10, 12, 1),
|
||||
PIN_FIELD_BASE(23, 23, IOCFG_RT1_BASE, 0x50, 0x10, 11, 1),
|
||||
PIN_FIELD_BASE(24, 24, IOCFG_RT1_BASE, 0x50, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(25, 25, IOCFG_RT1_BASE, 0x50, 0x10, 13, 1),
|
||||
PIN_FIELD_BASE(26, 26, IOCFG_RT1_BASE, 0x50, 0x10, 14, 1),
|
||||
PIN_FIELD_BASE(27, 27, IOCFG_RT2_BASE, 0x50, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(28, 28, IOCFG_RT2_BASE, 0x50, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(29, 29, IOCFG_RT2_BASE, 0x50, 0x10, 8, 1),
|
||||
PIN_FIELD_BASE(30, 30, IOCFG_RT2_BASE, 0x50, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(31, 31, IOCFG_TL_BASE, 0x50, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(32, 32, IOCFG_TL_BASE, 0x50, 0x10, 6, 1),
|
||||
|
||||
PIN_FIELD_BASE(39, 39, IOCFG_RT1_BASE, 0x50, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(40, 40, IOCFG_RT1_BASE, 0x50, 0x10, 2, 1),
|
||||
PIN_FIELD_BASE(41, 41, IOCFG_RT2_BASE, 0x50, 0x10, 0, 1),
|
||||
PIN_FIELD_BASE(42, 42, IOCFG_RT2_BASE, 0x50, 0x10, 1, 1),
|
||||
PIN_FIELD_BASE(43, 43, IOCFG_RT2_BASE, 0x50, 0x10, 4, 1),
|
||||
PIN_FIELD_BASE(44, 44, IOCFG_RT2_BASE, 0x50, 0x10, 5, 1),
|
||||
PIN_FIELD_BASE(45, 45, IOCFG_RT2_BASE, 0x50, 0x10, 6, 1),
|
||||
PIN_FIELD_BASE(46, 46, IOCFG_TL_BASE, 0x50, 0x10, 9, 1),
|
||||
PIN_FIELD_BASE(47, 47, IOCFG_TL_BASE, 0x50, 0x10, 10, 1),
|
||||
PIN_FIELD_BASE(48, 48, IOCFG_TL_BASE, 0x50, 0x10, 7, 1),
|
||||
PIN_FIELD_BASE(49, 49, IOCFG_TL_BASE, 0x50, 0x10, 8, 1),
|
||||
};
|
||||
|
||||
static const unsigned int mt7987_pull_type[] = {
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PUPD_R1R0_TYPE,/*7*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*8*/ MTK_PULL_PUPD_R1R0_TYPE,/*9*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*16*/ MTK_PULL_PUPD_R1R0_TYPE,/*17*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PU_PD_TYPE,/*33*/
|
||||
MTK_PULL_PU_PD_TYPE,/*34*/ MTK_PULL_PU_PD_TYPE,/*35*/
|
||||
MTK_PULL_PU_PD_TYPE,/*36*/ MTK_PULL_PU_PD_TYPE,/*37*/
|
||||
MTK_PULL_PU_PD_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
|
||||
MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
|
||||
};
|
||||
|
||||
static const struct mtk_pin_reg_calc mt7987_reg_cals[] = {
|
||||
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7987_pin_mode_range),
|
||||
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7987_pin_dir_range),
|
||||
[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7987_pin_di_range),
|
||||
[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7987_pin_do_range),
|
||||
[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7987_pin_smt_range),
|
||||
[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7987_pin_ies_range),
|
||||
[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7987_pin_pu_range),
|
||||
[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7987_pin_pd_range),
|
||||
[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7987_pin_drv_range),
|
||||
[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7987_pin_pupd_range),
|
||||
[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7987_pin_r0_range),
|
||||
[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7987_pin_r1_range),
|
||||
};
|
||||
|
||||
static const struct mtk_pin_desc mt7987_pins[] = {
|
||||
MT7987_PIN(0, "GPIO_WPS"),
|
||||
MT7987_PIN(1, "GPIO_RESET"),
|
||||
MT7987_PIN(2, "SYS_WATCHDOG"),
|
||||
MT7987_PIN(3, "JTAG_JTDO"),
|
||||
MT7987_PIN(4, "JTAG_JTDI"),
|
||||
MT7987_PIN(5, "JTAG_JTMS"),
|
||||
MT7987_PIN(6, "JTAG_JTCLK"),
|
||||
MT7987_PIN(7, "JTAG_JTRST_N"),
|
||||
MT7987_PIN(8, "PCM_DTX_I2S_DOUT"),
|
||||
MT7987_PIN(9, "PCM_DRX_I2S_DIN"),
|
||||
MT7987_PIN(10, "PCM_CLK_I2S_BCLK"),
|
||||
MT7987_PIN(11, "PCM_FS_I2S_LRCK"),
|
||||
MT7987_PIN(12, "PCM_MCK_I2S_MCLK"),
|
||||
MT7987_PIN(13, "PWM0"),
|
||||
MT7987_PIN(14, "USB_VBUS"),
|
||||
MT7987_PIN(15, "SPI0_CLK"),
|
||||
MT7987_PIN(16, "SPI0_MOSI"),
|
||||
MT7987_PIN(17, "SPI0_MISO"),
|
||||
MT7987_PIN(18, "SPI0_CS"),
|
||||
MT7987_PIN(19, "SPI0_HOLD"),
|
||||
MT7987_PIN(20, "SPI0_WP"),
|
||||
MT7987_PIN(21, "SPI1_CLK"),
|
||||
MT7987_PIN(22, "SPI1_MOSI"),
|
||||
MT7987_PIN(23, "SPI1_MISO"),
|
||||
MT7987_PIN(24, "SPI1_CS"),
|
||||
MT7987_PIN(25, "SPI2_CLK"),
|
||||
MT7987_PIN(26, "SPI2_MOSI"),
|
||||
MT7987_PIN(27, "SPI2_MISO"),
|
||||
MT7987_PIN(28, "SPI2_CS"),
|
||||
MT7987_PIN(29, "SPI2_HOLD"),
|
||||
MT7987_PIN(30, "SPI2_WP"),
|
||||
MT7987_PIN(31, "UART0_RXD"),
|
||||
MT7987_PIN(32, "UART0_TXD"),
|
||||
MT7987_PIN(33, "PCIE_PERESET_N_0"),
|
||||
MT7987_PIN(34, "PCIE_CLK_REQ_0"),
|
||||
MT7987_PIN(35, "PCIE_WAKE_N_0"),
|
||||
MT7987_PIN(36, "PCIE_PERESET_N_1"),
|
||||
MT7987_PIN(37, "PCIE_CLK_REQ_1"),
|
||||
MT7987_PIN(38, "PCIE_WAKE_N_1"),
|
||||
MT7987_PIN(39, "SMI_MDC"),
|
||||
MT7987_PIN(40, "SMI_MDIO"),
|
||||
MT7987_PIN(41, "GBE_INT"),
|
||||
MT7987_PIN(42, "GBE_RESET"),
|
||||
MT7987_PIN(43, "I2C_SCLK"),
|
||||
MT7987_PIN(44, "I2C_SDATA"),
|
||||
MT7987_PIN(45, "2P5G_LED0"),
|
||||
MT7987_PIN(46, "UART1_RXD"),
|
||||
MT7987_PIN(47, "UART1_TXD"),
|
||||
MT7987_PIN(48, "UART1_CTS"),
|
||||
MT7987_PIN(49, "UART1_RTS"),
|
||||
};
|
||||
|
||||
/* watchdog */
|
||||
static const int mt7987_watchdog_pins[] = {2};
|
||||
static const int mt7987_watchdog_funcs[] = {1};
|
||||
|
||||
/* jtag */
|
||||
static const int mt7987_jtag_pins[] = {3, 4, 5, 6, 7};
|
||||
static const int mt7987_jtag_funcs[] = {1, 1, 1, 1, 1};
|
||||
|
||||
/* pcm */
|
||||
static const int mt7987_pcm0_0_pins[] = {3, 4, 5, 6, 7};
|
||||
static const int mt7987_pcm0_0_funcs[] = {2, 2, 2, 2, 2};
|
||||
|
||||
static const int mt7987_pcm0_1_pins[] = {8, 9, 10, 11, 12};
|
||||
static const int mt7987_pcm0_1_funcs[] = {1, 1, 1, 1, 1};
|
||||
|
||||
/* uart */
|
||||
static const int mt7987_uart0_pins[] = {31, 32};
|
||||
static const int mt7987_uart0_funcs[] = {1, 1};
|
||||
|
||||
static const int mt7987_uart1_0_pins[] = {3, 4, 5, 6};
|
||||
static const int mt7987_uart1_0_funcs[] = {3, 3, 3, 3};
|
||||
|
||||
static const int mt7987_uart1_1_pins[] = {21, 22, 23, 24};
|
||||
static const int mt7987_uart1_1_funcs[] = {3, 3, 3, 3};
|
||||
|
||||
static const int mt7987_uart1_2_pins[] = {46, 47, 48, 49};
|
||||
static const int mt7987_uart1_2_funcs[] = {1, 1, 1, 1};
|
||||
|
||||
static const int mt7987_uart2_0_pins[] = {8, 9, 10, 11};
|
||||
static const int mt7987_uart2_0_funcs[] = {2, 2, 2, 2};
|
||||
|
||||
static const int mt7987_uart2_1_pins[] = {25, 26, 27, 28};
|
||||
static const int mt7987_uart2_1_funcs[] = {2, 2, 2, 2};
|
||||
|
||||
/* pwm */
|
||||
static const int mt7987_pwm0_pins[] = {13};
|
||||
static const int mt7987_pwm0_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pwm1_0_pins[] = {7};
|
||||
static const int mt7987_pwm1_0_funcs[] = {3};
|
||||
|
||||
static const int mt7987_pwm1_1_pins[] = {43};
|
||||
static const int mt7987_pwm1_1_funcs[] = {2};
|
||||
|
||||
static const int mt7987_pwm2_0_pins[] = {12};
|
||||
static const int mt7987_pwm2_0_funcs[] = {2};
|
||||
|
||||
static const int mt7987_pwm2_1_pins[] = {44};
|
||||
static const int mt7987_pwm2_1_funcs[] = {2};
|
||||
|
||||
/* vbus */
|
||||
static const int mt7987_drv_vbus_p1_pins[] = {14};
|
||||
static const int mt7987_drv_vbus_p1_funcs[] = {1};
|
||||
|
||||
static const int mt7987_drv_vbus_pins[] = {48};
|
||||
static const int mt7987_drv_vbus_funcs[] = {3};
|
||||
|
||||
/* 2p5gbe_led */
|
||||
static const int mt7987_2p5gbe_led0_pins[] = {45};
|
||||
static const int mt7987_2p5gbe_led0_funcs[] = {1};
|
||||
|
||||
static const int mt7987_2p5gbe_led1_0_pins[] = {13};
|
||||
static const int mt7987_2p5gbe_led1_0_funcs[] = {2};
|
||||
|
||||
static const int mt7987_2p5gbe_led1_1_pins[] = {49};
|
||||
static const int mt7987_2p5gbe_led1_1_funcs[] = {3};
|
||||
|
||||
/* mdc, mdio */
|
||||
static const int mt7987_2p5g_ext_mdc_mdio_pins[] = {23, 24};
|
||||
static const int mt7987_2p5g_ext_mdc_mdio_funcs[] = {4, 4};
|
||||
|
||||
static const int mt7987_mdc_mdio_pins[] = {39, 40};
|
||||
static const int mt7987_mdc_mdio_funcs[] = {1, 1};
|
||||
|
||||
/* spi */
|
||||
static const int mt7987_spi0_pins[] = {15, 16, 17, 18};
|
||||
static const int mt7987_spi0_funcs[] = {1, 1, 1, 1};
|
||||
|
||||
static const int mt7987_spi0_wp_hold_pins[] = {19, 20};
|
||||
static const int mt7987_spi0_wp_hold_funcs[] = {1, 1};
|
||||
|
||||
static const int mt7987_spi1_pins[] = {21, 22, 23, 24};
|
||||
static const int mt7987_spi1_funcs[] = {1, 1, 1, 1};
|
||||
|
||||
static const int mt7987_spi1_1_pins[] = {46, 47, 48, 49};
|
||||
static const int mt7987_spi1_1_funcs[] = {2, 2, 2, 2};
|
||||
|
||||
static const int mt7987_spi2_pins[] = {25, 26, 27, 28};
|
||||
static const int mt7987_spi2_funcs[] = {1, 1, 1, 1};
|
||||
|
||||
static const int mt7987_spi2_wp_hold_pins[] = {29, 30};
|
||||
static const int mt7987_spi2_wp_hold_funcs[] = {1, 1};
|
||||
|
||||
/* emmc */
|
||||
static const int mt7987_emmc_45_pins[] = {14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
|
||||
static const int mt7987_emmc_45_funcs[] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
|
||||
|
||||
/* sd */
|
||||
static const int mt7987_sd_pins[] = {15, 16, 17, 18, 23, 24};
|
||||
static const int mt7987_sd_funcs[] = {2, 2, 2, 2, 2, 2};
|
||||
|
||||
/* i2c */
|
||||
static const int mt7987_i2c0_0_pins[] = {29, 30};
|
||||
static const int mt7987_i2c0_0_funcs[] = {2, 2};
|
||||
|
||||
static const int mt7987_i2c0_1_pins[] = {39, 40};
|
||||
static const int mt7987_i2c0_1_funcs[] = {2, 2};
|
||||
|
||||
static const int mt7987_i2c0_2_pins[] = {43, 44};
|
||||
static const int mt7987_i2c0_2_funcs[] = {1, 1};
|
||||
|
||||
/* pcie */
|
||||
static const int mt7987_pcie0_pereset_pins[] = {33};
|
||||
static const int mt7987_pcie0_pereset_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pcie0_clkreq_pins[] = {34};
|
||||
static const int mt7987_pcie0_clkreq_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pcie0_wake_pins[] = {35};
|
||||
static const int mt7987_pcie0_wake_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pcie1_pereset_pins[] = {36};
|
||||
static const int mt7987_pcie1_pereset_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pcie1_clkreq_pins[] = {37};
|
||||
static const int mt7987_pcie1_clkreq_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pcie1_wake_pins[] = {38};
|
||||
static const int mt7987_pcie1_wake_funcs[] = {1};
|
||||
|
||||
static const int mt7987_pcie_phy_i2c_pins[] = {43, 44};
|
||||
static const int mt7987_pcie_phy_i2c_funcs[] = {3, 3};
|
||||
|
||||
/* snfi */
|
||||
static const int mt7987_snfi_pins[] = {25, 26, 27, 28, 29, 30};
|
||||
static const int mt7987_snfi_funcs[] = {3, 3, 3, 3, 3, 3};
|
||||
|
||||
/*
|
||||
* - int hsgmii :
|
||||
* For pin41 and pin46, they now can only be used as gpio mode for polling
|
||||
* event. Hence, there's no need to open their pinctrl setting.
|
||||
* - dfd, udi :
|
||||
* Due to dfd & udi functions are only used as detection pins for cpu during
|
||||
* dvt testing stage, we also remove their pinctrl setting.
|
||||
*/
|
||||
|
||||
//static mt7987_hsgmii_pins[] = {};
|
||||
//static mt7987_hsgmii_functs[] = {};
|
||||
//static mt7987_dfd_pins[] = {};
|
||||
//static mt7987_dfd_functs[] = {};
|
||||
//static mt7987_udi_pins[] = {};
|
||||
//static mt7987_udi_functs[] = {};
|
||||
|
||||
static const struct group_desc mt7987_groups[] = {
|
||||
PINCTRL_PIN_GROUP("watchdog", mt7987_watchdog),
|
||||
PINCTRL_PIN_GROUP("jtag", mt7987_jtag),
|
||||
PINCTRL_PIN_GROUP("pcm0_0", mt7987_pcm0_0),
|
||||
PINCTRL_PIN_GROUP("pcm0_1", mt7987_pcm0_1),
|
||||
PINCTRL_PIN_GROUP("uart0", mt7987_uart0),
|
||||
PINCTRL_PIN_GROUP("uart1_0", mt7987_uart1_0),
|
||||
PINCTRL_PIN_GROUP("uart1_1", mt7987_uart1_1),
|
||||
PINCTRL_PIN_GROUP("uart1_2", mt7987_uart1_2),
|
||||
PINCTRL_PIN_GROUP("uart2_0", mt7987_uart2_0),
|
||||
PINCTRL_PIN_GROUP("uart2_1", mt7987_uart2_1),
|
||||
PINCTRL_PIN_GROUP("pwm0", mt7987_pwm0),
|
||||
PINCTRL_PIN_GROUP("pwm1_0", mt7987_pwm1_0),
|
||||
PINCTRL_PIN_GROUP("pwm1_1", mt7987_pwm1_1),
|
||||
PINCTRL_PIN_GROUP("pwm2_0", mt7987_pwm2_0),
|
||||
PINCTRL_PIN_GROUP("pwm2_1", mt7987_pwm2_1),
|
||||
PINCTRL_PIN_GROUP("drv_vbus_p1", mt7987_drv_vbus_p1),
|
||||
PINCTRL_PIN_GROUP("drv_vbus", mt7987_drv_vbus),
|
||||
PINCTRL_PIN_GROUP("2p5gbe_led0", mt7987_2p5gbe_led0),
|
||||
PINCTRL_PIN_GROUP("2p5gbe_led1_0", mt7987_2p5gbe_led1_0),
|
||||
PINCTRL_PIN_GROUP("2p5gbe_led1_1", mt7987_2p5gbe_led1_1),
|
||||
PINCTRL_PIN_GROUP("2p5g_ext_mdc_mdio", mt7987_2p5g_ext_mdc_mdio),
|
||||
PINCTRL_PIN_GROUP("mdc_mdio", mt7987_mdc_mdio),
|
||||
PINCTRL_PIN_GROUP("spi0", mt7987_spi0),
|
||||
PINCTRL_PIN_GROUP("spi0_wp_hold", mt7987_spi0_wp_hold),
|
||||
PINCTRL_PIN_GROUP("spi1", mt7987_spi1),
|
||||
PINCTRL_PIN_GROUP("spi1_1", mt7987_spi1_1),
|
||||
PINCTRL_PIN_GROUP("spi2", mt7987_spi2),
|
||||
PINCTRL_PIN_GROUP("spi2_wp_hold", mt7987_spi2_wp_hold),
|
||||
PINCTRL_PIN_GROUP("emmc_45", mt7987_emmc_45),
|
||||
PINCTRL_PIN_GROUP("sd", mt7987_sd),
|
||||
PINCTRL_PIN_GROUP("i2c0_0", mt7987_i2c0_0),
|
||||
PINCTRL_PIN_GROUP("i2c0_1", mt7987_i2c0_1),
|
||||
PINCTRL_PIN_GROUP("i2c0_2", mt7987_i2c0_2),
|
||||
PINCTRL_PIN_GROUP("pcie0_pereset", mt7987_pcie0_pereset),
|
||||
PINCTRL_PIN_GROUP("pcie0_clkreq", mt7987_pcie0_clkreq),
|
||||
PINCTRL_PIN_GROUP("pcie0_wake", mt7987_pcie0_wake),
|
||||
PINCTRL_PIN_GROUP("pcie1_pereset", mt7987_pcie1_pereset),
|
||||
PINCTRL_PIN_GROUP("pcie1_clkreq", mt7987_pcie1_clkreq),
|
||||
PINCTRL_PIN_GROUP("pcie1_wake", mt7987_pcie1_wake),
|
||||
PINCTRL_PIN_GROUP("pcie1_pcie_phy_i2c", mt7987_pcie_phy_i2c),
|
||||
PINCTRL_PIN_GROUP("snfi", mt7987_snfi),
|
||||
};
|
||||
|
||||
static const char *const mt7987_wdt_groups[] = {"watchdog",};
|
||||
static const char *const mt7987_jtag_groups[] = {"jtag",};
|
||||
static const char *const mt7987_pcm_groups[] = {"pcm0_0", "pcm0_1"};
|
||||
static const char *const mt7987_uart_groups[] = {"uart0", "uart1_0", "uart1_1",
|
||||
"uart1_2", "uart2_0", "uart2_1",};
|
||||
static const char *const mt7987_pwm_groups[] = {"pwm0", "pwm1_0", "pwm1_1", "pwm2_0",
|
||||
"pwm2_1",};
|
||||
static const char *const mt7987_usb_groups[] = {"drv_vbus_p1", "drv_vbus",};
|
||||
static const char *const mt7987_led_groups[] = {"2p5gbe_led0", "2p5gbe_led1_0",
|
||||
"2p5gbe_led1_1",};
|
||||
static const char *const mt7987_ethernet_groups[] = {"2p5g_ext_mdc_mdio", "mdc_mdio",};
|
||||
static const char *const mt7987_spi_groups[] = {"spi0", "spi0_wp_hold", "spi1",
|
||||
"spi1_1", "spi2", "spi2_wp_hold",};
|
||||
static const char *const mt7987_flash_groups[] = {"emmc_45", "snfi", "sd"};
|
||||
static const char *const mt7987_i2c_groups[] = {"i2c0_0", "i2c0_1", "i2c0_2",};
|
||||
static const char *const mt7987_pcie_groups[] = {"pcie_phy_i2c", "pcie0_pereset",
|
||||
"pcie0_clkreq", "pcie0_wake",
|
||||
"pcie1_pereset", "pcie1_clkreq",
|
||||
"pcie1_wake",};
|
||||
static const char *const mt7987_i2s_groups[] = {"pcm0_0", "pcm0_1"};
|
||||
|
||||
|
||||
static const struct function_desc mt7987_functions[] = {
|
||||
{"wdt", mt7987_wdt_groups, ARRAY_SIZE(mt7987_wdt_groups)},
|
||||
{"jtag", mt7987_jtag_groups, ARRAY_SIZE(mt7987_jtag_groups)},
|
||||
{"pcm", mt7987_pcm_groups, ARRAY_SIZE(mt7987_pcm_groups)},
|
||||
{"uart", mt7987_uart_groups, ARRAY_SIZE(mt7987_uart_groups)},
|
||||
{"pwm", mt7987_pwm_groups, ARRAY_SIZE(mt7987_pwm_groups)},
|
||||
{"usb", mt7987_usb_groups, ARRAY_SIZE(mt7987_usb_groups)},
|
||||
{"led", mt7987_led_groups, ARRAY_SIZE(mt7987_led_groups)},
|
||||
{"eth", mt7987_ethernet_groups, ARRAY_SIZE(mt7987_ethernet_groups)},
|
||||
{"spi", mt7987_spi_groups, ARRAY_SIZE(mt7987_spi_groups)},
|
||||
{"flash", mt7987_flash_groups, ARRAY_SIZE(mt7987_flash_groups)},
|
||||
{"i2c", mt7987_i2c_groups, ARRAY_SIZE(mt7987_i2c_groups)},
|
||||
{"pcie", mt7987_pcie_groups, ARRAY_SIZE(mt7987_pcie_groups)},
|
||||
{"i2s", mt7987_i2s_groups, ARRAY_SIZE(mt7987_i2s_groups)},
|
||||
};
|
||||
|
||||
|
||||
static const struct mtk_eint_hw mt7987_eint_hw = {
|
||||
.port_mask = 7,
|
||||
.ports = 7,
|
||||
.ap_num = ARRAY_SIZE(mt7987_pins),
|
||||
.db_cnt = 16,
|
||||
};
|
||||
|
||||
static const char * const mt7987_pinctrl_register_base_names[] = {
|
||||
"gpio_base", "iocfg_rb_base", "iocfg_lb_base", "iocfg_rt1_base",
|
||||
"iocfg_rt2_base", "iocfg_tl_base",
|
||||
};
|
||||
|
||||
static struct mtk_pin_soc mt7987_data = {
|
||||
.reg_cal = mt7987_reg_cals,
|
||||
.pins = mt7987_pins,
|
||||
.npins = ARRAY_SIZE(mt7987_pins),
|
||||
.grps = mt7987_groups,
|
||||
.ngrps = ARRAY_SIZE(mt7987_groups),
|
||||
.funcs = mt7987_functions,
|
||||
.nfuncs = ARRAY_SIZE(mt7987_functions),
|
||||
.eint_hw = &mt7987_eint_hw,
|
||||
.gpio_m = 0,
|
||||
.ies_present = false,
|
||||
.base_names = mt7987_pinctrl_register_base_names,
|
||||
.nbase_names = ARRAY_SIZE(mt7987_pinctrl_register_base_names),
|
||||
.bias_disable_set = mtk_pinconf_bias_disable_set,
|
||||
.bias_disable_get = mtk_pinconf_bias_disable_get,
|
||||
.bias_set = mtk_pinconf_bias_set,
|
||||
.bias_get = mtk_pinconf_bias_get,
|
||||
.pull_type = mt7987_pull_type,
|
||||
.bias_set_combo = mtk_pinconf_bias_set_combo,
|
||||
.bias_get_combo = mtk_pinconf_bias_get_combo,
|
||||
.drive_set = mtk_pinconf_drive_set_rev1,
|
||||
.drive_get = mtk_pinconf_drive_get_rev1,
|
||||
.adv_pull_get = mtk_pinconf_adv_pull_get,
|
||||
.adv_pull_set = mtk_pinconf_adv_pull_set,
|
||||
};
|
||||
|
||||
static const struct of_device_id mt7987_pinctrl_of_match[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt7987-pinctrl",
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int mt7987_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
return mtk_moore_pinctrl_probe(pdev, &mt7987_data);
|
||||
}
|
||||
|
||||
static struct platform_driver mt7987_pinctrl_driver = {
|
||||
.driver = {
|
||||
.name = "mt7987-pinctrl",
|
||||
.of_match_table = mt7987_pinctrl_of_match,
|
||||
},
|
||||
.probe = mt7987_pinctrl_probe,
|
||||
};
|
||||
|
||||
static int __init mt7987_pinctrl_init(void)
|
||||
{
|
||||
return platform_driver_register(&mt7987_pinctrl_driver);
|
||||
}
|
||||
arch_initcall(mt7987_pinctrl_init);
|
||||
@@ -23,10 +23,36 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/thermal.h>
|
||||
#include "soc_temp_lvts.h"
|
||||
#include "../thermal_hwmon.h"
|
||||
|
||||
/*
|
||||
* Definition or macro function
|
||||
*/
|
||||
#define STOP_COUNTING_V6 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
|
||||
#define SET_RG_TSFM_LPDLY_V6 (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
|
||||
#define SET_COUNTING_WINDOW_20US1_V6 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
|
||||
#define SET_COUNTING_WINDOW_20US2_V6 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20)
|
||||
#define TOGGLE_TSDIV_EN_AND_TSVCO_TG_1_V6 \
|
||||
(DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xC7)
|
||||
#define TOGGLE_TSDIV_EN_AND_TSVCO_TG_2_V6 \
|
||||
(DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xCE)
|
||||
#define SET_TS_EN_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xC7)
|
||||
#define SET_TSBG_CHOP_EN_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D)
|
||||
#define SET_TS_RSV_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0x7C)
|
||||
#define SET_TSBG_RSV_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0xA8)
|
||||
#define SET_STR_EN_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_3 << 8 | 0x04)
|
||||
|
||||
#define SET_MANUAL_RCK_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x00)
|
||||
#define SET_RG_TSV2F_RSV_V6 (DEVICE_WRITE | RG_TSV2F_CTRL_3 << 8 | 0x0C)
|
||||
#define SELECT_SENSOR_RCK_V6(id) (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id))
|
||||
#define SET_DEVICE_SINGLE_MODE_V6 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0x78)
|
||||
#define KICK_OFF_RCK_COUNTING_V6 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02)
|
||||
#define GET_RCK_COUNT_DATA_V6 (DEVICE_WRITE | RG_TSFM_DATA_0 << 8 | 0x02)
|
||||
#define SET_SENSOR_NO_RCK_V6(id) \
|
||||
(DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10 | (id))
|
||||
#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V6 \
|
||||
(DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
|
||||
|
||||
#define STOP_COUNTING_V5 (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
|
||||
#define SET_RG_TSFM_LPDLY_V5 (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
|
||||
#define SET_COUNTING_WINDOW_20US1_V5 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
|
||||
@@ -911,6 +937,8 @@ static int lvts_register_thermal_zones(struct lvts_data *lvts_data)
|
||||
lvts_close(lvts_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
thermal_add_hwmon_sysfs(tzdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1234,6 +1262,105 @@ static int device_read_count_rc_n_v5(struct lvts_data *lvts_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* LVTS v6 common code
|
||||
*/
|
||||
static void device_enable_and_init_v6(struct lvts_data *lvts_data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < lvts_data->num_tc; i++) {
|
||||
lvts_write_device(lvts_data, STOP_COUNTING_V6, i);
|
||||
lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V6, i);
|
||||
lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V6, i);
|
||||
lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V6, i);
|
||||
lvts_write_device(lvts_data, SET_TS_EN_V6, i);
|
||||
lvts_write_device(lvts_data, SET_TSBG_CHOP_EN_V6, i);
|
||||
lvts_write_device(lvts_data, SET_TS_RSV_V6, i);
|
||||
lvts_write_device(lvts_data, SET_TSBG_RSV_V6, i);
|
||||
lvts_write_device(lvts_data, TOGGLE_TSDIV_EN_AND_TSVCO_TG_2_V6,
|
||||
i);
|
||||
lvts_write_device(lvts_data, TOGGLE_TSDIV_EN_AND_TSVCO_TG_1_V6,
|
||||
i);
|
||||
lvts_write_device(lvts_data, SET_STR_EN_V6, i);
|
||||
}
|
||||
|
||||
lvts_data->counting_window_us = 20;
|
||||
}
|
||||
|
||||
static int device_read_count_rc_n_v6(struct lvts_data *lvts_data)
|
||||
{
|
||||
/* Resistor-Capacitor Calibration */
|
||||
/* count_RC_N: count RC now */
|
||||
struct device *dev = lvts_data->dev;
|
||||
struct tc_settings *tc = lvts_data->tc;
|
||||
struct sensor_cal_data *cal_data = &lvts_data->cal_data;
|
||||
unsigned int offset, size, s_index, data;
|
||||
void __iomem *base;
|
||||
int ret, i, j;
|
||||
char buffer[512];
|
||||
|
||||
cal_data->count_rc_now =
|
||||
devm_kcalloc(dev, lvts_data->num_sensor,
|
||||
sizeof(*cal_data->count_rc_now), GFP_KERNEL);
|
||||
if (!cal_data->count_rc_now)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < lvts_data->num_tc; i++) {
|
||||
base = GET_BASE_ADDR(i);
|
||||
lvts_write_device(lvts_data, SET_MANUAL_RCK_V6, i);
|
||||
|
||||
for (j = 0; j < tc[i].num_sensor; j++) {
|
||||
s_index = tc[i].sensor_map[j];
|
||||
|
||||
lvts_write_device(lvts_data, SET_RG_TSV2F_RSV_V6, i);
|
||||
lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V6(j),
|
||||
i);
|
||||
lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V6,
|
||||
i);
|
||||
lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V6,
|
||||
i);
|
||||
lvts_write_device(lvts_data, GET_RCK_COUNT_DATA_V6, i);
|
||||
|
||||
udelay(50);
|
||||
|
||||
ret = readl_poll_timeout(
|
||||
LVTS_CONFIG_0 + base, data,
|
||||
!(data & DEVICE_SENSING_STATUS), 2, 200);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"Error: LVTS %d DEVICE_SENSING_STATUS didn't ready\n",
|
||||
i);
|
||||
|
||||
data = lvts_read_device(lvts_data, 0x00, i);
|
||||
|
||||
cal_data->count_rc_now[s_index] =
|
||||
(data & GENMASK(23, 0));
|
||||
|
||||
/* Recover Setting for Normal Access on
|
||||
* temperature fetch
|
||||
*/
|
||||
lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V6(j),
|
||||
i);
|
||||
lvts_write_device(lvts_data,
|
||||
SET_DEVICE_LOW_POWER_SINGLE_MODE_V6,
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof(buffer);
|
||||
offset = snprintf(buffer, size, "[COUNT_RC_NOW] ");
|
||||
for (i = 0; i < lvts_data->num_sensor; i++)
|
||||
offset += snprintf(buffer + offset, size - offset, "%d:%d ", i,
|
||||
cal_data->count_rc_now[i]);
|
||||
|
||||
buffer[offset] = '\0';
|
||||
dev_info(dev, "%s\n", buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* LVTS MT6873
|
||||
*/
|
||||
@@ -1479,8 +1606,8 @@ static struct tc_settings mt7988_tc_settings[] = {
|
||||
MT7988_TS2_3},
|
||||
.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
|
||||
.hw_filter = LVTS_FILTER_16_OF_18,
|
||||
.dominator_sensing_point = SENSING_POINT0,
|
||||
.hw_reboot_trip_point = 117000,
|
||||
.dominator_sensing_point = ALL_SENSING_POINTS,
|
||||
.hw_reboot_trip_point = 125000,
|
||||
.irq_bit = BIT(4),
|
||||
},
|
||||
[1] = {
|
||||
@@ -1491,8 +1618,8 @@ static struct tc_settings mt7988_tc_settings[] = {
|
||||
MT7988_TS3_3},
|
||||
.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
|
||||
.hw_filter = LVTS_FILTER_16_OF_18,
|
||||
.dominator_sensing_point = SENSING_POINT0,
|
||||
.hw_reboot_trip_point = 117000,
|
||||
.dominator_sensing_point = ALL_SENSING_POINTS,
|
||||
.hw_reboot_trip_point = 125000,
|
||||
.irq_bit = BIT(5),
|
||||
}
|
||||
|
||||
@@ -1525,6 +1652,72 @@ static struct lvts_data mt7988_lvts_data = {
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* LVTS MT7987
|
||||
*/
|
||||
|
||||
#define MT7987_NUM_LVTS (ARRAY_SIZE(mt7987_tc_settings))
|
||||
|
||||
enum mt7987_lvts_domain { MT7987_AP_DOMAIN, MT7987_NUM_DOMAIN };
|
||||
|
||||
enum mt7987_lvts_sensor_enum {
|
||||
MT7987_TS2_0,
|
||||
MT7987_TS2_1,
|
||||
MT7987_NUM_TS
|
||||
};
|
||||
|
||||
static void mt7987_efuse_to_cal_data(struct lvts_data *lvts_data)
|
||||
{
|
||||
struct sensor_cal_data *cal_data = &lvts_data->cal_data;
|
||||
|
||||
cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
|
||||
|
||||
cal_data->count_r[MT7987_TS2_0] = GET_CAL_DATA_BITMASK(1, 31, 0);
|
||||
cal_data->count_r[MT7987_TS2_1] = GET_CAL_DATA_BITMASK(2, 31, 0);
|
||||
cal_data->count_rc[MT7987_TS2_0] = GET_CAL_DATA_BITMASK(3, 31, 0);
|
||||
}
|
||||
|
||||
static struct tc_settings mt7987_tc_settings[] = {
|
||||
[0] = {
|
||||
.domain_index = MT7987_AP_DOMAIN,
|
||||
.addr_offset = 0x0,
|
||||
.num_sensor = 2,
|
||||
.sensor_map = {MT7987_TS2_0, MT7987_TS2_1},
|
||||
.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
|
||||
.hw_filter = LVTS_FILTER_16_OF_18,
|
||||
.dominator_sensing_point = ALL_SENSING_POINTS,
|
||||
.hw_reboot_trip_point = 125000,
|
||||
.irq_bit = BIT(4),
|
||||
},
|
||||
};
|
||||
|
||||
static struct lvts_data mt7987_lvts_data = {
|
||||
.num_domain = MT7987_NUM_DOMAIN,
|
||||
.num_tc = MT7987_NUM_LVTS,
|
||||
.tc = mt7987_tc_settings,
|
||||
.num_sensor = MT7987_NUM_TS,
|
||||
.ops = {
|
||||
.efuse_to_cal_data = mt7987_efuse_to_cal_data,
|
||||
.device_enable_and_init = device_enable_and_init_v6,
|
||||
.device_enable_auto_rck = device_enable_auto_rck_v4,
|
||||
.device_read_count_rc_n = device_read_count_rc_n_v6,
|
||||
.set_cal_data = set_calibration_data_v4,
|
||||
.init_controller = init_controller_v4,
|
||||
},
|
||||
.feature_bitmap = 0,
|
||||
.num_efuse_addr = 4,
|
||||
.num_efuse_block = 1,
|
||||
.cal_data = {
|
||||
.default_golden_temp = 60,
|
||||
.default_count_r = 19380,
|
||||
.default_count_rc = 5330,
|
||||
},
|
||||
.coeff = {
|
||||
.a = -204650,
|
||||
.b = 204650,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* LVTS MT8195
|
||||
*/
|
||||
@@ -1874,6 +2067,10 @@ static const struct of_device_id lvts_of_match[] = {
|
||||
.compatible = "mediatek,mt7988-lvts",
|
||||
.data = (void *)&mt7988_lvts_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt7987-lvts",
|
||||
.data = (void *)&mt7987_lvts_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lvts_of_match);
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2024 MediaTek Inc.
|
||||
* Author: Lu Tang <Lu.Tang@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.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_CLK_MT7987_H
|
||||
#define _DT_BINDINGS_CLK_MT7987_H
|
||||
|
||||
/* INFRACFG_AO */
|
||||
|
||||
#define CK_INFRA_MUX_UART0_SEL 0
|
||||
#define CK_INFRA_MUX_UART1_SEL 1
|
||||
#define CK_INFRA_MUX_UART2_SEL 2
|
||||
#define CK_INFRA_MUX_SPI0_SEL 3
|
||||
#define CK_INFRA_MUX_SPI1_SEL 4
|
||||
#define CK_INFRA_MUX_SPI2_BCK_SEL 5
|
||||
#define CK_INFRA_PWM_BCK_SEL 6
|
||||
#define CK_INFRA_PCIE_GFMUX_TL_O_P0_SEL 7
|
||||
#define CK_INFRA_PCIE_GFMUX_TL_O_P1_SEL 8
|
||||
#define CK_INFRA_66M_GPT_BCK 9
|
||||
#define CK_INFRA_66M_PWM_HCK 10
|
||||
#define CK_INFRA_66M_PWM_BCK 11
|
||||
#define CK_INFRA_133M_CQDMA_BCK 12
|
||||
#define CK_INFRA_66M_AUD_SLV_BCK 13
|
||||
#define CK_INFRA_AUD_26M 14
|
||||
#define CK_INFRA_AUD_L 15
|
||||
#define CK_INFRA_AUD_AUD 16
|
||||
#define CK_INFRA_AUD_EG2 17
|
||||
#define CK_INFRA_DRAMC_F26M 18
|
||||
#define CK_INFRA_133M_DBG_ACKM 19
|
||||
#define CK_INFRA_66M_AP_DMA_BCK 20
|
||||
#define CK_INFRA_MSDC200_SRC 21
|
||||
#define CK_INFRA_66M_SEJ_BCK 22
|
||||
#define CK_INFRA_PRE_CK_SEJ_F13M 23
|
||||
#define CK_INFRA_66M_TRNG 24
|
||||
#define CK_INFRA_26M_THERM_SYSTEM 25
|
||||
#define CK_INFRA_I2C_BCK 26
|
||||
#define CK_INFRA_66M_UART0_PCK 27
|
||||
#define CK_INFRA_66M_UART1_PCK 28
|
||||
#define CK_INFRA_66M_UART2_PCK 29
|
||||
#define CK_INFRA_52M_UART0_CK 30
|
||||
#define CK_INFRA_52M_UART1_CK 31
|
||||
#define CK_INFRA_52M_UART2_CK 32
|
||||
#define CK_INFRA_NFI 33
|
||||
#define CK_INFRA_66M_NFI_HCK 34
|
||||
#define CK_INFRA_104M_SPI0 35
|
||||
#define CK_INFRA_104M_SPI1 36
|
||||
#define CK_INFRA_104M_SPI2_BCK 37
|
||||
#define CK_INFRA_66M_SPI0_HCK 38
|
||||
#define CK_INFRA_66M_SPI1_HCK 39
|
||||
#define CK_INFRA_66M_SPI2_HCK 40
|
||||
#define CK_INFRA_66M_FLASHIF_AXI 41
|
||||
#define CK_INFRA_RTC 42
|
||||
#define CK_INFRA_26M_ADC_BCK 43
|
||||
#define CK_INFRA_RC_ADC 44
|
||||
#define CK_INFRA_MSDC400 45
|
||||
#define CK_INFRA_MSDC2_HCK 46
|
||||
#define CK_INFRA_133M_MSDC_0_HCK 47
|
||||
#define CK_INFRA_66M_MSDC_0_HCK 48
|
||||
#define CK_INFRA_133M_CPUM_BCK 49
|
||||
#define CK_INFRA_BIST2FPC 50
|
||||
#define CK_INFRA_I2C_X16W_MCK_CK_P1 51
|
||||
#define CK_INFRA_I2C_X16W_PCK_CK_P1 52
|
||||
#define CK_INFRA_133M_USB_HCK 53
|
||||
#define CK_INFRA_133M_USB_HCK_CK_P1 54
|
||||
#define CK_INFRA_66M_USB_HCK 55
|
||||
#define CK_INFRA_66M_USB_HCK_CK_P1 56
|
||||
#define CK_INFRA_USB_SYS_CK_P1 57
|
||||
#define CK_INFRA_USB_CK_P1 58
|
||||
#define CK_INFRA_USB_FRMCNT_CK_P1 59
|
||||
#define CK_INFRA_USB_PIPE_CK_P1 60
|
||||
#define CK_INFRA_USB_UTMI_CK_P1 61
|
||||
#define CK_INFRA_USB_XHCI_CK_P1 62
|
||||
#define CK_INFRA_PCIE_GFMUX_TL_P0 63
|
||||
#define CK_INFRA_PCIE_GFMUX_TL_P1 64
|
||||
#define CK_INFRA_PCIE_PIPE_P0 65
|
||||
#define CK_INFRA_PCIE_PIPE_P1 66
|
||||
#define CK_INFRA_133M_PCIE_CK_P0 67
|
||||
#define CK_INFRA_133M_PCIE_CK_P1 68
|
||||
#define CK_INFRA_PCIE_PERI_26M_CK_P0 69
|
||||
#define CK_INFRA_PCIE_PERI_26M_CK_P1 70
|
||||
#define CLK_INFRA_NR_CLK 71
|
||||
|
||||
/* TOPCKGEN */
|
||||
|
||||
#define CK_TOP_CB_M_D2 0
|
||||
#define CK_TOP_CB_M_D3 1
|
||||
#define CK_TOP_M_D3_D2 2
|
||||
#define CK_TOP_CB_M_D4 3
|
||||
#define CK_TOP_CB_M_D8 4
|
||||
#define CK_TOP_M_D8_D2 5
|
||||
#define CK_TOP_CB_APLL2_D4 6
|
||||
#define CK_TOP_CB_NET1_D3 7
|
||||
#define CK_TOP_CB_NET1_D4 8
|
||||
#define CK_TOP_CB_NET1_D5 9
|
||||
#define CK_TOP_NET1_D5_D2 10
|
||||
#define CK_TOP_NET1_D5_D4 11
|
||||
#define CK_TOP_CB_NET1_D7 12
|
||||
#define CK_TOP_NET1_D7_D2 13
|
||||
#define CK_TOP_NET1_D7_D4 14
|
||||
#define CK_TOP_NET1_D8_D2 15
|
||||
#define CK_TOP_NET1_D8_D4 16
|
||||
#define CK_TOP_NET1_D8_D8 17
|
||||
#define CK_TOP_NET1_D8_D16 18
|
||||
#define CK_TOP_CB_NET2_D2 19
|
||||
#define CK_TOP_CB_NET2_D4 20
|
||||
#define CK_TOP_NET2_D4_D4 21
|
||||
#define CK_TOP_NET2_D4_D8 22
|
||||
#define CK_TOP_CB_NET2_D6 23
|
||||
#define CK_TOP_NET2_D7_D2 24
|
||||
#define CK_TOP_CB_NET2_D8 25
|
||||
#define CK_TOP_MSDC_D2 26
|
||||
#define CK_TOP_CB_CKSQ_40M 27
|
||||
#define CK_TOP_CKSQ_40M_D2 28
|
||||
#define CK_TOP_CB_RTC_32K 29
|
||||
#define CK_TOP_CB_RTC_32P7K 30
|
||||
#define CK_TOP_NETSYS_SEL 31
|
||||
#define CK_TOP_NETSYS_500M_SEL 32
|
||||
#define CK_TOP_NETSYS_2X_SEL 33
|
||||
#define CK_TOP_ETH_GMII_SEL 34
|
||||
#define CK_TOP_EIP_SEL 35
|
||||
#define CK_TOP_AXI_INFRA_SEL 36
|
||||
#define CK_TOP_UART_SEL 37
|
||||
#define CK_TOP_EMMC_250M_SEL 38
|
||||
#define CK_TOP_EMMC_400M_SEL 39
|
||||
#define CK_TOP_SPI_SEL 40
|
||||
#define CK_TOP_SPIM_MST_SEL 41
|
||||
#define CK_TOP_NFI_SEL 42
|
||||
#define CK_TOP_PWM_SEL 43
|
||||
#define CK_TOP_I2C_SEL 44
|
||||
#define CK_TOP_PCIE_MBIST_250M_SEL 45
|
||||
#define CK_TOP_PEXTP_TL_SEL 46
|
||||
#define CK_TOP_PEXTP_TL_P1_SEL 47
|
||||
#define CK_TOP_USB_SYS_P1_SEL 48
|
||||
#define CK_TOP_USB_XHCI_P1_SEL 49
|
||||
#define CK_TOP_AUD_SEL 50
|
||||
#define CK_TOP_A1SYS_SEL 51
|
||||
#define CK_TOP_AUD_L_SEL 52
|
||||
#define CK_TOP_A_TUNER_SEL 53
|
||||
#define CK_TOP_USB_PHY_SEL 54
|
||||
#define CK_TOP_SGM_0_SEL 55
|
||||
#define CK_TOP_SGM_SBUS_0_SEL 56
|
||||
#define CK_TOP_SGM_1_SEL 57
|
||||
#define CK_TOP_SGM_SBUS_1_SEL 58
|
||||
#define CK_TOP_SYSAXI_SEL 59
|
||||
#define CK_TOP_SYSAPB_SEL 60
|
||||
#define CK_TOP_ETH_REFCK_50M_SEL 61
|
||||
#define CK_TOP_ETH_SYS_200M_SEL 62
|
||||
#define CK_TOP_ETH_SYS_SEL 63
|
||||
#define CK_TOP_ETH_XGMII_SEL 64
|
||||
#define CK_TOP_DRAMC_SEL 65
|
||||
#define CK_TOP_DRAMC_MD32_SEL 66
|
||||
#define CK_TOP_INFRA_F26M_SEL 67
|
||||
#define CK_TOP_PEXTP_P0_SEL 68
|
||||
#define CK_TOP_PEXTP_P1_SEL 69
|
||||
#define CK_TOP_DA_XTP_GLB_P0_SEL 70
|
||||
#define CK_TOP_DA_XTP_GLB_P1_SEL 71
|
||||
#define CK_TOP_CKM_SEL 72
|
||||
#define CK_TOP_DA_CKM_XTAL_SEL 73
|
||||
#define CK_TOP_PEXTP_SEL 74
|
||||
#define CK_TOP_ETH_MII_SEL 75
|
||||
#define CK_TOP_EMMC_200M_SEL 76
|
||||
#define CK_TOP_AUD_I2S_M 77
|
||||
#define CLK_TOP_NR_CLK 78
|
||||
|
||||
/* APMIXEDSYS */
|
||||
|
||||
#define CK_APMIXED_MPLL 0
|
||||
#define CK_APMIXED_APLL2 1
|
||||
#define CK_APMIXED_NET1PLL 2
|
||||
#define CK_APMIXED_NET2PLL 3
|
||||
#define CK_APMIXED_WEDMCUPLL 4
|
||||
#define CK_APMIXED_SGMPLL 5
|
||||
#define CK_APMIXED_ARM_LL 6
|
||||
#define CK_APMIXED_MSDCPLL 7
|
||||
#define CLK_APMIXED_NR_CLK 8
|
||||
|
||||
/* MCUSYS */
|
||||
|
||||
#define CK_MCU_BUS_DIV_SEL 0
|
||||
#define CLK_MCU_NR_CLK 1
|
||||
|
||||
/* SGMIISYS_0 */
|
||||
|
||||
#define CK_SGM0_TX_EN 0
|
||||
#define CK_SGM0_RX_EN 1
|
||||
#define CLK_SGMII0_NR_CLK 2
|
||||
|
||||
/* SGMIISYS_1 */
|
||||
|
||||
#define CK_SGM1_TX_EN 0
|
||||
#define CK_SGM1_RX_EN 1
|
||||
#define CLK_SGMII1_NR_CLK 2
|
||||
|
||||
/* ETHDMA */
|
||||
|
||||
#define CK_ETHDMA_FE_EN 0
|
||||
#define CK_ETHDMA_GP2_EN 1
|
||||
#define CK_ETHDMA_GP1_EN 2
|
||||
#define CK_ETHDMA_GP3_EN 3
|
||||
#define CLK_ETHDMA_NR_CLK 4
|
||||
|
||||
#endif /* _DT_BINDINGS_CLK_MT7987_H */
|
||||
|
||||
@@ -387,6 +387,21 @@ struct cb_rx_desc_info4 {
|
||||
(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->WCID)
|
||||
#define FOE_BSS_ID_TAIL(skb) \
|
||||
(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->BSSID)
|
||||
#define FOE_USR_INFO_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->USR_INFO)
|
||||
#define FOE_TID_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->TID)
|
||||
#define FOE_IS_FIXEDRATE_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *) \
|
||||
((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->IS_FIXEDRATE)
|
||||
#define FOE_IS_PRIOR_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->IS_PRIOR)
|
||||
#define FOE_IS_SP_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->IS_SP)
|
||||
#define FOE_HF_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->HF)
|
||||
#define FOE_AMSDU_TAIL(skb) \
|
||||
(((struct dmad_rx_descinfo4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->AMSDU)
|
||||
|
||||
#define FOE_PPE_TAIL(skb) \
|
||||
(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->ppe)
|
||||
|
||||
207
feeds/mediatek-sdk/mediatek/files-5.4/net/dsa/tag_mxl862xx.c
Normal file
207
feeds/mediatek-sdk/mediatek/files-5.4/net/dsa/tag_mxl862xx.c
Normal file
@@ -0,0 +1,207 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* net/dsa/tag_mxl862xx.c - DSA driver Special Tag support for MaxLinear 862xx switch chips
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#ifndef LINUX_VERSION_CODE
|
||||
#include <linux/version.h>
|
||||
#else
|
||||
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
|
||||
#include "dsa_priv.h"
|
||||
#else
|
||||
#include "tag.h"
|
||||
#endif
|
||||
|
||||
#define MXL862_NAME "mxl862xx"
|
||||
|
||||
/* To define the outgoing port and to discover the incoming port a special
|
||||
* tag is used by the GSW1xx.
|
||||
*
|
||||
* Dest MAC Src MAC special TAG EtherType
|
||||
* ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 7 8 | 1 2 |...
|
||||
* |<--------------->|
|
||||
*/
|
||||
|
||||
/* special tag in TX path header */
|
||||
#define MXL862_TX_HEADER_LEN 8
|
||||
|
||||
#define MXL862_RX_HEADER_LEN 8
|
||||
|
||||
/* Byte 7 */
|
||||
#define MXL862_IGP_EGP_SHIFT 0
|
||||
#define MXL862_IGP_EGP_MASK GENMASK(3, 0)
|
||||
|
||||
static struct sk_buff *mxl862_tag_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
|
||||
int err;
|
||||
#endif
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0))
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
#else
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
#endif
|
||||
struct dsa_port *cpu_dp = dp->cpu_dp;
|
||||
unsigned int cpu_port = cpu_dp->index + 1;
|
||||
unsigned int usr_port = dp->index + 1;
|
||||
|
||||
u8 *mxl862_tag;
|
||||
|
||||
if (skb == NULL)
|
||||
return skb;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
|
||||
err = skb_cow_head(skb, MXL862_TX_HEADER_LEN);
|
||||
if (err)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/* provide additional space 'MXL862_TX_HEADER_LEN' bytes */
|
||||
skb_push(skb, MXL862_TX_HEADER_LEN);
|
||||
|
||||
/* shift MAC address to the beginnig of the enlarged buffer,
|
||||
* releasing the space required for DSA tag (between MAC address and Ethertype) */
|
||||
memmove(skb->data, skb->data + MXL862_TX_HEADER_LEN, 2 * ETH_ALEN);
|
||||
|
||||
/* special tag ingress */
|
||||
mxl862_tag = skb->data + 2 * ETH_ALEN;
|
||||
mxl862_tag[0] = 0x88;
|
||||
mxl862_tag[1] = 0xc3;
|
||||
mxl862_tag[2] = 0;
|
||||
mxl862_tag[3] = 0;
|
||||
mxl862_tag[4] = 0;
|
||||
mxl862_tag[5] = usr_port + 16 - cpu_port;
|
||||
mxl862_tag[6] = 0;
|
||||
mxl862_tag[7] = (cpu_port)&MXL862_IGP_EGP_MASK;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
|
||||
static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct packet_type *pt)
|
||||
#else
|
||||
static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
#endif
|
||||
{
|
||||
int port;
|
||||
u8 *mxl862_tag;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
|
||||
struct dsa_port *dp;
|
||||
#endif
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, MXL862_RX_HEADER_LEN))) {
|
||||
dev_warn_ratelimited(&dev->dev,
|
||||
"Dropping packet, cannot pull SKB\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mxl862_tag = skb->data - 2;
|
||||
|
||||
if ((mxl862_tag[0] != 0x88) && (mxl862_tag[1] != 0xc3)) {
|
||||
dev_warn_ratelimited(
|
||||
&dev->dev,
|
||||
"Dropping packet due to invalid special tag marker\n");
|
||||
dev_warn_ratelimited(
|
||||
&dev->dev,
|
||||
"Rx Packet Tag: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
|
||||
mxl862_tag[0], mxl862_tag[1], mxl862_tag[2],
|
||||
mxl862_tag[3], mxl862_tag[4], mxl862_tag[5],
|
||||
mxl862_tag[6], mxl862_tag[7]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get source port information */
|
||||
port = (mxl862_tag[7] & MXL862_IGP_EGP_MASK) >> MXL862_IGP_EGP_SHIFT;
|
||||
port = port - 1;
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0))
|
||||
skb->dev = dsa_master_find_slave(dev, 0, port);
|
||||
#else
|
||||
skb->dev = dsa_conduit_find_user(dev, 0, port);
|
||||
#endif
|
||||
if (!skb->dev) {
|
||||
dev_warn_ratelimited(
|
||||
&dev->dev,
|
||||
"Dropping packet due to invalid source port\n");
|
||||
dev_warn_ratelimited(
|
||||
&dev->dev,
|
||||
"Rx Packet Tag: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
|
||||
mxl862_tag[0], mxl862_tag[1], mxl862_tag[2],
|
||||
mxl862_tag[3], mxl862_tag[4], mxl862_tag[5],
|
||||
mxl862_tag[6], mxl862_tag[7]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* remove the MxL862xx special tag between the MAC addresses and the current ethertype field. */
|
||||
skb_pull_rcsum(skb, MXL862_RX_HEADER_LEN);
|
||||
memmove(skb->data - ETH_HLEN,
|
||||
skb->data - (ETH_HLEN + MXL862_RX_HEADER_LEN), 2 * ETH_ALEN);
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
|
||||
dp = dsa_slave_to_port(skb->dev);
|
||||
if (dp->bridge_dev)
|
||||
skb->offload_fwd_mark = 1;
|
||||
#else
|
||||
dsa_default_offload_fwd_mark(skb);
|
||||
#endif
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
|
||||
const struct dsa_device_ops mxl862_netdev_ops = {
|
||||
.xmit = mxl862_tag_xmit,
|
||||
.rcv = mxl862_tag_rcv,
|
||||
};
|
||||
#else
|
||||
|
||||
static const struct dsa_device_ops mxl862_netdev_ops = {
|
||||
.name = "mxl862",
|
||||
.proto = DSA_TAG_PROTO_MXL862,
|
||||
.xmit = mxl862_tag_xmit,
|
||||
.rcv = mxl862_tag_rcv,
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
|
||||
.overhead = MXL862_RX_HEADER_LEN,
|
||||
#else
|
||||
.needed_headroom = MXL862_RX_HEADER_LEN,
|
||||
#endif
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862);
|
||||
#else
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862, MXL862_NAME);
|
||||
#endif
|
||||
|
||||
module_dsa_tag_driver(mxl862_netdev_ops);
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* net/dsa/tag_mxl862xx_8021q.c - DSA driver 802.1q based Special Tag support for MaxLinear 862xx switch chips
|
||||
*
|
||||
* Copyright (C) 2024 MaxLinear 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; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LINUX_VERSION_CODE
|
||||
#include <linux/version.h>
|
||||
#else
|
||||
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
|
||||
#endif
|
||||
|
||||
#include <linux/dsa/8021q.h>
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0))
|
||||
#include "tag_8021q.h"
|
||||
#endif
|
||||
#include <net/dsa.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
|
||||
#include "dsa_priv.h"
|
||||
#else
|
||||
#include "tag.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define MXL862_NAME "mxl862xx"
|
||||
|
||||
/* To define the outgoing port and to discover the incoming port
|
||||
* a special 4-byte outer VLAN tag is used by the MxL862xx.
|
||||
*
|
||||
* Dest MAC Src MAC special optional EtherType
|
||||
* outer inner
|
||||
* VLAN tag tag(s)
|
||||
* ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 | 1 2 3 4 | 1 2 |...
|
||||
* |<------->|
|
||||
*/
|
||||
|
||||
/* special tag in TX path header */
|
||||
|
||||
/* The mxl862_8021q 4-byte tagging is not yet supported in
|
||||
* kernels >= 5.16 due to differences in DSA 8021q tagging handlers.
|
||||
* DSA tx/rx vid functions are not avaliable, so dummy
|
||||
* functions are here to make the code compilable. */
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION (5, 16, 0))
|
||||
static u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION (5, 14, 0))
|
||||
static void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id)
|
||||
{
|
||||
u16 vid, tci;
|
||||
|
||||
skb_push_rcsum(skb, ETH_HLEN);
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
tci = skb_vlan_tag_get(skb);
|
||||
__vlan_hwaccel_clear_tag(skb);
|
||||
} else {
|
||||
__skb_vlan_pop(skb, &tci);
|
||||
}
|
||||
skb_pull_rcsum(skb, ETH_HLEN);
|
||||
|
||||
vid = tci & VLAN_VID_MASK;
|
||||
|
||||
*source_port = dsa_8021q_rx_source_port(vid);
|
||||
*switch_id = dsa_8021q_rx_switch_id(vid);
|
||||
skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
|
||||
}
|
||||
|
||||
/* If the ingress port offloads the bridge, we mark the frame as autonomously
|
||||
* forwarded by hardware, so the software bridge doesn't forward in twice, back
|
||||
* to us, because we already did. However, if we're in fallback mode and we do
|
||||
* software bridging, we are not offloading it, therefore the dp->bridge_dev
|
||||
* pointer is not populated, and flooding needs to be done by software (we are
|
||||
* effectively operating in standalone ports mode).
|
||||
*/
|
||||
static inline void dsa_default_offload_fwd_mark(struct sk_buff *skb)
|
||||
{
|
||||
struct dsa_port *dp = dsa_slave_to_port(skb->dev);
|
||||
|
||||
skb->offload_fwd_mark = !!(dp->bridge_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct sk_buff *mxl862_8021q_tag_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0))
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
#else
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
#endif
|
||||
unsigned int port = dp->index ;
|
||||
|
||||
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, port);
|
||||
u16 queue_mapping = skb_get_queue_mapping(skb);
|
||||
u8 pcp = netdev_txq_to_tc(dev, queue_mapping);
|
||||
|
||||
|
||||
dsa_8021q_xmit(skb, dev, ETH_P_8021Q,
|
||||
((pcp << VLAN_PRIO_SHIFT) | tx_vid));
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
|
||||
static struct sk_buff *mxl862_8021q_tag_rcv(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct packet_type *pt)
|
||||
#else
|
||||
static struct sk_buff *mxl862_8021q_tag_rcv(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
#endif
|
||||
{
|
||||
uint16_t vlan = ntohs(*(uint16_t*)(skb->data));
|
||||
int port = dsa_8021q_rx_source_port(vlan);
|
||||
int src_port = -1;
|
||||
int switch_id = -1;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0))
|
||||
skb->dev = dsa_master_find_slave(dev, 0, port);
|
||||
#else
|
||||
skb->dev = dsa_conduit_find_user(dev, 0, port);
|
||||
#endif
|
||||
if (!skb->dev) {
|
||||
dev_warn_ratelimited(&dev->dev,"Dropping packet due to invalid source port:%d\n", port);
|
||||
return NULL;
|
||||
}
|
||||
/* removes Outer VLAN tag */
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0))
|
||||
dsa_8021q_rcv(skb, &src_port, &switch_id);
|
||||
#else
|
||||
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL);
|
||||
#endif
|
||||
|
||||
dsa_default_offload_fwd_mark(skb);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static const struct dsa_device_ops mxl862_8021q_netdev_ops = {
|
||||
.name = "mxl862_8021q",
|
||||
.proto = DSA_TAG_PROTO_MXL862_8021Q,
|
||||
.xmit = mxl862_8021q_tag_xmit,
|
||||
.rcv = mxl862_8021q_tag_rcv,
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
|
||||
.overhead = VLAN_HLEN,
|
||||
#else
|
||||
.needed_headroom = VLAN_HLEN,
|
||||
#endif
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0) && \
|
||||
LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 0))
|
||||
.promisc_on_master = true,
|
||||
#elif (LINUX_VERSION_CODE > KERNEL_VERSION(6, 7, 0))
|
||||
.promisc_on_conduit = true,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862_8021Q);
|
||||
#else
|
||||
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862_8021Q, MXL862_NAME);
|
||||
#endif
|
||||
|
||||
module_dsa_tag_driver(mxl862_8021q_netdev_ops);
|
||||
@@ -67,6 +67,35 @@ endef
|
||||
|
||||
$(eval $(call KernelPackage,crypto-eip197))
|
||||
|
||||
define KernelPackage/crypto-eip196
|
||||
TITLE:= EIP-196 Crypto Engine module
|
||||
DEPENDS:=@TARGET_mediatek_mt7987 +eip197-mini-firmware
|
||||
DEFAULT:=y
|
||||
KCONFIG:= \
|
||||
CONFIG_CRYPTO_HW=y \
|
||||
CONFIG_CRYPTO_AUTHENC=y \
|
||||
CONFIG_CRYPTO_AES=y \
|
||||
CONFIG_CRYPTO_AEAD=y \
|
||||
CONFIG_CRYPTO_DES=y \
|
||||
CONFIG_CRYPTO_MD5=y \
|
||||
CONFIG_CRYPTO_SHA1=y \
|
||||
CONFIG_CRYPTO_SHA256=y \
|
||||
CONFIG_CRYPTO_SHA512=y \
|
||||
CONFIG_CRYPTO_SHA3=y \
|
||||
CONFIG_CRYPTO_HMAC=y \
|
||||
CONFIG_CRYPTO_CHACHA20POLY1305=y \
|
||||
CONFIG_CRYPTO_DEV_SAFEXCEL
|
||||
FILES:=$(LINUX_DIR)/drivers/crypto/inside-secure/crypto_safexcel.ko
|
||||
AUTOLOAD:=$(call AutoLoad,90,crypto-safexcel)
|
||||
$(call AddDepends/crypto)
|
||||
endef
|
||||
|
||||
define KernelPackage/crypto-eip196/description
|
||||
EIP-196 Cryptographic Engine driver.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,crypto-eip196))
|
||||
|
||||
define KernelPackage/mediatek_hnat
|
||||
SUBMENU:=Network Devices
|
||||
TITLE:=Mediatek HNAT module
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
CONFIG_64BIT=y
|
||||
CONFIG_AHCI_MTK=y
|
||||
# CONFIG_AN8855_GSW is not set
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
@@ -273,8 +274,13 @@ CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_SG_DMA_LENGTH=y
|
||||
CONFIG_NET_DEVLINK=y
|
||||
CONFIG_NET_DSA=y
|
||||
# CONFIG_NET_DSA_AN8855 is not set
|
||||
CONFIG_NET_DSA_MT7530=y
|
||||
# CONFIG_NET_DSA_MXL862 is not set
|
||||
# CONFIG_NET_DSA_TAG_AIROHA is not set
|
||||
CONFIG_NET_DSA_TAG_MTK=y
|
||||
# CONFIG_NET_DSA_TAG_MXL862 is not set
|
||||
# CONFIG_NET_DSA_TAG_MXL862_8021Q is not set
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
CONFIG_NET_MEDIATEK_SOC=y
|
||||
CONFIG_NET_SWITCHDEV=y
|
||||
|
||||
@@ -34,11 +34,13 @@ case "$board" in
|
||||
|
||||
if [ -f "$phy0_file" ]; then
|
||||
check_phy0=$(cat $phy0_file)
|
||||
echo "check_phy0 = $check_phy0"
|
||||
[ "$check_phy0" == 0 ] && echo 1 > $phy0_file
|
||||
fi
|
||||
|
||||
if [ -f "$phy1_file" ]; then
|
||||
check_phy1=$(cat $phy1_file)
|
||||
echo "check_phy1 = $check_phy1"
|
||||
[ "$check_phy1" == 0 ] && echo 1 > $phy1_file
|
||||
fi
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user