Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
commit
a6bb9d5a68
@ -0,0 +1,35 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 22 Nov 2021 21:39:38 +0100
|
||||
Subject: [PATCH] mac80211: fix rate control for retransmitted frames
|
||||
|
||||
Since retransmission clears info->control, rate control needs to be called
|
||||
again, otherwise the driver might crash due to invalid rates.
|
||||
|
||||
Cc: stable@vger.kernel.org # 5.14+
|
||||
Reported-by: Aaro Koskinen <aaro.koskinen@iki.fi>
|
||||
Reported-by: Robert W <rwbugreport@lost-in-the-void.net>
|
||||
Fixes: 03c3911d2d67 ("mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1825,15 +1825,15 @@ static int invoke_tx_handlers_late(struc
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
ieee80211_tx_result res = TX_CONTINUE;
|
||||
|
||||
+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
|
||||
+ CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
||||
+
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
|
||||
__skb_queue_tail(&tx->skbs, tx->skb);
|
||||
tx->skb = NULL;
|
||||
goto txh_done;
|
||||
}
|
||||
|
||||
- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
|
||||
- CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
||||
-
|
||||
CALL_TXH(ieee80211_tx_h_michael_mic_add);
|
||||
CALL_TXH(ieee80211_tx_h_sequence);
|
||||
CALL_TXH(ieee80211_tx_h_fragment);
|
@ -0,0 +1,44 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 24 Nov 2021 10:30:41 +0100
|
||||
Subject: [PATCH] mac80211: fix regression in SSN handling of addba tx
|
||||
|
||||
Some drivers that do their own sequence number allocation (e.g. ath9k) rely
|
||||
on being able to modify params->ssn on starting tx ampdu sessions.
|
||||
This was broken by a change that modified it to use sta->tid_seq[tid] instead.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Fixes: 31d8bb4e07f8 ("mac80211: agg-tx: refactor sending addba")
|
||||
Reported-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/agg-tx.c
|
||||
+++ b/net/mac80211/agg-tx.c
|
||||
@@ -480,8 +480,7 @@ static void ieee80211_send_addba_with_ti
|
||||
|
||||
/* send AddBA request */
|
||||
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
|
||||
- tid_tx->dialog_token,
|
||||
- sta->tid_seq[tid] >> 4,
|
||||
+ tid_tx->dialog_token, tid_tx->ssn,
|
||||
buf_size, tid_tx->timeout);
|
||||
|
||||
WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
|
||||
@@ -523,6 +522,7 @@ void ieee80211_tx_ba_session_handle_star
|
||||
|
||||
params.ssn = sta->tid_seq[tid] >> 4;
|
||||
ret = drv_ampdu_action(local, sdata, ¶ms);
|
||||
+ tid_tx->ssn = params.ssn;
|
||||
if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
|
||||
return;
|
||||
} else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -199,6 +199,7 @@ struct tid_ampdu_tx {
|
||||
u8 stop_initiator;
|
||||
bool tx_stop;
|
||||
u16 buf_size;
|
||||
+ u16 ssn;
|
||||
|
||||
u16 failed_bar_ssn;
|
||||
bool bar_pending;
|
@ -0,0 +1,62 @@
|
||||
From: Xing Song <xing.song@mediatek.com>
|
||||
Date: Tue, 23 Nov 2021 11:31:23 +0800
|
||||
Subject: [PATCH] mac80211: set up the fwd_skb->dev for mesh forwarding
|
||||
|
||||
Mesh forwarding requires that the fwd_skb->dev is set up for TX handling,
|
||||
otherwise the following warning will be generated, so set it up for the
|
||||
pending frames.
|
||||
|
||||
[ 72.835674 ] WARNING: CPU: 0 PID: 1193 at __skb_flow_dissect+0x284/0x1298
|
||||
[ 72.842379 ] Modules linked in: ksmbd pppoe ppp_async l2tp_ppp ...
|
||||
[ 72.962020 ] CPU: 0 PID: 1193 Comm: kworker/u5:1 Tainted: P S 5.4.137 #0
|
||||
[ 72.969938 ] Hardware name: MT7622_MT7531 RFB (DT)
|
||||
[ 72.974659 ] Workqueue: napi_workq napi_workfn
|
||||
[ 72.979025 ] pstate: 60000005 (nZCv daif -PAN -UAO)
|
||||
[ 72.983822 ] pc : __skb_flow_dissect+0x284/0x1298
|
||||
[ 72.988444 ] lr : __skb_flow_dissect+0x54/0x1298
|
||||
[ 72.992977 ] sp : ffffffc010c738c0
|
||||
[ 72.996293 ] x29: ffffffc010c738c0 x28: 0000000000000000
|
||||
[ 73.001615 ] x27: 000000000000ffc2 x26: ffffff800c2eb818
|
||||
[ 73.006937 ] x25: ffffffc010a987c8 x24: 00000000000000ce
|
||||
[ 73.012259 ] x23: ffffffc010c73a28 x22: ffffffc010a99c60
|
||||
[ 73.017581 ] x21: 000000000000ffc2 x20: ffffff80094da800
|
||||
[ 73.022903 ] x19: 0000000000000000 x18: 0000000000000014
|
||||
[ 73.028226 ] x17: 00000000084d16af x16: 00000000d1fc0bab
|
||||
[ 73.033548 ] x15: 00000000715f6034 x14: 000000009dbdd301
|
||||
[ 73.038870 ] x13: 00000000ea4dcbc3 x12: 0000000000000040
|
||||
[ 73.044192 ] x11: 000000000eb00ff0 x10: 0000000000000000
|
||||
[ 73.049513 ] x9 : 000000000eb00073 x8 : 0000000000000088
|
||||
[ 73.054834 ] x7 : 0000000000000000 x6 : 0000000000000001
|
||||
[ 73.060155 ] x5 : 0000000000000000 x4 : 0000000000000000
|
||||
[ 73.065476 ] x3 : ffffffc010a98000 x2 : 0000000000000000
|
||||
[ 73.070797 ] x1 : 0000000000000000 x0 : 0000000000000000
|
||||
[ 73.076120 ] Call trace:
|
||||
[ 73.078572 ] __skb_flow_dissect+0x284/0x1298
|
||||
[ 73.082846 ] __skb_get_hash+0x7c/0x228
|
||||
[ 73.086629 ] ieee80211_txq_may_transmit+0x7fc/0x17b8 [mac80211]
|
||||
[ 73.092564 ] ieee80211_tx_prepare_skb+0x20c/0x268 [mac80211]
|
||||
[ 73.098238 ] ieee80211_tx_pending+0x144/0x330 [mac80211]
|
||||
[ 73.103560 ] tasklet_action_common.isra.16+0xb4/0x158
|
||||
[ 73.108618 ] tasklet_action+0x2c/0x38
|
||||
[ 73.112286 ] __do_softirq+0x168/0x3b0
|
||||
[ 73.115954 ] do_softirq.part.15+0x88/0x98
|
||||
[ 73.119969 ] __local_bh_enable_ip+0xb0/0xb8
|
||||
[ 73.124156 ] napi_workfn+0x58/0x90
|
||||
[ 73.127565 ] process_one_work+0x20c/0x478
|
||||
[ 73.131579 ] worker_thread+0x50/0x4f0
|
||||
[ 73.135249 ] kthread+0x124/0x128
|
||||
[ 73.138484 ] ret_from_fork+0x10/0x1c
|
||||
|
||||
Signed-off-by: Xing Song <xing.song@mediatek.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2947,6 +2947,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
if (!fwd_skb)
|
||||
goto out;
|
||||
|
||||
+ fwd_skb->dev = sdata->dev;
|
||||
fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
|
||||
fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
|
||||
info = IEEE80211_SKB_CB(fwd_skb);
|
@ -0,0 +1,26 @@
|
||||
From: Xing Song <xing.song@mediatek.com>
|
||||
Date: Mon, 1 Nov 2021 10:46:57 +0800
|
||||
Subject: [PATCH] mac80211: do not access the IV when it was stripped
|
||||
|
||||
ieee80211_get_keyid() will return false value if IV has been stripped,
|
||||
such as return 0 for IP/ARP frames due to LLC header, and return -EINVAL
|
||||
for disassociation frames due to its length... etc. Don't try to access
|
||||
it if it's not present.
|
||||
|
||||
Signed-off-by: Xing Song <xing.song@mediatek.com>
|
||||
Link: https://lore.kernel.org/r/20211101024657.143026-1-xing.song@mediatek.com
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -1952,7 +1952,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_
|
||||
int keyid = rx->sta->ptk_idx;
|
||||
sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
|
||||
|
||||
- if (ieee80211_has_protected(fc)) {
|
||||
+ if (ieee80211_has_protected(fc) &&
|
||||
+ !(status->flag & RX_FLAG_IV_STRIPPED)) {
|
||||
cs = rx->sta->cipher_scheme;
|
||||
keyid = ieee80211_get_keyid(rx->skb, cs);
|
||||
|
@ -0,0 +1,49 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Tue, 9 Nov 2021 10:02:04 +0100
|
||||
Subject: [PATCH] mac80211: fix radiotap header generation
|
||||
|
||||
In commit 8c89f7b3d3f2 ("mac80211: Use flex-array for radiotap header
|
||||
bitmap") we accidentally pointed the position to the wrong place, so
|
||||
we overwrite a present bitmap, and thus cause all kinds of trouble.
|
||||
|
||||
To see the issue, note that the previous code read:
|
||||
|
||||
pos = (void *)(it_present + 1);
|
||||
|
||||
The requirement now is that we need to calculate pos via it_optional,
|
||||
to not trigger the compiler hardening checks, as:
|
||||
|
||||
pos = (void *)&rthdr->it_optional[...];
|
||||
|
||||
Rewriting the original expression, we get (obviously, since that just
|
||||
adds "+ x - x" terms):
|
||||
|
||||
pos = (void *)(it_present + 1 + rthdr->it_optional - rthdr->it_optional)
|
||||
|
||||
and moving the "+ rthdr->it_optional" outside to be used as an array:
|
||||
|
||||
pos = (void *)&rthdr->it_optional[it_present + 1 - rthdr->it_optional];
|
||||
|
||||
The original is off by one, fix it.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Fixes: 8c89f7b3d3f2 ("mac80211: Use flex-array for radiotap header bitmap")
|
||||
Reported-by: Sid Hayn <sidhayn@gmail.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
Tested-by: Sid Hayn <sidhayn@gmail.com>
|
||||
Reviewed-by: Kees Cook <keescook@chromium.org>
|
||||
Link: https://lore.kernel.org/r/20211109100203.c61007433ed6.I1dade57aba7de9c4f48d68249adbae62636fd98c@changeid
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -364,7 +364,7 @@ ieee80211_add_rx_radiotap_header(struct
|
||||
* the compiler to think we have walked past the end of the
|
||||
* struct member.
|
||||
*/
|
||||
- pos = (void *)&rthdr->it_optional[it_present - rthdr->it_optional];
|
||||
+ pos = (void *)&rthdr->it_optional[it_present + 1 - rthdr->it_optional];
|
||||
|
||||
/* the order of the following fields is important */
|
||||
|
@ -8,9 +8,9 @@ PKG_LICENSE_FILES:=
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/openwrt/mt76
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2021-11-22
|
||||
PKG_SOURCE_VERSION:=b1d0ad2e74fe8cad563556bb8781d5d92b24b690
|
||||
PKG_MIRROR_HASH:=7507fdc31aa5f3d90bfffa3c7db4957c4ac16df8426e1b017b112e7e6c97735b
|
||||
PKG_SOURCE_DATE:=2021-11-23
|
||||
PKG_SOURCE_VERSION:=99225b985cbcab4707589f1fa313436f4bf1e368
|
||||
PKG_MIRROR_HASH:=6444c7d49d778c7621b03f0f201ce41f6dc9ac00dedb29c66478360b4fd60492
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
PKG_USE_NINJA:=0
|
||||
|
@ -197,12 +197,12 @@ ismounted() {
|
||||
for dirname in $EXTRA_MOUNT ; do
|
||||
case "$filename" in
|
||||
"${dirname}/"* | "${dirname}" )
|
||||
return 1
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
append_addnhosts() {
|
||||
|
@ -0,0 +1,34 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 18 Feb 2019 12:57:11 +0100
|
||||
Subject: [PATCH] mesh: allow processing authentication frames in blocked state
|
||||
|
||||
If authentication fails repeatedly e.g. because of a weak signal, the link
|
||||
can end up in blocked state. If one of the nodes tries to establish a link
|
||||
again before it is unblocked on the other side, it will block the link to
|
||||
that other side. The same happens on the other side when it unblocks the
|
||||
link. In that scenario, the link never recovers on its own.
|
||||
|
||||
To fix this, allow restarting authentication even if the link is in blocked
|
||||
state, but don't initiate the attempt until the blocked period is over.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/src/ap/ieee802_11.c
|
||||
+++ b/src/ap/ieee802_11.c
|
||||
@@ -3761,15 +3761,6 @@ static void handle_auth(struct hostapd_d
|
||||
seq_ctrl);
|
||||
return;
|
||||
}
|
||||
-#ifdef CONFIG_MESH
|
||||
- if ((hapd->conf->mesh & MESH_ENABLED) &&
|
||||
- sta->plink_state == PLINK_BLOCKED) {
|
||||
- wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
|
||||
- " is blocked - drop Authentication frame",
|
||||
- MAC2STR(mgmt->sa));
|
||||
- return;
|
||||
- }
|
||||
-#endif /* CONFIG_MESH */
|
||||
#ifdef CONFIG_PASN
|
||||
if (auth_alg == WLAN_AUTH_PASN &&
|
||||
(sta->flags & WLAN_STA_ASSOC)) {
|
@ -126,7 +126,7 @@
|
||||
if (res == HOSTAPD_ACL_PENDING)
|
||||
return;
|
||||
|
||||
@@ -5454,7 +5466,7 @@ static void handle_assoc(struct hostapd_
|
||||
@@ -5445,7 +5457,7 @@ static void handle_assoc(struct hostapd_
|
||||
int resp = WLAN_STATUS_SUCCESS;
|
||||
u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
const u8 *pos;
|
||||
@ -135,7 +135,7 @@
|
||||
struct sta_info *sta;
|
||||
u8 *tmp = NULL;
|
||||
#ifdef CONFIG_FILS
|
||||
@@ -5667,6 +5679,11 @@ static void handle_assoc(struct hostapd_
|
||||
@@ -5658,6 +5670,11 @@ static void handle_assoc(struct hostapd_
|
||||
left = res;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
@ -147,7 +147,7 @@
|
||||
|
||||
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
|
||||
* is used */
|
||||
@@ -5765,6 +5782,13 @@ static void handle_assoc(struct hostapd_
|
||||
@@ -5756,6 +5773,13 @@ static void handle_assoc(struct hostapd_
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
@ -161,7 +161,7 @@
|
||||
fail:
|
||||
|
||||
/*
|
||||
@@ -5858,6 +5882,7 @@ static void handle_disassoc(struct hosta
|
||||
@@ -5849,6 +5873,7 @@ static void handle_disassoc(struct hosta
|
||||
wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
|
||||
MAC2STR(mgmt->sa),
|
||||
le_to_host16(mgmt->u.disassoc.reason_code));
|
||||
@ -169,7 +169,7 @@
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (sta == NULL) {
|
||||
@@ -5927,6 +5952,8 @@ static void handle_deauth(struct hostapd
|
||||
@@ -5918,6 +5943,8 @@ static void handle_deauth(struct hostapd
|
||||
/* Clear the PTKSA cache entries for PASN */
|
||||
ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
--- a/src/common/wpa_ctrl.c
|
||||
+++ b/src/common/wpa_ctrl.c
|
||||
@@ -135,7 +135,7 @@ try_again:
|
||||
return NULL;
|
||||
}
|
||||
tries++;
|
||||
-#ifdef ANDROID
|
||||
+
|
||||
/* Set client socket file permissions so that bind() creates the client
|
||||
* socket with these permissions and there is no need to try to change
|
||||
* them with chmod() after bind() which would have potential issues with
|
||||
@@ -147,7 +147,7 @@ try_again:
|
||||
* operations to allow the response to go through. Those are using the
|
||||
* no-deference-symlinks version to avoid races. */
|
||||
fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
-#endif /* ANDROID */
|
||||
+
|
||||
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
|
||||
sizeof(ctrl->local)) < 0) {
|
||||
if (errno == EADDRINUSE && tries < 2) {
|
||||
@@ -165,7 +165,11 @@ try_again:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-#ifdef ANDROID
|
||||
+#ifndef ANDROID
|
||||
+ /* Set group even if we do not have privileges to change owner */
|
||||
+ lchown(ctrl->local.sun_path, -1, 101);
|
||||
+ lchown(ctrl->local.sun_path, 101, 101);
|
||||
+#else
|
||||
/* Set group even if we do not have privileges to change owner */
|
||||
lchown(ctrl->local.sun_path, -1, AID_WIFI);
|
||||
lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
|
@ -65,7 +65,7 @@
|
||||
wpabuf_free(sta->hs20_ie);
|
||||
--- a/src/ap/ieee802_11.c
|
||||
+++ b/src/ap/ieee802_11.c
|
||||
@@ -4136,13 +4136,11 @@ static u16 copy_supp_rates(struct hostap
|
||||
@@ -4127,13 +4127,11 @@ static u16 copy_supp_rates(struct hostap
|
||||
static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ext_capab_ie, size_t ext_capab_ie_len)
|
||||
{
|
||||
|
@ -425,6 +425,7 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
|
||||
blobmsg_add_u32(&b, "freq", hapd->iface->freq);
|
||||
blobmsg_add_u32(&b, "channel", ieee80211_frequency_to_channel(hapd->iface->freq));
|
||||
blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
|
||||
|
||||
snprintf(phy_name, 17, "%s", hapd->iface->phy);
|
||||
blobmsg_add_string(&b, "phy", phy_name);
|
||||
|
@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/procd.git
|
||||
PKG_MIRROR_HASH:=0ff42d965b6c07fe9d1731395623b78967b83bbeb85deda900dd430a2883643f
|
||||
PKG_SOURCE_DATE:=2021-11-11
|
||||
PKG_SOURCE_VERSION:=9d1431e1309e1acee06c016acc08cb7650b1d0af
|
||||
PKG_MIRROR_HASH:=39f24aa076a61a3d570f4e5f7a3f38eb6b6e3b96a967c8be7f0dc3e3ffaeed1a
|
||||
PKG_SOURCE_DATE:=2021-11-23
|
||||
PKG_SOURCE_VERSION:=01ac2c4500cb0c7934640e6d2e5f99b08483bdf4
|
||||
CMAKE_INSTALL:=1
|
||||
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
@ -7,9 +7,19 @@
|
||||
[ "has", "MINOR" ]
|
||||
],
|
||||
[
|
||||
[ "if",
|
||||
[ "eq", "DEVNAME", "null" ],
|
||||
[
|
||||
[ "makedev", "/dev/%DEVNAME%", "0666" ],
|
||||
[ "exec", "/bin/ln", "-s", "/proc/self/fd/0", "/dev/stdin" ],
|
||||
[ "exec", "/bin/ln", "-s", "/proc/self/fd/1", "/dev/stdout" ],
|
||||
[ "exec", "/bin/ln", "-s", "/proc/self/fd/2", "/dev/stderr" ],
|
||||
[ "return" ]
|
||||
]
|
||||
],
|
||||
[ "if",
|
||||
[ "eq", "DEVNAME",
|
||||
[ "null", "full", "ptmx", "zero", "tty", "net", "random", "urandom" ]
|
||||
[ "full", "ptmx", "zero", "tty", "net", "random", "urandom" ]
|
||||
],
|
||||
[
|
||||
[ "makedev", "/dev/%DEVNAME%", "0666" ],
|
||||
|
@ -0,0 +1,131 @@
|
||||
From d3bc6269e21fc474763708e79c7a118740befb94 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 26 Oct 2021 11:37:16 +0200
|
||||
Subject: [PATCH] phy: bcm-ns-usb2: support updated DT binding with PHY reg
|
||||
space
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Updated DT binding maps just a PHY's register space instead of the whole
|
||||
DMU block. Accessing a common CRU reg is handled using syscon &
|
||||
regmap.
|
||||
|
||||
The old binding has been deprecated and remains supported as a fallback
|
||||
method.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Link: https://lore.kernel.org/r/20211026093716.5567-1-zajec5@gmail.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/broadcom/phy-bcm-ns-usb2.c | 52 +++++++++++++++++++++-----
|
||||
1 file changed, 43 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c
|
||||
+++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c
|
||||
@@ -9,17 +9,23 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct bcm_ns_usb2 {
|
||||
struct device *dev;
|
||||
struct clk *ref_clk;
|
||||
struct phy *phy;
|
||||
+ struct regmap *clkset;
|
||||
+ void __iomem *base;
|
||||
+
|
||||
+ /* Deprecated binding */
|
||||
void __iomem *dmu;
|
||||
};
|
||||
|
||||
@@ -27,7 +33,6 @@ static int bcm_ns_usb2_phy_init(struct p
|
||||
{
|
||||
struct bcm_ns_usb2 *usb2 = phy_get_drvdata(phy);
|
||||
struct device *dev = usb2->dev;
|
||||
- void __iomem *dmu = usb2->dmu;
|
||||
u32 ref_clk_rate, usb2ctl, usb_pll_ndiv, usb_pll_pdiv;
|
||||
int err = 0;
|
||||
|
||||
@@ -44,7 +49,10 @@ static int bcm_ns_usb2_phy_init(struct p
|
||||
goto err_clk_off;
|
||||
}
|
||||
|
||||
- usb2ctl = readl(dmu + BCMA_DMU_CRU_USB2_CONTROL);
|
||||
+ if (usb2->base)
|
||||
+ usb2ctl = readl(usb2->base);
|
||||
+ else
|
||||
+ usb2ctl = readl(usb2->dmu + BCMA_DMU_CRU_USB2_CONTROL);
|
||||
|
||||
if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) {
|
||||
usb_pll_pdiv = usb2ctl;
|
||||
@@ -58,15 +66,24 @@ static int bcm_ns_usb2_phy_init(struct p
|
||||
usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate;
|
||||
|
||||
/* Unlock DMU PLL settings with some magic value */
|
||||
- writel(0x0000ea68, dmu + BCMA_DMU_CRU_CLKSET_KEY);
|
||||
+ if (usb2->clkset)
|
||||
+ regmap_write(usb2->clkset, 0, 0x0000ea68);
|
||||
+ else
|
||||
+ writel(0x0000ea68, usb2->dmu + BCMA_DMU_CRU_CLKSET_KEY);
|
||||
|
||||
/* Write USB 2.0 PLL control setting */
|
||||
usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK;
|
||||
usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT;
|
||||
- writel(usb2ctl, dmu + BCMA_DMU_CRU_USB2_CONTROL);
|
||||
+ if (usb2->base)
|
||||
+ writel(usb2ctl, usb2->base);
|
||||
+ else
|
||||
+ writel(usb2ctl, usb2->dmu + BCMA_DMU_CRU_USB2_CONTROL);
|
||||
|
||||
/* Lock DMU PLL settings */
|
||||
- writel(0x00000000, dmu + BCMA_DMU_CRU_CLKSET_KEY);
|
||||
+ if (usb2->clkset)
|
||||
+ regmap_write(usb2->clkset, 0, 0x00000000);
|
||||
+ else
|
||||
+ writel(0x00000000, usb2->dmu + BCMA_DMU_CRU_CLKSET_KEY);
|
||||
|
||||
err_clk_off:
|
||||
clk_disable_unprepare(usb2->ref_clk);
|
||||
@@ -91,11 +108,28 @@ static int bcm_ns_usb2_probe(struct plat
|
||||
return -ENOMEM;
|
||||
usb2->dev = dev;
|
||||
|
||||
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu");
|
||||
- usb2->dmu = devm_ioremap_resource(dev, res);
|
||||
- if (IS_ERR(usb2->dmu)) {
|
||||
- dev_err(dev, "Failed to map DMU regs\n");
|
||||
- return PTR_ERR(usb2->dmu);
|
||||
+ if (of_find_property(dev->of_node, "brcm,syscon-clkset", NULL)) {
|
||||
+ usb2->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(usb2->base)) {
|
||||
+ dev_err(dev, "Failed to map control reg\n");
|
||||
+ return PTR_ERR(usb2->base);
|
||||
+ }
|
||||
+
|
||||
+ usb2->clkset = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
+ "brcm,syscon-clkset");
|
||||
+ if (IS_ERR(usb2->clkset)) {
|
||||
+ dev_err(dev, "Failed to lookup clkset regmap\n");
|
||||
+ return PTR_ERR(usb2->clkset);
|
||||
+ }
|
||||
+ } else {
|
||||
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu");
|
||||
+ usb2->dmu = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(usb2->dmu)) {
|
||||
+ dev_err(dev, "Failed to map DMU regs\n");
|
||||
+ return PTR_ERR(usb2->dmu);
|
||||
+ }
|
||||
+
|
||||
+ dev_warn(dev, "using deprecated DT binding\n");
|
||||
}
|
||||
|
||||
usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk");
|
@ -0,0 +1,52 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 23 Nov 2021 09:55:06 +0100
|
||||
Subject: [PATCH] ARM: dts: BCM5301X: use non-deprecated USB 2.0 PHY binding
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The new binding covers a single reg and uses syscon to reference shared
|
||||
register.
|
||||
|
||||
References: 55b9b741712d ("dt-bindings: phy: brcm,ns-usb2-phy: bind just a PHY block")
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
arch/arm/boot/dts/bcm5301x.dtsi | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/bcm5301x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
|
||||
@@ -148,15 +148,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
- usb2_phy: usb2-phy@1800c000 {
|
||||
- compatible = "brcm,ns-usb2-phy";
|
||||
- reg = <0x1800c000 0x1000>;
|
||||
- reg-names = "dmu";
|
||||
- #phy-cells = <0>;
|
||||
- clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
|
||||
- clock-names = "phy-ref-clk";
|
||||
- };
|
||||
-
|
||||
axi@18000000 {
|
||||
compatible = "brcm,bus-axi";
|
||||
reg = <0x18000000 0x1000>;
|
||||
@@ -450,7 +441,16 @@
|
||||
"sata1", "sata2";
|
||||
};
|
||||
|
||||
- syscon@180 {
|
||||
+ usb2_phy: phy@164 {
|
||||
+ compatible = "brcm,ns-usb2-phy";
|
||||
+ reg = <0x164 0x4>;
|
||||
+ brcm,syscon-clkset = <&cru_clkset>;
|
||||
+ clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
|
||||
+ clock-names = "phy-ref-clk";
|
||||
+ #phy-cells = <0>;
|
||||
+ };
|
||||
+
|
||||
+ cru_clkset: syscon@180 {
|
||||
compatible = "brcm,cru-clkset", "syscon";
|
||||
reg = <0x180 0x4>;
|
||||
};
|
@ -0,0 +1,62 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 23 Nov 2021 13:13:05 +0100
|
||||
Subject: [PATCH] ARM: dts: BCM5301X: Switch back to old clock nodes names
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
First of all using the same node name prefix resulted in trying to
|
||||
register 2 clocks under the same "clock-controller" name:
|
||||
|
||||
[ 0.000000] __clk_core_init: clk clock-controller already initialized
|
||||
[ 0.000000] ------------[ cut here ]------------
|
||||
[ 0.000000] WARNING: CPU: 0 PID: 0 at drivers/clk/bcm/clk-iproc-pll.c:802 iproc_pll_clk_setup+0x4c8/0x4f4
|
||||
[ 0.000000] Modules linked in:
|
||||
[ 0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.10.80 #0
|
||||
[ 0.000000] Hardware name: BCM5301X
|
||||
[ 0.000000] [<c0108410>] (unwind_backtrace) from [<c0104bc4>] (show_stack+0x10/0x14)
|
||||
[ 0.000000] [<c0104bc4>] (show_stack) from [<c03dca28>] (dump_stack+0x94/0xa8)
|
||||
[ 0.000000] [<c03dca28>] (dump_stack) from [<c0118440>] (__warn+0xb8/0x114)
|
||||
[ 0.000000] [<c0118440>] (__warn) from [<c0118504>] (warn_slowpath_fmt+0x68/0x78)
|
||||
[ 0.000000] [<c0118504>] (warn_slowpath_fmt) from [<c043281c>] (iproc_pll_clk_setup+0x4c8/0x4f4)
|
||||
[ 0.000000] [<c043281c>] (iproc_pll_clk_setup) from [<c0818c04>] (nsp_genpll_clk_init+0x30/0x38)
|
||||
[ 0.000000] [<c0818c04>] (nsp_genpll_clk_init) from [<c0818634>] (of_clk_init+0x118/0x1f8)
|
||||
[ 0.000000] [<c0818634>] (of_clk_init) from [<c08039b0>] (time_init+0x24/0x30)
|
||||
[ 0.000000] [<c08039b0>] (time_init) from [<c0800d14>] (start_kernel+0x398/0x50c)
|
||||
[ 0.000000] [<c0800d14>] (start_kernel) from [<00000000>] (0x0)
|
||||
[ 0.000000] ---[ end trace fe236bfe9559ee50 ]---
|
||||
|
||||
Secondly using any other names than "lcpll0" and "genpll" breaks output
|
||||
clocks:
|
||||
|
||||
$ cat /sys/kernel/debug/clk/usbclk/clk_rate
|
||||
0
|
||||
|
||||
For some reason iproc_clk_recalc_rate() gets called with "parent_rate"
|
||||
argument 0 whenever clocks aren't named "lcpll0" and "genpll".
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
arch/arm/boot/dts/bcm5301x.dtsi | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/bcm5301x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
|
||||
@@ -421,7 +421,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
- lcpll0: clock-controller@100 {
|
||||
+ lcpll0: lcpll0@100 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "brcm,nsp-lcpll0";
|
||||
reg = <0x100 0x14>;
|
||||
@@ -430,7 +430,7 @@
|
||||
"sdio", "ddr_phy";
|
||||
};
|
||||
|
||||
- genpll: clock-controller@140 {
|
||||
+ genpll: genpll@140 {
|
||||
#clock-cells = <1>;
|
||||
compatible = "brcm,nsp-genpll";
|
||||
reg = <0x140 0x24>;
|
@ -160,6 +160,7 @@ CONFIG_PINCTRL=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_REALTEK_OTTO_WDT=y
|
||||
CONFIG_REALTEK_PHY=y
|
||||
CONFIG_REALTEK_SOC_PHY=y
|
||||
CONFIG_REGMAP=y
|
||||
@ -190,5 +191,6 @@ CONFIG_TIMER_PROBE=y
|
||||
CONFIG_TINY_SRCU=y
|
||||
CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y
|
||||
CONFIG_USE_OF=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_ZLIB_DEFLATE=y
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
|
@ -8,10 +8,6 @@
|
||||
/ {
|
||||
compatible = "realtek,rtl838x-soc";
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x8000000>;
|
||||
|
@ -13,10 +13,6 @@
|
||||
led-upgrade = &led_sys;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x8000000>;
|
||||
|
@ -16,10 +16,6 @@
|
||||
led-upgrade = &led_sys;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x8000000>;
|
||||
|
@ -16,10 +16,6 @@
|
||||
led-upgrade = &led_power;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x8000000>;
|
||||
|
@ -13,10 +13,6 @@
|
||||
led-upgrade = &led_power;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x8000000>;
|
||||
|
@ -9,10 +9,6 @@
|
||||
compatible = "inaba,aml2-17gp", "realtek,rtl838x-soc";
|
||||
model = "INABA Abaniact AML2-17GP";
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x8000000>;
|
||||
|
@ -65,7 +65,13 @@
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,38400";
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
lx_clk: lx_clk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <200000000>;
|
||||
};
|
||||
|
||||
cpuintc: cpuintc {
|
||||
@ -116,7 +122,7 @@
|
||||
compatible = "ns16550a";
|
||||
reg = <0x2000 0x100>;
|
||||
|
||||
clock-frequency = <200000000>;
|
||||
clocks = <&lx_clk>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <31>;
|
||||
@ -134,7 +140,7 @@
|
||||
compatible = "ns16550a";
|
||||
reg = <0x2100 0x100>;
|
||||
|
||||
clock-frequency = <200000000>;
|
||||
clocks = <&lx_clk>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <30>;
|
||||
@ -147,6 +153,20 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
watchdog0: watchdog@3150 {
|
||||
compatible = "realtek,rtl8380-wdt";
|
||||
reg = <0x3150 0xc>;
|
||||
|
||||
realtek,reset-mode = "soc";
|
||||
|
||||
clocks = <&lx_clk>;
|
||||
timeout-sec = <30>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupt-names = "phase1", "phase2";
|
||||
interrupts = <19>, <18>;
|
||||
};
|
||||
|
||||
gpio0: gpio-controller@3500 {
|
||||
compatible = "realtek,rtl8380-gpio", "realtek,otto-gpio";
|
||||
reg = <0x3500 0x20>;
|
||||
|
@ -70,7 +70,7 @@
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "console=ttyS0,38400";
|
||||
bootargs = "console=ttyS0,115200";
|
||||
};
|
||||
|
||||
cpuintc: cpuintc {
|
||||
@ -80,11 +80,10 @@
|
||||
interrupt-controller;
|
||||
};
|
||||
|
||||
osc: oscillator {
|
||||
lx_clk: lx_clk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <1>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <175000000>;
|
||||
clock-output-names = "osc";
|
||||
};
|
||||
|
||||
soc: soc {
|
||||
@ -110,7 +109,9 @@
|
||||
<10 &cpuintc 1>, /* TC3 */
|
||||
<9 &cpuintc 1>, /* TC2 */
|
||||
<8 &cpuintc 1>, /* TC1 */
|
||||
<7 &cpuintc 5>; /* TC0 */
|
||||
<7 &cpuintc 5>, /* TC0 */
|
||||
<6 &cpuintc 5>, /* WDT_IP2 */
|
||||
<5 &cpuintc 4>; /* WDT_IP1 */
|
||||
};
|
||||
|
||||
timer: timer@3200 {
|
||||
@ -119,7 +120,7 @@
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <8>;
|
||||
interrupt-names = "ostimer";
|
||||
clocks = <&osc 0>;
|
||||
clocks = <&lx_clk>;
|
||||
};
|
||||
|
||||
spi0: spi@1200 {
|
||||
@ -134,7 +135,7 @@
|
||||
compatible = "ns16550a";
|
||||
reg = <0x2000 0x100>;
|
||||
|
||||
clock-frequency = <175000000>;
|
||||
clocks = <&lx_clk>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <30>;
|
||||
@ -149,7 +150,7 @@
|
||||
compatible = "ns16550a";
|
||||
reg = <0x2100 0x100>;
|
||||
|
||||
clock-frequency = <175000000>;
|
||||
clocks = <&lx_clk>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <31>;
|
||||
@ -162,6 +163,20 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
watchdog0: watchdog@3260 {
|
||||
compatible = "realtek,rtl9300-wdt";
|
||||
reg = <0x3260 0xc>;
|
||||
|
||||
realtek,reset-mode = "soc";
|
||||
|
||||
clocks = <&lx_clk>;
|
||||
timeout-sec = <30>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupt-names = "phase1", "phase2";
|
||||
interrupts = <5>, <6>;
|
||||
};
|
||||
|
||||
gpio0: gpio-controller@3500 {
|
||||
compatible = "realtek,rtl8380-gpio", "realtek,otto-gpio";
|
||||
reg = <0x3500 0x20>;
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/smp-ops.h>
|
||||
@ -29,100 +28,20 @@
|
||||
|
||||
extern struct rtl83xx_soc_info soc_info;
|
||||
|
||||
u32 pll_reset_value;
|
||||
|
||||
static void rtl838x_restart(char *command)
|
||||
{
|
||||
u32 pll = sw_r32(RTL838X_PLL_CML_CTRL);
|
||||
|
||||
pr_info("System restart.\n");
|
||||
pr_info("PLL control register: %x, applying reset value %x\n",
|
||||
pll, pll_reset_value);
|
||||
|
||||
sw_w32(3, RTL838X_INT_RW_CTRL);
|
||||
sw_w32(pll_reset_value, RTL838X_PLL_CML_CTRL);
|
||||
sw_w32(0, RTL838X_INT_RW_CTRL);
|
||||
|
||||
/* Reset Global Control1 Register */
|
||||
sw_w32(1, RTL838X_RST_GLB_CTRL_1);
|
||||
}
|
||||
|
||||
static void rtl839x_restart(char *command)
|
||||
{
|
||||
/* SoC reset vector (in flash memory): on RTL839x platform preferred way to reset */
|
||||
void (*f)(void) = (void *) 0xbfc00000;
|
||||
|
||||
pr_info("System restart.\n");
|
||||
/* Reset SoC */
|
||||
sw_w32(0xFFFFFFFF, RTL839X_RST_GLB_CTRL);
|
||||
/* and call reset vector */
|
||||
f();
|
||||
/* If this fails, halt the CPU */
|
||||
while
|
||||
(1);
|
||||
}
|
||||
|
||||
static void rtl930x_restart(char *command)
|
||||
{
|
||||
pr_info("System restart.\n");
|
||||
sw_w32(0x1, RTL930X_RST_GLB_CTRL_0);
|
||||
while
|
||||
(1);
|
||||
}
|
||||
|
||||
static void rtl931x_restart(char *command)
|
||||
{
|
||||
u32 v;
|
||||
|
||||
pr_info("System restart.\n");
|
||||
sw_w32(1, RTL931X_RST_GLB_CTRL);
|
||||
v = sw_r32(RTL931X_RST_GLB_CTRL);
|
||||
sw_w32(0x101, RTL931X_RST_GLB_CTRL);
|
||||
msleep(15);
|
||||
sw_w32(v, RTL931X_RST_GLB_CTRL);
|
||||
msleep(15);
|
||||
sw_w32(0x101, RTL931X_RST_GLB_CTRL);
|
||||
}
|
||||
|
||||
static void rtl838x_halt(void)
|
||||
{
|
||||
pr_info("System halted.\n");
|
||||
while
|
||||
(1);
|
||||
}
|
||||
|
||||
static void __init rtl838x_setup(void)
|
||||
{
|
||||
pr_info("Registering _machine_restart\n");
|
||||
_machine_restart = rtl838x_restart;
|
||||
_machine_halt = rtl838x_halt;
|
||||
|
||||
/* This PLL value needs to be restored before a reset and will then be
|
||||
* preserved over a SoC reset. A wrong value prevents the SoC from
|
||||
* connecting to the SPI flash controller at boot and reading the
|
||||
* reset routine */
|
||||
pll_reset_value = sw_r32(RTL838X_PLL_CML_CTRL);
|
||||
|
||||
/* Setup System LED. Bit 15 then allows to toggle it */
|
||||
sw_w32_mask(0, 3 << 16, RTL838X_LED_GLB_CTRL);
|
||||
}
|
||||
|
||||
static void __init rtl839x_setup(void)
|
||||
{
|
||||
pr_info("Registering _machine_restart\n");
|
||||
_machine_restart = rtl839x_restart;
|
||||
_machine_halt = rtl838x_halt;
|
||||
|
||||
/* Setup System LED. Bit 14 of RTL839X_LED_GLB_CTRL then allows to toggle it */
|
||||
sw_w32_mask(0, 3 << 15, RTL839X_LED_GLB_CTRL);
|
||||
}
|
||||
|
||||
static void __init rtl930x_setup(void)
|
||||
{
|
||||
pr_info("Registering _machine_restart\n");
|
||||
_machine_restart = rtl930x_restart;
|
||||
_machine_halt = rtl838x_halt;
|
||||
|
||||
if (soc_info.id == 0x9302)
|
||||
sw_w32_mask(0, 3 << 13, RTL9302_LED_GLB_CTRL);
|
||||
else
|
||||
@ -131,9 +50,6 @@ static void __init rtl930x_setup(void)
|
||||
|
||||
static void __init rtl931x_setup(void)
|
||||
{
|
||||
pr_info("Registering _machine_restart\n");
|
||||
_machine_restart = rtl931x_restart;
|
||||
_machine_halt = rtl838x_halt;
|
||||
sw_w32_mask(0, 3 << 12, RTL931X_LED_GLB_CTRL);
|
||||
}
|
||||
|
||||
@ -142,7 +58,6 @@ void __init plat_mem_setup(void)
|
||||
void *dtb;
|
||||
|
||||
set_io_port_base(KSEG1);
|
||||
_machine_restart = rtl838x_restart;
|
||||
|
||||
if (fw_passed_dtb) /* UHI interface */
|
||||
dtb = (void *)fw_passed_dtb;
|
||||
|
@ -630,6 +630,7 @@ static const struct rtl838x_reg rtl931x_reg = {
|
||||
static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv)
|
||||
{
|
||||
u32 int_saved, nbuf;
|
||||
u32 reset_mask;
|
||||
int i, pos;
|
||||
|
||||
pr_info("RESETTING %x, CPU_PORT %d\n", priv->family_id, priv->cpu_port);
|
||||
@ -662,15 +663,17 @@ static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv)
|
||||
sw_w32(0xffffffff, priv->r->dma_if_intr_sts);
|
||||
}
|
||||
|
||||
/* Reset NIC */
|
||||
/* Reset NIC (SW_NIC_RST) and queues (SW_Q_RST) */
|
||||
if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID)
|
||||
sw_w32(0x4, priv->r->rst_glb_ctrl);
|
||||
reset_mask = 0x6;
|
||||
else
|
||||
sw_w32(0x8, priv->r->rst_glb_ctrl);
|
||||
reset_mask = 0xc;
|
||||
|
||||
sw_w32(reset_mask, priv->r->rst_glb_ctrl);
|
||||
|
||||
do { /* Wait for reset of NIC and Queues done */
|
||||
udelay(20);
|
||||
} while (sw_r32(priv->r->rst_glb_ctrl) & 0xc);
|
||||
} while (sw_r32(priv->r->rst_glb_ctrl) & reset_mask);
|
||||
mdelay(100);
|
||||
|
||||
/* Setup Head of Line */
|
||||
|
@ -0,0 +1,456 @@
|
||||
From 2dbf0c6e0eebf523008c15794434d2d1a9b1260e Mon Sep 17 00:00:00 2001
|
||||
Message-Id: <2dbf0c6e0eebf523008c15794434d2d1a9b1260e.1636018117.git.sander@svanheule.net>
|
||||
In-Reply-To: <cover.1636018117.git.sander@svanheule.net>
|
||||
References: <cover.1636018117.git.sander@svanheule.net>
|
||||
From: Sander Vanheule <sander@svanheule.net>
|
||||
Date: Sun, 3 Oct 2021 09:25:27 +0200
|
||||
Subject: [PATCH v3 2/2] watchdog: Add Realtek Otto watchdog timer
|
||||
|
||||
Realtek MIPS SoCs (platform name Otto) have a watchdog timer with
|
||||
pretimeout notifitication support. The WDT can (partially) hard reset,
|
||||
or soft reset the SoC.
|
||||
|
||||
This driver implements all features as described in the devicetree
|
||||
binding, except the phase2 interrupt, and also functions as a restart
|
||||
handler. The cpu reset mode is considered to be a "warm" restart, since
|
||||
this mode does not reset all peripherals. Being an embedded system
|
||||
though, the "cpu" and "software" modes will still cause the bootloader
|
||||
to run on restart.
|
||||
|
||||
It is not known how a forced system reset can be disabled on the
|
||||
supported platforms. This means that the phase2 interrupt will only fire
|
||||
at the same time as reset, so implementing phase2 is of little use.
|
||||
|
||||
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||
---
|
||||
MAINTAINERS | 7 +
|
||||
drivers/watchdog/Kconfig | 13 +
|
||||
drivers/watchdog/Makefile | 1 +
|
||||
drivers/watchdog/realtek_otto_wdt.c | 361 ++++++++++++++++++++++++++++
|
||||
4 files changed, 382 insertions(+)
|
||||
create mode 100644 drivers/watchdog/realtek_otto_wdt.c
|
||||
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 2c9070aeba2a..54c8f788d3e5 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -15991,6 +15991,13 @@ S: Maintained
|
||||
F: include/sound/rt*.h
|
||||
F: sound/soc/codecs/rt*
|
||||
|
||||
+REALTEK OTTO WATCHDOG
|
||||
+M: Sander Vanheule <sander@svanheule.net>
|
||||
+L: linux-watchdog@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml
|
||||
+F: driver/watchdog/realtek_otto_wdt.c
|
||||
+
|
||||
REALTEK RTL83xx SMI DSA ROUTER CHIPS
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
S: Maintained
|
||||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
|
||||
index bf59faeb3de1..d308e13a9aa1 100644
|
||||
--- a/drivers/watchdog/Kconfig
|
||||
+++ b/drivers/watchdog/Kconfig
|
||||
@@ -954,6 +954,19 @@ config RTD119X_WATCHDOG
|
||||
Say Y here to include support for the watchdog timer in
|
||||
Realtek RTD1295 SoCs.
|
||||
|
||||
+config REALTEK_OTTO_WDT
|
||||
+ tristate "Realtek Otto MIPS watchdog support"
|
||||
+ depends on MACH_REALTEK_RTL || COMPILE_TEST
|
||||
+ depends on COMMON_CLK
|
||||
+ select WATCHDOG_CORE
|
||||
+ default MACH_REALTEK_RTL
|
||||
+ help
|
||||
+ Say Y here to include support for the watchdog timer on Realtek
|
||||
+ RTL838x, RTL839x, RTL930x SoCs. This watchdog has pretimeout
|
||||
+ notifications and system reset on timeout.
|
||||
+
|
||||
+ When built as a module this will be called realtek_otto_wdt.
|
||||
+
|
||||
config SPRD_WATCHDOG
|
||||
tristate "Spreadtrum watchdog support"
|
||||
depends on ARCH_SPRD || COMPILE_TEST
|
||||
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
|
||||
index 1bd2d6f37c53..a8dccf819163 100644
|
||||
--- a/drivers/watchdog/Makefile
|
||||
+++ b/drivers/watchdog/Makefile
|
||||
@@ -171,6 +171,7 @@ obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
|
||||
obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o
|
||||
obj-$(CONFIG_PIC32_WDT) += pic32-wdt.o
|
||||
obj-$(CONFIG_PIC32_DMT) += pic32-dmt.o
|
||||
+obj-$(CONFIG_REALTEK_OTTO_WDT) += realtek_otto_wdt.o
|
||||
|
||||
# PARISC Architecture
|
||||
|
||||
diff --git a/drivers/watchdog/realtek_otto_wdt.c b/drivers/watchdog/realtek_otto_wdt.c
|
||||
new file mode 100644
|
||||
index 000000000000..48bc8dfefc25
|
||||
--- /dev/null
|
||||
+++ b/drivers/watchdog/realtek_otto_wdt.c
|
||||
@@ -0,0 +1,361 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+
|
||||
+/*
|
||||
+ * Realtek Otto MIPS platform watchdog
|
||||
+ *
|
||||
+ * Watchdog timer that will reset the system after timeout, using the selected
|
||||
+ * reset mode.
|
||||
+ *
|
||||
+ * Counter scaling and timeouts:
|
||||
+ * - Base prescale of (2 << 25), providing tick duration T_0: 168ms @ 200MHz
|
||||
+ * - PRESCALE: logarithmic prescaler adding a factor of {1, 2, 4, 8}
|
||||
+ * - Phase 1: Times out after (PHASE1 + 1) × PRESCALE × T_0
|
||||
+ * Generates an interrupt, WDT cannot be stopped after phase 1
|
||||
+ * - Phase 2: starts after phase 1, times out after (PHASE2 + 1) × PRESCALE × T_0
|
||||
+ * Resets the system according to RST_MODE
|
||||
+ */
|
||||
+
|
||||
+#include <linux/bits.h>
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/math.h>
|
||||
+#include <linux/minmax.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/property.h>
|
||||
+#include <linux/reboot.h>
|
||||
+#include <linux/watchdog.h>
|
||||
+
|
||||
+#define OTTO_WDT_REG_CNTR 0x0
|
||||
+#define OTTO_WDT_CNTR_PING BIT(31)
|
||||
+
|
||||
+#define OTTO_WDT_REG_INTR 0x4
|
||||
+#define OTTO_WDT_INTR_PHASE_1 BIT(31)
|
||||
+#define OTTO_WDT_INTR_PHASE_2 BIT(30)
|
||||
+
|
||||
+#define OTTO_WDT_REG_CTRL 0x8
|
||||
+#define OTTO_WDT_CTRL_ENABLE BIT(31)
|
||||
+#define OTTO_WDT_CTRL_PRESCALE GENMASK(30, 29)
|
||||
+#define OTTO_WDT_CTRL_PHASE1 GENMASK(26, 22)
|
||||
+#define OTTO_WDT_CTRL_PHASE2 GENMASK(19, 15)
|
||||
+#define OTTO_WDT_CTRL_RST_MODE GENMASK(1, 0)
|
||||
+#define OTTO_WDT_MODE_SOC 0
|
||||
+#define OTTO_WDT_MODE_CPU 1
|
||||
+#define OTTO_WDT_MODE_SOFTWARE 2
|
||||
+#define OTTO_WDT_CTRL_DEFAULT OTTO_WDT_MODE_CPU
|
||||
+
|
||||
+#define OTTO_WDT_PRESCALE_MAX 3
|
||||
+
|
||||
+/*
|
||||
+ * One higher than the max values contained in PHASE{1,2}, since a value of 0
|
||||
+ * corresponds to one tick.
|
||||
+ */
|
||||
+#define OTTO_WDT_PHASE_TICKS_MAX 32
|
||||
+
|
||||
+/*
|
||||
+ * The maximum reset delay is actually 2×32 ticks, but that would require large
|
||||
+ * pretimeout values for timeouts longer than 32 ticks. Limit the maximum timeout
|
||||
+ * to 32 + 1 to ensure small pretimeout values can be configured as expected.
|
||||
+ */
|
||||
+#define OTTO_WDT_TIMEOUT_TICKS_MAX (OTTO_WDT_PHASE_TICKS_MAX + 1)
|
||||
+
|
||||
+struct otto_wdt_ctrl {
|
||||
+ struct watchdog_device wdev;
|
||||
+ struct device *dev;
|
||||
+ void __iomem *base;
|
||||
+ struct clk *clk;
|
||||
+ int irq_phase1;
|
||||
+};
|
||||
+
|
||||
+static int otto_wdt_start(struct watchdog_device *wdev)
|
||||
+{
|
||||
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
|
||||
+ u32 v;
|
||||
+
|
||||
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+ v |= OTTO_WDT_CTRL_ENABLE;
|
||||
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_stop(struct watchdog_device *wdev)
|
||||
+{
|
||||
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
|
||||
+ u32 v;
|
||||
+
|
||||
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+ v &= ~OTTO_WDT_CTRL_ENABLE;
|
||||
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_ping(struct watchdog_device *wdev)
|
||||
+{
|
||||
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
|
||||
+
|
||||
+ iowrite32(OTTO_WDT_CNTR_PING, ctrl->base + OTTO_WDT_REG_CNTR);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_tick_ms(struct otto_wdt_ctrl *ctrl, int prescale)
|
||||
+{
|
||||
+ unsigned int rate_khz = clk_get_rate(ctrl->clk) / 1000;
|
||||
+
|
||||
+ if (!rate_khz)
|
||||
+ return 0;
|
||||
+
|
||||
+ return DIV_ROUND_CLOSEST(1 << (25 + prescale), rate_khz);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * The timer asserts the PHASE1/PHASE2 IRQs when the number of ticks exceeds
|
||||
+ * the value stored in those fields. This means each phase will run for at least
|
||||
+ * one tick, so small values need to be clamped to correctly reflect the timeout.
|
||||
+ */
|
||||
+static inline unsigned int div_round_ticks(unsigned int val, unsigned int tick_duration,
|
||||
+ unsigned int min_ticks)
|
||||
+{
|
||||
+ return max(min_ticks, DIV_ROUND_UP(val, tick_duration));
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned int timeout,
|
||||
+ unsigned int pretimeout)
|
||||
+{
|
||||
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
|
||||
+ unsigned int pretimeout_ms = pretimeout * 1000;
|
||||
+ unsigned int timeout_ms = timeout * 1000;
|
||||
+ unsigned int prescale_next = 0;
|
||||
+ unsigned int phase1_ticks;
|
||||
+ unsigned int phase2_ticks;
|
||||
+ unsigned int total_ticks;
|
||||
+ unsigned int prescale;
|
||||
+ unsigned int tick_ms;
|
||||
+ u32 v;
|
||||
+
|
||||
+ do {
|
||||
+ prescale = prescale_next;
|
||||
+ if (prescale > OTTO_WDT_PRESCALE_MAX)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tick_ms = otto_wdt_tick_ms(ctrl, prescale);
|
||||
+ total_ticks = div_round_ticks(timeout_ms, tick_ms, 2);
|
||||
+ phase1_ticks = div_round_ticks(timeout_ms - pretimeout_ms, tick_ms, 1);
|
||||
+ phase2_ticks = total_ticks - phase1_ticks;
|
||||
+
|
||||
+ prescale_next++;
|
||||
+ } while (phase1_ticks > OTTO_WDT_PHASE_TICKS_MAX
|
||||
+ || phase2_ticks > OTTO_WDT_PHASE_TICKS_MAX);
|
||||
+
|
||||
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ v &= ~(OTTO_WDT_CTRL_PRESCALE | OTTO_WDT_CTRL_PHASE1 | OTTO_WDT_CTRL_PHASE2);
|
||||
+ v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE1, phase1_ticks - 1);
|
||||
+ v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE2, phase2_ticks - 1);
|
||||
+ v |= FIELD_PREP(OTTO_WDT_CTRL_PRESCALE, prescale);
|
||||
+
|
||||
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ timeout_ms = total_ticks * tick_ms;
|
||||
+ ctrl->wdev.timeout = timeout_ms / 1000;
|
||||
+
|
||||
+ pretimeout_ms = phase2_ticks * tick_ms;
|
||||
+ ctrl->wdev.pretimeout = pretimeout_ms / 1000;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)
|
||||
+{
|
||||
+ return otto_wdt_determine_timeouts(wdev, val, min(wdev->pretimeout, val - 1));
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_set_pretimeout(struct watchdog_device *wdev, unsigned int val)
|
||||
+{
|
||||
+ return otto_wdt_determine_timeouts(wdev, wdev->timeout, val);
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_restart(struct watchdog_device *wdev, unsigned long reboot_mode,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
|
||||
+ u32 reset_mode;
|
||||
+ u32 v;
|
||||
+
|
||||
+ disable_irq(ctrl->irq_phase1);
|
||||
+
|
||||
+ switch (reboot_mode) {
|
||||
+ case REBOOT_SOFT:
|
||||
+ reset_mode = OTTO_WDT_MODE_SOFTWARE;
|
||||
+ break;
|
||||
+ case REBOOT_WARM:
|
||||
+ reset_mode = OTTO_WDT_MODE_CPU;
|
||||
+ break;
|
||||
+ default:
|
||||
+ reset_mode = OTTO_WDT_MODE_SOC;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Configure for shortest timeout and wait for reset to occur */
|
||||
+ v = FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, reset_mode) | OTTO_WDT_CTRL_ENABLE;
|
||||
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ mdelay(3 * otto_wdt_tick_ms(ctrl, 0));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t otto_wdt_phase1_isr(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct otto_wdt_ctrl *ctrl = dev_id;
|
||||
+
|
||||
+ iowrite32(OTTO_WDT_INTR_PHASE_1, ctrl->base + OTTO_WDT_REG_INTR);
|
||||
+ dev_crit(ctrl->dev, "phase 1 timeout\n");
|
||||
+ watchdog_notify_pretimeout(&ctrl->wdev);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static const struct watchdog_ops otto_wdt_ops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .start = otto_wdt_start,
|
||||
+ .stop = otto_wdt_stop,
|
||||
+ .ping = otto_wdt_ping,
|
||||
+ .set_timeout = otto_wdt_set_timeout,
|
||||
+ .set_pretimeout = otto_wdt_set_pretimeout,
|
||||
+ .restart = otto_wdt_restart,
|
||||
+};
|
||||
+
|
||||
+static const struct watchdog_info otto_wdt_info = {
|
||||
+ .identity = "Realtek Otto watchdog timer",
|
||||
+ .options = WDIOF_KEEPALIVEPING |
|
||||
+ WDIOF_MAGICCLOSE |
|
||||
+ WDIOF_SETTIMEOUT |
|
||||
+ WDIOF_PRETIMEOUT,
|
||||
+};
|
||||
+
|
||||
+static int otto_wdt_probe_reset_mode(struct otto_wdt_ctrl *ctrl)
|
||||
+{
|
||||
+ static const char *mode_property = "realtek,reset-mode";
|
||||
+ const struct fwnode_handle *node = ctrl->dev->fwnode;
|
||||
+ int mode_count;
|
||||
+ u32 mode;
|
||||
+ u32 v;
|
||||
+
|
||||
+ if (!node)
|
||||
+ return -ENXIO;
|
||||
+
|
||||
+ mode_count = fwnode_property_string_array_count(node, mode_property);
|
||||
+ if (mode_count < 0)
|
||||
+ return mode_count;
|
||||
+ else if (mode_count == 0)
|
||||
+ return 0;
|
||||
+ else if (mode_count != 1)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (fwnode_property_match_string(node, mode_property, "soc") == 0)
|
||||
+ mode = OTTO_WDT_MODE_SOC;
|
||||
+ else if (fwnode_property_match_string(node, mode_property, "cpu") == 0)
|
||||
+ mode = OTTO_WDT_MODE_CPU;
|
||||
+ else if (fwnode_property_match_string(node, mode_property, "software") == 0)
|
||||
+ mode = OTTO_WDT_MODE_SOFTWARE;
|
||||
+ else
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+ v &= ~OTTO_WDT_CTRL_RST_MODE;
|
||||
+ v |= FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, mode);
|
||||
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int otto_wdt_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct otto_wdt_ctrl *ctrl;
|
||||
+ unsigned int max_tick_ms;
|
||||
+ int ret;
|
||||
+
|
||||
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
|
||||
+ if (!ctrl)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ctrl->dev = dev;
|
||||
+ ctrl->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(ctrl->base))
|
||||
+ return PTR_ERR(ctrl->base);
|
||||
+
|
||||
+ /* Clear any old interrupts and reset initial state */
|
||||
+ iowrite32(OTTO_WDT_INTR_PHASE_1 | OTTO_WDT_INTR_PHASE_2,
|
||||
+ ctrl->base + OTTO_WDT_REG_INTR);
|
||||
+ iowrite32(OTTO_WDT_CTRL_DEFAULT, ctrl->base + OTTO_WDT_REG_CTRL);
|
||||
+
|
||||
+ ctrl->clk = devm_clk_get(dev, NULL);
|
||||
+ if (IS_ERR(ctrl->clk))
|
||||
+ return dev_err_probe(dev, PTR_ERR(ctrl->clk), "Failed to get clock\n");
|
||||
+
|
||||
+ ctrl->irq_phase1 = platform_get_irq_byname(pdev, "phase1");
|
||||
+ if (ctrl->irq_phase1 < 0)
|
||||
+ return dev_err_probe(dev, ctrl->irq_phase1, "phase1 IRQ not found\n");
|
||||
+
|
||||
+ ret = devm_request_irq(dev, ctrl->irq_phase1, otto_wdt_phase1_isr, 0,
|
||||
+ "realtek-otto-wdt", ctrl);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "Failed to get IRQ for phase1\n");
|
||||
+
|
||||
+ ret = otto_wdt_probe_reset_mode(ctrl);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "Invalid reset mode specified\n");
|
||||
+
|
||||
+ ctrl->wdev.parent = dev;
|
||||
+ ctrl->wdev.info = &otto_wdt_info;
|
||||
+ ctrl->wdev.ops = &otto_wdt_ops;
|
||||
+
|
||||
+ /*
|
||||
+ * Since pretimeout cannot be disabled, min. timeout is twice the
|
||||
+ * subsystem resolution. max. timeout is ca. 43s at a bus clock of 200MHz.
|
||||
+ */
|
||||
+ ctrl->wdev.min_timeout = 2;
|
||||
+ max_tick_ms = otto_wdt_tick_ms(ctrl, OTTO_WDT_PRESCALE_MAX);
|
||||
+ ctrl->wdev.max_hw_heartbeat_ms = max_tick_ms * OTTO_WDT_TIMEOUT_TICKS_MAX;
|
||||
+ ctrl->wdev.timeout = min(30U, ctrl->wdev.max_hw_heartbeat_ms / 1000);
|
||||
+
|
||||
+ watchdog_set_drvdata(&ctrl->wdev, ctrl);
|
||||
+ watchdog_init_timeout(&ctrl->wdev, 0, dev);
|
||||
+ watchdog_stop_on_reboot(&ctrl->wdev);
|
||||
+ watchdog_set_restart_priority(&ctrl->wdev, 128);
|
||||
+
|
||||
+ ret = otto_wdt_determine_timeouts(&ctrl->wdev, ctrl->wdev.timeout, 1);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "Failed to set timeout\n");
|
||||
+
|
||||
+ return devm_watchdog_register_device(dev, &ctrl->wdev);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id otto_wdt_ids[] = {
|
||||
+ { .compatible = "realtek,rtl8380-wdt" },
|
||||
+ { .compatible = "realtek,rtl8390-wdt" },
|
||||
+ { .compatible = "realtek,rtl9300-wdt" },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, otto_wdt_ids);
|
||||
+
|
||||
+static struct platform_driver otto_wdt_driver = {
|
||||
+ .probe = otto_wdt_probe,
|
||||
+ .driver = {
|
||||
+ .name = "realtek-otto-watchdog",
|
||||
+ .of_match_table = otto_wdt_ids,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(otto_wdt_driver);
|
||||
+
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
+MODULE_DESCRIPTION("Realtek Otto watchdog timer driver");
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,17 @@
|
||||
Index: linux-5.10.76/drivers/watchdog/Kconfig
|
||||
===================================================================
|
||||
--- linux-5.10.76.orig/drivers/watchdog/Kconfig
|
||||
+++ linux-5.10.76/drivers/watchdog/Kconfig
|
||||
@@ -997,10 +997,10 @@ config RTD119X_WATCHDOG
|
||||
|
||||
config REALTEK_OTTO_WDT
|
||||
tristate "Realtek Otto MIPS watchdog support"
|
||||
- depends on MACH_REALTEK_RTL || COMPILE_TEST
|
||||
+ depends on RTL838X
|
||||
depends on COMMON_CLK
|
||||
select WATCHDOG_CORE
|
||||
- default MACH_REALTEK_RTL
|
||||
+ default RTL838X
|
||||
help
|
||||
Say Y here to include support for the watchdog timer on Realtek
|
||||
RTL838x, RTL839x, RTL930x SoCs. This watchdog has pretimeout
|
@ -0,0 +1,13 @@
|
||||
Index: linux-5.10.72/drivers/watchdog/realtek_otto_wdt.c
|
||||
===================================================================
|
||||
--- linux-5.10.72.orig/drivers/watchdog/realtek_otto_wdt.c
|
||||
+++ linux-5.10.72/drivers/watchdog/realtek_otto_wdt.c
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
-#include <linux/math.h>
|
||||
+#include <linux/kernel.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
@ -14,9 +14,10 @@ LLVM_VERSION := $(shell cat $(STAGING_DIR_HOST)/llvm-bpf/.llvm-version)
|
||||
LLVM_BPF_PREFIX := llvm-bpf-$(LLVM_VERSION).$(HOST_OS)-$(HOST_ARCH)
|
||||
LLVM_TAR := $(BIN_DIR)/$(LLVM_BPF_PREFIX).tar.xz
|
||||
|
||||
$(LLVM_TAR): $(HOST_STAMP_INSTALLED)
|
||||
$(LLVM_TAR): $(STAGING_DIR_HOST)/llvm-bpf/.llvm-version
|
||||
tar -C $(STAGING_DIR_HOST) \
|
||||
-I '$(STAGING_DIR_HOST)/bin/xz -7e -T$(if $(filter 1,$(NPROC)),2,0)' \
|
||||
$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
|
||||
-cf $@.tmp llvm-bpf $(LLVM_BPF_PREFIX)
|
||||
mv $@.tmp $@
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user