From c0afe3a5d2239fb40aa566e4d81666b4461f07fb Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Mon, 23 Aug 2021 21:48:06 +0200 Subject: [PATCH 01/37] odhcpd: update to latest git HEAD 01b4e60 dhcpv4: fix uninitialized hostname in some ubus events 1666769 dhcpv6-ia: allow up to 64 bit wide hostid Signed-off-by: Hans Dedecker --- package/network/services/odhcpd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/services/odhcpd/Makefile b/package/network/services/odhcpd/Makefile index d7919d6836..ec7fbb3601 100644 --- a/package/network/services/odhcpd/Makefile +++ b/package/network/services/odhcpd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcpd.git -PKG_SOURCE_DATE:=2021-07-18 -PKG_SOURCE_VERSION:=bc9d317f2921ae6b529f2c9f8de79b75992e206f -PKG_MIRROR_HASH:=be96c4984821b8af95bfee1a29c082bb9eaa052cd3e03d8632ff02afd2debc81 +PKG_SOURCE_DATE:=2021-08-11 +PKG_SOURCE_VERSION:=01b4e6046f10e21809c3f380f2d33bf3fe59698d +PKG_MIRROR_HASH:=419bbc1dd159c25852da4abdcb9ffee8d72d12b8b998ff14e343d5f2455d8d2a PKG_MAINTAINER:=Hans Dedecker PKG_LICENSE:=GPL-2.0 From 6393ea15815e57802377ebecb17edf8ad20a0736 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Fri, 20 Aug 2021 14:33:51 +0300 Subject: [PATCH 02/37] uhttpd: add config option for json_script Add a config option for json_script instead of unconditionally including all json files in /etc/uhttpd in every uhttpd instance. This makes it possible to configure a single instance with an unconditional redirect, which currently renders all other uhttpd instances unusable. Signed-off-by: Stijn Tintel Acked-by: Felix Fietkau --- package/network/services/uhttpd/Makefile | 2 +- package/network/services/uhttpd/files/uhttpd.init | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile index 781512bd99..dce5aa87b8 100644 --- a/package/network/services/uhttpd/Makefile +++ b/package/network/services/uhttpd/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uhttpd -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/uhttpd.git diff --git a/package/network/services/uhttpd/files/uhttpd.init b/package/network/services/uhttpd/files/uhttpd.init index e7709941c2..30fd7b4259 100755 --- a/package/network/services/uhttpd/files/uhttpd.init +++ b/package/network/services/uhttpd/files/uhttpd.init @@ -196,7 +196,8 @@ start_instance() append_bool "$cfg" redirect_https "-q" 0 } - for file in /etc/uhttpd/*.json; do + config_get json_script "$cfg" json_script + for file in $json_script; do [ -s "$file" ] && procd_append_param command -H "$file" done From a0d81ba0d5e9d055c55b5e478cb913c217122317 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 16 Aug 2021 10:05:14 +0200 Subject: [PATCH 03/37] mac80211: fix HT40 mode for 6G band The channel offset used for VHT segment calculation was missing for HT Signed-off-by: Felix Fietkau --- .../kernel/mac80211/files/lib/netifd/wireless/mac80211.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index 0b7a84d7c9..4574a9881a 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -147,6 +147,9 @@ mac80211_hostapd_setup_base() { [ "$noscan" -gt 0 ] && hostapd_noscan=1 [ "$tx_burst" = 0 ] && tx_burst= + chan_ofs=0 + [ "$band" = "6g" ] && chan_ofs=1 + ieee80211n=1 ht_capab= case "$htmode" in @@ -154,7 +157,7 @@ mac80211_hostapd_setup_base() { HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160) case "$hwmode" in a) - case "$(( ($channel / 4) % 2 ))" in + case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in 1) ht_capab="[HT40+]";; 0) ht_capab="[HT40-]";; esac @@ -223,8 +226,6 @@ mac80211_hostapd_setup_base() { enable_ac=0 vht_oper_chwidth=0 vht_center_seg0= - chan_ofs=0 - [ "$band" = "6g" ] && chan_ofs=1 idx="$channel" case "$htmode" in From c26d741d07632451337810aaecd500a0b3cbf44f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 16 Aug 2021 10:07:55 +0200 Subject: [PATCH 04/37] hostapd: enable ht40 in wpa_supplicant when using wider HE modes Signed-off-by: Felix Fietkau --- package/network/services/hostapd/files/hostapd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 821905b05e..4f306317c7 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -1167,7 +1167,7 @@ wpa_supplicant_set_fixed_freq() { case "$htmode" in NOHT) append network_data "disable_ht=1" "$N$T";; HE20|HT20|VHT20) append network_data "disable_ht40=1" "$N$T";; - HT40*|VHT40*|VHT80*|VHT160*) append network_data "ht40=1" "$N$T";; + HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160) append network_data "ht40=1" "$N$T";; esac case "$htmode" in VHT*) append network_data "vht=1" "$N$T";; From f04c0ead33d6dac274ebd686e9bd9c05b1ead321 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 16 Aug 2021 14:09:46 +0200 Subject: [PATCH 05/37] mac80211: refresh patch Signed-off-by: Felix Fietkau --- ...ss-the-dst-buffer-to-of_get_mac_address.patch | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch b/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch index b9731552c0..5d94362155 100644 --- a/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch +++ b/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch @@ -180,11 +180,9 @@ Signed-off-by: David S. Miller net/ethernet/eth.c | 11 ++-- 85 files changed, 218 insertions(+), 364 deletions(-) -diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c -index 01f9c26f9bf37..e9a36dd7144f1 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -617,7 +617,6 @@ static int ath9k_of_init(struct ath_softc *sc) +@@ -618,7 +618,6 @@ static int ath9k_of_init(struct ath_soft struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); enum ath_bus_type bus_type = common->bus_ops->ath_bus_type; @@ -192,7 +190,7 @@ index 01f9c26f9bf37..e9a36dd7144f1 100644 char eeprom_name[100]; int ret; -@@ -640,9 +639,7 @@ static int ath9k_of_init(struct ath_softc *sc) +@@ -641,9 +640,7 @@ static int ath9k_of_init(struct ath_soft ah->ah_flags |= AH_NO_EEP_SWAP; } @@ -203,11 +201,9 @@ index 01f9c26f9bf37..e9a36dd7144f1 100644 return 0; } -diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c -index 665b54c5c8ae5..6d895738222ad 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c -@@ -91,15 +91,9 @@ void +@@ -90,15 +90,9 @@ out_put_node: void mt76_eeprom_override(struct mt76_dev *dev) { @@ -224,11 +220,9 @@ index 665b54c5c8ae5..6d895738222ad 100644 if (!is_valid_ether_addr(dev->macaddr)) { eth_random_addr(dev->macaddr); -diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c -index 61a4f1ad31e28..e95c101c27111 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c -@@ -989,11 +989,7 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry, +@@ -990,11 +990,7 @@ static void rt2x00lib_rate(struct ieee80 void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr) { @@ -241,5 +235,3 @@ index 61a4f1ad31e28..e95c101c27111 100644 if (!is_valid_ether_addr(eeprom_mac_addr)) { eth_random_addr(eeprom_mac_addr); --- -cgit 1.2.3-1.el7 From 0f6887972adc48449a1f5efaa143fa3f740a8c36 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 16 Aug 2021 14:10:19 +0200 Subject: [PATCH 06/37] mac80211: add missing change for encap offload on devices with sw rate control Signed-off-by: Felix Fietkau --- ...te-control-support-for-encap-offload.patch | 58 ++++++++++++------- ...bling-4-address-mode-on-a-sta-vif-af.patch | 2 +- ...eck-per-vif-offload_flags-in-Tx-path.patch | 26 +++++++++ 3 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch diff --git a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch index 43a4a1334d..2a4551023f 100644 --- a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch +++ b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch @@ -7,24 +7,6 @@ The software rate control cannot deal with encap offload, so fix it. Signed-off-by: Ryder Lee --- ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -2024,6 +2024,15 @@ static inline void ieee80211_tx_skb(stru - ieee80211_tx_skb_tid(sdata, skb, 7); - } - -+static inline bool ieee80211_is_tx_data(struct sk_buff *skb) -+{ -+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ -+ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP || -+ ieee80211_is_data(hdr->frame_control); -+} -+ - u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, - struct ieee802_11_elems *elems, - u64 filter, u32 crc, u8 *transmitter_bssid, --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -297,15 +297,11 @@ void ieee80211_check_rate_mask(struct ie @@ -44,7 +26,18 @@ Signed-off-by: Ryder Lee } static void rc_send_low_basicrate(struct ieee80211_tx_rate *rate, -@@ -870,7 +866,6 @@ void ieee80211_get_tx_rates(struct ieee8 +@@ -396,6 +392,10 @@ static bool rate_control_send_low(struct + int mcast_rate; + bool use_basicrate = false; + ++ if (ieee80211_is_tx_data(txrc->skb) && ++ info->flags & IEEE80211_TX_CTL_NO_ACK) ++ return false; ++ + if (!pubsta || rc_no_data_or_no_ack_use_min(txrc)) { + __rate_control_send_low(txrc->hw, sband, pubsta, info, + txrc->rate_idx_mask); +@@ -870,7 +870,6 @@ void ieee80211_get_tx_rates(struct ieee8 int max_rates) { struct ieee80211_sub_if_data *sdata; @@ -52,7 +45,7 @@ Signed-off-by: Ryder Lee struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_supported_band *sband; -@@ -882,7 +877,7 @@ void ieee80211_get_tx_rates(struct ieee8 +@@ -882,7 +881,7 @@ void ieee80211_get_tx_rates(struct ieee8 sdata = vif_to_sdata(vif); sband = sdata->local->hw.wiphy->bands[info->band]; @@ -117,3 +110,28 @@ Signed-off-by: Ryder Lee if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { struct sta_info *sta = container_of(txq->sta, struct sta_info, +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6728,4 +6728,22 @@ struct sk_buff *ieee80211_get_fils_disco + struct sk_buff * + ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); ++ ++/** ++ * ieee80211_is_tx_data - check if frame is a data frame ++ * ++ * The function is used to check if a frame is a data frame. Frames with ++ * hardware encapsulation enabled are data frames. ++ * ++ * @skb: the frame to be transmitted. ++ */ ++static inline bool ieee80211_is_tx_data(struct sk_buff *skb) ++{ ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_hdr *hdr = (void *) skb->data; ++ ++ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP || ++ ieee80211_is_data(hdr->frame_control); ++} ++ + #endif /* MAC80211_H */ diff --git a/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch b/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch index 5a82f00c9e..c1f77ff5d9 100644 --- a/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch +++ b/package/kernel/mac80211/patches/subsys/383-mac80211-fix-enabling-4-address-mode-on-a-sta-vif-af.patch @@ -48,7 +48,7 @@ Signed-off-by: Felix Fietkau if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -2224,6 +2224,8 @@ void ieee80211_dynamic_ps_timer(struct t +@@ -2215,6 +2215,8 @@ void ieee80211_dynamic_ps_timer(struct t void ieee80211_send_nullfunc(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, bool powersave); diff --git a/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch b/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch new file mode 100644 index 0000000000..cfad1c3927 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch @@ -0,0 +1,26 @@ +From: Ryder Lee +Date: Fri, 18 Jun 2021 04:38:59 +0800 +Subject: [PATCH] mac80211: check per vif offload_flags in Tx path + +offload_flags has been introduced to indicate encap status of each interface. +An interface can encap offload at runtime, or if it has some extra limitations +it can simply override the flags, so it's more flexible to check offload_flags +in Tx path. + +Signed-off-by: Ryder Lee +Link: https://lore.kernel.org/r/177785418cf407808bf3a44760302d0647076990.1623961575.git.ryder.lee@mediatek.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3309,6 +3309,9 @@ static bool ieee80211_amsdu_aggregate(st + if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) + return false; + ++ if (sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) ++ return false; ++ + if (skb_is_gso(skb)) + return false; + From ca77ffcef2287211005691d747694c0e73f3940b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 24 Aug 2021 13:16:58 +0200 Subject: [PATCH 07/37] libubox: update to the latest version d716ac4bc423 list.h: add a few missing iterator macros Signed-off-by: Felix Fietkau --- package/libs/libubox/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile index 42a3f4ac3c..33aa73eef7 100644 --- a/package/libs/libubox/Makefile +++ b/package/libs/libubox/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE=2 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git -PKG_MIRROR_HASH:=7dd1db1e0074a9c7c722db654cce3111b3bd3cff0bfd791c4497cb0f6c22d3ca -PKG_SOURCE_DATE:=2021-05-16 -PKG_SOURCE_VERSION:=b14c4688612c05c78ce984d7bde633bce8703b1e +PKG_MIRROR_HASH:=1cdb91ac0ee925f133ee9f70eac131a99def312fe7cf0aed44df84eb1762e30b +PKG_SOURCE_DATE:=2021-08-19 +PKG_SOURCE_VERSION:=d716ac4bc4236031d4c3cc1ed362b502e20e3787 PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE)) CMAKE_INSTALL:=1 From 1796812e1d1864df261d06ff6535718d3ae1a6c5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 24 Aug 2021 13:22:15 +0200 Subject: [PATCH 08/37] netifd: update to the latest version 94170ae24bc9 device: extend device settings flags to 64 bit 1eb0fafaa986 device: add support for configuring device link speed/duplex ed84473b7af9 bridge: memset bst->config by default to avoid stale config values 6519cf31e4b0 bridge: add support for an external STP daemon 454e9c33c906 bridge: tune default stp parameters Signed-off-by: Felix Fietkau --- package/network/config/netifd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile index d835973624..c33e0c2134 100644 --- a/package/network/config/netifd/Makefile +++ b/package/network/config/netifd/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git -PKG_SOURCE_DATE:=2021-07-26 -PKG_SOURCE_VERSION:=440eb0647708274cc8d7d9e7c2bb0cfdfba90023 -PKG_MIRROR_HASH:=eed957036ab608fdc49bdf801fc5b4405fcd2a3a5e5d3343ec39898e156c10e9 +PKG_SOURCE_DATE:=2021-08-24 +PKG_SOURCE_VERSION:=454e9c33c90691d5bea12263f1801a7dc38c20b1 +PKG_MIRROR_HASH:=b8c6d8a1d0cb60c353c0272b8a526d8e28e6ee7d385e96b18018d1bc13b54cc2 PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=GPL-2.0 From 76f46f4105ae33d0e4bb2348b5998746000658cd Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 24 Aug 2021 18:48:35 +0100 Subject: [PATCH 09/37] procd: update to git HEAD 8a8306d uxc.c: fix coverity resource leak warning 7f2398e jail: devices: create parent folder when creating devices 0603c8d jail: return to hook callback instead of just calling it 3edb7eb jail: check return value when opening console af048a3 jail: use portable sizeof(void *) 6010bd3 utils: make sure read() string is 0 terminated f6daca3 uxc: free string returned by blobmsg_format_json_indent() 51f1cd2 trace: free string returned by blobmsg_format_json_indent() d716cb5 trace: handle open() return value and make sure string is terminated b824a89 jail: preload: avoid NULL-dereference in case things go wrong 167dc24 jail: protect against strcat buffer overflows Signed-off-by: Daniel Golle --- package/system/procd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile index 98f1ed1775..b202afff8a 100644 --- a/package/system/procd/Makefile +++ b/package/system/procd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/procd.git -PKG_SOURCE_DATE:=2021-08-15 -PKG_SOURCE_VERSION:=104b49d6ab25a8cf067e6d8d1f2da7defb9876d4 -PKG_MIRROR_HASH:=d13b566a14e84f6babe8b7d3dfb88e34c3dff0e97d7770d6fe71174685bca628 +PKG_SOURCE_DATE:=2021-08-23 +PKG_SOURCE_VERSION:=167dc249b0a55fdb973afbd797059a3880bb7aea +PKG_MIRROR_HASH:=fdb5206f41a8e74710abaca3a26bb2276a5eb0e9fb14672c6685950d18ba3775 CMAKE_INSTALL:=1 PKG_LICENSE:=GPL-2.0 From c4143505e0c0ef39a4254888397c801b5dab455c Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Tue, 24 Aug 2021 15:46:16 +0200 Subject: [PATCH 10/37] ramips: mt7620: move Phicomm MAC address setup to DTSI The setup is the same for all devices, so move it up one level. Signed-off-by: Adrian Schmutzler --- target/linux/ramips/dts/mt7620a_phicomm_k2g.dts | 13 ------------- target/linux/ramips/dts/mt7620a_phicomm_k2x.dtsi | 15 +++++++++++++++ .../linux/ramips/dts/mt7620a_phicomm_psg1218a.dts | 13 ------------- .../linux/ramips/dts/mt7620a_phicomm_psg1218b.dts | 15 --------------- 4 files changed, 15 insertions(+), 41 deletions(-) diff --git a/target/linux/ramips/dts/mt7620a_phicomm_k2g.dts b/target/linux/ramips/dts/mt7620a_phicomm_k2g.dts index fd6cc7f82b..d113edc19f 100644 --- a/target/linux/ramips/dts/mt7620a_phicomm_k2g.dts +++ b/target/linux/ramips/dts/mt7620a_phicomm_k2g.dts @@ -23,9 +23,6 @@ pinctrl-names = "default"; pinctrl-0 = <&rgmii2_pins &mdio_pins>; - nvmem-cells = <&macaddr_factory_28>; - nvmem-cell-names = "mac-address"; - mediatek,portmap = "llllw"; port@5 { @@ -48,13 +45,3 @@ pinctrl-names = "default"; pinctrl-0 = <&pa_pins>; }; - -&factory { - compatible = "nvmem-cells"; - #address-cells = <1>; - #size-cells = <1>; - - macaddr_factory_28: macaddr@28 { - reg = <0x28 0x6>; - }; -}; diff --git a/target/linux/ramips/dts/mt7620a_phicomm_k2x.dtsi b/target/linux/ramips/dts/mt7620a_phicomm_k2x.dtsi index c7728e0442..a8a900eac1 100644 --- a/target/linux/ramips/dts/mt7620a_phicomm_k2x.dtsi +++ b/target/linux/ramips/dts/mt7620a_phicomm_k2x.dtsi @@ -96,6 +96,21 @@ }; }; +ðernet { + nvmem-cells = <&macaddr_factory_28>; + nvmem-cell-names = "mac-address"; +}; + &wmac { ralink,mtd-eeprom = <&factory 0x0>; }; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_28: macaddr@28 { + reg = <0x28 0x6>; + }; +}; diff --git a/target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts b/target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts index 3a9a57d90b..cda05173b1 100644 --- a/target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts +++ b/target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts @@ -14,9 +14,6 @@ }; ðernet { - nvmem-cells = <&macaddr_factory_28>; - nvmem-cell-names = "mac-address"; - mediatek,portmap = "llllw"; }; @@ -24,13 +21,3 @@ pinctrl-names = "default"; pinctrl-0 = <&pa_pins>; }; - -&factory { - compatible = "nvmem-cells"; - #address-cells = <1>; - #size-cells = <1>; - - macaddr_factory_28: macaddr@28 { - reg = <0x28 0x6>; - }; -}; diff --git a/target/linux/ramips/dts/mt7620a_phicomm_psg1218b.dts b/target/linux/ramips/dts/mt7620a_phicomm_psg1218b.dts index 916479c252..704be2b5d7 100644 --- a/target/linux/ramips/dts/mt7620a_phicomm_psg1218b.dts +++ b/target/linux/ramips/dts/mt7620a_phicomm_psg1218b.dts @@ -12,18 +12,3 @@ reg = <0x50000 0x7b0000>; }; }; - -ðernet { - nvmem-cells = <&macaddr_factory_28>; - nvmem-cell-names = "mac-address"; -}; - -&factory { - compatible = "nvmem-cells"; - #address-cells = <1>; - #size-cells = <1>; - - macaddr_factory_28: macaddr@28 { - reg = <0x28 0x6>; - }; -}; From 80e70be0ab8461f2856ababa4b74fff9c9a331ed Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Tue, 27 Jul 2021 12:45:05 +0800 Subject: [PATCH 11/37] ramips: add new flash layout support to Phicomm K2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Descriptions: Phicomm K2 (PSG1218) got a new "permanent_config" partition after update firmware to v22.5. This partition located in front of the firmware partition, same as The Phicomm K2P and K2G. Due to this change the new bootloader can't load previous firmware any more. This commit is aimed at add support for Phicomm K2 which official firmware version is 22.5.x or newer. For which runs old firmware version, just update OpenWrt that has a prefix of "k2-v22.4". For uniform naming, this commit also changed the model name PSG1218 to a more recognizable name K2, refer to Phicomm K2G, K2P K2T. OpenWrt selection table: official firmware version OpenWrt v22.4.x.x or older phicomm_k2-v22.4 v22.5.x.x or newer phicomm_k2-v22.5 Installation: Same as Phicomm K2G, K2P, PSG1208. a. TFTP + U-Boot b. Open telnet by some web page vulnerability (Search Baidu by key words "K2 telnet"), and then we can upload firmware image to /tmp and write it to firmware partition with mtd instruction. Signed-off-by: Shiji Yang [rebase, add/harmonize version in model variables, fix version typo in commit message, wrap commit message properly] Signed-off-by: Adrian Schmutzler --- ...1218a.dts => mt7620a_phicomm_k2-v22.4.dts} | 4 +-- .../ramips/dts/mt7620a_phicomm_k2-v22.5.dts | 29 +++++++++++++++++ target/linux/ramips/image/mt7620.mk | 32 ++++++++++++------- .../mt7620/base-files/etc/board.d/02_network | 6 ++-- 4 files changed, 56 insertions(+), 15 deletions(-) rename target/linux/ramips/dts/{mt7620a_phicomm_psg1218a.dts => mt7620a_phicomm_k2-v22.4.dts} (71%) create mode 100644 target/linux/ramips/dts/mt7620a_phicomm_k2-v22.5.dts diff --git a/target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts b/target/linux/ramips/dts/mt7620a_phicomm_k2-v22.4.dts similarity index 71% rename from target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts rename to target/linux/ramips/dts/mt7620a_phicomm_k2-v22.4.dts index cda05173b1..4e9fc1307b 100644 --- a/target/linux/ramips/dts/mt7620a_phicomm_psg1218a.dts +++ b/target/linux/ramips/dts/mt7620a_phicomm_k2-v22.4.dts @@ -1,8 +1,8 @@ #include "mt7620a_phicomm_k2x.dtsi" / { - compatible = "phicomm,psg1218a", "phicomm,psg1218", "ralink,mt7620a-soc"; - model = "Phicomm PSG1218 rev.A"; + compatible = "phicomm,k2-v22.4", "ralink,mt7620a-soc"; + model = "Phicomm K2 v22.4 or older"; }; &partitions { diff --git a/target/linux/ramips/dts/mt7620a_phicomm_k2-v22.5.dts b/target/linux/ramips/dts/mt7620a_phicomm_k2-v22.5.dts new file mode 100644 index 0000000000..2a682872c6 --- /dev/null +++ b/target/linux/ramips/dts/mt7620a_phicomm_k2-v22.5.dts @@ -0,0 +1,29 @@ +#include "mt7620a_phicomm_k2x.dtsi" + +/ { + compatible = "phicomm,k2-v22.5", "ralink,mt7620a-soc"; + model = "Phicomm K2 v22.5 or newer"; +}; + +&partitions { + partition@50000 { + label = "permanent_config"; + reg = <0x50000 0x50000>; + read-only; + }; + + partition@a0000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0xa0000 0x760000>; + }; +}; + +ðernet { + mediatek,portmap = "llllw"; +}; + +&wmac { + pinctrl-names = "default"; + pinctrl-0 = <&pa_pins>; +}; diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk index c3b9bc9f6b..bfc7fa7db0 100644 --- a/target/linux/ramips/image/mt7620.mk +++ b/target/linux/ramips/image/mt7620.mk @@ -807,6 +807,27 @@ define Device/ohyeah_oy-0001 endef TARGET_DEVICES += ohyeah_oy-0001 +define Device/phicomm_k2-v22.4 + SOC := mt7620a + IMAGE_SIZE := 7872k + DEVICE_VENDOR := Phicomm + DEVICE_MODEL := K2 + DEVICE_VARIANT:= v22.4 or older + DEVICE_PACKAGES := kmod-mt76x2 + SUPPORTED_DEVICES += psg1218 psg1218a phicomm,psg1218a +endef +TARGET_DEVICES += phicomm_k2-v22.4 + +define Device/phicomm_k2-v22.5 + SOC := mt7620a + IMAGE_SIZE := 7552k + DEVICE_VENDOR := Phicomm + DEVICE_MODEL := K2 + DEVICE_VARIANT:= v22.5 or newer + DEVICE_PACKAGES := kmod-mt76x2 +endef +TARGET_DEVICES += phicomm_k2-v22.5 + define Device/phicomm_k2g SOC := mt7620a IMAGE_SIZE := 7552k @@ -826,17 +847,6 @@ define Device/phicomm_psg1208 endef TARGET_DEVICES += phicomm_psg1208 -define Device/phicomm_psg1218a - SOC := mt7620a - IMAGE_SIZE := 7872k - DEVICE_VENDOR := Phicomm - DEVICE_MODEL := PSG1218 - DEVICE_VARIANT:= Ax - DEVICE_PACKAGES := kmod-mt76x2 - SUPPORTED_DEVICES += psg1218 psg1218a -endef -TARGET_DEVICES += phicomm_psg1218a - define Device/phicomm_psg1218b SOC := mt7620a IMAGE_SIZE := 7872k diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network index eaa8cbf7aa..057428e622 100644 --- a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network @@ -107,7 +107,8 @@ ramips_setup_interfaces() ;; dlink,dir-810l|\ netgear,jwnr2010-v5|\ - phicomm,psg1218a|\ + phicomm,k2-v22.4|\ + phicomm,k2-v22.5|\ trendnet,tew-810dr|\ zbtlink,zbt-we2026) ucidef_add_switch "switch0" \ @@ -339,8 +340,9 @@ ramips_setup_macs() wan_mac=$(macaddr_add "$(mtd_get_mac_binary u-boot 0x1fc20)" 2) ;; lb-link,bl-w1200|\ + phicomm,k2-v22.4|\ + phicomm,k2-v22.5|\ phicomm,k2g|\ - phicomm,psg1218a|\ phicomm,psg1218b) wan_mac=$(mtd_get_mac_binary factory 0x2e) label_mac=$wan_mac From fcc075e12f6f4718ccac6b5eb68cb8346064ee43 Mon Sep 17 00:00:00 2001 From: Chukun Pan Date: Mon, 7 Jun 2021 23:35:15 +0800 Subject: [PATCH 12/37] ipq806x: Askey RT4230W REV6: fix caldata script The partition name in the device dts is '0:ART'. Be independent to prevent this part from becoming incorrect once the kernel v5.4 gone. Fixes: da8428d277cd ("ipq806x: add support for Askey RT4230W REV6") Signed-off-by: Chukun Pan --- .../base-files/etc/hotplug.d/firmware/11-ath10k-caldata | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index d2bdf034b7..8cea017ea4 100644 --- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -9,7 +9,9 @@ board=$(board_name) case "$FIRMWARE" in "ath10k/pre-cal-pci-0000:01:00.0.bin") case $board in - askey,rt4230w-rev6 |\ + askey,rt4230w-rev6) + caldata_extract "0:ART" 0x1000 0x2f20 + ;; asrock,g10) if [ -b "$(find_mtd_part 0:art)" ]; then caldata_extract "0:art" 0x1000 0x2f20 @@ -69,7 +71,9 @@ case "$FIRMWARE" in ;; "ath10k/pre-cal-pci-0001:01:00.0.bin") case $board in - askey,rt4230w-rev6 |\ + askey,rt4230w-rev6) + caldata_extract "0:ART" 0x5000 0x2f20 + ;; asrock,g10) if [ -b "$(find_mtd_part 0:art)" ]; then caldata_extract "0:art" 0x5000 0x2f20 From 09143282bde3abd560a3b70f76df6d77b6ac6f12 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Tue, 24 Aug 2021 22:59:59 +0800 Subject: [PATCH 13/37] ramips: add support for Motorola MWR03 Specifications: * SOC: MT7628AN + MT7612E * ROM: 8 MiB Flash * RAM: 64 MiB DDR2 * WAN: 10/100M *1 * LAN: 10/100M *3 * Button: Reset *1 * LEDs: orange *1, white *1 * Antennas: 2.4 GHz *2 + 5 GHz *2 * TTL Baudrate: 57600 * TFTP Upgrade: IP: 192.168.51.1, Server: 192.168.51.100 MAC addresses as verified by OEM firmware: use address source 2g *:d8 factory 0x0004 (label) 5g *:d9 factory 0x8004 LAN *:d7 factory $label -1 WAN *:da factory $label +2 Installation (TFTP + U-Boot): * Connect device with a TTL cable and open a serial session by PuTTY. * Press "2" when booting to select "Load system code then write to Flash via TFTP". * Configure the IP of local host server. * Upload firmware by tftpd64, it will boot when write instruction is executed. Signed-off-by: Shiji Yang [fix DTS line endings, fix label MAC address, adjust status LED names, convert mtd-mac-address-increment to mac-address-increment] Signed-off-by: Adrian Schmutzler --- .../ramips/dts/mt7628an_motorola_mwr03.dts | 141 ++++++++++++++++++ target/linux/ramips/image/mt76x8.mk | 8 + .../mt76x8/base-files/etc/board.d/02_network | 8 + 3 files changed, 157 insertions(+) create mode 100644 target/linux/ramips/dts/mt7628an_motorola_mwr03.dts diff --git a/target/linux/ramips/dts/mt7628an_motorola_mwr03.dts b/target/linux/ramips/dts/mt7628an_motorola_mwr03.dts new file mode 100644 index 0000000000..2179c48b22 --- /dev/null +++ b/target/linux/ramips/dts/mt7628an_motorola_mwr03.dts @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7628an.dtsi" + +#include +#include + +/ { + model = "Motorola MWR03"; + compatible = "motorola,mwr03", "mediatek,mt7628an-soc"; + + aliases { + led-boot = &led_status_orange; + led-failsafe = &led_status_orange; + led-running = &led_status_white; + led-upgrade = &led_status_orange; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led_status_orange: status_orange { + label = "orange:status"; + gpios = <&gpio 3 GPIO_ACTIVE_LOW>; + }; + + led_status_white: status_white { + label = "white:status"; + gpios = <&gpio 2 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <80000000>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "config"; + reg = <0x30000 0x10000>; + read-only; + }; + + factory: partition@40000 { + label = "factory"; + reg = <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x50000 0x7b0000>; + }; + }; + }; +}; + +&state_default { + gpio { + groups = "i2c", "i2s"; + function = "gpio"; + }; +}; + +&usbphy { + status = "disabled"; +}; + +&ehci { + status = "disabled"; +}; + +&ohci { + status = "disabled"; +}; + +ðernet { + nvmem-cells = <&macaddr_factory_4>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <(-1)>; +}; + +&esw { + mediatek,portmap = <0x3e>; + mediatek,portdisable = <0x30>; +}; + +&pcie { + status = "okay"; +}; + +&pcie0 { + wifi@0,0 { + reg = <0x0000 0 0 0 0>; + mediatek,mtd-eeprom = <&factory 0x8000>; + ieee80211-freq-limit = <5000000 6000000>; + }; +}; + +&wmac { + status = "okay"; + + mediatek,mtd-eeprom = <&factory 0x0>; +}; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_4: macaddr@4 { + reg = <0x4 0x6>; + }; +}; diff --git a/target/linux/ramips/image/mt76x8.mk b/target/linux/ramips/image/mt76x8.mk index 3f6f842db7..f63930adb1 100644 --- a/target/linux/ramips/image/mt76x8.mk +++ b/target/linux/ramips/image/mt76x8.mk @@ -278,6 +278,14 @@ define Device/minew_g1-c endef TARGET_DEVICES += minew_g1-c +define Device/motorola_mwr03 + IMAGE_SIZE := 7872k + DEVICE_VENDOR := Motorola + DEVICE_MODEL := MWR03 + DEVICE_PACKAGES := kmod-mt76x2 +endef +TARGET_DEVICES += motorola_mwr03 + define Device/netgear_r6020 $(Device/netgear_sercomm_nor) IMAGE_SIZE := 7104k diff --git a/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network b/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network index ca115fd618..ea04391f9c 100644 --- a/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network @@ -109,6 +109,10 @@ ramips_setup_interfaces() ucidef_add_switch "switch0" \ "0:lan" "1:lan" "2:lan" "6@eth0" ;; + motorola,mwr03) + ucidef_add_switch "switch0" \ + "1:lan" "2:lan" "3:lan" "0:wan" "6@eth0" + ;; netgear,r6020|\ netgear,r6080|\ netgear,r6120) @@ -216,6 +220,10 @@ ramips_setup_macs() mercury,mac1200r-v2) wan_mac=$(macaddr_add "$(mtd_get_mac_binary factory_info 0xd)" 1) ;; + motorola,mwr03) + label_mac=$(mtd_get_mac_binary factory 0x4) + wan_mac=$(macaddr_add "$label_mac" 2) + ;; onion,omega2|\ onion,omega2p|\ vocore,vocore2|\ From a73a8269e13f9387a2ac883dac7fe0dd49999ede Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Tue, 27 Jul 2021 12:32:00 +0800 Subject: [PATCH 14/37] ramips: add support for DomyWifi DM202/DM203/DW22D Specifications: * SOC: MT7620A + MT7610E * ROM: 16 MiB spi flash (W25Q128FVSG) * RAM: 128 MiB DDR2 (W971GG6KB-25) * WAN: 10/100M *1 * LAN: 10/100M *4 * USB: Type-A USB2.0 *1 * SD: MicroSD *1 * Button: Reset *1 * Antennas: 2.4 GHz *2 + 5 GHz *1 * TTL Baudrate: 57600 * U-Boot Recovery: IP: 10.10.10.123, Server: 10.10.10.3 Installation: * Web UI Update 1. Open http://192.168.10.1/upgrade.html in the browser. 2. Rename firmware to a short name like firmware.bin and then upload it. 3. Fill in the password column with the following content: password | mtd -x mIp2osnRG3qZGdIlQPh1 -r write /tmp/firmware.bin firmware * TFTP + U-Boot 1. Connect device with a TTL cable. 2. Press "2" when booting to select "Load system code then write to Flash via TFTP". 3. Upload firmware by tftpd64, it will boot when write instruction is executed. Signed-off-by: Shiji Yang --- target/linux/ramips/dts/mt7620a_domywifi.dtsi | 189 ++++++++++++++++++ .../ramips/dts/mt7620a_domywifi_dm202.dts | 8 + .../ramips/dts/mt7620a_domywifi_dm203.dts | 8 + .../ramips/dts/mt7620a_domywifi_dw22d.dts | 8 + target/linux/ramips/image/mt7620.mk | 27 +++ .../mt7620/base-files/etc/board.d/01_leds | 9 + .../mt7620/base-files/etc/board.d/02_network | 6 + 7 files changed, 255 insertions(+) create mode 100644 target/linux/ramips/dts/mt7620a_domywifi.dtsi create mode 100644 target/linux/ramips/dts/mt7620a_domywifi_dm202.dts create mode 100644 target/linux/ramips/dts/mt7620a_domywifi_dm203.dts create mode 100644 target/linux/ramips/dts/mt7620a_domywifi_dw22d.dts diff --git a/target/linux/ramips/dts/mt7620a_domywifi.dtsi b/target/linux/ramips/dts/mt7620a_domywifi.dtsi new file mode 100644 index 0000000000..9a96b0a275 --- /dev/null +++ b/target/linux/ramips/dts/mt7620a_domywifi.dtsi @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7620a.dtsi" + +#include +#include + +/ { + aliases { + led-boot = &led_system_amber; + led-failsafe = &led_system_amber; + led-running = &led_system_green; + led-upgrade = &led_system_amber; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led_system_green: system_green { + label = "green:system"; + gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + }; + + led_system_amber: system_amber { + label = "amber:system"; + gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; + }; + + internet_green { + label = "green:internet"; + gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; + }; + + internet_amber { + label = "amber:internet"; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + }; + + lan1 { + label = "amber:lan1"; + gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + }; + + lan2 { + label = "amber:lan2"; + gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + }; + + lan3 { + label = "amber:lan3"; + gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + }; + + lan4 { + label = "amber:lan4"; + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + }; + + wan { + label = "amber:wan"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + }; + + wlan2g { + label = "green:wlan2g"; + gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy1tpt"; + }; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <80000000>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "config"; + reg = <0x30000 0x10000>; + read-only; + }; + + factory: partition@40000 { + label = "factory"; + reg = <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x50000 0xfb0000>; + }; + }; + }; +}; + +&state_default { + gpio { + groups = "uartf", "rgmii1", "wled"; + function = "gpio"; + }; +}; + +ðernet { + pinctrl-names = "default"; + pinctrl-0 = <&ephy_pins>; + + mediatek,portmap = "wllll"; + + nvmem-cells = <&macaddr_factory_28>; + nvmem-cell-names = "mac-address"; +}; + +&sdhci { + status = "okay"; +}; + +&ehci { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&pcie { + status = "okay"; +}; + +&pcie0 { + wifi@0,0 { + reg = <0x0000 0 0 0 0>; + mediatek,mtd-eeprom = <&factory 0x8000>; + ieee80211-freq-limit = <5000000 6000000>; + + led { + led-sources = <0>; + led-active-low; + }; + }; +}; + +&wmac { + ralink,mtd-eeprom = <&factory 0x0>; +}; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_28: macaddr@28 { + reg = <0x28 0x6>; + }; +}; diff --git a/target/linux/ramips/dts/mt7620a_domywifi_dm202.dts b/target/linux/ramips/dts/mt7620a_domywifi_dm202.dts new file mode 100644 index 0000000000..f4676edc32 --- /dev/null +++ b/target/linux/ramips/dts/mt7620a_domywifi_dm202.dts @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7620a_domywifi.dtsi" + +/ { + compatible = "domywifi,dm202", "ralink,mt7620a-soc"; + model = "DomyWifi DM202"; +}; diff --git a/target/linux/ramips/dts/mt7620a_domywifi_dm203.dts b/target/linux/ramips/dts/mt7620a_domywifi_dm203.dts new file mode 100644 index 0000000000..a51737a279 --- /dev/null +++ b/target/linux/ramips/dts/mt7620a_domywifi_dm203.dts @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7620a_domywifi.dtsi" + +/ { + compatible = "domywifi,dm203", "ralink,mt7620a-soc"; + model = "DomyWifi DM203"; +}; diff --git a/target/linux/ramips/dts/mt7620a_domywifi_dw22d.dts b/target/linux/ramips/dts/mt7620a_domywifi_dw22d.dts new file mode 100644 index 0000000000..bfcc04b447 --- /dev/null +++ b/target/linux/ramips/dts/mt7620a_domywifi_dw22d.dts @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7620a_domywifi.dtsi" + +/ { + compatible = "domywifi,dw22d", "ralink,mt7620a-soc"; + model = "DomyWifi DW22D"; +}; diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk index bfc7fa7db0..86751aad31 100644 --- a/target/linux/ramips/image/mt7620.mk +++ b/target/linux/ramips/image/mt7620.mk @@ -308,6 +308,33 @@ define Device/dlink_dwr-960 endef TARGET_DEVICES += dlink_dwr-960 +define Device/domywifi_dm202 + SOC := mt7620a + IMAGE_SIZE := 16064k + DEVICE_VENDOR := DomyWifi + DEVICE_MODEL := DM202 + DEVICE_PACKAGES := kmod-mt76x0e kmod-sdhci-mt7620 kmod-usb2 kmod-usb-ohci +endef +TARGET_DEVICES += domywifi_dm202 + +define Device/domywifi_dm203 + SOC := mt7620a + IMAGE_SIZE := 16064k + DEVICE_VENDOR := DomyWifi + DEVICE_MODEL := DM203 + DEVICE_PACKAGES := kmod-mt76x0e kmod-sdhci-mt7620 kmod-usb2 kmod-usb-ohci +endef +TARGET_DEVICES += domywifi_dm203 + +define Device/domywifi_dw22d + SOC := mt7620a + IMAGE_SIZE := 16064k + DEVICE_VENDOR := DomyWifi + DEVICE_MODEL := DW22D + DEVICE_PACKAGES := kmod-mt76x0e kmod-sdhci-mt7620 kmod-usb2 kmod-usb-ohci +endef +TARGET_DEVICES += domywifi_dw22d + define Device/dovado_tiny-ac SOC := mt7620a IMAGE_SIZE := 7872k diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds index 53487d7526..5c104b98c2 100644 --- a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds +++ b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds @@ -81,6 +81,15 @@ dlink,dwr-960) ucidef_set_led_switch "lan" "lan" "green:lan" "switch0" "0x2e" ucidef_set_led_switch "wan" "wan" "green:wan" "switch0" "0x01" ;; +domywifi,dm202|\ +domywifi,dm203|\ +domywifi,dw22d) + ucidef_set_led_switch "lan1" "lan1" "amber:lan1" "switch0" "0x02" + ucidef_set_led_switch "lan2" "lan2" "amber:lan2" "switch0" "0x04" + ucidef_set_led_switch "lan3" "lan3" "amber:lan3" "switch0" "0x08" + ucidef_set_led_switch "lan4" "lan4" "amber:lan4" "switch0" "0x10" + ucidef_set_led_switch "wan" "wan" "amber:wan" "switch0" "0x01" + ;; dovado,tiny-ac) ucidef_set_led_netdev "wifi_led" "wifi" "orange:wifi" "wlan0" ;; diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network index 057428e622..6732a2cb0b 100644 --- a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network @@ -76,6 +76,9 @@ ramips_setup_interfaces() asus,rt-ac54u|\ asus,rt-n14u|\ bdcom,wap2100-sk|\ + domywifi,dm202|\ + domywifi,dm203|\ + domywifi,dw22d|\ edimax,ew-7478apc|\ glinet,gl-mt300a|\ glinet,gl-mt300n|\ @@ -281,6 +284,9 @@ ramips_setup_macs() wan_mac=$(macaddr_add "$(mtd_get_mac_binary factory 0x28)" 1) ;; alfa-network,r36m-e4g|\ + domywifi,dm202|\ + domywifi,dm203|\ + domywifi,dw22d|\ zbtlink,zbt-we1026-h-32m) wan_mac=$(mtd_get_mac_binary factory 0x2e) label_mac=$(mtd_get_mac_binary factory 0x4) From 269758a5bcea1376d037dfea62f161ff8562e489 Mon Sep 17 00:00:00 2001 From: Chukun Pan Date: Tue, 8 Jun 2021 23:10:18 +0800 Subject: [PATCH 15/37] ipq806x: Askey RT4230W REV6: use usual writing for pcie part The problem has been fixed in f47cb405cafd ("ipq806x: fix pci broken on bootm command"), now the pcie part can be written in the usual way. Signed-off-by: Chukun Pan Reviewed-by: Ansuel Smith --- .../files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts index 54356e2ff1..0ad2dfa57b 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts @@ -294,14 +294,16 @@ &pcie0 { status = "okay"; reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>; - /delete-property/ perst-gpios; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; }; &pcie1 { status = "okay"; reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>; - /delete-property/ perst-gpios; - force_gen1 = <1>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; }; &ART { From e2d08084c30e1f25559bfc1c745c0d0854a75636 Mon Sep 17 00:00:00 2001 From: Romain Mahoux Date: Tue, 8 Jun 2021 11:52:18 +0200 Subject: [PATCH 16/37] ath79: add support for Compex WPJ558 (16M) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Specifications: - SoC: QCA9558 - DRAM: 128MB DDR2 - Flash: 16MB SPI-NOR - Wireless: on-board abgn 2×2 2.4GHz radio - Ethernet: 2x 10/100/1000 Mbps (1x 802.11af PoE) - miniPCIe slot Flash instruction: - From u-boot tftpboot 0x80500000 openwrt-ath79-generic-compex_wpj558-16m-squashfs-sysupgrade.bin erase 0x9f030000 +$filesize cp.b $fileaddr 0x9f030000 $filesize boot - From cpximg loader The cpximg loader can be started either by holding the reset button during power up. Once it's running, a TFTP-server under 192.168.1.1 will accept the image appropriate for the board revision that is etched on the board. For example, if the board is labelled '6A07': tftp -v -m binary 192.168.1.1 -c put openwrt-ath79-generic-compex_wpj558-16m-squashfs-cpximg-6a07.bin Signed-off-by: Romain Mahoux [convert to nvmem, remove redundant lan_mac in 02_network] Signed-off-by: Adrian Schmutzler --- .../ath79/dts/qca9558_compex_wpj558-16m.dts | 143 ++++++++++++++++++ .../generic/base-files/etc/board.d/02_network | 5 + target/linux/ath79/image/generic.mk | 14 ++ 3 files changed, 162 insertions(+) create mode 100644 target/linux/ath79/dts/qca9558_compex_wpj558-16m.dts diff --git a/target/linux/ath79/dts/qca9558_compex_wpj558-16m.dts b/target/linux/ath79/dts/qca9558_compex_wpj558-16m.dts new file mode 100644 index 0000000000..61597c8909 --- /dev/null +++ b/target/linux/ath79/dts/qca9558_compex_wpj558-16m.dts @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qca955x.dtsi" + +#include +#include + +/ { + compatible = "compex,wpj558-16m", "qca,qca9558"; + model = "Compex WPJ558 (16MB flash)"; + + aliases { + label-mac-device = ð0; + led-boot = &led_sig4; + led-failsafe = &led_sig4; + led-running = &led_sig4; + led-upgrade = &led_sig4; + }; + + leds { + compatible = "gpio-leds"; + + sig1 { + label = "red:sig1"; + gpios = <&gpio 14 GPIO_ACTIVE_LOW>; + }; + + sig2 { + label = "yellow:sig2"; + gpios = <&gpio 15 GPIO_ACTIVE_LOW>; + }; + + sig3 { + label = "green:sig3"; + gpios = <&gpio 22 GPIO_ACTIVE_LOW>; + }; + + led_sig4: sig4 { + label = "green:sig4"; + gpios = <&gpio 23 GPIO_ACTIVE_LOW>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "Reset"; + linux,code = ; + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; + + beeper { + compatible = "gpio-beeper"; + gpios = <&gpio 4 GPIO_ACTIVE_HIGH>; + }; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + uboot: partition@0 { + label = "u-boot"; + reg = <0x000000 0x030000>; + read-only; + }; + + firmware@30000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x030000 0xfc0000>; + }; + + art: partition@ff0000 { + label = "art"; + reg = <0xff0000 0x010000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + phy0: ethernet-phy@0 { + reg = <0>; + + qca,ar8327-initvals = < + 0x04 0x00080080 /* PORT0 PAD MODE CTRL */ + 0x0c 0x07600000 /* PORT6 PAD MODE CTRL */ + 0x50 0xcc35cc35 /* LED_CTRL0 */ + 0x54 0x00000000 /* LED_CTRL1 */ + 0x58 0x00000000 /* LED_CTRL2 */ + 0x5c 0x03ffff00 /* LED_CTRL3 */ + 0x7c 0x0000007e /* PORT0_STATUS */ + 0x94 0x0000007e /* PORT6 STATUS */ + >; + }; +}; + +ð0 { + status = "okay"; + + pll-data = <0x56000000 0x00000101 0x00001616>; + phy-handle = <&phy0>; + + nvmem-cells = <&macaddr_uboot_2e010>; + nvmem-cell-names = "mac-address"; +}; + +&wmac { + status = "okay"; + + mtd-cal-data = <&art 0x1000>; +}; + +&pcie0 { + status = "okay"; +}; + +&uboot { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_uboot_2e010: macaddr@2e010 { + reg = <0x2e010 0x6>; + }; +}; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index d37fa4ba2b..e45d1aa73a 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -221,6 +221,10 @@ ath79_setup_interfaces() ucidef_add_switch "switch0" \ "0@eth0" "3:lan" "2:wan" ;; + compex,wpj558-16m) + ucidef_add_switch "switch0" \ + "1:wan" "5:lan" "6@eth0" + ;; devolo,dlan-pro-1200plus-ac|\ devolo,magic-2-wifi) ucidef_add_switch "switch0" \ @@ -528,6 +532,7 @@ ath79_setup_macs() wan_mac=$(macaddr_add $(mtd_get_mac_binary art 0x0) 1) ;; compex,wpj344-16m|\ + compex,wpj558-16m|\ compex,wpj563) wan_mac=$(mtd_get_mac_binary u-boot 0x2e018) ;; diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index 4b943ba282..5bcd4779d3 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -682,6 +682,20 @@ define Device/compex_wpj531-16m endef TARGET_DEVICES += compex_wpj531-16m +define Device/compex_wpj558-16m + SOC := qca9558 + IMAGE_SIZE := 16128k + DEVICE_VENDOR := Compex + DEVICE_MODEL := WPJ558 + DEVICE_VARIANT := 16M + SUPPORTED_DEVICES += wpj558 + IMAGES += cpximg-6a07.bin + IMAGE/cpximg-6a07.bin := append-kernel | pad-to $$$$(BLOCKSIZE) | \ + append-rootfs | pad-rootfs | mkmylofw_16m 0x691 3 + DEVICE_PACKAGES := kmod-gpio-beeper +endef +TARGET_DEVICES += compex_wpj558-16m + define Device/compex_wpj563 SOC := qca9563 DEVICE_PACKAGES := kmod-usb2 kmod-usb3 From d57ba86e489e363be3b26b9cb880048da5dfd12c Mon Sep 17 00:00:00 2001 From: Giovanni Cascione Date: Thu, 8 Jul 2021 18:30:53 +0200 Subject: [PATCH 17/37] ramips: add support for D-Link DAP-1325-A1 This patch adds support for D-Link DAP-1325-A1 (Range Extender Wi-Fi N300) Specifications: - SoC: 580Mhz MT7628NN - RAM: 64MB, DDR2 SDRAM - Storage: 8MB, SPI (W25Q64JVSSIQ) - Ethernet: 1x 10/100 LAN port - WIFI: 2.4 GHz 802.11bgn - LED: Status (2x to provide 3 colors), Wi-Fi Signal Strength (4x) - Buttons: Reset, WPS - UART: Serial console (57600, 8n1) Row of 4 holes near LAN port, starting from square hole: 3.3V, TX,RX,GND - FCC ID: fccid.io/KA2AP1325A1/ Installation: Failsafe UI Firmware can be uploaded with Failsafe UI web page: - turn device off - press and hold reset button - turn device on - keep holding reset until red wifi strength led turns on (ab. 10sec) - connect to device through LAN port PC must be configured with static ip (192.168.0.x) - connect to 192.168.0.50 - select image to be flashed and upload. Device will reboot after successful update Serial port/TFTP server - Connect through serial connectors on PCB (e.g. with teraterm) - Set up a TFTP server, and connect through LAN with static IP - Put image file in the root of the server - Boot the device and select '2' at U-Boot startup - Set device IP, server IP and image file name - Start upload and flash Signed-off-by: Giovanni Cascione [fix whitespaces in DTS, convert to nvmem, add mtd-eeprom] Signed-off-by: Adrian Schmutzler --- .../ramips/dts/mt7628an_dlink_dap-1325-a1.dts | 139 ++++++++++++++++++ target/linux/ramips/image/mt76x8.mk | 7 + .../mt76x8/base-files/etc/board.d/01_leds | 7 + .../mt76x8/base-files/etc/board.d/02_network | 1 + 4 files changed, 154 insertions(+) create mode 100644 target/linux/ramips/dts/mt7628an_dlink_dap-1325-a1.dts diff --git a/target/linux/ramips/dts/mt7628an_dlink_dap-1325-a1.dts b/target/linux/ramips/dts/mt7628an_dlink_dap-1325-a1.dts new file mode 100644 index 0000000000..5b50674f0b --- /dev/null +++ b/target/linux/ramips/dts/mt7628an_dlink_dap-1325-a1.dts @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7628an.dtsi" + +#include +#include + +/ { + compatible = "dlink,dap-1325-a1", "mediatek,mt7628an-soc"; + model = "D-Link DAP-1325 A1"; + + aliases { + led-boot = &led_status_green; + led-failsafe = &led_status_green; + led-running = &led_status_green; + led-upgrade = &led_status_red; + }; + + leds { + compatible = "gpio-leds"; + + led_status_red: status_red { + label = "red:status"; + gpios = <&gpio 37 GPIO_ACTIVE_LOW>; + }; + + led_status_green: status_green { + label = "green:status"; + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + + wifi-high { + label = "green:wifi-high"; + gpios = <&gpio 44 GPIO_ACTIVE_LOW>; + }; + + wifi-mid { + label = "green:wifi-mid"; + gpios = <&gpio 3 GPIO_ACTIVE_LOW>; + }; + + wifi-low { + label = "green:wifi-low"; + gpios = <&gpio 0 GPIO_ACTIVE_LOW>; + }; + + wifi-verylow { + label = "red:wifi-verylow"; + gpios = <&gpio 2 GPIO_ACTIVE_LOW>; + }; + }; + + keys { + compatible = "gpio-keys"; + + wps { + label = "wps"; + gpios = <&gpio 45 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&gpio 38 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&state_default { + gpio { + groups = "refclk", "gpio", "wled_an", "i2s", "uart1", "wdt"; + function = "gpio"; + }; +}; + +ðernet { + nvmem-cells = <&macaddr_factory_28>; + nvmem-cell-names = "mac-address"; +}; + +&wmac { + status = "okay"; + + mediatek,mtd-eeprom = <&factory 0x0>; + + nvmem-cells = <&macaddr_factory_28>; + nvmem-cell-names = "mac-address"; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "u-boot-env"; + reg = <0x30000 0x10000>; + read-only; + }; + + factory: partition@40000 { + label = "factory"; + reg = <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x50000 0x7b0000>; + }; + }; + }; +}; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_28: macaddr@28 { + reg = <0x28 0x6>; + }; +}; diff --git a/target/linux/ramips/image/mt76x8.mk b/target/linux/ramips/image/mt76x8.mk index f63930adb1..7862f7b799 100644 --- a/target/linux/ramips/image/mt76x8.mk +++ b/target/linux/ramips/image/mt76x8.mk @@ -100,6 +100,13 @@ define Device/d-team_pbr-d1 endef TARGET_DEVICES += d-team_pbr-d1 +define Device/dlink_dap-1325-a1 + IMAGE_SIZE := 7872k + DEVICE_VENDOR := D-Link + DEVICE_MODEL := DAP-1325 A1 +endef +TARGET_DEVICES += dlink_dap-1325-a1 + define Device/duzun_dm06 IMAGE_SIZE := 7872k DEVICE_VENDOR := DuZun diff --git a/target/linux/ramips/mt76x8/base-files/etc/board.d/01_leds b/target/linux/ramips/mt76x8/base-files/etc/board.d/01_leds index e2fb44c81e..98a693c2e9 100644 --- a/target/linux/ramips/mt76x8/base-files/etc/board.d/01_leds +++ b/target/linux/ramips/mt76x8/base-files/etc/board.d/01_leds @@ -24,6 +24,13 @@ cudy,wr1000) ucidef_set_led_switch "lan1" "lan1" "blue:lan1" "switch0" "0x08" ucidef_set_led_switch "lan2" "lan2" "blue:lan2" "switch0" "0x04" ;; +dlink,dap-1325-a1) + ucidef_set_rssimon "wlan0" "200000" "1" + ucidef_set_led_rssi "wifi-verylow" "wifi-verylow" "red:wifi-verylow" "wlan0" "1" "24" + ucidef_set_led_rssi "wifi-low" "wifi-low" "green:wifi-low" "wlan0" "25" "100" + ucidef_set_led_rssi "wifi-med" "wifi-med" "green:wifi-mid" "wlan0" "50" "100" + ucidef_set_led_rssi "wifi-high" "wifi-high" "green:wifi-high" "wlan0" "75" "100" + ;; elecom,wrc-1167fs) ucidef_set_led_switch "lan" "lan" "green:lan" "switch0" "0x8" ucidef_set_led_switch "internet" "internet" "green:internet" "switch0" "0x10" diff --git a/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network b/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network index ea04391f9c..7c9da8f3e4 100644 --- a/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt76x8/base-files/etc/board.d/02_network @@ -10,6 +10,7 @@ ramips_setup_interfaces() case $board in alfa-network,awusfree1|\ d-team,pbr-d1|\ + dlink,dap-1325-a1|\ glinet,microuter-n300|\ glinet,vixmini|\ hak5,wifi-pineapple-mk7|\ From a6c410ae10ea51f5541fe2fdc3bd39011bff3f0e Mon Sep 17 00:00:00 2001 From: David Yang Date: Sun, 11 Jul 2021 22:13:21 +0800 Subject: [PATCH 18/37] ramips: increase flash freq for miwifi-mini The flash is Winbond 25Q128. As it has large rom, better to increase flash frequency to 70MHz according to the flash spec and enable fast-read. Signed-off-by: David Yang --- target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts b/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts index 49ef40827b..d89ded78a5 100644 --- a/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts +++ b/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts @@ -60,7 +60,8 @@ flash@0 { compatible = "jedec,spi-nor"; reg = <0>; - spi-max-frequency = <10000000>; + spi-max-frequency = <70000000>; + m25p,fast-read; partitions { compatible = "fixed-partitions"; From 5ed11012e7d990a11256917a5112f528cb983c89 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sun, 11 Jul 2021 22:16:54 +0800 Subject: [PATCH 19/37] ramips: lock u-boot partition and unlock u-boot-env for miwifi-mini Generally u-boot should keep read-only to avoid mis-overwriting and bricking the device, but u-boot-env could be safely modified with u-boot setenv tool. Signed-off-by: David Yang --- target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts b/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts index d89ded78a5..b2e46a7a56 100644 --- a/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts +++ b/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts @@ -71,12 +71,12 @@ partition@0 { label = "u-boot"; reg = <0x0 0x30000>; + read-only; }; partition@30000 { label = "u-boot-env"; reg = <0x30000 0x10000>; - read-only; }; factory: partition@40000 { From 38cb5005166dd49fb3d69ba68a905b97cc23f6a3 Mon Sep 17 00:00:00 2001 From: David Yang Date: Sun, 11 Jul 2021 23:17:43 +0800 Subject: [PATCH 20/37] ramips: expose ephy leds for miwifi-mini Give users more control by exposing ephy leds. Signed-off-by: David Yang [remove execute bit on 01_leds, add status for gpio2] Signed-off-by: Adrian Schmutzler --- .../ramips/dts/mt7620a_xiaomi_miwifi-mini.dts | 24 +++++++++++++++---- .../mt7620/base-files/etc/board.d/01_leds | 5 ++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts b/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts index b2e46a7a56..9f5df5dd79 100644 --- a/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts +++ b/target/linux/ramips/dts/mt7620a_xiaomi_miwifi-mini.dts @@ -37,6 +37,21 @@ label = "red:status"; gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; }; + + wan { + label = "green:wan"; + gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; + }; + + lan1 { + label = "green:lan1"; + gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + }; + + lan2 { + label = "green:lan2"; + gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; + }; }; keys { @@ -54,6 +69,10 @@ status = "okay"; }; +&gpio2 { + status = "okay"; +}; + &spi0 { status = "okay"; @@ -119,9 +138,6 @@ }; ðernet { - pinctrl-names = "default"; - pinctrl-0 = <&ephy_pins>; - nvmem-cells = <&macaddr_factory_28>; nvmem-cell-names = "mac-address"; @@ -148,7 +164,7 @@ &state_default { gpio { - groups = "i2c", "rgmii1"; + groups = "ephy", "i2c", "rgmii1"; function = "gpio"; }; }; diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds index 5c104b98c2..ff3a5c8c0c 100644 --- a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds +++ b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds @@ -207,6 +207,11 @@ wavlink,wl-wn579x3) ucidef_set_led_switch "lan" "lan" "blue:lan" "switch0" "0x20" ucidef_set_led_switch "wan" "wan" "blue:wan" "switch0" "0x10" ;; +xiaomi,miwifi-mini) + ucidef_set_led_switch "lan1" "lan1" "green:lan1" "switch0" "0x02" + ucidef_set_led_switch "lan2" "lan2" "green:lan2" "switch0" "0x01" + ucidef_set_led_switch "wan" "wan" "green:wan" "switch0" "0x10" + ;; zbtlink,zbt-ape522ii) ucidef_set_led_netdev "wlan2g4" "wlan1-link" "green:wlan2g4" "wlan1" ucidef_set_led_netdev "sys1" "wlan1" "green:sys1" "wlan1" "tx rx" From 4ab0b5fabd2e98264fbefb48da19fcc7b56a854a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 25 Aug 2021 10:24:33 +0200 Subject: [PATCH 21/37] bmips: backport accepted watchdog patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch has been accepted for linux v5.14. Signed-off-by: Álvaro Fernández Rojas --- ...g-bcm7038_wdt-add-big-endian-support.patch | 86 +++++++++++++++++++ ...bcm7038-add-big-endian-compatibility.patch | 66 -------------- 2 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 target/linux/bmips/patches-5.10/080-v5.14-watchdog-bcm7038_wdt-add-big-endian-support.patch delete mode 100644 target/linux/bmips/patches-5.10/120-wdt-bcm7038-add-big-endian-compatibility.patch diff --git a/target/linux/bmips/patches-5.10/080-v5.14-watchdog-bcm7038_wdt-add-big-endian-support.patch b/target/linux/bmips/patches-5.10/080-v5.14-watchdog-bcm7038_wdt-add-big-endian-support.patch new file mode 100644 index 0000000000..3ddba6c937 --- /dev/null +++ b/target/linux/bmips/patches-5.10/080-v5.14-watchdog-bcm7038_wdt-add-big-endian-support.patch @@ -0,0 +1,86 @@ +From e379c2199de4280243e43118dceb4ea5e97059a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Tue, 23 Feb 2021 09:00:42 +0100 +Subject: [PATCH] watchdog: bcm7038_wdt: add big endian support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +bcm7038_wdt can be used on bmips big endian (bcm63xx) devices too. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20210223080042.29569-1-noltari@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +--- + drivers/watchdog/bcm7038_wdt.c | 31 +++++++++++++++++++++++++------ + 1 file changed, 25 insertions(+), 6 deletions(-) + +--- a/drivers/watchdog/bcm7038_wdt.c ++++ b/drivers/watchdog/bcm7038_wdt.c +@@ -34,6 +34,25 @@ struct bcm7038_watchdog { + + static bool nowayout = WATCHDOG_NOWAYOUT; + ++static inline void bcm7038_wdt_write(u32 value, void __iomem *addr) ++{ ++ /* MIPS chips strapped for BE will automagically configure the ++ * peripheral registers for CPU-native byte order. ++ */ ++ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) ++ __raw_writel(value, addr); ++ else ++ writel_relaxed(value, addr); ++} ++ ++static inline u32 bcm7038_wdt_read(void __iomem *addr) ++{ ++ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) ++ return __raw_readl(addr); ++ else ++ return readl_relaxed(addr); ++} ++ + static void bcm7038_wdt_set_timeout_reg(struct watchdog_device *wdog) + { + struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); +@@ -41,15 +60,15 @@ static void bcm7038_wdt_set_timeout_reg( + + timeout = wdt->rate * wdog->timeout; + +- writel(timeout, wdt->base + WDT_TIMEOUT_REG); ++ bcm7038_wdt_write(timeout, wdt->base + WDT_TIMEOUT_REG); + } + + static int bcm7038_wdt_ping(struct watchdog_device *wdog) + { + struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); + +- writel(WDT_START_1, wdt->base + WDT_CMD_REG); +- writel(WDT_START_2, wdt->base + WDT_CMD_REG); ++ bcm7038_wdt_write(WDT_START_1, wdt->base + WDT_CMD_REG); ++ bcm7038_wdt_write(WDT_START_2, wdt->base + WDT_CMD_REG); + + return 0; + } +@@ -66,8 +85,8 @@ static int bcm7038_wdt_stop(struct watch + { + struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); + +- writel(WDT_STOP_1, wdt->base + WDT_CMD_REG); +- writel(WDT_STOP_2, wdt->base + WDT_CMD_REG); ++ bcm7038_wdt_write(WDT_STOP_1, wdt->base + WDT_CMD_REG); ++ bcm7038_wdt_write(WDT_STOP_2, wdt->base + WDT_CMD_REG); + + return 0; + } +@@ -88,7 +107,7 @@ static unsigned int bcm7038_wdt_get_time + struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); + u32 time_left; + +- time_left = readl(wdt->base + WDT_CMD_REG); ++ time_left = bcm7038_wdt_read(wdt->base + WDT_CMD_REG); + + return time_left / wdt->rate; + } diff --git a/target/linux/bmips/patches-5.10/120-wdt-bcm7038-add-big-endian-compatibility.patch b/target/linux/bmips/patches-5.10/120-wdt-bcm7038-add-big-endian-compatibility.patch deleted file mode 100644 index e4fc24a92e..0000000000 --- a/target/linux/bmips/patches-5.10/120-wdt-bcm7038-add-big-endian-compatibility.patch +++ /dev/null @@ -1,66 +0,0 @@ ---- a/drivers/watchdog/bcm7038_wdt.c -+++ b/drivers/watchdog/bcm7038_wdt.c -@@ -34,6 +34,24 @@ struct bcm7038_watchdog { - - static bool nowayout = WATCHDOG_NOWAYOUT; - -+static inline void bcm7038_wdt_write(unsigned long data, void __iomem *reg) -+{ -+#ifdef CONFIG_CPU_BIG_ENDIAN -+ iowrite32be(data, reg); -+#else -+ writel(data, reg); -+#endif -+} -+ -+static inline unsigned long bcm7038_wdt_read(void __iomem *reg) -+{ -+#ifdef CONFIG_CPU_BIG_ENDIAN -+ return ioread32be(reg); -+#else -+ return readl(reg); -+#endif -+} -+ - static void bcm7038_wdt_set_timeout_reg(struct watchdog_device *wdog) - { - struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); -@@ -41,15 +59,15 @@ static void bcm7038_wdt_set_timeout_reg( - - timeout = wdt->rate * wdog->timeout; - -- writel(timeout, wdt->base + WDT_TIMEOUT_REG); -+ bcm7038_wdt_write(timeout, wdt->base + WDT_TIMEOUT_REG); - } - - static int bcm7038_wdt_ping(struct watchdog_device *wdog) - { - struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); - -- writel(WDT_START_1, wdt->base + WDT_CMD_REG); -- writel(WDT_START_2, wdt->base + WDT_CMD_REG); -+ bcm7038_wdt_write(WDT_START_1, wdt->base + WDT_CMD_REG); -+ bcm7038_wdt_write(WDT_START_2, wdt->base + WDT_CMD_REG); - - return 0; - } -@@ -66,8 +84,8 @@ static int bcm7038_wdt_stop(struct watch - { - struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); - -- writel(WDT_STOP_1, wdt->base + WDT_CMD_REG); -- writel(WDT_STOP_2, wdt->base + WDT_CMD_REG); -+ bcm7038_wdt_write(WDT_STOP_1, wdt->base + WDT_CMD_REG); -+ bcm7038_wdt_write(WDT_STOP_2, wdt->base + WDT_CMD_REG); - - return 0; - } -@@ -88,7 +106,7 @@ static unsigned int bcm7038_wdt_get_time - struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog); - u32 time_left; - -- time_left = readl(wdt->base + WDT_CMD_REG); -+ time_left = bcm7038_wdt_read(wdt->base + WDT_CMD_REG); - - return time_left / wdt->rate; - } From 364bd887a148a1963bf9a94fe7dd171f36afb87e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Aug 2021 22:49:00 +0100 Subject: [PATCH 22/37] fstools: update to git HEAD 50e6b20 libfstools: handle open() return value properly in F2FS check e1b6811 blockd: include missing libubox/utils.h Signed-off-by: Daniel Golle --- package/system/fstools/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile index 438cb8fee8..232b1fa807 100644 --- a/package/system/fstools/Makefile +++ b/package/system/fstools/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git -PKG_MIRROR_HASH:=faa4679562ae31cb6dbbc90b7f3f297294a51f7be1b12d10a5f0b7acfaae7252 -PKG_SOURCE_DATE:=2021-08-14 -PKG_SOURCE_VERSION:=2e3aca299ea7bbe74f219860510c4b34e77c7aa4 +PKG_MIRROR_HASH:=c3b711047324b5eb149164b9d82f3ffb155ed579c9b00d7054a35b572201c2b6 +PKG_SOURCE_DATE:=2021-08-25 +PKG_SOURCE_VERSION:=e1b68111e1661c92a773cc5131b55f98d943888f CMAKE_INSTALL:=1 PKG_LICENSE:=GPL-2.0 From 3ebbf795df2633bbd277a5ec8651d4b093a775a2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 24 Aug 2021 17:40:28 +0200 Subject: [PATCH 23/37] ustp: add OpenWrt STP/RSTP daemon This integrates with netifd in order to provide STP/RSTP protocol support in user space. It defaults to using RSTP for bridges with stp enabled. This daemon has no config files, it uses the configuration passed from netifd via ubus Signed-off-by: Felix Fietkau --- package/network/services/ustp/Makefile | 41 +++++++++++++++++++ .../network/services/ustp/files/ustpd.init | 14 +++++++ 2 files changed, 55 insertions(+) create mode 100644 package/network/services/ustp/Makefile create mode 100644 package/network/services/ustp/files/ustpd.init diff --git a/package/network/services/ustp/Makefile b/package/network/services/ustp/Makefile new file mode 100644 index 0000000000..682bd9f350 --- /dev/null +++ b/package/network/services/ustp/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2021 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=ustp +PKG_RELEASE:=1 + +PKG_SOURCE_URL=$(PROJECT_GIT)/project/ustp.git +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2021-08-25 +PKG_SOURCE_VERSION:=9622264cf92691f18ae9222b0a4c9db95af5d80d +PKG_MIRROR_HASH:=de4ed29eee21192b60e8683633d916d251bcccd5701bdac83b5ba435189297f1 + +PKG_MAINTAINER:=Felix Fietkau +PKG_LICENSE:=GPL-2.0 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/ustp + SECTION:=net + CATEGORY:=Network + TITLE:=OpenWrt STP/RSTP daemon + DEPENDS:=+libubox +libubus +endef + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include -flto +TARGET_LDFLAGS += -flto -fuse-linker-plugin + +define Package/ustp/install + $(INSTALL_DIR) $(1)/sbin $(1)/etc/init.d + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ipkg-install/sbin/* $(1)/sbin/ + $(INSTALL_BIN) ./files/ustpd.init $(1)/etc/init.d/ustpd +endef + +$(eval $(call BuildPackage,ustp)) diff --git a/package/network/services/ustp/files/ustpd.init b/package/network/services/ustp/files/ustpd.init new file mode 100644 index 0000000000..9b741fec78 --- /dev/null +++ b/package/network/services/ustp/files/ustpd.init @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (c) 2021 OpenWrt.org + +START=50 + +USE_PROCD=1 +PROG=/sbin/ustpd + +start_service() { + procd_open_instance + procd_set_param command "$PROG" + procd_set_param respawn + procd_close_instance +} From d98738b5c118fc45068b45f07b8b6938e91f35d2 Mon Sep 17 00:00:00 2001 From: Jan-Niklas Burfeind Date: Mon, 23 Aug 2021 15:07:38 +0200 Subject: [PATCH 24/37] ath79: add support for onion omega The Onion Omega is a hardware development platform with built-in WiFi. https://onioniot.github.io/wiki/ Specifications: - QCA9331 @ 400 MHz (MIPS 24Kc Big-Endian Processor) - 64MB of DDR2 RAM running at 400 MHz - 16MB of on-board flash storage - Support for USB 2.0 - Support for Ethernet at 100 Mbps - 802.11b/g/n WiFi at 150 Mbps - 18 digital GPIOs - A single Serial UART - Support for SPI - Support for I2S Flash instructions: The device is running OpenWrt upon release using the ar71xx target. Both a sysupgrade and uploading the factory image using u-boots web-UI do work fine. Depending on the ssh client, it might be necessary to enable outdated KeyExchange methods e.g. in the clients ssh-config: Host 192.168.1.1 KexAlgorithms +diffie-hellman-group1-sha1 The stock credentials are: root onioneer For u-boots web-UI manually configure `192.168.1.2/24` on your computer, connect to `192.168.1.1`. MAC addresses as verified by OEM firmware: 2G phy0 label LAN eth0 label - 1 LAN is only available in combination with an optional expansion dock. Based on vendor acked commit: commit 5cd49bb067ca ("ar71xx: add support for Onion Omega") Partly reverts: commit fc553c7e4c8e ("ath79: drop unused/incomplete dts") Signed-off-by: Jan-Niklas Burfeind --- target/linux/ath79/dts/ar9331_onion_omega.dts | 137 ++++++++++++++++++ .../generic/base-files/etc/board.d/02_network | 1 + target/linux/ath79/image/generic.mk | 13 ++ 3 files changed, 151 insertions(+) create mode 100644 target/linux/ath79/dts/ar9331_onion_omega.dts diff --git a/target/linux/ath79/dts/ar9331_onion_omega.dts b/target/linux/ath79/dts/ar9331_onion_omega.dts new file mode 100644 index 0000000000..09e4234194 --- /dev/null +++ b/target/linux/ath79/dts/ar9331_onion_omega.dts @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "ar9331.dtsi" + +#include +#include + +/ { + model = "Onion Omega"; + compatible = "onion,omega", "qca,ar9331"; + + aliases { + serial0 = &uart; + label-mac-device = &wmac; + led-boot = &led_system; + led-failsafe = &led_system; + led-running = &led_system; + led-upgrade = &led_system; + }; + + leds { + compatible = "gpio-leds"; + + led_system: system { + label = "amber:system"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + linux,code = ; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + debounce-interval = <60>; + }; + }; + + reg_usb_vbus: reg_usb_vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&usb { + status = "okay"; + + vbus-supply = <®_usb_vbus>; + dr_mode = "host"; +}; + +&usb_phy { + status = "okay"; +}; + +ð0 { + status = "okay"; + + compatible = "syscon", "simple-mfd"; +}; + +ð1 { + status = "okay"; + + nvmem-cells = <&macaddr_uboot_1fc00>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <(-1)>; + + gmac-config { + device = <&gmac>; + switch-phy-addr-swap = <4>; + switch-phy-swap = <4>; + }; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <25000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + uboot: partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + read-only; + }; + + partition@20000 { + compatible = "tplink,firmware"; + label = "firmware"; + reg = <0x020000 0xfd0000>; + }; + + art: partition@ff0000 { + label = "art"; + reg = <0xff0000 0x010000>; + read-only; + }; + }; + }; +}; + +&wmac { + status = "okay"; + + mtd-cal-data = <&art 0x1000>; + + nvmem-cells = <&macaddr_uboot_1fc00>; + nvmem-cell-names = "mac-address"; +}; + +&uboot { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_uboot_1fc00: macaddr@1fc00 { + reg = <0x1fc00 0x6>; + }; +}; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index e45d1aa73a..9cec8d5098 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -45,6 +45,7 @@ ath79_setup_interfaces() netgear,ex7300|\ ocedo,koala|\ ocedo,raccoon|\ + onion,omega|\ openmesh,mr600-v1|\ openmesh,mr600-v2|\ openmesh,mr900-v1|\ diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index 5bcd4779d3..e540806bb7 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -1688,6 +1688,19 @@ define Device/ocedo_ursus endef TARGET_DEVICES += ocedo_ursus +define Device/onion_omega + $(Device/tplink-16mlzma) + SOC := ar9331 + DEVICE_VENDOR := Onion + DEVICE_MODEL := Omega + DEVICE_PACKAGES := kmod-usb-chipidea2 + SUPPORTED_DEVICES += onion-omega + KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | uImage lzma + IMAGE_SIZE := 16192k + TPLINK_HWID := 0x04700001 +endef +TARGET_DEVICES += onion_omega + define Device/openmesh_common_64k DEVICE_VENDOR := OpenMesh DEVICE_PACKAGES := uboot-envtools From 2b0378cf9f3163bac29fa9946b3aa1607fc03802 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 5 Aug 2021 15:29:25 +0200 Subject: [PATCH 25/37] gpio-button-hotplug: convert to gpio descriptor (gpiod_) API OpenWrt's special gpio-button-hotplug driver is still using exclusively the legacy GPIO Subsystem gpio_ API. While it still does work fine for most devices, upstream linux is starting to convert platform support like that of the APU2/3/4 to the new GPIOD LOOKUP tables that are not supported by it. Hence, this patch replaces the gpio_ calls present in gpio-button-hotplug with gpiod_ equivalent wherever it's possible. This allows the driver to use the gpiod lookup tables and still have a fallback for legacy platform data code that just sets button->gpio set to the real button/switch GPIO. As a bonus: the active_low logic is now being handled by the linux's gpio subsystem too. Another issue that was address is the of_handle leak in the dt parser error path. Tested with legacy platform data: x86_64: APU2, MX-100 Tested on OF: ATH79; MR18, APM821xx: Netgear WNDR4700, RAMIPS: WL-330N3G LANTIQ: AVM FritzBox 7360v1 Reported-by: Chris Blake Tested-by: Chris Blake Reviewed-by: Linus Walleij Signed-off-by: Christian Lamparter --- .../src/gpio-button-hotplug.c | 144 ++++++++---------- 1 file changed, 64 insertions(+), 80 deletions(-) diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c index 9575c6245b..fcaf7f59de 100644 --- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c +++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c @@ -242,11 +242,11 @@ static int gpio_button_get_value(struct gpio_keys_button_data *bdata) int val; if (bdata->can_sleep) - val = !!gpio_get_value_cansleep(bdata->b->gpio); + val = !!gpiod_get_value_cansleep(bdata->gpiod); else - val = !!gpio_get_value(bdata->b->gpio); + val = !!gpiod_get_value(bdata->gpiod); - return val ^ bdata->b->active_low; + return val; } static void gpio_keys_handle_button(struct gpio_keys_button_data *bdata) @@ -365,7 +365,6 @@ gpio_keys_get_devtree_pdata(struct device *dev) struct device_node *node, *pp; struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; - int error; int nbuttons; int i = 0; @@ -375,14 +374,12 @@ gpio_keys_get_devtree_pdata(struct device *dev) nbuttons = of_get_child_count(node); if (nbuttons == 0) - return NULL; + return ERR_PTR(-EINVAL); pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * (sizeof *button), GFP_KERNEL); - if (!pdata) { - error = -ENOMEM; - goto err_out; - } + if (!pdata) + return ERR_PTR(-ENOMEM); pdata->buttons = (struct gpio_keys_button *)(pdata + 1); pdata->nbuttons = nbuttons; @@ -391,37 +388,13 @@ gpio_keys_get_devtree_pdata(struct device *dev) of_property_read_u32(node, "poll-interval", &pdata->poll_interval); for_each_child_of_node(node, pp) { - enum of_gpio_flags flags; - - if (!of_find_property(pp, "gpios", NULL)) { - pdata->nbuttons--; - dev_warn(dev, "Found button without gpios\n"); - continue; - } - button = (struct gpio_keys_button *)(&pdata->buttons[i++]); - button->irq = irq_of_parse_and_map(pp, 0); - - button->gpio = of_get_gpio_flags(pp, 0, &flags); - if (button->gpio < 0) { - error = button->gpio; - if (error != -ENOENT) { - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - return ERR_PTR(error); - } - } else { - button->active_low = !!(flags & OF_GPIO_ACTIVE_LOW); - } - if (of_property_read_u32(pp, "linux,code", &button->code)) { - dev_err(dev, "Button without keycode: 0x%x\n", - button->gpio); - error = -EINVAL; - goto err_out; + dev_err(dev, "Button node '%s' without keycode\n", + pp->full_name); + of_node_put(pp); + return ERR_PTR(-EINVAL); } button->desc = of_get_property(pp, "label", NULL); @@ -434,17 +407,12 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; - } - if (pdata->nbuttons == 0) { - error = -EINVAL; - goto err_out; + button->irq = irq_of_parse_and_map(pp, 0); + button->gpio = -ENOENT; /* mark this as device-tree */ } return pdata; - -err_out: - return ERR_PTR(error); } static struct of_device_id gpio_keys_of_match[] = { @@ -471,11 +439,12 @@ gpio_keys_get_devtree_pdata(struct device *dev) static int gpio_keys_button_probe(struct platform_device *pdev, struct gpio_keys_button_dev **_bdev, int polled) { - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; + struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); struct gpio_keys_button_dev *bdev; struct gpio_keys_button *buttons; - int error; + struct device_node *prev = NULL; + int error = 0; int i; if (!pdata) { @@ -514,46 +483,67 @@ static int gpio_keys_button_probe(struct platform_device *pdev, for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &buttons[i]; struct gpio_keys_button_data *bdata = &bdev->data[i]; - unsigned int gpio = button->gpio; + const char *desc = button->desc ? button->desc : DRV_NAME; if (button->wakeup) { dev_err(dev, "does not support wakeup\n"); - return -EINVAL; + error = -EINVAL; + goto out; } bdata->map_entry = button_get_index(button->code); if (bdata->map_entry < 0) { - dev_warn(dev, "does not support key code:%u\n", + dev_err(dev, "does not support key code:%u\n", button->code); - continue; + error = -EINVAL; + goto out; } if (!(button->type == 0 || button->type == EV_KEY || button->type == EV_SW)) { - dev_warn(dev, "only supports buttons or switches\n"); - continue; + dev_err(dev, "only supports buttons or switches\n"); + error = -EINVAL; + goto out; } - error = devm_gpio_request(dev, gpio, - button->desc ? button->desc : DRV_NAME); - if (error) { - dev_err(dev, "unable to claim gpio %u, err=%d\n", - gpio, error); - return error; - } - bdata->gpiod = gpio_to_desc(gpio); - if (!bdata->gpiod) - return -EINVAL; + if (gpio_is_valid(button->gpio)) { + /* legacy platform data... but is it the lookup table? */ + bdata->gpiod = devm_gpiod_get_index(dev, desc, i, + GPIOD_IN); + if (IS_ERR(bdata->gpiod)) { + /* or the legacy (button->gpio is good) way? */ + error = devm_gpio_request_one(dev, + button->gpio, GPIOF_IN | ( + button->active_low ? GPIOF_ACTIVE_LOW : + 0), desc); + if (error) { + if (error != -EPROBE_DEFER) { + dev_err(dev, "unable to claim gpio %d, err=%d\n", + button->gpio, error); + } + goto out; + } - error = gpio_direction_input(gpio); - if (error) { - dev_err(dev, - "unable to set direction on gpio %u, err=%d\n", - gpio, error); - return error; + bdata->gpiod = gpio_to_desc(button->gpio); + } + } else { + /* Device-tree */ + struct device_node *child = + of_get_next_child(dev->of_node, prev); + + bdata->gpiod = devm_gpiod_get_from_of_node(dev, + child, "gpios", 0, GPIOD_IN, desc); + + prev = child; } - bdata->can_sleep = gpio_cansleep(gpio); + if (IS_ERR_OR_NULL(bdata->gpiod)) { + error = IS_ERR(bdata->gpiod) ? PTR_ERR(bdata->gpiod) : + -EINVAL; + goto out; + } + + bdata->can_sleep = gpiod_cansleep(bdata->gpiod); bdata->last_state = -1; /* Unknown state on boot */ if (bdev->polled) { @@ -584,8 +574,11 @@ static int gpio_keys_button_probe(struct platform_device *pdev, platform_set_drvdata(pdev, bdev); *_bdev = bdev; + error = 0; - return 0; +out: + of_node_put(prev); + return error; } static int gpio_keys_probe(struct platform_device *pdev) @@ -594,9 +587,7 @@ static int gpio_keys_probe(struct platform_device *pdev) struct gpio_keys_button_dev *bdev; int ret, i; - ret = gpio_keys_button_probe(pdev, &bdev, 0); - if (ret) return ret; @@ -608,12 +599,8 @@ static int gpio_keys_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&bdata->work, gpio_keys_irq_work_func); - if (!bdata->gpiod) - continue; - if (!button->irq) { - bdata->irq = gpio_to_irq(button->gpio); - + bdata->irq = gpiod_to_irq(bdata->gpiod); if (bdata->irq < 0) { dev_err(&pdev->dev, "failed to get irq for gpio:%d\n", button->gpio); @@ -631,7 +618,6 @@ static int gpio_keys_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, bdata->irq, NULL, button_handle_irq, irqflags, dev_name(&pdev->dev), bdata); - if (ret < 0) { bdata->irq = 0; dev_err(&pdev->dev, "failed to request irq:%d for gpio:%d\n", @@ -653,14 +639,12 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) int ret; ret = gpio_keys_button_probe(pdev, &bdev, 1); - if (ret) return ret; INIT_DELAYED_WORK(&bdev->work, gpio_keys_polled_poll); pdata = bdev->pdata; - if (pdata->enable) pdata->enable(bdev->dev); From a1bd8109f02e3d8ef66a2f79ab8078055d7cd0b1 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 22 Aug 2021 11:27:08 +0200 Subject: [PATCH 26/37] ath79: remove obsolete pci-ath9k-fixup.[c,h] files This was old code from the AR71XXs target days that doesn't get compiled and used anymore. Bringing up AR92xx and earlier chips from their OWL-Emulator state is currently done by the upstream ath9k-pci-owl-loader module. (see the kmod-owl-loader package). Signed-off-by: Christian Lamparter --- .../files/arch/mips/ath79/pci-ath9k-fixup.c | 126 ------------------ .../files/arch/mips/ath79/pci-ath9k-fixup.h | 6 - 2 files changed, 132 deletions(-) delete mode 100644 target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.c delete mode 100644 target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.h diff --git a/target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.c b/target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.c deleted file mode 100644 index 2202351806..0000000000 --- a/target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Atheros AP94 reference board PCI initialization - * - * Copyright (C) 2009-2010 Gabor Juhos - * - * 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. - */ - -#include -#include - -#include -#include - -struct ath9k_fixup { - u16 *cal_data; - unsigned slot; -}; - -static int ath9k_num_fixups; -static struct ath9k_fixup ath9k_fixups[2]; - -static void ath9k_pci_fixup(struct pci_dev *dev) -{ - void __iomem *mem; - u16 *cal_data = NULL; - u16 cmd; - u32 bar0; - u32 val; - unsigned i; - - for (i = 0; i < ath9k_num_fixups; i++) { - if (ath9k_fixups[i].cal_data == NULL) - continue; - - if (ath9k_fixups[i].slot != PCI_SLOT(dev->devfn)) - continue; - - cal_data = ath9k_fixups[i].cal_data; - break; - } - - if (cal_data == NULL) - return; - - if (*cal_data != 0xa55a) { - pr_err("pci %s: invalid calibration data\n", pci_name(dev)); - return; - } - - pr_info("pci %s: fixup device configuration\n", pci_name(dev)); - - mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000); - if (!mem) { - pr_err("pci %s: ioremap error\n", pci_name(dev)); - return; - } - - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0); - - switch (ath79_soc) { - case ATH79_SOC_AR7161: - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - AR71XX_PCI_MEM_BASE); - break; - case ATH79_SOC_AR7240: - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff); - break; - - case ATH79_SOC_AR7241: - case ATH79_SOC_AR7242: - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x1000ffff); - break; - case ATH79_SOC_AR9344: - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x1000ffff); - break; - - default: - BUG(); - } - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; - pci_write_config_word(dev, PCI_COMMAND, cmd); - - /* set pointer to first reg address */ - cal_data += 3; - while (*cal_data != 0xffff) { - u32 reg; - reg = *cal_data++; - val = *cal_data++; - val |= (*cal_data++) << 16; - - __raw_writel(val, mem + reg); - udelay(100); - } - - pci_read_config_dword(dev, PCI_VENDOR_ID, &val); - dev->vendor = val & 0xffff; - dev->device = (val >> 16) & 0xffff; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &val); - dev->revision = val & 0xff; - dev->class = val >> 8; /* upper 3 bytes */ - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); - pci_write_config_word(dev, PCI_COMMAND, cmd); - - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0); - - iounmap(mem); -} -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath9k_pci_fixup); - -void __init pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data) -{ - if (ath9k_num_fixups >= ARRAY_SIZE(ath9k_fixups)) - return; - - ath9k_fixups[ath9k_num_fixups].slot = slot; - ath9k_fixups[ath9k_num_fixups].cal_data = cal_data; - ath9k_num_fixups++; -} diff --git a/target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.h b/target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.h deleted file mode 100644 index 5794941f08..0000000000 --- a/target/linux/ath79/files/arch/mips/ath79/pci-ath9k-fixup.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _PCI_ATH9K_FIXUP -#define _PCI_ATH9K_FIXUP - -void pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data) __init; - -#endif /* _PCI_ATH9K_FIXUP */ From d24efa92e1c0918526c6eae6c2f2e98ec1a8c048 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 21 Aug 2021 00:39:47 +0200 Subject: [PATCH 27/37] ath9k: owl-loader: remove obsolete AR71XX patch this is no longer necessary as the AR71XX target was superseded by ath79. Signed-off-by: Christian Lamparter --- .../patches/ath/120-owl-loader-compat.patch | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch diff --git a/package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch b/package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch deleted file mode 100644 index d1d6c9e2e3..0000000000 --- a/package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch +++ /dev/null @@ -1,53 +0,0 @@ -From: Christian Lamparter -Date: Sat, 16 Nov 2019 19:25:24 +0100 -Subject: [PATCH] owl_loader: compatibility patch - -This patch includes OpenWrt specific changes that are -not included in the upstream owl-loader. - -This includes a platform data handling changes for ar71xx. - -Signed-off-by: Christian Lamparter - ---- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c -+++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c -@@ -103,6 +103,7 @@ static void owl_fw_cb(const struct firmw - { - struct pci_dev *pdev = (struct pci_dev *)context; - struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev); -+ struct ath9k_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct pci_bus *bus; - - complete(&ctx->eeprom_load); -@@ -118,6 +119,16 @@ static void owl_fw_cb(const struct firmw - goto release; - } - -+ if (pdata) { -+ memcpy(pdata->eeprom_data, fw->data, fw->size); -+ -+ /* -+ * eeprom has been successfully loaded - pass the data to ath9k -+ * but remove the eeprom_name, so it doesn't try to load it too. -+ */ -+ pdata->eeprom_name = NULL; -+ } -+ - if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size)) - goto release; - -@@ -137,8 +148,14 @@ release: - static const char *owl_get_eeprom_name(struct pci_dev *pdev) - { - struct device *dev = &pdev->dev; -+ struct ath9k_platform_data *pdata; - char *eeprom_name; - -+ /* try the existing platform data first */ -+ pdata = dev_get_platdata(dev); -+ if (pdata && pdata->eeprom_name) -+ return pdata->eeprom_name; -+ - dev_dbg(dev, "using auto-generated eeprom filename\n"); - - eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL); From 7119fd32d397567931e63dbbf72014e95624018f Mon Sep 17 00:00:00 2001 From: Eneas U de Queiroz Date: Thu, 26 Aug 2021 14:34:28 -0300 Subject: [PATCH 28/37] openssl: bump to 1.1.1l This version fixes two vulnerabilities: - SM2 Decryption Buffer Overflow (CVE-2021-3711) Severity: High - Read buffer overruns processing ASN.1 strings (CVE-2021-3712) Severity: Medium Signed-off-by: Eneas U de Queiroz --- package/libs/openssl/Makefile | 4 ++-- .../410-eng_devcrypto-add-configuration-options.patch | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package/libs/openssl/Makefile b/package/libs/openssl/Makefile index 11e5ecfccb..3f5fe90d9c 100644 --- a/package/libs/openssl/Makefile +++ b/package/libs/openssl/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=openssl PKG_BASE:=1.1.1 -PKG_BUGFIX:=k +PKG_BUGFIX:=l PKG_VERSION:=$(PKG_BASE)$(PKG_BUGFIX) PKG_RELEASE:=1 PKG_USE_MIPS16:=0 @@ -26,7 +26,7 @@ PKG_SOURCE_URL:= \ ftp://ftp.pca.dfn.de/pub/tools/net/openssl/source/ \ ftp://ftp.pca.dfn.de/pub/tools/net/openssl/source/old/$(PKG_BASE)/ -PKG_HASH:=892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5 +PKG_HASH:=0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1 PKG_LICENSE:=OpenSSL PKG_LICENSE_FILES:=LICENSE diff --git a/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch b/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch index 8745364cf2..6d0fbfc982 100644 --- a/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch +++ b/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch @@ -1,4 +1,4 @@ -From 1c2fabcdb34e436286b4a8760cfbfbff11ea551a Mon Sep 17 00:00:00 2001 +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Eneas U de Queiroz Date: Sat, 3 Nov 2018 15:41:10 -0300 Subject: eng_devcrypto: add configuration options @@ -14,7 +14,6 @@ Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/7585) diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c -index a2c9a966f7..5ec38ca8f3 100644 --- a/crypto/engine/eng_devcrypto.c +++ b/crypto/engine/eng_devcrypto.c @@ -16,6 +16,7 @@ @@ -558,7 +557,7 @@ index a2c9a966f7..5ec38ca8f3 100644 /****************************************************************************** * * LOAD / UNLOAD -@@ -793,6 +1109,8 @@ void engine_load_devcrypto_int() +@@ -806,6 +1122,8 @@ void engine_load_devcrypto_int() if (!ENGINE_set_id(e, "devcrypto") || !ENGINE_set_name(e, "/dev/crypto engine") From 050621aa017273086d46ccf22dfb6942a367e049 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Tue, 25 May 2021 21:25:14 +0800 Subject: [PATCH 29/37] mediatek: add a new spi-nand driver for kernel 5.10 This patch adds a new spi-nand driver which implements the SNFI of mt7622 and mt7629. Unlike the existing snfi driver which makes use of the spi-mem framework and the spi-nand framework with modified ecc support, this driver is implemented directly on the mtd framework with other components untouched, and provides better performance, and behaves exactly the same as the nand framework. Signed-off-by: Weijie Gao --- .../files-5.10/drivers/mtd/mtk-snand/Kconfig | 13 + .../files-5.10/drivers/mtd/mtk-snand/Makefile | 10 + .../drivers/mtd/mtk-snand/mtk-snand-def.h | 268 +++ .../drivers/mtd/mtk-snand/mtk-snand-ecc.c | 379 ++++ .../drivers/mtd/mtk-snand/mtk-snand-ids.c | 511 +++++ .../drivers/mtd/mtk-snand/mtk-snand-mtd.c | 677 ++++++ .../drivers/mtd/mtk-snand/mtk-snand-os.c | 48 + .../drivers/mtd/mtk-snand/mtk-snand-os.h | 127 ++ .../drivers/mtd/mtk-snand/mtk-snand.c | 1862 +++++++++++++++++ .../drivers/mtd/mtk-snand/mtk-snand.h | 76 + .../360-mtd-add-mtk-snand-driver.patch | 21 + 11 files changed, 3992 insertions(+) create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Kconfig create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Makefile create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-def.h create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ecc.c create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ids.c create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.c create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.h create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.c create mode 100644 target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.h create mode 100644 target/linux/mediatek/patches-5.10/360-mtd-add-mtk-snand-driver.patch diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Kconfig b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Kconfig new file mode 100644 index 0000000000..58aa563832 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2020 MediaTek Inc. All rights reserved. +# Author: Weijie Gao +# + +config MTK_SPI_NAND + tristate "MediaTek SPI NAND flash controller driver" + depends on MTD + default n + help + This option enables access to SPI-NAND flashes through the + MTD interface of MediaTek SPI NAND Flash Controller diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Makefile b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Makefile new file mode 100644 index 0000000000..e6b3710046 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2020 MediaTek Inc. All rights reserved. +# Author: Weijie Gao +# + +obj-y += mtk-snand.o mtk-snand-ecc.o mtk-snand-ids.o mtk-snand-os.o \ + mtk-snand-mtd.o + +ccflags-y += -DPRIVATE_MTK_SNAND_HEADER diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-def.h b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-def.h new file mode 100644 index 0000000000..1a93d93dcd --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-def.h @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#ifndef _MTK_SNAND_DEF_H_ +#define _MTK_SNAND_DEF_H_ + +#include "mtk-snand-os.h" + +#ifdef PRIVATE_MTK_SNAND_HEADER +#include "mtk-snand.h" +#else +#include +#endif + +struct mtk_snand_plat_dev; + +enum snand_flash_io { + SNAND_IO_1_1_1, + SNAND_IO_1_1_2, + SNAND_IO_1_2_2, + SNAND_IO_1_1_4, + SNAND_IO_1_4_4, + + __SNAND_IO_MAX +}; + +#define SPI_IO_1_1_1 BIT(SNAND_IO_1_1_1) +#define SPI_IO_1_1_2 BIT(SNAND_IO_1_1_2) +#define SPI_IO_1_2_2 BIT(SNAND_IO_1_2_2) +#define SPI_IO_1_1_4 BIT(SNAND_IO_1_1_4) +#define SPI_IO_1_4_4 BIT(SNAND_IO_1_4_4) + +struct snand_opcode { + uint8_t opcode; + uint8_t dummy; +}; + +struct snand_io_cap { + uint8_t caps; + struct snand_opcode opcodes[__SNAND_IO_MAX]; +}; + +#define SNAND_OP(_io, _opcode, _dummy) [_io] = { .opcode = (_opcode), \ + .dummy = (_dummy) } + +#define SNAND_IO_CAP(_name, _caps, ...) \ + struct snand_io_cap _name = { .caps = (_caps), \ + .opcodes = { __VA_ARGS__ } } + +#define SNAND_MAX_ID_LEN 4 + +enum snand_id_type { + SNAND_ID_DYMMY, + SNAND_ID_ADDR = SNAND_ID_DYMMY, + SNAND_ID_DIRECT, + + __SNAND_ID_TYPE_MAX +}; + +struct snand_id { + uint8_t type; /* enum snand_id_type */ + uint8_t len; + uint8_t id[SNAND_MAX_ID_LEN]; +}; + +#define SNAND_ID(_type, ...) \ + { .type = (_type), .id = { __VA_ARGS__ }, \ + .len = sizeof((uint8_t[]) { __VA_ARGS__ }) } + +struct snand_mem_org { + uint16_t pagesize; + uint16_t sparesize; + uint16_t pages_per_block; + uint16_t blocks_per_die; + uint16_t planes_per_die; + uint16_t ndies; +}; + +#define SNAND_MEMORG(_ps, _ss, _ppb, _bpd, _ppd, _nd) \ + { .pagesize = (_ps), .sparesize = (_ss), .pages_per_block = (_ppb), \ + .blocks_per_die = (_bpd), .planes_per_die = (_ppd), .ndies = (_nd) } + +typedef int (*snand_select_die_t)(struct mtk_snand *snf, uint32_t dieidx); + +struct snand_flash_info { + const char *model; + struct snand_id id; + const struct snand_mem_org memorg; + const struct snand_io_cap *cap_rd; + const struct snand_io_cap *cap_pl; + snand_select_die_t select_die; +}; + +#define SNAND_INFO(_model, _id, _memorg, _cap_rd, _cap_pl, ...) \ + { .model = (_model), .id = _id, .memorg = _memorg, \ + .cap_rd = (_cap_rd), .cap_pl = (_cap_pl), __VA_ARGS__ } + +const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type, + const uint8_t *id); + +struct mtk_snand_soc_data { + uint16_t sector_size; + uint16_t max_sectors; + uint16_t fdm_size; + uint16_t fdm_ecc_size; + uint16_t fifo_size; + + bool bbm_swap; + bool empty_page_check; + uint32_t mastersta_mask; + + const uint8_t *spare_sizes; + uint32_t num_spare_size; +}; + +enum mtk_ecc_regs { + ECC_DECDONE, +}; + +struct mtk_ecc_soc_data { + const uint8_t *ecc_caps; + uint32_t num_ecc_cap; + const uint32_t *regs; + uint16_t mode_shift; + uint8_t errnum_bits; + uint8_t errnum_shift; +}; + +struct mtk_snand { + struct mtk_snand_plat_dev *pdev; + + void __iomem *nfi_base; + void __iomem *ecc_base; + + enum mtk_snand_soc soc; + const struct mtk_snand_soc_data *nfi_soc; + const struct mtk_ecc_soc_data *ecc_soc; + bool snfi_quad_spi; + bool quad_spi_op; + + const char *model; + uint64_t size; + uint64_t die_size; + uint32_t erasesize; + uint32_t writesize; + uint32_t oobsize; + + uint32_t num_dies; + snand_select_die_t select_die; + + uint8_t opcode_rfc; + uint8_t opcode_pl; + uint8_t dummy_rfc; + uint8_t mode_rfc; + uint8_t mode_pl; + + uint32_t writesize_mask; + uint32_t writesize_shift; + uint32_t erasesize_mask; + uint32_t erasesize_shift; + uint64_t die_mask; + uint32_t die_shift; + + uint32_t spare_per_sector; + uint32_t raw_sector_size; + uint32_t ecc_strength; + uint32_t ecc_steps; + uint32_t ecc_bytes; + uint32_t ecc_parity_bits; + + uint8_t *page_cache; /* Used by read/write page */ + uint8_t *buf_cache; /* Used by block bad/markbad & auto_oob */ + int *sect_bf; /* Used by ECC correction */ +}; + +enum mtk_snand_log_category { + SNAND_LOG_NFI, + SNAND_LOG_SNFI, + SNAND_LOG_ECC, + SNAND_LOG_CHIP, + + __SNAND_LOG_CAT_MAX +}; + +int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes, + uint32_t msg_size); +int mtk_snand_ecc_encoder_start(struct mtk_snand *snf); +void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf); +int mtk_snand_ecc_decoder_start(struct mtk_snand *snf); +void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf); +int mtk_ecc_wait_decoder_done(struct mtk_snand *snf); +int mtk_ecc_check_decode_error(struct mtk_snand *snf); +int mtk_ecc_fixup_empty_sector(struct mtk_snand *snf, uint32_t sect); + +int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen, + uint8_t *in, uint32_t inlen); +int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val); + +int mtk_snand_log(struct mtk_snand_plat_dev *pdev, + enum mtk_snand_log_category cat, const char *fmt, ...); + +#define snand_log_nfi(pdev, fmt, ...) \ + mtk_snand_log(pdev, SNAND_LOG_NFI, fmt, ##__VA_ARGS__) + +#define snand_log_snfi(pdev, fmt, ...) \ + mtk_snand_log(pdev, SNAND_LOG_SNFI, fmt, ##__VA_ARGS__) + +#define snand_log_ecc(pdev, fmt, ...) \ + mtk_snand_log(pdev, SNAND_LOG_ECC, fmt, ##__VA_ARGS__) + +#define snand_log_chip(pdev, fmt, ...) \ + mtk_snand_log(pdev, SNAND_LOG_CHIP, fmt, ##__VA_ARGS__) + +/* ffs64 */ +static inline int mtk_snand_ffs64(uint64_t x) +{ + if (!x) + return 0; + + if (!(x & 0xffffffff)) + return ffs((uint32_t)(x >> 32)) + 32; + + return ffs((uint32_t)(x & 0xffffffff)); +} + +/* NFI dummy commands */ +#define NFI_CMD_DUMMY_READ 0x00 +#define NFI_CMD_DUMMY_WRITE 0x80 + +/* SPI-NAND opcodes */ +#define SNAND_CMD_RESET 0xff +#define SNAND_CMD_BLOCK_ERASE 0xd8 +#define SNAND_CMD_READ_FROM_CACHE_QUAD 0xeb +#define SNAND_CMD_WINBOND_SELECT_DIE 0xc2 +#define SNAND_CMD_READ_FROM_CACHE_DUAL 0xbb +#define SNAND_CMD_READID 0x9f +#define SNAND_CMD_READ_FROM_CACHE_X4 0x6b +#define SNAND_CMD_READ_FROM_CACHE_X2 0x3b +#define SNAND_CMD_PROGRAM_LOAD_X4 0x32 +#define SNAND_CMD_SET_FEATURE 0x1f +#define SNAND_CMD_READ_TO_CACHE 0x13 +#define SNAND_CMD_PROGRAM_EXECUTE 0x10 +#define SNAND_CMD_GET_FEATURE 0x0f +#define SNAND_CMD_READ_FROM_CACHE 0x0b +#define SNAND_CMD_WRITE_ENABLE 0x06 +#define SNAND_CMD_PROGRAM_LOAD 0x02 + +/* SPI-NAND feature addresses */ +#define SNAND_FEATURE_MICRON_DIE_ADDR 0xd0 +#define SNAND_MICRON_DIE_SEL_1 BIT(6) + +#define SNAND_FEATURE_STATUS_ADDR 0xc0 +#define SNAND_STATUS_OIP BIT(0) +#define SNAND_STATUS_WEL BIT(1) +#define SNAND_STATUS_ERASE_FAIL BIT(2) +#define SNAND_STATUS_PROGRAM_FAIL BIT(3) + +#define SNAND_FEATURE_CONFIG_ADDR 0xb0 +#define SNAND_FEATURE_QUAD_ENABLE BIT(0) +#define SNAND_FEATURE_ECC_EN BIT(4) + +#define SNAND_FEATURE_PROTECT_ADDR 0xa0 + +#endif /* _MTK_SNAND_DEF_H_ */ diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ecc.c b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ecc.c new file mode 100644 index 0000000000..6dd0f346c8 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ecc.c @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#include "mtk-snand-def.h" + +/* ECC registers */ +#define ECC_ENCCON 0x000 +#define ENC_EN BIT(0) + +#define ECC_ENCCNFG 0x004 +#define ENC_MS_S 16 +#define ENC_BURST_EN BIT(8) +#define ENC_TNUM_S 0 + +#define ECC_ENCIDLE 0x00c +#define ENC_IDLE BIT(0) + +#define ECC_DECCON 0x100 +#define DEC_EN BIT(0) + +#define ECC_DECCNFG 0x104 +#define DEC_EMPTY_EN BIT(31) +#define DEC_CS_S 16 +#define DEC_CON_S 12 +#define DEC_CON_CORRECT 3 +#define DEC_BURST_EN BIT(8) +#define DEC_TNUM_S 0 + +#define ECC_DECIDLE 0x10c +#define DEC_IDLE BIT(0) + +#define ECC_DECENUM0 0x114 +#define ECC_DECENUM(n) (ECC_DECENUM0 + (n) * 4) + +/* ECC_ENCIDLE & ECC_DECIDLE */ +#define ECC_IDLE BIT(0) + +/* ENC_MODE & DEC_MODE */ +#define ECC_MODE_NFI 1 + +#define ECC_TIMEOUT 500000 + +static const uint8_t mt7622_ecc_caps[] = { 4, 6, 8, 10, 12 }; + +static const uint32_t mt7622_ecc_regs[] = { + [ECC_DECDONE] = 0x11c, +}; + +static const struct mtk_ecc_soc_data mtk_ecc_socs[__SNAND_SOC_MAX] = { + [SNAND_SOC_MT7622] = { + .ecc_caps = mt7622_ecc_caps, + .num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps), + .regs = mt7622_ecc_regs, + .mode_shift = 4, + .errnum_bits = 5, + .errnum_shift = 5, + }, + [SNAND_SOC_MT7629] = { + .ecc_caps = mt7622_ecc_caps, + .num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps), + .regs = mt7622_ecc_regs, + .mode_shift = 4, + .errnum_bits = 5, + .errnum_shift = 5, + }, +}; + +static inline uint32_t ecc_read32(struct mtk_snand *snf, uint32_t reg) +{ + return readl(snf->ecc_base + reg); +} + +static inline void ecc_write32(struct mtk_snand *snf, uint32_t reg, + uint32_t val) +{ + writel(val, snf->ecc_base + reg); +} + +static inline void ecc_write16(struct mtk_snand *snf, uint32_t reg, + uint16_t val) +{ + writew(val, snf->ecc_base + reg); +} + +static int mtk_ecc_poll(struct mtk_snand *snf, uint32_t reg, uint32_t bits) +{ + uint32_t val; + + return read16_poll_timeout(snf->ecc_base + reg, val, (val & bits), 0, + ECC_TIMEOUT); +} + +static int mtk_ecc_wait_idle(struct mtk_snand *snf, uint32_t reg) +{ + int ret; + + ret = mtk_ecc_poll(snf, reg, ECC_IDLE); + if (ret) { + snand_log_ecc(snf->pdev, "ECC engine is busy\n"); + return -EBUSY; + } + + return 0; +} + +int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes, + uint32_t msg_size) +{ + uint32_t i, val, ecc_msg_bits, ecc_strength; + int ret; + + snf->ecc_soc = &mtk_ecc_socs[snf->soc]; + + snf->ecc_parity_bits = fls(1 + 8 * msg_size); + ecc_strength = max_ecc_bytes * 8 / snf->ecc_parity_bits; + + for (i = snf->ecc_soc->num_ecc_cap - 1; i >= 0; i--) { + if (snf->ecc_soc->ecc_caps[i] <= ecc_strength) + break; + } + + if (unlikely(i < 0)) { + snand_log_ecc(snf->pdev, "Page size %u+%u is not supported\n", + snf->writesize, snf->oobsize); + return -ENOTSUPP; + } + + snf->ecc_strength = snf->ecc_soc->ecc_caps[i]; + snf->ecc_bytes = DIV_ROUND_UP(snf->ecc_strength * snf->ecc_parity_bits, + 8); + + /* Encoder config */ + ecc_write16(snf, ECC_ENCCON, 0); + ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE); + if (ret) + return ret; + + ecc_msg_bits = msg_size * 8; + val = (ecc_msg_bits << ENC_MS_S) | + (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i; + ecc_write32(snf, ECC_ENCCNFG, val); + + /* Decoder config */ + ecc_write16(snf, ECC_DECCON, 0); + ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE); + if (ret) + return ret; + + ecc_msg_bits += snf->ecc_strength * snf->ecc_parity_bits; + val = DEC_EMPTY_EN | (ecc_msg_bits << DEC_CS_S) | + (DEC_CON_CORRECT << DEC_CON_S) | + (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i; + ecc_write32(snf, ECC_DECCNFG, val); + + return 0; +} + +int mtk_snand_ecc_encoder_start(struct mtk_snand *snf) +{ + int ret; + + ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE); + if (ret) { + ecc_write16(snf, ECC_ENCCON, 0); + mtk_ecc_wait_idle(snf, ECC_ENCIDLE); + } + + ecc_write16(snf, ECC_ENCCON, ENC_EN); + + return 0; +} + +void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf) +{ + mtk_ecc_wait_idle(snf, ECC_ENCIDLE); + ecc_write16(snf, ECC_ENCCON, 0); +} + +int mtk_snand_ecc_decoder_start(struct mtk_snand *snf) +{ + int ret; + + ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE); + if (ret) { + ecc_write16(snf, ECC_DECCON, 0); + mtk_ecc_wait_idle(snf, ECC_DECIDLE); + } + + ecc_write16(snf, ECC_DECCON, DEC_EN); + + return 0; +} + +void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf) +{ + mtk_ecc_wait_idle(snf, ECC_DECIDLE); + ecc_write16(snf, ECC_DECCON, 0); +} + +int mtk_ecc_wait_decoder_done(struct mtk_snand *snf) +{ + uint16_t val, step_mask = (1 << snf->ecc_steps) - 1; + uint32_t reg = snf->ecc_soc->regs[ECC_DECDONE]; + int ret; + + ret = read16_poll_timeout(snf->ecc_base + reg, val, + (val & step_mask) == step_mask, 0, + ECC_TIMEOUT); + if (ret) + snand_log_ecc(snf->pdev, "ECC decoder is busy\n"); + + return ret; +} + +int mtk_ecc_check_decode_error(struct mtk_snand *snf) +{ + uint32_t i, regi, fi, errnum; + uint32_t errnum_shift = snf->ecc_soc->errnum_shift; + uint32_t errnum_mask = (1 << snf->ecc_soc->errnum_bits) - 1; + int ret = 0; + + for (i = 0; i < snf->ecc_steps; i++) { + regi = i / 4; + fi = i % 4; + + errnum = ecc_read32(snf, ECC_DECENUM(regi)); + errnum = (errnum >> (fi * errnum_shift)) & errnum_mask; + + if (errnum <= snf->ecc_strength) { + snf->sect_bf[i] = errnum; + } else { + snf->sect_bf[i] = -1; + ret = -EBADMSG; + } + } + + return ret; +} + +static int mtk_ecc_check_buf_bitflips(struct mtk_snand *snf, const void *buf, + size_t len, uint32_t bitflips) +{ + const uint8_t *buf8 = buf; + const uint32_t *buf32; + uint32_t d, weight; + + while (len && ((uintptr_t)buf8) % sizeof(uint32_t)) { + weight = hweight8(*buf8); + bitflips += BITS_PER_BYTE - weight; + buf8++; + len--; + + if (bitflips > snf->ecc_strength) + return -EBADMSG; + } + + buf32 = (const uint32_t *)buf8; + while (len >= sizeof(uint32_t)) { + d = *buf32; + + if (d != ~0) { + weight = hweight32(d); + bitflips += sizeof(uint32_t) * BITS_PER_BYTE - weight; + } + + buf32++; + len -= sizeof(uint32_t); + + if (bitflips > snf->ecc_strength) + return -EBADMSG; + } + + buf8 = (const uint8_t *)buf32; + while (len) { + weight = hweight8(*buf8); + bitflips += BITS_PER_BYTE - weight; + buf8++; + len--; + + if (bitflips > snf->ecc_strength) + return -EBADMSG; + } + + return bitflips; +} + +static int mtk_ecc_check_parity_bitflips(struct mtk_snand *snf, const void *buf, + uint32_t bits, uint32_t bitflips) +{ + uint32_t len, i; + uint8_t b; + int rc; + + len = bits >> 3; + bits &= 7; + + rc = mtk_ecc_check_buf_bitflips(snf, buf, len, bitflips); + if (!bits || rc < 0) + return rc; + + bitflips = rc; + + /* We want a precise count of bits */ + b = ((const uint8_t *)buf)[len]; + for (i = 0; i < bits; i++) { + if (!(b & BIT(i))) + bitflips++; + } + + if (bitflips > snf->ecc_strength) + return -EBADMSG; + + return bitflips; +} + +static void mtk_ecc_reset_parity(void *buf, uint32_t bits) +{ + uint32_t len; + + len = bits >> 3; + bits &= 7; + + memset(buf, 0xff, len); + + /* Only reset bits protected by ECC to 1 */ + if (bits) + ((uint8_t *)buf)[len] |= GENMASK(bits - 1, 0); +} + +int mtk_ecc_fixup_empty_sector(struct mtk_snand *snf, uint32_t sect) +{ + uint32_t ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size; + uint8_t *oob = snf->page_cache + snf->writesize; + uint8_t *data_ptr, *fdm_ptr, *ecc_ptr; + int bitflips = 0, ecc_bits, parity_bits; + + parity_bits = fls(snf->nfi_soc->sector_size * 8); + ecc_bits = snf->ecc_strength * parity_bits; + + data_ptr = snf->page_cache + sect * snf->nfi_soc->sector_size; + fdm_ptr = oob + sect * snf->nfi_soc->fdm_size; + ecc_ptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size + + sect * ecc_bytes; + + /* + * Check whether DATA + FDM + ECC of a sector contains correctable + * bitflips + */ + bitflips = mtk_ecc_check_buf_bitflips(snf, data_ptr, + snf->nfi_soc->sector_size, + bitflips); + if (bitflips < 0) + return -EBADMSG; + + bitflips = mtk_ecc_check_buf_bitflips(snf, fdm_ptr, + snf->nfi_soc->fdm_ecc_size, + bitflips); + if (bitflips < 0) + return -EBADMSG; + + bitflips = mtk_ecc_check_parity_bitflips(snf, ecc_ptr, ecc_bits, + bitflips); + if (bitflips < 0) + return -EBADMSG; + + if (!bitflips) + return 0; + + /* Reset the data of this sector to 0xff */ + memset(data_ptr, 0xff, snf->nfi_soc->sector_size); + memset(fdm_ptr, 0xff, snf->nfi_soc->fdm_ecc_size); + mtk_ecc_reset_parity(ecc_ptr, ecc_bits); + + return bitflips; +} diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ids.c b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ids.c new file mode 100644 index 0000000000..1756ff7e30 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-ids.c @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#include "mtk-snand-def.h" + +static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx); +static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx); + +#define SNAND_MEMORG_512M_2K_64 SNAND_MEMORG(2048, 64, 64, 512, 1, 1) +#define SNAND_MEMORG_1G_2K_64 SNAND_MEMORG(2048, 64, 64, 1024, 1, 1) +#define SNAND_MEMORG_2G_2K_64 SNAND_MEMORG(2048, 64, 64, 2048, 1, 1) +#define SNAND_MEMORG_2G_2K_120 SNAND_MEMORG(2048, 120, 64, 2048, 1, 1) +#define SNAND_MEMORG_4G_2K_64 SNAND_MEMORG(2048, 64, 64, 4096, 1, 1) +#define SNAND_MEMORG_1G_2K_120 SNAND_MEMORG(2048, 120, 64, 1024, 1, 1) +#define SNAND_MEMORG_1G_2K_128 SNAND_MEMORG(2048, 128, 64, 1024, 1, 1) +#define SNAND_MEMORG_2G_2K_128 SNAND_MEMORG(2048, 128, 64, 2048, 1, 1) +#define SNAND_MEMORG_4G_2K_128 SNAND_MEMORG(2048, 128, 64, 4096, 1, 1) +#define SNAND_MEMORG_4G_4K_240 SNAND_MEMORG(4096, 240, 64, 2048, 1, 1) +#define SNAND_MEMORG_4G_4K_256 SNAND_MEMORG(4096, 256, 64, 2048, 1, 1) +#define SNAND_MEMORG_8G_4K_256 SNAND_MEMORG(4096, 256, 64, 4096, 1, 1) +#define SNAND_MEMORG_2G_2K_64_2P SNAND_MEMORG(2048, 64, 64, 2048, 2, 1) +#define SNAND_MEMORG_2G_2K_64_2D SNAND_MEMORG(2048, 64, 64, 1024, 1, 2) +#define SNAND_MEMORG_2G_2K_128_2P SNAND_MEMORG(2048, 128, 64, 2048, 2, 1) +#define SNAND_MEMORG_4G_2K_64_2P SNAND_MEMORG(2048, 64, 64, 4096, 2, 1) +#define SNAND_MEMORG_4G_2K_128_2P_2D SNAND_MEMORG(2048, 128, 64, 2048, 2, 2) +#define SNAND_MEMORG_8G_4K_256_2D SNAND_MEMORG(4096, 256, 64, 2048, 1, 2) + +static const SNAND_IO_CAP(snand_cap_read_from_cache_quad, + SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 | + SPI_IO_1_4_4, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), + SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), + SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4), + SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8), + SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 4)); + +static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_q2d, + SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 | + SPI_IO_1_4_4, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), + SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), + SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4), + SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8), + SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 2)); + +static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_a8d, + SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 | + SPI_IO_1_4_4, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), + SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), + SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 8), + SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8), + SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 8)); + +static const SNAND_IO_CAP(snand_cap_read_from_cache_x4, + SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_1_4, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), + SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8), + SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8)); + +static const SNAND_IO_CAP(snand_cap_read_from_cache_x4_only, + SPI_IO_1_1_1 | SPI_IO_1_1_4, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8), + SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8)); + +static const SNAND_IO_CAP(snand_cap_program_load_x1, + SPI_IO_1_1_1, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0)); + +static const SNAND_IO_CAP(snand_cap_program_load_x4, + SPI_IO_1_1_1 | SPI_IO_1_1_4, + SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0), + SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_PROGRAM_LOAD_X4, 0)); + +static const struct snand_flash_info snand_flash_ids[] = { + SNAND_INFO("W25N512GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x20), + SNAND_MEMORG_512M_2K_64, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("W25N01GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x21), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("W25M02GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xab, 0x21), + SNAND_MEMORG_2G_2K_64_2D, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4, + mtk_snand_winbond_select_die), + SNAND_INFO("W25N02KV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x22), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + + SNAND_INFO("GD5F1GQ4UAWxx", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x10), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F1GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd1), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F1GQ4UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd9), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F1GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf1), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F2GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd2), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F2GQ5UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x32), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_a8d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F2GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf2), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F4GQ4UBxIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd4), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F4GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf4), + SNAND_MEMORG_4G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F2GQ5UExxG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x52), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("GD5F4GQ4UCxIG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0xb4), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + + SNAND_INFO("MX35LF1GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x12), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF1G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x14), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("MX31LF1GE4BC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x1e), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF2GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x22), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF2G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x24), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF2GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x26), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF2G14AC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x20), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF4G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x35), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("MX35LF4GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x37), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + + SNAND_INFO("MT29F1G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x12), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x1), + SNAND_INFO("MT29F1G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x14), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("MT29F2G01AAAED", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x9f), + SNAND_MEMORG_2G_2K_64_2P, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x1), + SNAND_INFO("MT29F2G01ABAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x24), + SNAND_MEMORG_2G_2K_128_2P, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("MT29F4G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x32), + SNAND_MEMORG_4G_2K_64_2P, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x1), + SNAND_INFO("MT29F4G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x34), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("MT29F4G01ADAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x36), + SNAND_MEMORG_4G_2K_128_2P_2D, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4, + mtk_snand_micron_select_die), + SNAND_INFO("MT29F8G01ADAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x46), + SNAND_MEMORG_8G_4K_256_2D, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4, + mtk_snand_micron_select_die), + + SNAND_INFO("TC58CVG0S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xc2), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x1), + SNAND_INFO("TC58CVG1S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcb), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x1), + SNAND_INFO("TC58CVG2S0HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcd), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x1), + SNAND_INFO("TC58CVG0S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe2), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("TC58CVG1S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xeb), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("TC58CVG2S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xed), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("TH58CVG3S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe4), + SNAND_MEMORG_8G_4K_256, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + + SNAND_INFO("F50L512M41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x20), + SNAND_MEMORG_512M_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("F50L1G41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + SNAND_INFO("F50L1G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x01), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4), + SNAND_INFO("F50L2G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x0a), + SNAND_MEMORG_2G_2K_64_2D, + &snand_cap_read_from_cache_quad, + &snand_cap_program_load_x4, + mtk_snand_winbond_select_die), + + SNAND_INFO("CS11G0T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x00), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("CS11G0G0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x10), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("CS11G0S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x20), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("CS11G1T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x01), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("CS11G1S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x21), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("CS11G2T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x02), + SNAND_MEMORG_4G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("CS11G2S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x22), + SNAND_MEMORG_4G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + + SNAND_INFO("EM73B044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x01), + SNAND_MEMORG_512M_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x11), + SNAND_MEMORG_1G_2K_120, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x09), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x18), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x19), + SNAND_MEMORG(2048, 64, 128, 512, 1, 1), + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1c), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1e), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044VCC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x22), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044VCF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x25), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x31), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0a), + SNAND_MEMORG_2G_2K_120, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x12), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x10), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x13), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x14), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x17), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCH", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1b), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1f), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x20), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCL", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2e), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x32), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73E044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x03), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73E044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0b), + SNAND_MEMORG_4G_4K_240, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73E044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x23), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73E044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2c), + SNAND_MEMORG_4G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73E044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2f), + SNAND_MEMORG_4G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73F044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x24), + SNAND_MEMORG_8G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73F044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2d), + SNAND_MEMORG_8G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73E044SNE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0e), + SNAND_MEMORG_8G_4K_256, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73C044SNG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0c), + SNAND_MEMORG_1G_2K_120, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("EM73D044VCN", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0f), + SNAND_MEMORG_2G_2K_64, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + + SNAND_INFO("FM35Q1GA", SNAND_ID(SNAND_ID_DYMMY, 0xe5, 0x71), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + + SNAND_INFO("PN26G01A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe1), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("PN26G02A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe2), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + + SNAND_INFO("IS37SML01G1", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4, + &snand_cap_program_load_x4), + + SNAND_INFO("ATO25D1GA", SNAND_ID(SNAND_ID_DYMMY, 0x9b, 0x12), + SNAND_MEMORG_1G_2K_64, + &snand_cap_read_from_cache_x4_only, + &snand_cap_program_load_x4), + + SNAND_INFO("HYF1GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x51), + SNAND_MEMORG_1G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), + SNAND_INFO("HYF2GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x52), + SNAND_MEMORG_2G_2K_128, + &snand_cap_read_from_cache_quad_q2d, + &snand_cap_program_load_x4), +}; + +static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx) +{ + uint8_t op[2]; + + if (dieidx > 1) { + snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx); + return -EINVAL; + } + + op[0] = SNAND_CMD_WINBOND_SELECT_DIE; + op[1] = (uint8_t)dieidx; + + return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0); +} + +static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx) +{ + int ret; + + if (dieidx > 1) { + snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx); + return -EINVAL; + } + + ret = mtk_snand_set_feature(snf, SNAND_FEATURE_MICRON_DIE_ADDR, + SNAND_MICRON_DIE_SEL_1); + if (ret) { + snand_log_chip(snf->pdev, + "Failed to set die selection feature\n"); + return ret; + } + + return 0; +} + +const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type, + const uint8_t *id) +{ + const struct snand_id *fid; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(snand_flash_ids); i++) { + if (snand_flash_ids[i].id.type != type) + continue; + + fid = &snand_flash_ids[i].id; + if (memcmp(fid->id, id, fid->len)) + continue; + + return &snand_flash_ids[i]; + } + + return NULL; +} diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c new file mode 100644 index 0000000000..b0fcda446d --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c @@ -0,0 +1,677 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk-snand.h" +#include "mtk-snand-os.h" + +struct mtk_snand_of_id { + enum mtk_snand_soc soc; +}; + +struct mtk_snand_mtd { + struct mtk_snand_plat_dev pdev; + + struct clk *nfi_clk; + struct clk *pad_clk; + struct clk *ecc_clk; + + void __iomem *nfi_regs; + void __iomem *ecc_regs; + + int irq; + + bool quad_spi; + enum mtk_snand_soc soc; + + struct mtd_info mtd; + struct mtk_snand *snf; + struct mtk_snand_chip_info cinfo; + uint8_t *page_cache; + struct mutex lock; +}; + +#define mtd_to_msm(mtd) container_of(mtd, struct mtk_snand_mtd, mtd) + +static int mtk_snand_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + u64 start_addr, end_addr; + int ret; + + /* Do not allow write past end of device */ + if ((instr->addr + instr->len) > mtd->size) { + dev_err(msm->pdev.dev, + "attempt to erase beyond end of device\n"); + return -EINVAL; + } + + start_addr = instr->addr & (~mtd->erasesize_mask); + end_addr = instr->addr + instr->len; + if (end_addr & mtd->erasesize_mask) { + end_addr = (end_addr + mtd->erasesize_mask) & + (~mtd->erasesize_mask); + } + + mutex_lock(&msm->lock); + + while (start_addr < end_addr) { + if (mtk_snand_block_isbad(msm->snf, start_addr)) { + instr->fail_addr = start_addr; + ret = -EIO; + break; + } + + ret = mtk_snand_erase_block(msm->snf, start_addr); + if (ret) { + instr->fail_addr = start_addr; + break; + } + + start_addr += mtd->erasesize; + } + + mutex_unlock(&msm->lock); + + return ret; +} + +static int mtk_snand_mtd_read_data(struct mtk_snand_mtd *msm, uint64_t addr, + struct mtd_oob_ops *ops) +{ + struct mtd_info *mtd = &msm->mtd; + size_t len, ooblen, maxooblen, chklen; + uint32_t col, ooboffs; + uint8_t *datcache, *oobcache; + bool ecc_failed = false, raw = ops->mode == MTD_OPS_RAW ? true : false; + int ret, max_bitflips = 0; + + col = addr & mtd->writesize_mask; + addr &= ~mtd->writesize_mask; + maxooblen = mtd_oobavail(mtd, ops); + ooboffs = ops->ooboffs; + ooblen = ops->ooblen; + len = ops->len; + + datcache = len ? msm->page_cache : NULL; + oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL; + + ops->oobretlen = 0; + ops->retlen = 0; + + while (len || ooblen) { + if (ops->mode == MTD_OPS_AUTO_OOB) + ret = mtk_snand_read_page_auto_oob(msm->snf, addr, + datcache, oobcache, maxooblen, NULL, raw); + else + ret = mtk_snand_read_page(msm->snf, addr, datcache, + oobcache, raw); + + if (ret < 0 && ret != -EBADMSG) + return ret; + + if (ret == -EBADMSG) { + mtd->ecc_stats.failed++; + ecc_failed = true; + } else { + mtd->ecc_stats.corrected += ret; + max_bitflips = max_t(int, ret, max_bitflips); + } + + if (len) { + /* Move data */ + chklen = mtd->writesize - col; + if (chklen > len) + chklen = len; + + memcpy(ops->datbuf + ops->retlen, datcache + col, + chklen); + len -= chklen; + col = 0; /* (col + chklen) % */ + ops->retlen += chklen; + } + + if (ooblen) { + /* Move oob */ + chklen = maxooblen - ooboffs; + if (chklen > ooblen) + chklen = ooblen; + + memcpy(ops->oobbuf + ops->oobretlen, oobcache + ooboffs, + chklen); + ooblen -= chklen; + ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */ + ops->oobretlen += chklen; + } + + addr += mtd->writesize; + } + + return ecc_failed ? -EBADMSG : max_bitflips; +} + +static int mtk_snand_mtd_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + uint32_t maxooblen; + int ret; + + if (!ops->oobbuf && !ops->datbuf) { + if (ops->ooblen || ops->len) + return -EINVAL; + + return 0; + } + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: + break; + default: + dev_err(msm->pdev.dev, "unsupported oob mode: %u\n", ops->mode); + return -EINVAL; + } + + maxooblen = mtd_oobavail(mtd, ops); + + /* Do not allow read past end of device */ + if (ops->datbuf && (from + ops->len) > mtd->size) { + dev_err(msm->pdev.dev, + "attempt to read beyond end of device\n"); + return -EINVAL; + } + + if (unlikely(ops->ooboffs >= maxooblen)) { + dev_err(msm->pdev.dev, "attempt to start read outside oob\n"); + return -EINVAL; + } + + if (unlikely(from >= mtd->size || + ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) - + (from >> mtd->writesize_shift)) * maxooblen)) { + dev_err(msm->pdev.dev, + "attempt to read beyond end of device\n"); + return -EINVAL; + } + + mutex_lock(&msm->lock); + ret = mtk_snand_mtd_read_data(msm, from, ops); + mutex_unlock(&msm->lock); + + return ret; +} + +static int mtk_snand_mtd_write_data(struct mtk_snand_mtd *msm, uint64_t addr, + struct mtd_oob_ops *ops) +{ + struct mtd_info *mtd = &msm->mtd; + size_t len, ooblen, maxooblen, chklen, oobwrlen; + uint32_t col, ooboffs; + uint8_t *datcache, *oobcache; + bool raw = ops->mode == MTD_OPS_RAW ? true : false; + int ret; + + col = addr & mtd->writesize_mask; + addr &= ~mtd->writesize_mask; + maxooblen = mtd_oobavail(mtd, ops); + ooboffs = ops->ooboffs; + ooblen = ops->ooblen; + len = ops->len; + + datcache = len ? msm->page_cache : NULL; + oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL; + + ops->oobretlen = 0; + ops->retlen = 0; + + while (len || ooblen) { + if (len) { + /* Move data */ + chklen = mtd->writesize - col; + if (chklen > len) + chklen = len; + + memset(datcache, 0xff, col); + memcpy(datcache + col, ops->datbuf + ops->retlen, + chklen); + memset(datcache + col + chklen, 0xff, + mtd->writesize - col - chklen); + len -= chklen; + col = 0; /* (col + chklen) % */ + ops->retlen += chklen; + } + + oobwrlen = 0; + if (ooblen) { + /* Move oob */ + chklen = maxooblen - ooboffs; + if (chklen > ooblen) + chklen = ooblen; + + memset(oobcache, 0xff, ooboffs); + memcpy(oobcache + ooboffs, + ops->oobbuf + ops->oobretlen, chklen); + memset(oobcache + ooboffs + chklen, 0xff, + mtd->oobsize - ooboffs - chklen); + oobwrlen = chklen + ooboffs; + ooblen -= chklen; + ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */ + ops->oobretlen += chklen; + } + + if (ops->mode == MTD_OPS_AUTO_OOB) + ret = mtk_snand_write_page_auto_oob(msm->snf, addr, + datcache, oobcache, oobwrlen, NULL, raw); + else + ret = mtk_snand_write_page(msm->snf, addr, datcache, + oobcache, raw); + + if (ret) + return ret; + + addr += mtd->writesize; + } + + return 0; +} + +static int mtk_snand_mtd_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + uint32_t maxooblen; + int ret; + + if (!ops->oobbuf && !ops->datbuf) { + if (ops->ooblen || ops->len) + return -EINVAL; + + return 0; + } + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: + break; + default: + dev_err(msm->pdev.dev, "unsupported oob mode: %u\n", ops->mode); + return -EINVAL; + } + + maxooblen = mtd_oobavail(mtd, ops); + + /* Do not allow write past end of device */ + if (ops->datbuf && (to + ops->len) > mtd->size) { + dev_err(msm->pdev.dev, + "attempt to write beyond end of device\n"); + return -EINVAL; + } + + if (unlikely(ops->ooboffs >= maxooblen)) { + dev_err(msm->pdev.dev, + "attempt to start write outside oob\n"); + return -EINVAL; + } + + if (unlikely(to >= mtd->size || + ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) - + (to >> mtd->writesize_shift)) * maxooblen)) { + dev_err(msm->pdev.dev, + "attempt to write beyond end of device\n"); + return -EINVAL; + } + + mutex_lock(&msm->lock); + ret = mtk_snand_mtd_write_data(msm, to, ops); + mutex_unlock(&msm->lock); + + return ret; +} + +static int mtk_snand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + int ret; + + mutex_lock(&msm->lock); + ret = mtk_snand_block_isbad(msm->snf, offs); + mutex_unlock(&msm->lock); + + return ret; +} + +static int mtk_snand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + int ret; + + mutex_lock(&msm->lock); + ret = mtk_snand_block_markbad(msm->snf, offs); + mutex_unlock(&msm->lock); + + return ret; +} + +static int mtk_snand_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobecc) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + + if (section) + return -ERANGE; + + oobecc->offset = msm->cinfo.fdm_size * msm->cinfo.num_sectors; + oobecc->length = mtd->oobsize - oobecc->offset; + + return 0; +} + +static int mtk_snand_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobfree) +{ + struct mtk_snand_mtd *msm = mtd_to_msm(mtd); + + if (section >= msm->cinfo.num_sectors) + return -ERANGE; + + oobfree->length = msm->cinfo.fdm_size - 1; + oobfree->offset = section * msm->cinfo.fdm_size + 1; + + return 0; +} + +static irqreturn_t mtk_snand_irq(int irq, void *id) +{ + struct mtk_snand_mtd *msm = id; + int ret; + + ret = mtk_snand_irq_process(msm->snf); + if (ret > 0) + return IRQ_HANDLED; + + return IRQ_NONE; +} + +static int mtk_snand_enable_clk(struct mtk_snand_mtd *msm) +{ + int ret; + + ret = clk_prepare_enable(msm->nfi_clk); + if (ret) { + dev_err(msm->pdev.dev, "unable to enable nfi clk\n"); + return ret; + } + + ret = clk_prepare_enable(msm->pad_clk); + if (ret) { + dev_err(msm->pdev.dev, "unable to enable pad clk\n"); + clk_disable_unprepare(msm->nfi_clk); + return ret; + } + + ret = clk_prepare_enable(msm->ecc_clk); + if (ret) { + dev_err(msm->pdev.dev, "unable to enable ecc clk\n"); + clk_disable_unprepare(msm->nfi_clk); + clk_disable_unprepare(msm->pad_clk); + return ret; + } + + return 0; +} + +static void mtk_snand_disable_clk(struct mtk_snand_mtd *msm) +{ + clk_disable_unprepare(msm->nfi_clk); + clk_disable_unprepare(msm->pad_clk); + clk_disable_unprepare(msm->ecc_clk); +} + +static const struct mtd_ooblayout_ops mtk_snand_ooblayout = { + .ecc = mtk_snand_ooblayout_ecc, + .free = mtk_snand_ooblayout_free, +}; + +static struct mtk_snand_of_id mt7622_soc_id = { .soc = SNAND_SOC_MT7622 }; +static struct mtk_snand_of_id mt7629_soc_id = { .soc = SNAND_SOC_MT7629 }; + +static const struct of_device_id mtk_snand_ids[] = { + { .compatible = "mediatek,mt7622-snand", .data = &mt7622_soc_id }, + { .compatible = "mediatek,mt7629-snand", .data = &mt7629_soc_id }, + { }, +}; + +MODULE_DEVICE_TABLE(of, mtk_snand_ids); + +static int mtk_snand_probe(struct platform_device *pdev) +{ + struct mtk_snand_platdata mtk_snand_pdata = {}; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_soc_id; + const struct mtk_snand_of_id *soc_id; + struct mtk_snand_mtd *msm; + struct mtd_info *mtd; + struct resource *r; + uint32_t size; + int ret; + + of_soc_id = of_match_node(mtk_snand_ids, np); + if (!of_soc_id) + return -EINVAL; + + soc_id = of_soc_id->data; + + msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL); + if (!msm) + return -ENOMEM; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi"); + msm->nfi_regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(msm->nfi_regs)) { + ret = PTR_ERR(msm->nfi_regs); + goto errout1; + } + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc"); + msm->ecc_regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(msm->ecc_regs)) { + ret = PTR_ERR(msm->ecc_regs); + goto errout1; + } + + msm->pdev.dev = &pdev->dev; + msm->quad_spi = of_property_read_bool(np, "mediatek,quad-spi"); + msm->soc = soc_id->soc; + + msm->nfi_clk = devm_clk_get(msm->pdev.dev, "nfi_clk"); + if (IS_ERR(msm->nfi_clk)) { + ret = PTR_ERR(msm->nfi_clk); + dev_err(msm->pdev.dev, "unable to get nfi_clk, err = %d\n", + ret); + goto errout1; + } + + msm->ecc_clk = devm_clk_get(msm->pdev.dev, "ecc_clk"); + if (IS_ERR(msm->ecc_clk)) { + ret = PTR_ERR(msm->ecc_clk); + dev_err(msm->pdev.dev, "unable to get ecc_clk, err = %d\n", + ret); + goto errout1; + } + + msm->pad_clk = devm_clk_get(msm->pdev.dev, "pad_clk"); + if (IS_ERR(msm->pad_clk)) { + ret = PTR_ERR(msm->pad_clk); + dev_err(msm->pdev.dev, "unable to get pad_clk, err = %d\n", + ret); + goto errout1; + } + + ret = mtk_snand_enable_clk(msm); + if (ret) + goto errout1; + + /* Probe SPI-NAND Flash */ + mtk_snand_pdata.soc = msm->soc; + mtk_snand_pdata.quad_spi = msm->quad_spi; + mtk_snand_pdata.nfi_base = msm->nfi_regs; + mtk_snand_pdata.ecc_base = msm->ecc_regs; + + ret = mtk_snand_init(&msm->pdev, &mtk_snand_pdata, &msm->snf); + if (ret) + goto errout1; + + msm->irq = platform_get_irq(pdev, 0); + if (msm->irq >= 0) { + ret = devm_request_irq(msm->pdev.dev, msm->irq, mtk_snand_irq, + 0x0, "mtk-snand", msm); + if (ret) { + dev_err(msm->pdev.dev, "failed to request snfi irq\n"); + goto errout2; + } + + ret = dma_set_mask(msm->pdev.dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(msm->pdev.dev, "failed to set dma mask\n"); + goto errout3; + } + } + + mtk_snand_get_chip_info(msm->snf, &msm->cinfo); + + size = msm->cinfo.pagesize + msm->cinfo.sparesize; + msm->page_cache = devm_kmalloc(msm->pdev.dev, size, GFP_KERNEL); + if (!msm->page_cache) { + dev_err(msm->pdev.dev, "failed to allocate page cache\n"); + ret = -ENOMEM; + goto errout3; + } + + mutex_init(&msm->lock); + + dev_info(msm->pdev.dev, + "chip is %s, size %lluMB, page size %u, oob size %u\n", + msm->cinfo.model, msm->cinfo.chipsize >> 20, + msm->cinfo.pagesize, msm->cinfo.sparesize); + + /* Initialize mtd for SPI-NAND */ + mtd = &msm->mtd; + + mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + + mtd_set_of_node(mtd, np); + + mtd->size = msm->cinfo.chipsize; + mtd->erasesize = msm->cinfo.blocksize; + mtd->writesize = msm->cinfo.pagesize; + mtd->writebufsize = mtd->writesize; + mtd->oobsize = msm->cinfo.sparesize; + mtd->oobavail = msm->cinfo.num_sectors * (msm->cinfo.fdm_size - 1); + + mtd->erasesize_shift = ffs(mtd->erasesize) - 1; + mtd->writesize_shift = ffs(mtd->writesize) - 1; + mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; + mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; + + mtd->ooblayout = &mtk_snand_ooblayout; + + mtd->ecc_strength = msm->cinfo.ecc_strength; + mtd->bitflip_threshold = (mtd->ecc_strength * 3) / 4; + mtd->ecc_step_size = msm->cinfo.sector_size; + + mtd->_erase = mtk_snand_mtd_erase; + mtd->_read_oob = mtk_snand_mtd_read_oob; + mtd->_write_oob = mtk_snand_mtd_write_oob; + mtd->_block_isbad = mtk_snand_mtd_block_isbad; + mtd->_block_markbad = mtk_snand_mtd_block_markbad; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + dev_err(msm->pdev.dev, "failed to register mtd partition\n"); + goto errout4; + } + + platform_set_drvdata(pdev, msm); + + return 0; + +errout4: + devm_kfree(msm->pdev.dev, msm->page_cache); + +errout3: + if (msm->irq >= 0) + devm_free_irq(msm->pdev.dev, msm->irq, msm); + +errout2: + mtk_snand_cleanup(msm->snf); + +errout1: + devm_kfree(msm->pdev.dev, msm); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int mtk_snand_remove(struct platform_device *pdev) +{ + struct mtk_snand_mtd *msm = platform_get_drvdata(pdev); + struct mtd_info *mtd = &msm->mtd; + int ret; + + ret = mtd_device_unregister(mtd); + if (ret) + return ret; + + mtk_snand_cleanup(msm->snf); + + if (msm->irq >= 0) + devm_free_irq(msm->pdev.dev, msm->irq, msm); + + mtk_snand_disable_clk(msm); + + devm_kfree(msm->pdev.dev, msm->page_cache); + devm_kfree(msm->pdev.dev, msm); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver mtk_snand_driver = { + .probe = mtk_snand_probe, + .remove = mtk_snand_remove, + .driver = { + .name = "mtk-snand", + .of_match_table = mtk_snand_ids, + }, +}; + +module_platform_driver(mtk_snand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Weijie Gao "); +MODULE_DESCRIPTION("MeidaTek SPI-NAND Flash Controller Driver"); diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.c b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.c new file mode 100644 index 0000000000..0c3ffec8b4 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#include "mtk-snand-def.h" + +int mtk_snand_log(struct mtk_snand_plat_dev *pdev, + enum mtk_snand_log_category cat, const char *fmt, ...) +{ + const char *catname = ""; + va_list ap; + char *msg; + + switch (cat) { + case SNAND_LOG_NFI: + catname = "NFI"; + break; + case SNAND_LOG_SNFI: + catname = "SNFI"; + break; + case SNAND_LOG_ECC: + catname = "ECC"; + break; + default: + break; + } + + va_start(ap, fmt); + msg = kvasprintf(GFP_KERNEL, fmt, ap); + va_end(ap); + + if (!msg) { + dev_warn(pdev->dev, "unable to print log\n"); + return -1; + } + + if (*catname) + dev_warn(pdev->dev, "%s: %s", catname, msg); + else + dev_warn(pdev->dev, "%s", msg); + + kfree(msg); + + return 0; +} diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.h b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.h new file mode 100644 index 0000000000..eeeb83b53d --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-os.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#ifndef _MTK_SNAND_OS_H_ +#define _MTK_SNAND_OS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mtk_snand_plat_dev { + struct device *dev; + struct completion done; +}; + +/* Polling helpers */ +#define read16_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ + readw_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us)) + +#define read32_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ + readl_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us)) + +/* Timer helpers */ +#define mtk_snand_time_t ktime_t + +static inline mtk_snand_time_t timer_get_ticks(void) +{ + return ktime_get(); +} + +static inline mtk_snand_time_t timer_time_to_tick(uint32_t timeout_us) +{ + return ktime_add_us(ktime_set(0, 0), timeout_us); +} + +static inline bool timer_is_timeout(mtk_snand_time_t start_tick, + mtk_snand_time_t timeout_tick) +{ + ktime_t tmo = ktime_add(start_tick, timeout_tick); + + return ktime_compare(ktime_get(), tmo) > 0; +} + +/* Memory helpers */ +static inline void *generic_mem_alloc(struct mtk_snand_plat_dev *pdev, + size_t size) +{ + return devm_kzalloc(pdev->dev, size, GFP_KERNEL); +} +static inline void generic_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr) +{ + devm_kfree(pdev->dev, ptr); +} + +static inline void *dma_mem_alloc(struct mtk_snand_plat_dev *pdev, size_t size) +{ + return kzalloc(size, GFP_KERNEL); +} +static inline void dma_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr) +{ + kfree(ptr); +} + +static inline int dma_mem_map(struct mtk_snand_plat_dev *pdev, void *vaddr, + uintptr_t *dma_addr, size_t size, bool to_device) +{ + dma_addr_t addr; + int ret; + + addr = dma_map_single(pdev->dev, vaddr, size, + to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + ret = dma_mapping_error(pdev->dev, addr); + if (ret) + return ret; + + *dma_addr = (uintptr_t)addr; + + return 0; +} + +static inline void dma_mem_unmap(struct mtk_snand_plat_dev *pdev, + uintptr_t dma_addr, size_t size, + bool to_device) +{ + dma_unmap_single(pdev->dev, dma_addr, size, + to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +} + +/* Interrupt helpers */ +static inline void irq_completion_done(struct mtk_snand_plat_dev *pdev) +{ + complete(&pdev->done); +} + +static inline void irq_completion_init(struct mtk_snand_plat_dev *pdev) +{ + init_completion(&pdev->done); +} + +static inline int irq_completion_wait(struct mtk_snand_plat_dev *pdev, + void __iomem *reg, uint32_t bit, + uint32_t timeout_us) +{ + int ret; + + ret = wait_for_completion_timeout(&pdev->done, + usecs_to_jiffies(timeout_us)); + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +#endif /* _MTK_SNAND_OS_H_ */ diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.c b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.c new file mode 100644 index 0000000000..729fd82d39 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.c @@ -0,0 +1,1862 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#include "mtk-snand-def.h" + +/* NFI registers */ +#define NFI_CNFG 0x000 +#define CNFG_OP_MODE_S 12 +#define CNFG_OP_MODE_CUST 6 +#define CNFG_OP_MODE_PROGRAM 3 +#define CNFG_AUTO_FMT_EN BIT(9) +#define CNFG_HW_ECC_EN BIT(8) +#define CNFG_DMA_BURST_EN BIT(2) +#define CNFG_READ_MODE BIT(1) +#define CNFG_DMA_MODE BIT(0) + +#define NFI_PAGEFMT 0x0004 +#define NFI_SPARE_SIZE_LS_S 16 +#define NFI_FDM_ECC_NUM_S 12 +#define NFI_FDM_NUM_S 8 +#define NFI_SPARE_SIZE_S 4 +#define NFI_SEC_SEL_512 BIT(2) +#define NFI_PAGE_SIZE_S 0 +#define NFI_PAGE_SIZE_512_2K 0 +#define NFI_PAGE_SIZE_2K_4K 1 +#define NFI_PAGE_SIZE_4K_8K 2 +#define NFI_PAGE_SIZE_8K_16K 3 + +#define NFI_CON 0x008 +#define CON_SEC_NUM_S 12 +#define CON_BWR BIT(9) +#define CON_BRD BIT(8) +#define CON_NFI_RST BIT(1) +#define CON_FIFO_FLUSH BIT(0) + +#define NFI_INTR_EN 0x010 +#define NFI_INTR_STA 0x014 +#define NFI_IRQ_INTR_EN BIT(31) +#define NFI_IRQ_CUS_READ BIT(8) +#define NFI_IRQ_CUS_PG BIT(7) + +#define NFI_CMD 0x020 + +#define NFI_STRDATA 0x040 +#define STR_DATA BIT(0) + +#define NFI_STA 0x060 +#define NFI_NAND_FSM GENMASK(28, 24) +#define NFI_FSM GENMASK(19, 16) +#define READ_EMPTY BIT(12) + +#define NFI_FIFOSTA 0x064 +#define FIFO_WR_REMAIN_S 8 +#define FIFO_RD_REMAIN_S 0 + +#define NFI_ADDRCNTR 0x070 +#define SEC_CNTR GENMASK(16, 12) +#define SEC_CNTR_S 12 +#define NFI_SEC_CNTR(val) (((val) & SEC_CNTR) >> SEC_CNTR_S) + +#define NFI_STRADDR 0x080 + +#define NFI_BYTELEN 0x084 +#define BUS_SEC_CNTR(val) (((val) & SEC_CNTR) >> SEC_CNTR_S) + +#define NFI_FDM0L 0x0a0 +#define NFI_FDM0M 0x0a4 +#define NFI_FDML(n) (NFI_FDM0L + (n) * 8) +#define NFI_FDMM(n) (NFI_FDM0M + (n) * 8) + +#define NFI_DEBUG_CON1 0x220 +#define WBUF_EN BIT(2) + +#define NFI_MASTERSTA 0x224 +#define MAS_ADDR GENMASK(11, 9) +#define MAS_RD GENMASK(8, 6) +#define MAS_WR GENMASK(5, 3) +#define MAS_RDDLY GENMASK(2, 0) +#define NFI_MASTERSTA_MASK_7622 (MAS_ADDR | MAS_RD | MAS_WR | MAS_RDDLY) + +/* SNFI registers */ +#define SNF_MAC_CTL 0x500 +#define MAC_XIO_SEL BIT(4) +#define SF_MAC_EN BIT(3) +#define SF_TRIG BIT(2) +#define WIP_READY BIT(1) +#define WIP BIT(0) + +#define SNF_MAC_OUTL 0x504 +#define SNF_MAC_INL 0x508 + +#define SNF_RD_CTL2 0x510 +#define DATA_READ_DUMMY_S 8 +#define DATA_READ_CMD_S 0 + +#define SNF_RD_CTL3 0x514 + +#define SNF_PG_CTL1 0x524 +#define PG_LOAD_CMD_S 8 + +#define SNF_PG_CTL2 0x528 + +#define SNF_MISC_CTL 0x538 +#define SW_RST BIT(28) +#define FIFO_RD_LTC_S 25 +#define PG_LOAD_X4_EN BIT(20) +#define DATA_READ_MODE_S 16 +#define DATA_READ_MODE GENMASK(18, 16) +#define DATA_READ_MODE_X1 0 +#define DATA_READ_MODE_X2 1 +#define DATA_READ_MODE_X4 2 +#define DATA_READ_MODE_DUAL 5 +#define DATA_READ_MODE_QUAD 6 +#define PG_LOAD_CUSTOM_EN BIT(7) +#define DATARD_CUSTOM_EN BIT(6) +#define CS_DESELECT_CYC_S 0 + +#define SNF_MISC_CTL2 0x53c +#define PROGRAM_LOAD_BYTE_NUM_S 16 +#define READ_DATA_BYTE_NUM_S 11 + +#define SNF_DLY_CTL3 0x548 +#define SFCK_SAM_DLY_S 0 + +#define SNF_STA_CTL1 0x550 +#define CUS_PG_DONE BIT(28) +#define CUS_READ_DONE BIT(27) +#define SPI_STATE_S 0 +#define SPI_STATE GENMASK(3, 0) + +#define SNF_CFG 0x55c +#define SPI_MODE BIT(0) + +#define SNF_GPRAM 0x800 +#define SNF_GPRAM_SIZE 0xa0 + +#define SNFI_POLL_INTERVAL 1000000 + +static const uint8_t mt7622_spare_sizes[] = { 16, 26, 27, 28 }; + +static const struct mtk_snand_soc_data mtk_snand_socs[__SNAND_SOC_MAX] = { + [SNAND_SOC_MT7622] = { + .sector_size = 512, + .max_sectors = 8, + .fdm_size = 8, + .fdm_ecc_size = 1, + .fifo_size = 32, + .bbm_swap = false, + .empty_page_check = false, + .mastersta_mask = NFI_MASTERSTA_MASK_7622, + .spare_sizes = mt7622_spare_sizes, + .num_spare_size = ARRAY_SIZE(mt7622_spare_sizes) + }, + [SNAND_SOC_MT7629] = { + .sector_size = 512, + .max_sectors = 8, + .fdm_size = 8, + .fdm_ecc_size = 1, + .fifo_size = 32, + .bbm_swap = true, + .empty_page_check = false, + .mastersta_mask = NFI_MASTERSTA_MASK_7622, + .spare_sizes = mt7622_spare_sizes, + .num_spare_size = ARRAY_SIZE(mt7622_spare_sizes) + }, +}; + +static inline uint32_t nfi_read32(struct mtk_snand *snf, uint32_t reg) +{ + return readl(snf->nfi_base + reg); +} + +static inline void nfi_write32(struct mtk_snand *snf, uint32_t reg, + uint32_t val) +{ + writel(val, snf->nfi_base + reg); +} + +static inline void nfi_write16(struct mtk_snand *snf, uint32_t reg, + uint16_t val) +{ + writew(val, snf->nfi_base + reg); +} + +static inline void nfi_rmw32(struct mtk_snand *snf, uint32_t reg, uint32_t clr, + uint32_t set) +{ + uint32_t val; + + val = readl(snf->nfi_base + reg); + val &= ~clr; + val |= set; + writel(val, snf->nfi_base + reg); +} + +static void nfi_write_data(struct mtk_snand *snf, uint32_t reg, + const uint8_t *data, uint32_t len) +{ + uint32_t i, val = 0, es = sizeof(uint32_t); + + for (i = reg; i < reg + len; i++) { + val |= ((uint32_t)*data++) << (8 * (i % es)); + + if (i % es == es - 1 || i == reg + len - 1) { + nfi_write32(snf, i & ~(es - 1), val); + val = 0; + } + } +} + +static void nfi_read_data(struct mtk_snand *snf, uint32_t reg, uint8_t *data, + uint32_t len) +{ + uint32_t i, val = 0, es = sizeof(uint32_t); + + for (i = reg; i < reg + len; i++) { + if (i == reg || i % es == 0) + val = nfi_read32(snf, i & ~(es - 1)); + + *data++ = (uint8_t)(val >> (8 * (i % es))); + } +} + +static inline void do_bm_swap(uint8_t *bm1, uint8_t *bm2) +{ + uint8_t tmp = *bm1; + *bm1 = *bm2; + *bm2 = tmp; +} + +static void mtk_snand_bm_swap_raw(struct mtk_snand *snf) +{ + uint32_t fdm_bbm_pos; + + if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) + return; + + fdm_bbm_pos = (snf->ecc_steps - 1) * snf->raw_sector_size + + snf->nfi_soc->sector_size; + do_bm_swap(&snf->page_cache[fdm_bbm_pos], + &snf->page_cache[snf->writesize]); +} + +static void mtk_snand_bm_swap(struct mtk_snand *snf) +{ + uint32_t buf_bbm_pos, fdm_bbm_pos; + + if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) + return; + + buf_bbm_pos = snf->writesize - + (snf->ecc_steps - 1) * snf->spare_per_sector; + fdm_bbm_pos = snf->writesize + + (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size; + do_bm_swap(&snf->page_cache[fdm_bbm_pos], + &snf->page_cache[buf_bbm_pos]); +} + +static void mtk_snand_fdm_bm_swap_raw(struct mtk_snand *snf) +{ + uint32_t fdm_bbm_pos1, fdm_bbm_pos2; + + if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) + return; + + fdm_bbm_pos1 = snf->nfi_soc->sector_size; + fdm_bbm_pos2 = (snf->ecc_steps - 1) * snf->raw_sector_size + + snf->nfi_soc->sector_size; + do_bm_swap(&snf->page_cache[fdm_bbm_pos1], + &snf->page_cache[fdm_bbm_pos2]); +} + +static void mtk_snand_fdm_bm_swap(struct mtk_snand *snf) +{ + uint32_t fdm_bbm_pos1, fdm_bbm_pos2; + + if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1) + return; + + fdm_bbm_pos1 = snf->writesize; + fdm_bbm_pos2 = snf->writesize + + (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size; + do_bm_swap(&snf->page_cache[fdm_bbm_pos1], + &snf->page_cache[fdm_bbm_pos2]); +} + +static int mtk_nfi_reset(struct mtk_snand *snf) +{ + uint32_t val, fifo_mask; + int ret; + + nfi_write32(snf, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST); + + ret = read16_poll_timeout(snf->nfi_base + NFI_MASTERSTA, val, + !(val & snf->nfi_soc->mastersta_mask), 0, + SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, + "NFI master is still busy after reset\n"); + return ret; + } + + ret = read32_poll_timeout(snf->nfi_base + NFI_STA, val, + !(val & (NFI_FSM | NFI_NAND_FSM)), 0, + SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, "Failed to reset NFI\n"); + return ret; + } + + fifo_mask = ((snf->nfi_soc->fifo_size - 1) << FIFO_RD_REMAIN_S) | + ((snf->nfi_soc->fifo_size - 1) << FIFO_WR_REMAIN_S); + ret = read16_poll_timeout(snf->nfi_base + NFI_FIFOSTA, val, + !(val & fifo_mask), 0, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, "NFI FIFOs are not empty\n"); + return ret; + } + + return 0; +} + +static int mtk_snand_mac_reset(struct mtk_snand *snf) +{ + int ret; + uint32_t val; + + nfi_rmw32(snf, SNF_MISC_CTL, 0, SW_RST); + + ret = read32_poll_timeout(snf->nfi_base + SNF_STA_CTL1, val, + !(val & SPI_STATE), 0, SNFI_POLL_INTERVAL); + if (ret) + snand_log_snfi(snf->pdev, "Failed to reset SNFI MAC\n"); + + nfi_write32(snf, SNF_MISC_CTL, (2 << FIFO_RD_LTC_S) | + (10 << CS_DESELECT_CYC_S)); + + return ret; +} + +static int mtk_snand_mac_trigger(struct mtk_snand *snf, uint32_t outlen, + uint32_t inlen) +{ + int ret; + uint32_t val; + + nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN); + nfi_write32(snf, SNF_MAC_OUTL, outlen); + nfi_write32(snf, SNF_MAC_INL, inlen); + + nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN | SF_TRIG); + + ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val, + val & WIP_READY, 0, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_snfi(snf->pdev, "Timed out waiting for WIP_READY\n"); + goto cleanup; + } + + ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val, + !(val & WIP), 0, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_snfi(snf->pdev, + "Timed out waiting for WIP cleared\n"); + } + +cleanup: + nfi_write32(snf, SNF_MAC_CTL, 0); + + return ret; +} + +int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen, + uint8_t *in, uint32_t inlen) +{ + int ret; + + if (outlen + inlen > SNF_GPRAM_SIZE) + return -EINVAL; + + mtk_snand_mac_reset(snf); + + nfi_write_data(snf, SNF_GPRAM, out, outlen); + + ret = mtk_snand_mac_trigger(snf, outlen, inlen); + if (ret) + return ret; + + if (!inlen) + return 0; + + nfi_read_data(snf, SNF_GPRAM + outlen, in, inlen); + + return 0; +} + +static int mtk_snand_get_feature(struct mtk_snand *snf, uint32_t addr) +{ + uint8_t op[2], val; + int ret; + + op[0] = SNAND_CMD_GET_FEATURE; + op[1] = (uint8_t)addr; + + ret = mtk_snand_mac_io(snf, op, sizeof(op), &val, 1); + if (ret) + return ret; + + return val; +} + +int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val) +{ + uint8_t op[3]; + + op[0] = SNAND_CMD_SET_FEATURE; + op[1] = (uint8_t)addr; + op[2] = (uint8_t)val; + + return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0); +} + +static int mtk_snand_poll_status(struct mtk_snand *snf, uint32_t wait_us) +{ + int val; + mtk_snand_time_t time_start, tmo; + + time_start = timer_get_ticks(); + tmo = timer_time_to_tick(wait_us); + + do { + val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR); + if (!(val & SNAND_STATUS_OIP)) + return val & (SNAND_STATUS_ERASE_FAIL | + SNAND_STATUS_PROGRAM_FAIL); + } while (!timer_is_timeout(time_start, tmo)); + + return -ETIMEDOUT; +} + +int mtk_snand_chip_reset(struct mtk_snand *snf) +{ + uint8_t op = SNAND_CMD_RESET; + int ret; + + ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0); + if (ret) + return ret; + + ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); + if (ret < 0) + return ret; + + return 0; +} + +static int mtk_snand_config_feature(struct mtk_snand *snf, uint8_t clr, + uint8_t set) +{ + int val, newval; + int ret; + + val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR); + if (val < 0) { + snand_log_chip(snf->pdev, + "Failed to get configuration feature\n"); + return val; + } + + newval = (val & (~clr)) | set; + + if (newval == val) + return 0; + + ret = mtk_snand_set_feature(snf, SNAND_FEATURE_CONFIG_ADDR, + (uint8_t)newval); + if (val < 0) { + snand_log_chip(snf->pdev, + "Failed to set configuration feature\n"); + return ret; + } + + val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR); + if (val < 0) { + snand_log_chip(snf->pdev, + "Failed to get configuration feature\n"); + return val; + } + + if (newval != val) + return -ENOTSUPP; + + return 0; +} + +static int mtk_snand_ondie_ecc_control(struct mtk_snand *snf, bool enable) +{ + int ret; + + if (enable) + ret = mtk_snand_config_feature(snf, 0, SNAND_FEATURE_ECC_EN); + else + ret = mtk_snand_config_feature(snf, SNAND_FEATURE_ECC_EN, 0); + + if (ret) { + snand_log_chip(snf->pdev, "Failed to %s On-Die ECC engine\n", + enable ? "enable" : "disable"); + } + + return ret; +} + +static int mtk_snand_qspi_control(struct mtk_snand *snf, bool enable) +{ + int ret; + + if (enable) { + ret = mtk_snand_config_feature(snf, 0, + SNAND_FEATURE_QUAD_ENABLE); + } else { + ret = mtk_snand_config_feature(snf, + SNAND_FEATURE_QUAD_ENABLE, 0); + } + + if (ret) { + snand_log_chip(snf->pdev, "Failed to %s quad spi\n", + enable ? "enable" : "disable"); + } + + return ret; +} + +static int mtk_snand_unlock(struct mtk_snand *snf) +{ + int ret; + + ret = mtk_snand_set_feature(snf, SNAND_FEATURE_PROTECT_ADDR, 0); + if (ret) { + snand_log_chip(snf->pdev, "Failed to set protection feature\n"); + return ret; + } + + return 0; +} + +static int mtk_snand_write_enable(struct mtk_snand *snf) +{ + uint8_t op = SNAND_CMD_WRITE_ENABLE; + int ret, val; + + ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0); + if (ret) + return ret; + + val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR); + if (val < 0) + return ret; + + if (val & SNAND_STATUS_WEL) + return 0; + + snand_log_chip(snf->pdev, "Failed to send write-enable command\n"); + + return -ENOTSUPP; +} + +static int mtk_snand_select_die(struct mtk_snand *snf, uint32_t dieidx) +{ + if (!snf->select_die) + return 0; + + return snf->select_die(snf, dieidx); +} + +static uint64_t mtk_snand_select_die_address(struct mtk_snand *snf, + uint64_t addr) +{ + uint32_t dieidx; + + if (!snf->select_die) + return addr; + + dieidx = addr >> snf->die_shift; + + mtk_snand_select_die(snf, dieidx); + + return addr & snf->die_mask; +} + +static uint32_t mtk_snand_get_plane_address(struct mtk_snand *snf, + uint32_t page) +{ + uint32_t pages_per_block; + + pages_per_block = 1 << (snf->erasesize_shift - snf->writesize_shift); + + if (page & pages_per_block) + return 1 << (snf->writesize_shift + 1); + + return 0; +} + +static int mtk_snand_page_op(struct mtk_snand *snf, uint32_t page, uint8_t cmd) +{ + uint8_t op[4]; + + op[0] = cmd; + op[1] = (page >> 16) & 0xff; + op[2] = (page >> 8) & 0xff; + op[3] = page & 0xff; + + return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0); +} + +static void mtk_snand_read_fdm(struct mtk_snand *snf, uint8_t *buf) +{ + uint32_t vall, valm; + uint8_t *oobptr = buf; + int i, j; + + for (i = 0; i < snf->ecc_steps; i++) { + vall = nfi_read32(snf, NFI_FDML(i)); + valm = nfi_read32(snf, NFI_FDMM(i)); + + for (j = 0; j < snf->nfi_soc->fdm_size; j++) + oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8); + + oobptr += snf->nfi_soc->fdm_size; + } +} + +static int mtk_snand_read_ecc_parity(struct mtk_snand *snf, uint32_t page, + uint32_t sect, uint8_t *oob) +{ + uint32_t ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size; + uint32_t coladdr, raw_offs, offs; + uint8_t op[4]; + + if (sizeof(op) + ecc_bytes > SNF_GPRAM_SIZE) { + snand_log_snfi(snf->pdev, + "ECC parity size does not fit the GPRAM\n"); + return -ENOTSUPP; + } + + raw_offs = sect * snf->raw_sector_size + snf->nfi_soc->sector_size + + snf->nfi_soc->fdm_size; + offs = snf->ecc_steps * snf->nfi_soc->fdm_size + sect * ecc_bytes; + + /* Column address with plane bit */ + coladdr = raw_offs | mtk_snand_get_plane_address(snf, page); + + op[0] = SNAND_CMD_READ_FROM_CACHE; + op[1] = (coladdr >> 8) & 0xff; + op[2] = coladdr & 0xff; + op[3] = 0; + + return mtk_snand_mac_io(snf, op, sizeof(op), oob + offs, ecc_bytes); +} + +static int mtk_snand_check_ecc_result(struct mtk_snand *snf, uint32_t page) +{ + uint8_t *oob = snf->page_cache + snf->writesize; + int i, rc, ret = 0, max_bitflips = 0; + + for (i = 0; i < snf->ecc_steps; i++) { + if (snf->sect_bf[i] >= 0) { + if (snf->sect_bf[i] > max_bitflips) + max_bitflips = snf->sect_bf[i]; + continue; + } + + rc = mtk_snand_read_ecc_parity(snf, page, i, oob); + if (rc) + return rc; + + rc = mtk_ecc_fixup_empty_sector(snf, i); + if (rc < 0) { + ret = -EBADMSG; + + snand_log_ecc(snf->pdev, + "Uncorrectable bitflips in page %u sect %u\n", + page, i); + } else if (rc) { + snf->sect_bf[i] = rc; + + if (snf->sect_bf[i] > max_bitflips) + max_bitflips = snf->sect_bf[i]; + + snand_log_ecc(snf->pdev, + "%u bitflip%s corrected in page %u sect %u\n", + rc, rc > 1 ? "s" : "", page, i); + } else { + snf->sect_bf[i] = 0; + } + } + + return ret ? ret : max_bitflips; +} + +static int mtk_snand_read_cache(struct mtk_snand *snf, uint32_t page, bool raw) +{ + uint32_t coladdr, rwbytes, mode, len, val; + uintptr_t dma_addr; + int ret; + + /* Column address with plane bit */ + coladdr = mtk_snand_get_plane_address(snf, page); + + mtk_snand_mac_reset(snf); + mtk_nfi_reset(snf); + + /* Command and dummy cycles */ + nfi_write32(snf, SNF_RD_CTL2, + ((uint32_t)snf->dummy_rfc << DATA_READ_DUMMY_S) | + (snf->opcode_rfc << DATA_READ_CMD_S)); + + /* Column address */ + nfi_write32(snf, SNF_RD_CTL3, coladdr); + + /* Set read mode */ + mode = (uint32_t)snf->mode_rfc << DATA_READ_MODE_S; + nfi_rmw32(snf, SNF_MISC_CTL, DATA_READ_MODE, mode | DATARD_CUSTOM_EN); + + /* Set bytes to read */ + rwbytes = snf->ecc_steps * snf->raw_sector_size; + nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) | + rwbytes); + + /* NFI read prepare */ + mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN; + nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_CUST << CNFG_OP_MODE_S) | + CNFG_DMA_BURST_EN | CNFG_READ_MODE | CNFG_DMA_MODE | mode); + + nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S)); + + /* Prepare for DMA read */ + len = snf->writesize + snf->oobsize; + ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, false); + if (ret) { + snand_log_nfi(snf->pdev, + "DMA map from device failed with %d\n", ret); + return ret; + } + + nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr); + + if (!raw) + mtk_snand_ecc_decoder_start(snf); + + /* Prepare for custom read interrupt */ + nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_READ); + irq_completion_init(snf->pdev); + + /* Trigger NFI into custom mode */ + nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_READ); + + /* Start DMA read */ + nfi_rmw32(snf, NFI_CON, 0, CON_BRD); + nfi_write16(snf, NFI_STRDATA, STR_DATA); + + /* Wait for operation finished */ + ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1, + CUS_READ_DONE, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, + "DMA timed out for reading from cache\n"); + goto cleanup; + } + + /* Wait for BUS_SEC_CNTR returning expected value */ + ret = read32_poll_timeout(snf->nfi_base + NFI_BYTELEN, val, + BUS_SEC_CNTR(val) >= snf->ecc_steps, + 0, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, + "Timed out waiting for BUS_SEC_CNTR\n"); + goto cleanup; + } + + /* Wait for bus becoming idle */ + ret = read32_poll_timeout(snf->nfi_base + NFI_MASTERSTA, val, + !(val & snf->nfi_soc->mastersta_mask), + 0, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, + "Timed out waiting for bus becoming idle\n"); + goto cleanup; + } + + if (!raw) { + ret = mtk_ecc_wait_decoder_done(snf); + if (ret) + goto cleanup; + + mtk_snand_read_fdm(snf, snf->page_cache + snf->writesize); + + mtk_ecc_check_decode_error(snf); + mtk_snand_ecc_decoder_stop(snf); + + ret = mtk_snand_check_ecc_result(snf, page); + } + +cleanup: + /* DMA cleanup */ + dma_mem_unmap(snf->pdev, dma_addr, len, false); + + /* Stop read */ + nfi_write32(snf, NFI_CON, 0); + nfi_write16(snf, NFI_CNFG, 0); + + /* Clear SNF done flag */ + nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE); + nfi_write32(snf, SNF_STA_CTL1, 0); + + /* Disable interrupt */ + nfi_read32(snf, NFI_INTR_STA); + nfi_write32(snf, NFI_INTR_EN, 0); + + nfi_rmw32(snf, SNF_MISC_CTL, DATARD_CUSTOM_EN, 0); + + return ret; +} + +static void mtk_snand_from_raw_page(struct mtk_snand *snf, void *buf, void *oob) +{ + uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size; + uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size; + uint8_t *bufptr = buf, *oobptr = oob, *raw_sector; + + for (i = 0; i < snf->ecc_steps; i++) { + raw_sector = snf->page_cache + i * snf->raw_sector_size; + + if (buf) { + memcpy(bufptr, raw_sector, snf->nfi_soc->sector_size); + bufptr += snf->nfi_soc->sector_size; + } + + raw_sector += snf->nfi_soc->sector_size; + + if (oob) { + memcpy(oobptr, raw_sector, snf->nfi_soc->fdm_size); + oobptr += snf->nfi_soc->fdm_size; + raw_sector += snf->nfi_soc->fdm_size; + + memcpy(eccptr, raw_sector, ecc_bytes); + eccptr += ecc_bytes; + } + } +} + +static int mtk_snand_do_read_page(struct mtk_snand *snf, uint64_t addr, + void *buf, void *oob, bool raw, bool format) +{ + uint64_t die_addr; + uint32_t page; + int ret; + + die_addr = mtk_snand_select_die_address(snf, addr); + page = die_addr >> snf->writesize_shift; + + ret = mtk_snand_page_op(snf, page, SNAND_CMD_READ_TO_CACHE); + if (ret) + return ret; + + ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); + if (ret < 0) { + snand_log_chip(snf->pdev, "Read to cache command timed out\n"); + return ret; + } + + ret = mtk_snand_read_cache(snf, page, raw); + if (ret < 0 && ret != -EBADMSG) + return ret; + + if (raw) { + if (format) { + mtk_snand_bm_swap_raw(snf); + mtk_snand_fdm_bm_swap_raw(snf); + mtk_snand_from_raw_page(snf, buf, oob); + } else { + if (buf) + memcpy(buf, snf->page_cache, snf->writesize); + + if (oob) { + memset(oob, 0xff, snf->oobsize); + memcpy(oob, snf->page_cache + snf->writesize, + snf->ecc_steps * snf->spare_per_sector); + } + } + } else { + mtk_snand_bm_swap(snf); + mtk_snand_fdm_bm_swap(snf); + + if (buf) + memcpy(buf, snf->page_cache, snf->writesize); + + if (oob) { + memset(oob, 0xff, snf->oobsize); + memcpy(oob, snf->page_cache + snf->writesize, + snf->ecc_steps * snf->nfi_soc->fdm_size); + } + } + + return ret; +} + +int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf, + void *oob, bool raw) +{ + if (!snf || (!buf && !oob)) + return -EINVAL; + + if (addr >= snf->size) + return -EINVAL; + + return mtk_snand_do_read_page(snf, addr, buf, oob, raw, true); +} + +static void mtk_snand_write_fdm(struct mtk_snand *snf, const uint8_t *buf) +{ + uint32_t vall, valm, fdm_size = snf->nfi_soc->fdm_size; + const uint8_t *oobptr = buf; + int i, j; + + for (i = 0; i < snf->ecc_steps; i++) { + vall = 0; + valm = 0; + + for (j = 0; j < 8; j++) { + if (j < 4) + vall |= (j < fdm_size ? oobptr[j] : 0xff) + << (j * 8); + else + valm |= (j < fdm_size ? oobptr[j] : 0xff) + << ((j - 4) * 8); + } + + nfi_write32(snf, NFI_FDML(i), vall); + nfi_write32(snf, NFI_FDMM(i), valm); + + oobptr += fdm_size; + } +} + +static int mtk_snand_program_load(struct mtk_snand *snf, uint32_t page, + bool raw) +{ + uint32_t coladdr, rwbytes, mode, len, val; + uintptr_t dma_addr; + int ret; + + /* Column address with plane bit */ + coladdr = mtk_snand_get_plane_address(snf, page); + + mtk_snand_mac_reset(snf); + mtk_nfi_reset(snf); + + /* Write FDM registers if necessary */ + if (!raw) + mtk_snand_write_fdm(snf, snf->page_cache + snf->writesize); + + /* Command */ + nfi_write32(snf, SNF_PG_CTL1, (snf->opcode_pl << PG_LOAD_CMD_S)); + + /* Column address */ + nfi_write32(snf, SNF_PG_CTL2, coladdr); + + /* Set write mode */ + mode = snf->mode_pl ? PG_LOAD_X4_EN : 0; + nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_X4_EN, mode | PG_LOAD_CUSTOM_EN); + + /* Set bytes to write */ + rwbytes = snf->ecc_steps * snf->raw_sector_size; + nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) | + rwbytes); + + /* NFI write prepare */ + mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN; + nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_PROGRAM << CNFG_OP_MODE_S) | + CNFG_DMA_BURST_EN | CNFG_DMA_MODE | mode); + + nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S)); + + /* Prepare for DMA write */ + len = snf->writesize + snf->oobsize; + ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, true); + if (ret) { + snand_log_nfi(snf->pdev, + "DMA map to device failed with %d\n", ret); + return ret; + } + + nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr); + + if (!raw) + mtk_snand_ecc_encoder_start(snf); + + /* Prepare for custom write interrupt */ + nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG); + irq_completion_init(snf->pdev); + + /* Trigger NFI into custom mode */ + nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE); + + /* Start DMA write */ + nfi_rmw32(snf, NFI_CON, 0, CON_BWR); + nfi_write16(snf, NFI_STRDATA, STR_DATA); + + /* Wait for operation finished */ + ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1, + CUS_PG_DONE, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, + "DMA timed out for program load\n"); + goto cleanup; + } + + /* Wait for NFI_SEC_CNTR returning expected value */ + ret = read32_poll_timeout(snf->nfi_base + NFI_ADDRCNTR, val, + NFI_SEC_CNTR(val) >= snf->ecc_steps, + 0, SNFI_POLL_INTERVAL); + if (ret) { + snand_log_nfi(snf->pdev, + "Timed out waiting for NFI_SEC_CNTR\n"); + goto cleanup; + } + + if (!raw) + mtk_snand_ecc_encoder_stop(snf); + +cleanup: + /* DMA cleanup */ + dma_mem_unmap(snf->pdev, dma_addr, len, true); + + /* Stop write */ + nfi_write32(snf, NFI_CON, 0); + nfi_write16(snf, NFI_CNFG, 0); + + /* Clear SNF done flag */ + nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_PG_DONE); + nfi_write32(snf, SNF_STA_CTL1, 0); + + /* Disable interrupt */ + nfi_read32(snf, NFI_INTR_STA); + nfi_write32(snf, NFI_INTR_EN, 0); + + nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_CUSTOM_EN, 0); + + return ret; +} + +static void mtk_snand_to_raw_page(struct mtk_snand *snf, + const void *buf, const void *oob, + bool empty_ecc) +{ + uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size; + const uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size; + const uint8_t *bufptr = buf, *oobptr = oob; + uint8_t *raw_sector; + + memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize); + for (i = 0; i < snf->ecc_steps; i++) { + raw_sector = snf->page_cache + i * snf->raw_sector_size; + + if (buf) { + memcpy(raw_sector, bufptr, snf->nfi_soc->sector_size); + bufptr += snf->nfi_soc->sector_size; + } + + raw_sector += snf->nfi_soc->sector_size; + + if (oob) { + memcpy(raw_sector, oobptr, snf->nfi_soc->fdm_size); + oobptr += snf->nfi_soc->fdm_size; + raw_sector += snf->nfi_soc->fdm_size; + + if (empty_ecc) + memset(raw_sector, 0xff, ecc_bytes); + else + memcpy(raw_sector, eccptr, ecc_bytes); + eccptr += ecc_bytes; + } + } +} + +static bool mtk_snand_is_empty_page(struct mtk_snand *snf, const void *buf, + const void *oob) +{ + const uint8_t *p = buf; + uint32_t i, j; + + if (buf) { + for (i = 0; i < snf->writesize; i++) { + if (p[i] != 0xff) + return false; + } + } + + if (oob) { + for (j = 0; j < snf->ecc_steps; j++) { + p = oob + j * snf->nfi_soc->fdm_size; + + for (i = 0; i < snf->nfi_soc->fdm_ecc_size; i++) { + if (p[i] != 0xff) + return false; + } + } + } + + return true; +} + +static int mtk_snand_do_write_page(struct mtk_snand *snf, uint64_t addr, + const void *buf, const void *oob, + bool raw, bool format) +{ + uint64_t die_addr; + bool empty_ecc = false; + uint32_t page; + int ret; + + die_addr = mtk_snand_select_die_address(snf, addr); + page = die_addr >> snf->writesize_shift; + + if (!raw && mtk_snand_is_empty_page(snf, buf, oob)) { + /* + * If the data in the page to be ecc-ed is full 0xff, + * change to raw write mode + */ + raw = true; + format = true; + + /* fill ecc parity code region with 0xff */ + empty_ecc = true; + } + + if (raw) { + if (format) { + mtk_snand_to_raw_page(snf, buf, oob, empty_ecc); + mtk_snand_fdm_bm_swap_raw(snf); + mtk_snand_bm_swap_raw(snf); + } else { + memset(snf->page_cache, 0xff, + snf->writesize + snf->oobsize); + + if (buf) + memcpy(snf->page_cache, buf, snf->writesize); + + if (oob) { + memcpy(snf->page_cache + snf->writesize, oob, + snf->ecc_steps * snf->spare_per_sector); + } + } + } else { + memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize); + if (buf) + memcpy(snf->page_cache, buf, snf->writesize); + + if (oob) { + memcpy(snf->page_cache + snf->writesize, oob, + snf->ecc_steps * snf->nfi_soc->fdm_size); + } + + mtk_snand_fdm_bm_swap(snf); + mtk_snand_bm_swap(snf); + } + + ret = mtk_snand_write_enable(snf); + if (ret) + return ret; + + ret = mtk_snand_program_load(snf, page, raw); + if (ret) + return ret; + + ret = mtk_snand_page_op(snf, page, SNAND_CMD_PROGRAM_EXECUTE); + if (ret) + return ret; + + ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); + if (ret < 0) { + snand_log_chip(snf->pdev, + "Page program command timed out on page %u\n", + page); + return ret; + } + + if (ret & SNAND_STATUS_PROGRAM_FAIL) { + snand_log_chip(snf->pdev, + "Page program failed on page %u\n", page); + return -EIO; + } + + return 0; +} + +int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf, + const void *oob, bool raw) +{ + if (!snf || (!buf && !oob)) + return -EINVAL; + + if (addr >= snf->size) + return -EINVAL; + + return mtk_snand_do_write_page(snf, addr, buf, oob, raw, true); +} + +int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr) +{ + uint64_t die_addr; + uint32_t page, block; + int ret; + + if (!snf) + return -EINVAL; + + if (addr >= snf->size) + return -EINVAL; + + die_addr = mtk_snand_select_die_address(snf, addr); + block = die_addr >> snf->erasesize_shift; + page = block << (snf->erasesize_shift - snf->writesize_shift); + + ret = mtk_snand_write_enable(snf); + if (ret) + return ret; + + ret = mtk_snand_page_op(snf, page, SNAND_CMD_BLOCK_ERASE); + if (ret) + return ret; + + ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL); + if (ret < 0) { + snand_log_chip(snf->pdev, + "Block erase command timed out on block %u\n", + block); + return ret; + } + + if (ret & SNAND_STATUS_ERASE_FAIL) { + snand_log_chip(snf->pdev, + "Block erase failed on block %u\n", block); + return -EIO; + } + + return 0; +} + +static int mtk_snand_block_isbad_std(struct mtk_snand *snf, uint64_t addr) +{ + int ret; + + ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true, + false); + if (ret && ret != -EBADMSG) + return ret; + + return snf->buf_cache[0] != 0xff; +} + +static int mtk_snand_block_isbad_mtk(struct mtk_snand *snf, uint64_t addr) +{ + int ret; + + ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true, + true); + if (ret && ret != -EBADMSG) + return ret; + + return snf->buf_cache[0] != 0xff; +} + +int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr) +{ + if (!snf) + return -EINVAL; + + if (addr >= snf->size) + return -EINVAL; + + addr &= ~snf->erasesize_mask; + + if (snf->nfi_soc->bbm_swap) + return mtk_snand_block_isbad_std(snf, addr); + + return mtk_snand_block_isbad_mtk(snf, addr); +} + +static int mtk_snand_block_markbad_std(struct mtk_snand *snf, uint64_t addr) +{ + /* Standard BBM position */ + memset(snf->buf_cache, 0xff, snf->oobsize); + snf->buf_cache[0] = 0; + + return mtk_snand_do_write_page(snf, addr, NULL, snf->buf_cache, true, + false); +} + +static int mtk_snand_block_markbad_mtk(struct mtk_snand *snf, uint64_t addr) +{ + /* Write the whole page with zeros */ + memset(snf->buf_cache, 0, snf->writesize + snf->oobsize); + + return mtk_snand_do_write_page(snf, addr, snf->buf_cache, + snf->buf_cache + snf->writesize, true, + true); +} + +int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr) +{ + if (!snf) + return -EINVAL; + + if (addr >= snf->size) + return -EINVAL; + + addr &= ~snf->erasesize_mask; + + if (snf->nfi_soc->bbm_swap) + return mtk_snand_block_markbad_std(snf, addr); + + return mtk_snand_block_markbad_mtk(snf, addr); +} + +int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw, + const uint8_t *oobbuf, size_t ooblen) +{ + size_t len = ooblen, sect_fdm_len; + const uint8_t *oob = oobbuf; + uint32_t step = 0; + + if (!snf || !oobraw || !oob) + return -EINVAL; + + while (len && step < snf->ecc_steps) { + sect_fdm_len = snf->nfi_soc->fdm_size - 1; + if (sect_fdm_len > len) + sect_fdm_len = len; + + memcpy(oobraw + step * snf->nfi_soc->fdm_size + 1, oob, + sect_fdm_len); + + len -= sect_fdm_len; + oob += sect_fdm_len; + step++; + } + + return len; +} + +int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf, + size_t ooblen, const uint8_t *oobraw) +{ + size_t len = ooblen, sect_fdm_len; + uint8_t *oob = oobbuf; + uint32_t step = 0; + + if (!snf || !oobraw || !oob) + return -EINVAL; + + while (len && step < snf->ecc_steps) { + sect_fdm_len = snf->nfi_soc->fdm_size - 1; + if (sect_fdm_len > len) + sect_fdm_len = len; + + memcpy(oob, oobraw + step * snf->nfi_soc->fdm_size + 1, + sect_fdm_len); + + len -= sect_fdm_len; + oob += sect_fdm_len; + step++; + } + + return len; +} + +int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr, + void *buf, void *oob, size_t ooblen, + size_t *actualooblen, bool raw) +{ + int ret, oobremain; + + if (!snf) + return -EINVAL; + + if (!oob) + return mtk_snand_read_page(snf, addr, buf, NULL, raw); + + ret = mtk_snand_read_page(snf, addr, buf, snf->buf_cache, raw); + if (ret && ret != -EBADMSG) { + if (actualooblen) + *actualooblen = 0; + return ret; + } + + oobremain = mtk_snand_transfer_oob(snf, oob, ooblen, snf->buf_cache); + if (actualooblen) + *actualooblen = ooblen - oobremain; + + return ret; +} + +int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr, + const void *buf, const void *oob, + size_t ooblen, size_t *actualooblen, bool raw) +{ + int oobremain; + + if (!snf) + return -EINVAL; + + if (!oob) + return mtk_snand_write_page(snf, addr, buf, NULL, raw); + + memset(snf->buf_cache, 0xff, snf->oobsize); + oobremain = mtk_snand_fill_oob(snf, snf->buf_cache, oob, ooblen); + if (actualooblen) + *actualooblen = ooblen - oobremain; + + return mtk_snand_write_page(snf, addr, buf, snf->buf_cache, raw); +} + +int mtk_snand_get_chip_info(struct mtk_snand *snf, + struct mtk_snand_chip_info *info) +{ + if (!snf || !info) + return -EINVAL; + + info->model = snf->model; + info->chipsize = snf->size; + info->blocksize = snf->erasesize; + info->pagesize = snf->writesize; + info->sparesize = snf->oobsize; + info->spare_per_sector = snf->spare_per_sector; + info->fdm_size = snf->nfi_soc->fdm_size; + info->fdm_ecc_size = snf->nfi_soc->fdm_ecc_size; + info->num_sectors = snf->ecc_steps; + info->sector_size = snf->nfi_soc->sector_size; + info->ecc_strength = snf->ecc_strength; + info->ecc_bytes = snf->ecc_bytes; + + return 0; +} + +int mtk_snand_irq_process(struct mtk_snand *snf) +{ + uint32_t sta, ien; + + if (!snf) + return -EINVAL; + + sta = nfi_read32(snf, NFI_INTR_STA); + ien = nfi_read32(snf, NFI_INTR_EN); + + if (!(sta & ien)) + return 0; + + nfi_write32(snf, NFI_INTR_EN, 0); + irq_completion_done(snf->pdev); + + return 1; +} + +static int mtk_snand_select_spare_per_sector(struct mtk_snand *snf) +{ + uint32_t spare_per_step = snf->oobsize / snf->ecc_steps; + int i, mul = 1; + + /* + * If we're using the 1KB sector size, HW will automatically + * double the spare size. So we should only use half of the value. + */ + if (snf->nfi_soc->sector_size == 1024) + mul = 2; + + spare_per_step /= mul; + + for (i = snf->nfi_soc->num_spare_size - 1; i >= 0; i--) { + if (snf->nfi_soc->spare_sizes[i] <= spare_per_step) { + snf->spare_per_sector = snf->nfi_soc->spare_sizes[i]; + snf->spare_per_sector *= mul; + return i; + } + } + + snand_log_nfi(snf->pdev, + "Page size %u+%u is not supported\n", snf->writesize, + snf->oobsize); + + return -1; +} + +static int mtk_snand_pagefmt_setup(struct mtk_snand *snf) +{ + uint32_t spare_size_idx, spare_size_shift, pagesize_idx; + uint32_t sector_size_512; + + if (snf->nfi_soc->sector_size == 512) { + sector_size_512 = NFI_SEC_SEL_512; + spare_size_shift = NFI_SPARE_SIZE_S; + } else { + sector_size_512 = 0; + spare_size_shift = NFI_SPARE_SIZE_LS_S; + } + + switch (snf->writesize) { + case SZ_512: + pagesize_idx = NFI_PAGE_SIZE_512_2K; + break; + case SZ_2K: + if (snf->nfi_soc->sector_size == 512) + pagesize_idx = NFI_PAGE_SIZE_2K_4K; + else + pagesize_idx = NFI_PAGE_SIZE_512_2K; + break; + case SZ_4K: + if (snf->nfi_soc->sector_size == 512) + pagesize_idx = NFI_PAGE_SIZE_4K_8K; + else + pagesize_idx = NFI_PAGE_SIZE_2K_4K; + break; + case SZ_8K: + if (snf->nfi_soc->sector_size == 512) + pagesize_idx = NFI_PAGE_SIZE_8K_16K; + else + pagesize_idx = NFI_PAGE_SIZE_4K_8K; + break; + case SZ_16K: + pagesize_idx = NFI_PAGE_SIZE_8K_16K; + break; + default: + snand_log_nfi(snf->pdev, "Page size %u is not supported\n", + snf->writesize); + return -ENOTSUPP; + } + + spare_size_idx = mtk_snand_select_spare_per_sector(snf); + if (unlikely(spare_size_idx < 0)) + return -ENOTSUPP; + + snf->raw_sector_size = snf->nfi_soc->sector_size + + snf->spare_per_sector; + + /* Setup page format */ + nfi_write32(snf, NFI_PAGEFMT, + (snf->nfi_soc->fdm_ecc_size << NFI_FDM_ECC_NUM_S) | + (snf->nfi_soc->fdm_size << NFI_FDM_NUM_S) | + (spare_size_idx << spare_size_shift) | + (pagesize_idx << NFI_PAGE_SIZE_S) | + sector_size_512); + + return 0; +} + +static enum snand_flash_io mtk_snand_select_opcode(struct mtk_snand *snf, + uint32_t snfi_caps, uint8_t *opcode, + uint8_t *dummy, + const struct snand_io_cap *op_cap) +{ + uint32_t i, caps; + + caps = snfi_caps & op_cap->caps; + + i = fls(caps); + if (i > 0) { + *opcode = op_cap->opcodes[i - 1].opcode; + if (dummy) + *dummy = op_cap->opcodes[i - 1].dummy; + return i - 1; + } + + return __SNAND_IO_MAX; +} + +static int mtk_snand_select_opcode_rfc(struct mtk_snand *snf, + uint32_t snfi_caps, + const struct snand_io_cap *op_cap) +{ + enum snand_flash_io idx; + + static const uint8_t rfc_modes[__SNAND_IO_MAX] = { + [SNAND_IO_1_1_1] = DATA_READ_MODE_X1, + [SNAND_IO_1_1_2] = DATA_READ_MODE_X2, + [SNAND_IO_1_2_2] = DATA_READ_MODE_DUAL, + [SNAND_IO_1_1_4] = DATA_READ_MODE_X4, + [SNAND_IO_1_4_4] = DATA_READ_MODE_QUAD, + }; + + idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_rfc, + &snf->dummy_rfc, op_cap); + if (idx >= __SNAND_IO_MAX) { + snand_log_snfi(snf->pdev, + "No capable opcode for read from cache\n"); + return -ENOTSUPP; + } + + snf->mode_rfc = rfc_modes[idx]; + + if (idx == SNAND_IO_1_1_4 || idx == SNAND_IO_1_4_4) + snf->quad_spi_op = true; + + return 0; +} + +static int mtk_snand_select_opcode_pl(struct mtk_snand *snf, uint32_t snfi_caps, + const struct snand_io_cap *op_cap) +{ + enum snand_flash_io idx; + + static const uint8_t pl_modes[__SNAND_IO_MAX] = { + [SNAND_IO_1_1_1] = 0, + [SNAND_IO_1_1_4] = 1, + }; + + idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_pl, + NULL, op_cap); + if (idx >= __SNAND_IO_MAX) { + snand_log_snfi(snf->pdev, + "No capable opcode for program load\n"); + return -ENOTSUPP; + } + + snf->mode_pl = pl_modes[idx]; + + if (idx == SNAND_IO_1_1_4) + snf->quad_spi_op = true; + + return 0; +} + +static int mtk_snand_setup(struct mtk_snand *snf, + const struct snand_flash_info *snand_info) +{ + const struct snand_mem_org *memorg = &snand_info->memorg; + uint32_t i, msg_size, snfi_caps; + int ret; + + /* Calculate flash memory organization */ + snf->model = snand_info->model; + snf->writesize = memorg->pagesize; + snf->oobsize = memorg->sparesize; + snf->erasesize = snf->writesize * memorg->pages_per_block; + snf->die_size = (uint64_t)snf->erasesize * memorg->blocks_per_die; + snf->size = snf->die_size * memorg->ndies; + snf->num_dies = memorg->ndies; + + snf->writesize_mask = snf->writesize - 1; + snf->erasesize_mask = snf->erasesize - 1; + snf->die_mask = snf->die_size - 1; + + snf->writesize_shift = ffs(snf->writesize) - 1; + snf->erasesize_shift = ffs(snf->erasesize) - 1; + snf->die_shift = mtk_snand_ffs64(snf->die_size) - 1; + + snf->select_die = snand_info->select_die; + + /* Determine opcodes for read from cache/program load */ + snfi_caps = SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2; + if (snf->snfi_quad_spi) + snfi_caps |= SPI_IO_1_1_4 | SPI_IO_1_4_4; + + ret = mtk_snand_select_opcode_rfc(snf, snfi_caps, snand_info->cap_rd); + if (ret) + return ret; + + ret = mtk_snand_select_opcode_pl(snf, snfi_caps, snand_info->cap_pl); + if (ret) + return ret; + + /* ECC and page format */ + snf->ecc_steps = snf->writesize / snf->nfi_soc->sector_size; + if (snf->ecc_steps > snf->nfi_soc->max_sectors) { + snand_log_nfi(snf->pdev, "Page size %u is not supported\n", + snf->writesize); + return -ENOTSUPP; + } + + ret = mtk_snand_pagefmt_setup(snf); + if (ret) + return ret; + + msg_size = snf->nfi_soc->sector_size + snf->nfi_soc->fdm_ecc_size; + ret = mtk_ecc_setup(snf, snf->nfi_base + NFI_FDM0L, + snf->spare_per_sector - snf->nfi_soc->fdm_size, + msg_size); + if (ret) + return ret; + + nfi_write16(snf, NFI_CNFG, 0); + + /* Tuning options */ + nfi_write16(snf, NFI_DEBUG_CON1, WBUF_EN); + nfi_write32(snf, SNF_DLY_CTL3, (40 << SFCK_SAM_DLY_S)); + + /* Interrupts */ + nfi_read32(snf, NFI_INTR_STA); + nfi_write32(snf, NFI_INTR_EN, 0); + + /* Clear SNF done flag */ + nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE | CUS_PG_DONE); + nfi_write32(snf, SNF_STA_CTL1, 0); + + /* Initialization on all dies */ + for (i = 0; i < snf->num_dies; i++) { + mtk_snand_select_die(snf, i); + + /* Disable On-Die ECC engine */ + ret = mtk_snand_ondie_ecc_control(snf, false); + if (ret) + return ret; + + /* Disable block protection */ + mtk_snand_unlock(snf); + + /* Enable/disable quad-spi */ + mtk_snand_qspi_control(snf, snf->quad_spi_op); + } + + mtk_snand_select_die(snf, 0); + + return 0; +} + +static int mtk_snand_id_probe(struct mtk_snand *snf, + const struct snand_flash_info **snand_info) +{ + uint8_t id[4], op[2]; + int ret; + + /* Read SPI-NAND JEDEC ID, OP + dummy/addr + ID */ + op[0] = SNAND_CMD_READID; + op[1] = 0; + ret = mtk_snand_mac_io(snf, op, 2, id, sizeof(id)); + if (ret) + return ret; + + *snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id); + if (*snand_info) + return 0; + + /* Read SPI-NAND JEDEC ID, OP + ID */ + op[0] = SNAND_CMD_READID; + ret = mtk_snand_mac_io(snf, op, 1, id, sizeof(id)); + if (ret) + return ret; + + *snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id); + if (*snand_info) + return 0; + + snand_log_chip(snf->pdev, + "Unrecognized SPI-NAND ID: %02x %02x %02x %02x\n", + id[0], id[1], id[2], id[3]); + + return -EINVAL; +} + +int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata, + struct mtk_snand **psnf) +{ + const struct snand_flash_info *snand_info; + uint32_t rawpage_size, sect_bf_size; + struct mtk_snand tmpsnf, *snf; + int ret; + + if (!pdata || !psnf) + return -EINVAL; + + if (pdata->soc >= __SNAND_SOC_MAX) { + snand_log_chip(dev, "Invalid SOC %u for MTK-SNAND\n", + pdata->soc); + return -EINVAL; + } + + /* Dummy instance only for initial reset and id probe */ + tmpsnf.nfi_base = pdata->nfi_base; + tmpsnf.ecc_base = pdata->ecc_base; + tmpsnf.soc = pdata->soc; + tmpsnf.nfi_soc = &mtk_snand_socs[pdata->soc]; + tmpsnf.pdev = dev; + + /* Switch to SNFI mode */ + writel(SPI_MODE, tmpsnf.nfi_base + SNF_CFG); + + /* Reset SNFI & NFI */ + mtk_snand_mac_reset(&tmpsnf); + mtk_nfi_reset(&tmpsnf); + + /* Reset SPI-NAND chip */ + ret = mtk_snand_chip_reset(&tmpsnf); + if (ret) { + snand_log_chip(dev, "Failed to reset SPI-NAND chip\n"); + return ret; + } + + /* Probe SPI-NAND flash by JEDEC ID */ + ret = mtk_snand_id_probe(&tmpsnf, &snand_info); + if (ret) + return ret; + + rawpage_size = snand_info->memorg.pagesize + + snand_info->memorg.sparesize; + + sect_bf_size = mtk_snand_socs[pdata->soc].max_sectors * + sizeof(*snf->sect_bf); + + /* Allocate memory for instance and cache */ + snf = generic_mem_alloc(dev, + sizeof(*snf) + rawpage_size + sect_bf_size); + if (!snf) { + snand_log_chip(dev, "Failed to allocate memory for instance\n"); + return -ENOMEM; + } + + snf->sect_bf = (int *)((uintptr_t)snf + sizeof(*snf)); + snf->buf_cache = (uint8_t *)((uintptr_t)snf->sect_bf + sect_bf_size); + + /* Allocate memory for DMA buffer */ + snf->page_cache = dma_mem_alloc(dev, rawpage_size); + if (!snf->page_cache) { + generic_mem_free(dev, snf); + snand_log_chip(dev, + "Failed to allocate memory for DMA buffer\n"); + return -ENOMEM; + } + + /* Fill up instance */ + snf->pdev = dev; + snf->nfi_base = pdata->nfi_base; + snf->ecc_base = pdata->ecc_base; + snf->soc = pdata->soc; + snf->nfi_soc = &mtk_snand_socs[pdata->soc]; + snf->snfi_quad_spi = pdata->quad_spi; + + /* Initialize SNFI & ECC engine */ + ret = mtk_snand_setup(snf, snand_info); + if (ret) { + dma_mem_free(dev, snf->page_cache); + generic_mem_free(dev, snf); + return ret; + } + + *psnf = snf; + + return 0; +} + +int mtk_snand_cleanup(struct mtk_snand *snf) +{ + if (!snf) + return 0; + + dma_mem_free(snf->pdev, snf->page_cache); + generic_mem_free(snf->pdev, snf); + + return 0; +} diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.h b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.h new file mode 100644 index 0000000000..73c5cc60c9 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao + */ + +#ifndef _MTK_SNAND_H_ +#define _MTK_SNAND_H_ + +#ifndef PRIVATE_MTK_SNAND_HEADER +#include +#include +#include +#endif + +enum mtk_snand_soc { + SNAND_SOC_MT7622, + SNAND_SOC_MT7629, + + __SNAND_SOC_MAX +}; + +struct mtk_snand_platdata { + void *nfi_base; + void *ecc_base; + enum mtk_snand_soc soc; + bool quad_spi; +}; + +struct mtk_snand_chip_info { + const char *model; + uint64_t chipsize; + uint32_t blocksize; + uint32_t pagesize; + uint32_t sparesize; + uint32_t spare_per_sector; + uint32_t fdm_size; + uint32_t fdm_ecc_size; + uint32_t num_sectors; + uint32_t sector_size; + uint32_t ecc_strength; + uint32_t ecc_bytes; +}; + +struct mtk_snand; +struct snand_flash_info; + +int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata, + struct mtk_snand **psnf); +int mtk_snand_cleanup(struct mtk_snand *snf); + +int mtk_snand_chip_reset(struct mtk_snand *snf); +int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf, + void *oob, bool raw); +int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf, + const void *oob, bool raw); +int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr); +int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr); +int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr); +int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw, + const uint8_t *oobbuf, size_t ooblen); +int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf, + size_t ooblen, const uint8_t *oobraw); +int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr, + void *buf, void *oob, size_t ooblen, + size_t *actualooblen, bool raw); +int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr, + const void *buf, const void *oob, + size_t ooblen, size_t *actualooblen, + bool raw); +int mtk_snand_get_chip_info(struct mtk_snand *snf, + struct mtk_snand_chip_info *info); +int mtk_snand_irq_process(struct mtk_snand *snf); + +#endif /* _MTK_SNAND_H_ */ diff --git a/target/linux/mediatek/patches-5.10/360-mtd-add-mtk-snand-driver.patch b/target/linux/mediatek/patches-5.10/360-mtd-add-mtk-snand-driver.patch new file mode 100644 index 0000000000..ebba6ffaad --- /dev/null +++ b/target/linux/mediatek/patches-5.10/360-mtd-add-mtk-snand-driver.patch @@ -0,0 +1,21 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -238,6 +238,8 @@ source "drivers/mtd/ubi/Kconfig" + + source "drivers/mtd/hyperbus/Kconfig" + ++source "drivers/mtd/mtk-snand/Kconfig" ++ + source "drivers/mtd/composite/Kconfig" + + endif # MTD +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -34,5 +34,7 @@ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ + obj-$(CONFIG_MTD_UBI) += ubi/ + obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ + ++obj-$(CONFIG_MTK_SPI_NAND) += mtk-snand/ ++ + # Composite drivers must be loaded last + obj-y += composite/ From e8e8487603d306f989f6d582ff04a93e1f0636b1 Mon Sep 17 00:00:00 2001 From: Weijie Gao Date: Tue, 25 May 2021 21:26:09 +0800 Subject: [PATCH 30/37] mediatek: enable new spi-nand driver for kernel 5.10 This patch enables new spi-nand driver for mt7622 and mt7629. Signed-off-by: Weijie Gao Signed-off-by: Chuanhong Guo --- target/linux/mediatek/mt7622/config-5.10 | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/mediatek/mt7622/config-5.10 b/target/linux/mediatek/mt7622/config-5.10 index a95b719f03..97b19fe7a6 100644 --- a/target/linux/mediatek/mt7622/config-5.10 +++ b/target/linux/mediatek/mt7622/config-5.10 @@ -273,6 +273,7 @@ CONFIG_MTK_HSDMA=y CONFIG_MTK_INFRACFG=y CONFIG_MTK_PMIC_WRAP=y CONFIG_MTK_SCPSYS=y +CONFIG_MTK_SPI_NAND=y CONFIG_MTK_THERMAL=y CONFIG_MTK_TIMER=y # CONFIG_MTK_UART_APDMA is not set From c6ed31630d6c9a1cb8b83a37bac77e480bc127b7 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Fri, 20 Aug 2021 14:23:38 +0800 Subject: [PATCH 31/37] mediatek: remove spi-nand hacks from 5.10 we now have a standalone mtd driver and the old spi-mem driver along with the hack in spi-nand core can be removed. Signed-off-by: Chuanhong Guo --- ...e-mtk-ecc-header-file-to-include-mtd.patch | 139 -- .../310-mtd-spinand-disable-on-die-ECC.patch | 31 - ...aTek-Add-SPI-NAND-Flash-interface-dr.patch | 1246 ----------------- ...Add-support-for-the-Fidelix-FM35X1GA.patch | 122 -- 4 files changed, 1538 deletions(-) delete mode 100644 target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch delete mode 100644 target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch delete mode 100644 target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch delete mode 100644 target/linux/mediatek/patches-5.10/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch diff --git a/target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch b/target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch deleted file mode 100644 index d9ab339fa8..0000000000 --- a/target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch +++ /dev/null @@ -1,139 +0,0 @@ -From a2479dc254ebe31c84fbcfda73f35e2321576494 Mon Sep 17 00:00:00 2001 -From: Xiangsheng Hou -Date: Tue, 19 Mar 2019 13:57:38 +0800 -Subject: [PATCH 1/6] mtd: mtk ecc: move mtk ecc header file to include/mtd - -Change-Id: I8dc1d30e21b40d68ef5efd9587012f82970156a5 -Signed-off-by: Xiangsheng Hou ---- - drivers/mtd/nand/raw/mtk_ecc.c | 3 +-- - drivers/mtd/nand/raw/mtk_nand.c | 2 +- - {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h | 0 - 3 files changed, 2 insertions(+), 3 deletions(-) - rename {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h (100%) - ---- a/drivers/mtd/nand/raw/mtk_ecc.c -+++ b/drivers/mtd/nand/raw/mtk_ecc.c -@@ -15,8 +15,7 @@ - #include - #include - #include -- --#include "mtk_ecc.h" -+#include - - #define ECC_IDLE_MASK BIT(0) - #define ECC_IRQ_EN BIT(0) ---- a/drivers/mtd/nand/raw/mtk_nand.c -+++ b/drivers/mtd/nand/raw/mtk_nand.c -@@ -17,7 +17,7 @@ - #include - #include - #include --#include "mtk_ecc.h" -+#include - - /* NAND controller register definition */ - #define NFI_CNFG (0x00) ---- /dev/null -+++ b/include/linux/mtd/mtk_ecc.h -@@ -0,0 +1,49 @@ -+/* -+ * MTK SDG1 ECC controller -+ * -+ * Copyright (c) 2016 Mediatek -+ * Authors: Xiaolei Li -+ * Jorge Ramirez-Ortiz -+ * 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. -+ */ -+ -+#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__ -+#define __DRIVERS_MTD_NAND_MTK_ECC_H__ -+ -+#include -+ -+enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1}; -+enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE}; -+ -+struct device_node; -+struct mtk_ecc; -+ -+struct mtk_ecc_stats { -+ u32 corrected; -+ u32 bitflips; -+ u32 failed; -+}; -+ -+struct mtk_ecc_config { -+ enum mtk_ecc_operation op; -+ enum mtk_ecc_mode mode; -+ dma_addr_t addr; -+ u32 strength; -+ u32 sectors; -+ u32 len; -+}; -+ -+int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32); -+void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int); -+int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation); -+int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *); -+void mtk_ecc_disable(struct mtk_ecc *); -+void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p); -+unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc); -+ -+struct mtk_ecc *of_mtk_ecc_get(struct device_node *); -+void mtk_ecc_release(struct mtk_ecc *); -+ -+#endif ---- a/drivers/mtd/nand/raw/mtk_ecc.h -+++ /dev/null -@@ -1,47 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 OR MIT */ --/* -- * MTK SDG1 ECC controller -- * -- * Copyright (c) 2016 Mediatek -- * Authors: Xiaolei Li -- * Jorge Ramirez-Ortiz -- */ -- --#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__ --#define __DRIVERS_MTD_NAND_MTK_ECC_H__ -- --#include -- --enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1}; --enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE}; -- --struct device_node; --struct mtk_ecc; -- --struct mtk_ecc_stats { -- u32 corrected; -- u32 bitflips; -- u32 failed; --}; -- --struct mtk_ecc_config { -- enum mtk_ecc_operation op; -- enum mtk_ecc_mode mode; -- dma_addr_t addr; -- u32 strength; -- u32 sectors; -- u32 len; --}; -- --int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32); --void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int); --int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation); --int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *); --void mtk_ecc_disable(struct mtk_ecc *); --void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p); --unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc); -- --struct mtk_ecc *of_mtk_ecc_get(struct device_node *); --void mtk_ecc_release(struct mtk_ecc *); -- --#endif diff --git a/target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch b/target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch deleted file mode 100644 index e608113865..0000000000 --- a/target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch +++ /dev/null @@ -1,31 +0,0 @@ -From b341f120cfc9ca1dfd48364b7f36ac2c1fbdea43 Mon Sep 17 00:00:00 2001 -From: Xiangsheng Hou -Date: Wed, 3 Apr 2019 16:30:01 +0800 -Subject: [PATCH 3/6] mtd: spinand: disable on-die ECC - -Change-Id: I9745adaed5295202fabbe8ab8947885c57a5b847 -Signed-off-by: Xiangsheng Hou ---- - drivers/mtd/nand/spi/core.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/mtd/nand/spi/core.c -+++ b/drivers/mtd/nand/spi/core.c -@@ -493,7 +493,7 @@ static int spinand_mtd_read(struct mtd_i - int ret = 0; - - if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout) -- enable_ecc = true; -+ enable_ecc = false; - - mutex_lock(&spinand->lock); - -@@ -541,7 +541,7 @@ static int spinand_mtd_write(struct mtd_ - int ret = 0; - - if (ops->mode != MTD_OPS_RAW && mtd->ooblayout) -- enable_ecc = true; -+ enable_ecc = false; - - mutex_lock(&spinand->lock); - diff --git a/target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch b/target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch deleted file mode 100644 index 53e2aed51e..0000000000 --- a/target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch +++ /dev/null @@ -1,1246 +0,0 @@ -From 1ecb38eabd90efe93957d0a822a167560c39308a Mon Sep 17 00:00:00 2001 -From: Xiangsheng Hou -Date: Wed, 20 Mar 2019 16:19:51 +0800 -Subject: [PATCH 6/6] spi: spi-mem: MediaTek: Add SPI NAND Flash interface - driver for MediaTek MT7622 - -Change-Id: I3e78406bb9b46b0049d3988a5c71c7069e4f809c -Signed-off-by: Xiangsheng Hou ---- - drivers/spi/Kconfig | 9 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-mtk-snfi.c | 1183 ++++++++++++++++++++++++++++++++++++ - 3 files changed, 1193 insertions(+) - create mode 100644 drivers/spi/spi-mtk-snfi.c - ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -67,6 +67,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mp - obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o - obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o - obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o -+obj-$(CONFIG_SPI_MTK_SNFI) += spi-mtk-snfi.o - obj-$(CONFIG_SPI_MT7621) += spi-mt7621.o - obj-$(CONFIG_SPI_MTK_NOR) += spi-mtk-nor.o - obj-$(CONFIG_SPI_MXIC) += spi-mxic.o ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -495,6 +495,15 @@ config SPI_MT65XX - say Y or M here.If you are not sure, say N. - SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs. - -+config SPI_MTK_SNFI -+ tristate "MediaTek SPI NAND interface" -+ select MTD_SPI_NAND -+ help -+ This selects the SPI NAND FLASH interface(SNFI), -+ which could be found on MediaTek Soc. -+ Say Y or M here.If you are not sure, say N. -+ Note Parallel Nand and SPI NAND is alternative on MediaTek SoCs. -+ - config SPI_MT7621 - tristate "MediaTek MT7621 SPI Controller" - depends on RALINK || COMPILE_TEST ---- /dev/null -+++ b/drivers/spi/spi-mtk-snfi.c -@@ -0,0 +1,1200 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Driver for MediaTek SPI Nand interface -+ * -+ * Copyright (C) 2018 MediaTek Inc. -+ * Authors: Xiangsheng Hou -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* NAND controller register definition */ -+/* NFI control */ -+#define NFI_CNFG 0x00 -+#define CNFG_DMA BIT(0) -+#define CNFG_READ_EN BIT(1) -+#define CNFG_DMA_BURST_EN BIT(2) -+#define CNFG_BYTE_RW BIT(6) -+#define CNFG_HW_ECC_EN BIT(8) -+#define CNFG_AUTO_FMT_EN BIT(9) -+#define CNFG_OP_PROGRAM (3UL << 12) -+#define CNFG_OP_CUST (6UL << 12) -+#define NFI_PAGEFMT 0x04 -+#define PAGEFMT_512 0 -+#define PAGEFMT_2K 1 -+#define PAGEFMT_4K 2 -+#define PAGEFMT_FDM_SHIFT 8 -+#define PAGEFMT_FDM_ECC_SHIFT 12 -+#define NFI_CON 0x08 -+#define CON_FIFO_FLUSH BIT(0) -+#define CON_NFI_RST BIT(1) -+#define CON_BRD BIT(8) -+#define CON_BWR BIT(9) -+#define CON_SEC_SHIFT 12 -+#define NFI_INTR_EN 0x10 -+#define INTR_AHB_DONE_EN BIT(6) -+#define NFI_INTR_STA 0x14 -+#define NFI_CMD 0x20 -+#define NFI_STA 0x60 -+#define STA_EMP_PAGE BIT(12) -+#define NAND_FSM_MASK (0x1f << 24) -+#define NFI_FSM_MASK (0xf << 16) -+#define NFI_ADDRCNTR 0x70 -+#define CNTR_MASK GENMASK(16, 12) -+#define ADDRCNTR_SEC_SHIFT 12 -+#define ADDRCNTR_SEC(val) \ -+ (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT) -+#define NFI_STRADDR 0x80 -+#define NFI_BYTELEN 0x84 -+#define NFI_CSEL 0x90 -+#define NFI_FDML(x) (0xa0 + (x) * sizeof(u32) * 2) -+#define NFI_FDMM(x) (0xa4 + (x) * sizeof(u32) * 2) -+#define NFI_MASTER_STA 0x224 -+#define MASTER_STA_MASK 0x0fff -+/* NFI_SPI control */ -+#define SNFI_MAC_OUTL 0x504 -+#define SNFI_MAC_INL 0x508 -+#define SNFI_RD_CTL2 0x510 -+#define RD_CMD_MASK 0x00ff -+#define RD_DUMMY_SHIFT 8 -+#define SNFI_RD_CTL3 0x514 -+#define RD_ADDR_MASK 0xffff -+#define SNFI_MISC_CTL 0x538 -+#define RD_MODE_X2 BIT(16) -+#define RD_MODE_X4 (2UL << 16) -+#define RD_QDUAL_IO (4UL << 16) -+#define RD_MODE_MASK (7UL << 16) -+#define RD_CUSTOM_EN BIT(6) -+#define WR_CUSTOM_EN BIT(7) -+#define WR_X4_EN BIT(20) -+#define SW_RST BIT(28) -+#define SNFI_MISC_CTL2 0x53c -+#define WR_LEN_SHIFT 16 -+#define SNFI_PG_CTL1 0x524 -+#define WR_LOAD_CMD_SHIFT 8 -+#define SNFI_PG_CTL2 0x528 -+#define WR_LOAD_ADDR_MASK 0xffff -+#define SNFI_MAC_CTL 0x500 -+#define MAC_WIP BIT(0) -+#define MAC_WIP_READY BIT(1) -+#define MAC_TRIG BIT(2) -+#define MAC_EN BIT(3) -+#define MAC_SIO_SEL BIT(4) -+#define SNFI_STA_CTL1 0x550 -+#define SPI_STATE_IDLE 0xf -+#define SNFI_CNFG 0x55c -+#define SNFI_MODE_EN BIT(0) -+#define SNFI_GPRAM_DATA 0x800 -+#define SNFI_GPRAM_MAX_LEN 16 -+ -+/* Dummy command trigger NFI to spi mode */ -+#define NAND_CMD_DUMMYREAD 0x00 -+#define NAND_CMD_DUMMYPROG 0x80 -+ -+#define MTK_TIMEOUT 500000 -+#define MTK_RESET_TIMEOUT 1000000 -+#define MTK_SNFC_MIN_SPARE 16 -+#define KB(x) ((x) * 1024UL) -+ -+/* -+ * supported spare size of each IP. -+ * order should be the same with the spare size bitfiled defination of -+ * register NFI_PAGEFMT. -+ */ -+static const u8 spare_size_mt7622[] = { -+ 16, 26, 27, 28 -+}; -+ -+struct mtk_snfi_caps { -+ const u8 *spare_size; -+ u8 num_spare_size; -+ u32 nand_sec_size; -+ u8 nand_fdm_size; -+ u8 nand_fdm_ecc_size; -+ u8 ecc_parity_bits; -+ u8 pageformat_spare_shift; -+ u8 bad_mark_swap; -+}; -+ -+struct mtk_snfi_bad_mark_ctl { -+ void (*bm_swap)(struct spi_mem *mem, u8 *buf, int raw); -+ u32 sec; -+ u32 pos; -+}; -+ -+struct mtk_snfi_nand_chip { -+ struct mtk_snfi_bad_mark_ctl bad_mark; -+ u32 spare_per_sector; -+}; -+ -+struct mtk_snfi_clk { -+ struct clk *nfi_clk; -+ struct clk *spi_clk; -+}; -+ -+struct mtk_snfi { -+ const struct mtk_snfi_caps *caps; -+ struct mtk_snfi_nand_chip snfi_nand; -+ struct mtk_snfi_clk clk; -+ struct mtk_ecc_config ecc_cfg; -+ struct mtk_ecc *ecc; -+ struct completion done; -+ struct device *dev; -+ -+ void __iomem *regs; -+ -+ u8 *buffer; -+}; -+ -+static inline u8 *oob_ptr(struct spi_mem *mem, int i) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u8 *poi; -+ -+ /* map the sector's FDM data to free oob: -+ * the beginning of the oob area stores the FDM data of bad mark -+ */ -+ -+ if (i < snfi_nand->bad_mark.sec) -+ poi = spinand->oobbuf + (i + 1) * snfi->caps->nand_fdm_size; -+ else if (i == snfi_nand->bad_mark.sec) -+ poi = spinand->oobbuf; -+ else -+ poi = spinand->oobbuf + i * snfi->caps->nand_fdm_size; -+ -+ return poi; -+} -+ -+static inline int mtk_data_len(struct spi_mem *mem) -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ -+ return snfi->caps->nand_sec_size + snfi_nand->spare_per_sector; -+} -+ -+static inline u8 *mtk_oob_ptr(struct spi_mem *mem, -+ const u8 *p, int i) -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ -+ return (u8 *)p + i * mtk_data_len(mem) + snfi->caps->nand_sec_size; -+} -+ -+static void mtk_snfi_bad_mark_swap(struct spi_mem *mem, -+ u8 *buf, int raw) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u32 bad_pos = snfi_nand->bad_mark.pos; -+ -+ if (raw) -+ bad_pos += snfi_nand->bad_mark.sec * mtk_data_len(mem); -+ else -+ bad_pos += snfi_nand->bad_mark.sec * snfi->caps->nand_sec_size; -+ -+ swap(spinand->oobbuf[0], buf[bad_pos]); -+} -+ -+static void mtk_snfi_set_bad_mark_ctl(struct mtk_snfi_bad_mark_ctl *bm_ctl, -+ struct spi_mem *mem) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ -+ bm_ctl->bm_swap = mtk_snfi_bad_mark_swap; -+ bm_ctl->sec = mtd->writesize / mtk_data_len(mem); -+ bm_ctl->pos = mtd->writesize % mtk_data_len(mem); -+} -+ -+static void mtk_snfi_mac_enable(struct mtk_snfi *snfi) -+{ -+ u32 mac; -+ -+ mac = readl(snfi->regs + SNFI_MAC_CTL); -+ mac &= ~MAC_SIO_SEL; -+ mac |= MAC_EN; -+ -+ writel(mac, snfi->regs + SNFI_MAC_CTL); -+} -+ -+static int mtk_snfi_mac_trigger(struct mtk_snfi *snfi) -+{ -+ u32 mac, reg; -+ int ret = 0; -+ -+ mac = readl(snfi->regs + SNFI_MAC_CTL); -+ mac |= MAC_TRIG; -+ writel(mac, snfi->regs + SNFI_MAC_CTL); -+ -+ ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg, -+ reg & MAC_WIP_READY, 10, -+ MTK_TIMEOUT); -+ if (ret < 0) { -+ dev_err(snfi->dev, "polling wip ready for read timeout\n"); -+ return -EIO; -+ } -+ -+ ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg, -+ !(reg & MAC_WIP), 10, -+ MTK_TIMEOUT); -+ if (ret < 0) { -+ dev_err(snfi->dev, "polling flash update timeout\n"); -+ return -EIO; -+ } -+ -+ return ret; -+} -+ -+static void mtk_snfi_mac_leave(struct mtk_snfi *snfi) -+{ -+ u32 mac; -+ -+ mac = readl(snfi->regs + SNFI_MAC_CTL); -+ mac &= ~(MAC_TRIG | MAC_EN | MAC_SIO_SEL); -+ writel(mac, snfi->regs + SNFI_MAC_CTL); -+} -+ -+static int mtk_snfi_mac_op(struct mtk_snfi *snfi) -+{ -+ int ret = 0; -+ -+ mtk_snfi_mac_enable(snfi); -+ -+ ret = mtk_snfi_mac_trigger(snfi); -+ if (ret) -+ return ret; -+ -+ mtk_snfi_mac_leave(snfi); -+ -+ return ret; -+} -+ -+static irqreturn_t mtk_snfi_irq(int irq, void *id) -+{ -+ struct mtk_snfi *snfi = id; -+ u16 sta, ien; -+ -+ sta = readw(snfi->regs + NFI_INTR_STA); -+ ien = readw(snfi->regs + NFI_INTR_EN); -+ -+ if (!(sta & ien)) -+ return IRQ_NONE; -+ -+ writew(~sta & ien, snfi->regs + NFI_INTR_EN); -+ complete(&snfi->done); -+ -+ return IRQ_HANDLED; -+} -+ -+static int mtk_snfi_enable_clk(struct device *dev, struct mtk_snfi_clk *clk) -+{ -+ int ret; -+ -+ ret = clk_prepare_enable(clk->nfi_clk); -+ if (ret) { -+ dev_err(dev, "failed to enable nfi clk\n"); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clk->spi_clk); -+ if (ret) { -+ dev_err(dev, "failed to enable spi clk\n"); -+ clk_disable_unprepare(clk->nfi_clk); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void mtk_snfi_disable_clk(struct mtk_snfi_clk *clk) -+{ -+ clk_disable_unprepare(clk->nfi_clk); -+ clk_disable_unprepare(clk->spi_clk); -+} -+ -+static int mtk_snfi_reset(struct mtk_snfi *snfi) -+{ -+ u32 val; -+ int ret; -+ -+ /* SW reset controller */ -+ val = readl(snfi->regs + SNFI_MISC_CTL) | SW_RST; -+ writel(val, snfi->regs + SNFI_MISC_CTL); -+ -+ ret = readw_poll_timeout(snfi->regs + SNFI_STA_CTL1, val, -+ !(val & SPI_STATE_IDLE), 50, -+ MTK_RESET_TIMEOUT); -+ if (ret) { -+ dev_warn(snfi->dev, "spi state active in reset [0x%x] = 0x%x\n", -+ SNFI_STA_CTL1, val); -+ return ret; -+ } -+ -+ val = readl(snfi->regs + SNFI_MISC_CTL); -+ val &= ~SW_RST; -+ writel(val, snfi->regs + SNFI_MISC_CTL); -+ -+ /* reset all registers and force the NFI master to terminate */ -+ writew(CON_FIFO_FLUSH | CON_NFI_RST, snfi->regs + NFI_CON); -+ ret = readw_poll_timeout(snfi->regs + NFI_STA, val, -+ !(val & (NFI_FSM_MASK | NAND_FSM_MASK)), 50, -+ MTK_RESET_TIMEOUT); -+ if (ret) { -+ dev_warn(snfi->dev, "nfi active in reset [0x%x] = 0x%x\n", -+ NFI_STA, val); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int mtk_snfi_set_spare_per_sector(struct spinand_device *spinand, -+ const struct mtk_snfi_caps *caps, -+ u32 *sps) -+{ -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ const u8 *spare = caps->spare_size; -+ u32 sectors, i, closest_spare = 0; -+ -+ sectors = mtd->writesize / caps->nand_sec_size; -+ *sps = mtd->oobsize / sectors; -+ -+ if (*sps < MTK_SNFC_MIN_SPARE) -+ return -EINVAL; -+ -+ for (i = 0; i < caps->num_spare_size; i++) { -+ if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) { -+ closest_spare = i; -+ if (*sps == spare[i]) -+ break; -+ } -+ } -+ -+ *sps = spare[closest_spare]; -+ -+ return 0; -+} -+ -+static void mtk_snfi_read_fdm_data(struct spi_mem *mem, -+ u32 sectors) -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ const struct mtk_snfi_caps *caps = snfi->caps; -+ u32 vall, valm; -+ int i, j; -+ u8 *oobptr; -+ -+ for (i = 0; i < sectors; i++) { -+ oobptr = oob_ptr(mem, i); -+ vall = readl(snfi->regs + NFI_FDML(i)); -+ valm = readl(snfi->regs + NFI_FDMM(i)); -+ -+ for (j = 0; j < caps->nand_fdm_size; j++) -+ oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8); -+ } -+} -+ -+static void mtk_snfi_write_fdm_data(struct spi_mem *mem, -+ u32 sectors) -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ const struct mtk_snfi_caps *caps = snfi->caps; -+ u32 vall, valm; -+ int i, j; -+ u8 *oobptr; -+ -+ for (i = 0; i < sectors; i++) { -+ oobptr = oob_ptr(mem, i); -+ vall = 0; -+ valm = 0; -+ for (j = 0; j < 8; j++) { -+ if (j < 4) -+ vall |= (j < caps->nand_fdm_size ? oobptr[j] : -+ 0xff) << (j * 8); -+ else -+ valm |= (j < caps->nand_fdm_size ? oobptr[j] : -+ 0xff) << ((j - 4) * 8); -+ } -+ writel(vall, snfi->regs + NFI_FDML(i)); -+ writel(valm, snfi->regs + NFI_FDMM(i)); -+ } -+} -+ -+static int mtk_snfi_update_ecc_stats(struct spi_mem *mem, -+ u8 *buf, u32 sectors) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct mtk_ecc_stats stats; -+ int rc, i; -+ -+ rc = readl(snfi->regs + NFI_STA) & STA_EMP_PAGE; -+ if (rc) { -+ memset(buf, 0xff, sectors * snfi->caps->nand_sec_size); -+ for (i = 0; i < sectors; i++) -+ memset(spinand->oobbuf, 0xff, -+ snfi->caps->nand_fdm_size); -+ return 0; -+ } -+ -+ mtk_ecc_get_stats(snfi->ecc, &stats, sectors); -+ mtd->ecc_stats.corrected += stats.corrected; -+ mtd->ecc_stats.failed += stats.failed; -+ -+ return 0; -+} -+ -+static int mtk_snfi_hw_runtime_config(struct spi_mem *mem) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ struct nand_device *nand = mtd_to_nanddev(mtd); -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ const struct mtk_snfi_caps *caps = snfi->caps; -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u32 fmt, spare, i = 0; -+ int ret; -+ -+ ret = mtk_snfi_set_spare_per_sector(spinand, caps, &spare); -+ if (ret) -+ return ret; -+ -+ /* calculate usable oob bytes for ecc parity data */ -+ snfi_nand->spare_per_sector = spare; -+ spare -= caps->nand_fdm_size; -+ -+ nand->memorg.oobsize = snfi_nand->spare_per_sector -+ * (mtd->writesize / caps->nand_sec_size); -+ mtd->oobsize = nanddev_per_page_oobsize(nand); -+ -+ snfi->ecc_cfg.strength = (spare << 3) / caps->ecc_parity_bits; -+ mtk_ecc_adjust_strength(snfi->ecc, &snfi->ecc_cfg.strength); -+ -+ switch (mtd->writesize) { -+ case 512: -+ fmt = PAGEFMT_512; -+ break; -+ case KB(2): -+ fmt = PAGEFMT_2K; -+ break; -+ case KB(4): -+ fmt = PAGEFMT_4K; -+ break; -+ default: -+ dev_err(snfi->dev, "invalid page len: %d\n", mtd->writesize); -+ return -EINVAL; -+ } -+ -+ /* Setup PageFormat */ -+ while (caps->spare_size[i] != snfi_nand->spare_per_sector) { -+ i++; -+ if (i == (caps->num_spare_size - 1)) { -+ dev_err(snfi->dev, "invalid spare size %d\n", -+ snfi_nand->spare_per_sector); -+ return -EINVAL; -+ } -+ } -+ -+ fmt |= i << caps->pageformat_spare_shift; -+ fmt |= caps->nand_fdm_size << PAGEFMT_FDM_SHIFT; -+ fmt |= caps->nand_fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT; -+ writel(fmt, snfi->regs + NFI_PAGEFMT); -+ -+ snfi->ecc_cfg.len = caps->nand_sec_size + caps->nand_fdm_ecc_size; -+ -+ mtk_snfi_set_bad_mark_ctl(&snfi_nand->bad_mark, mem); -+ -+ return 0; -+} -+ -+static int mtk_snfi_read_from_cache(struct spi_mem *mem, -+ const struct spi_mem_op *op, int oob_on) -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ u32 sectors = mtd->writesize / snfi->caps->nand_sec_size; -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u32 reg, len, col_addr = 0; -+ int dummy_cycle, ret; -+ dma_addr_t dma_addr; -+ -+ len = sectors * (snfi->caps->nand_sec_size -+ + snfi_nand->spare_per_sector); -+ -+ dma_addr = dma_map_single(snfi->dev, snfi->buffer, -+ len, DMA_FROM_DEVICE); -+ ret = dma_mapping_error(snfi->dev, dma_addr); -+ if (ret) { -+ dev_err(snfi->dev, "dma mapping error\n"); -+ return -EINVAL; -+ } -+ -+ /* set Read cache command and dummy cycle */ -+ dummy_cycle = (op->dummy.nbytes << 3) >> (ffs(op->dummy.buswidth) - 1); -+ reg = ((op->cmd.opcode & RD_CMD_MASK) | -+ (dummy_cycle << RD_DUMMY_SHIFT)); -+ writel(reg, snfi->regs + SNFI_RD_CTL2); -+ -+ writel((col_addr & RD_ADDR_MASK), snfi->regs + SNFI_RD_CTL3); -+ -+ reg = readl(snfi->regs + SNFI_MISC_CTL); -+ reg |= RD_CUSTOM_EN; -+ reg &= ~(RD_MODE_MASK | WR_X4_EN); -+ -+ /* set data and addr buswidth */ -+ if (op->data.buswidth == 4) -+ reg |= RD_MODE_X4; -+ else if (op->data.buswidth == 2) -+ reg |= RD_MODE_X2; -+ -+ if (op->addr.buswidth == 4 || op->addr.buswidth == 2) -+ reg |= RD_QDUAL_IO; -+ writel(reg, snfi->regs + SNFI_MISC_CTL); -+ -+ writel(len, snfi->regs + SNFI_MISC_CTL2); -+ writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON); -+ reg = readw(snfi->regs + NFI_CNFG); -+ reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | CNFG_OP_CUST; -+ -+ if (!oob_on) { -+ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; -+ writew(reg, snfi->regs + NFI_CNFG); -+ -+ snfi->ecc_cfg.mode = ECC_NFI_MODE; -+ snfi->ecc_cfg.sectors = sectors; -+ snfi->ecc_cfg.op = ECC_DECODE; -+ ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg); -+ if (ret) { -+ dev_err(snfi->dev, "ecc enable failed\n"); -+ /* clear NFI_CNFG */ -+ reg &= ~(CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | -+ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); -+ writew(reg, snfi->regs + NFI_CNFG); -+ goto out; -+ } -+ } else { -+ writew(reg, snfi->regs + NFI_CNFG); -+ } -+ -+ writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR); -+ readw(snfi->regs + NFI_INTR_STA); -+ writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN); -+ -+ init_completion(&snfi->done); -+ -+ /* set dummy command to trigger NFI enter SPI mode */ -+ writew(NAND_CMD_DUMMYREAD, snfi->regs + NFI_CMD); -+ reg = readl(snfi->regs + NFI_CON) | CON_BRD; -+ writew(reg, snfi->regs + NFI_CON); -+ -+ ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500)); -+ if (!ret) { -+ dev_err(snfi->dev, "read ahb done timeout\n"); -+ writew(0, snfi->regs + NFI_INTR_EN); -+ ret = -ETIMEDOUT; -+ goto out; -+ } -+ -+ ret = readl_poll_timeout_atomic(snfi->regs + NFI_BYTELEN, reg, -+ ADDRCNTR_SEC(reg) >= sectors, 10, -+ MTK_TIMEOUT); -+ if (ret < 0) { -+ dev_err(snfi->dev, "polling read byte len timeout\n"); -+ ret = -EIO; -+ } else { -+ if (!oob_on) { -+ ret = mtk_ecc_wait_done(snfi->ecc, ECC_DECODE); -+ if (ret) { -+ dev_warn(snfi->dev, "wait ecc done timeout\n"); -+ } else { -+ mtk_snfi_update_ecc_stats(mem, snfi->buffer, -+ sectors); -+ mtk_snfi_read_fdm_data(mem, sectors); -+ } -+ } -+ } -+ -+ if (oob_on) -+ goto out; -+ -+ mtk_ecc_disable(snfi->ecc); -+out: -+ dma_unmap_single(snfi->dev, dma_addr, len, DMA_FROM_DEVICE); -+ writel(0, snfi->regs + NFI_CON); -+ writel(0, snfi->regs + NFI_CNFG); -+ reg = readl(snfi->regs + SNFI_MISC_CTL); -+ reg &= ~RD_CUSTOM_EN; -+ writel(reg, snfi->regs + SNFI_MISC_CTL); -+ -+ return ret; -+} -+ -+static int mtk_snfi_write_to_cache(struct spi_mem *mem, -+ const struct spi_mem_op *op, -+ int oob_on) -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ u32 sectors = mtd->writesize / snfi->caps->nand_sec_size; -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u32 reg, len, col_addr = 0; -+ dma_addr_t dma_addr; -+ int ret; -+ -+ len = sectors * (snfi->caps->nand_sec_size -+ + snfi_nand->spare_per_sector); -+ -+ dma_addr = dma_map_single(snfi->dev, snfi->buffer, len, -+ DMA_TO_DEVICE); -+ ret = dma_mapping_error(snfi->dev, dma_addr); -+ if (ret) { -+ dev_err(snfi->dev, "dma mapping error\n"); -+ return -EINVAL; -+ } -+ -+ /* set program load cmd and address */ -+ reg = (op->cmd.opcode << WR_LOAD_CMD_SHIFT); -+ writel(reg, snfi->regs + SNFI_PG_CTL1); -+ writel(col_addr & WR_LOAD_ADDR_MASK, snfi->regs + SNFI_PG_CTL2); -+ -+ reg = readl(snfi->regs + SNFI_MISC_CTL); -+ reg |= WR_CUSTOM_EN; -+ reg &= ~(RD_MODE_MASK | WR_X4_EN); -+ -+ if (op->data.buswidth == 4) -+ reg |= WR_X4_EN; -+ writel(reg, snfi->regs + SNFI_MISC_CTL); -+ -+ writel(len << WR_LEN_SHIFT, snfi->regs + SNFI_MISC_CTL2); -+ writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON); -+ -+ reg = readw(snfi->regs + NFI_CNFG); -+ reg &= ~(CNFG_READ_EN | CNFG_BYTE_RW); -+ reg |= CNFG_DMA | CNFG_DMA_BURST_EN | CNFG_OP_PROGRAM; -+ -+ if (!oob_on) { -+ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; -+ writew(reg, snfi->regs + NFI_CNFG); -+ -+ snfi->ecc_cfg.mode = ECC_NFI_MODE; -+ snfi->ecc_cfg.op = ECC_ENCODE; -+ ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg); -+ if (ret) { -+ dev_err(snfi->dev, "ecc enable failed\n"); -+ /* clear NFI_CNFG */ -+ reg &= ~(CNFG_DMA_BURST_EN | CNFG_DMA | -+ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); -+ writew(reg, snfi->regs + NFI_CNFG); -+ dma_unmap_single(snfi->dev, dma_addr, len, -+ DMA_FROM_DEVICE); -+ goto out; -+ } -+ /* write OOB into the FDM registers (OOB area in MTK NAND) */ -+ mtk_snfi_write_fdm_data(mem, sectors); -+ } else { -+ writew(reg, snfi->regs + NFI_CNFG); -+ } -+ writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR); -+ readw(snfi->regs + NFI_INTR_STA); -+ writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN); -+ -+ init_completion(&snfi->done); -+ -+ /* set dummy command to trigger NFI enter SPI mode */ -+ writew(NAND_CMD_DUMMYPROG, snfi->regs + NFI_CMD); -+ reg = readl(snfi->regs + NFI_CON) | CON_BWR; -+ writew(reg, snfi->regs + NFI_CON); -+ -+ ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500)); -+ if (!ret) { -+ dev_err(snfi->dev, "custom program done timeout\n"); -+ writew(0, snfi->regs + NFI_INTR_EN); -+ ret = -ETIMEDOUT; -+ goto ecc_disable; -+ } -+ -+ ret = readl_poll_timeout_atomic(snfi->regs + NFI_ADDRCNTR, reg, -+ ADDRCNTR_SEC(reg) >= sectors, -+ 10, MTK_TIMEOUT); -+ if (ret) -+ dev_err(snfi->dev, "hwecc write timeout\n"); -+ -+ecc_disable: -+ mtk_ecc_disable(snfi->ecc); -+ -+out: -+ dma_unmap_single(snfi->dev, dma_addr, len, DMA_TO_DEVICE); -+ writel(0, snfi->regs + NFI_CON); -+ writel(0, snfi->regs + NFI_CNFG); -+ reg = readl(snfi->regs + SNFI_MISC_CTL); -+ reg &= ~WR_CUSTOM_EN; -+ writel(reg, snfi->regs + SNFI_MISC_CTL); -+ -+ return ret; -+} -+ -+static int mtk_snfi_read(struct spi_mem *mem, -+ const struct spi_mem_op *op) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u32 col_addr = op->addr.val; -+ int i, ret, sectors, oob_on = false; -+ -+ if (col_addr == mtd->writesize) -+ oob_on = true; -+ -+ ret = mtk_snfi_read_from_cache(mem, op, oob_on); -+ if (ret) { -+ dev_warn(snfi->dev, "read from cache fail\n"); -+ return ret; -+ } -+ -+ sectors = mtd->writesize / snfi->caps->nand_sec_size; -+ for (i = 0; i < sectors; i++) { -+ if (oob_on) -+ memcpy(oob_ptr(mem, i), -+ mtk_oob_ptr(mem, snfi->buffer, i), -+ snfi->caps->nand_fdm_size); -+ -+ if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap) -+ snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, -+ oob_on); -+ } -+ -+ if (!oob_on) -+ memcpy(spinand->databuf, snfi->buffer, mtd->writesize); -+ -+ return ret; -+} -+ -+static int mtk_snfi_write(struct spi_mem *mem, -+ const struct spi_mem_op *op) -+{ -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; -+ u32 ret, i, sectors, col_addr = op->addr.val; -+ int oob_on = false; -+ -+ if (col_addr == mtd->writesize) -+ oob_on = true; -+ -+ sectors = mtd->writesize / snfi->caps->nand_sec_size; -+ memset(snfi->buffer, 0xff, mtd->writesize + mtd->oobsize); -+ -+ if (!oob_on) -+ memcpy(snfi->buffer, spinand->databuf, mtd->writesize); -+ -+ for (i = 0; i < sectors; i++) { -+ if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap) -+ snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, oob_on); -+ -+ if (oob_on) -+ memcpy(mtk_oob_ptr(mem, snfi->buffer, i), -+ oob_ptr(mem, i), -+ snfi->caps->nand_fdm_size); -+ } -+ -+ ret = mtk_snfi_write_to_cache(mem, op, oob_on); -+ if (ret) -+ dev_warn(snfi->dev, "write to cache fail\n"); -+ -+ return ret; -+} -+ -+static int mtk_snfi_command_exec(struct mtk_snfi *snfi, -+ const u8 *txbuf, u8 *rxbuf, -+ const u32 txlen, const u32 rxlen) -+{ -+ u32 tmp, i, j, reg, m; -+ u8 *p_tmp = (u8 *)(&tmp); -+ int ret = 0; -+ -+ /* Moving tx data to NFI_SPI GPRAM */ -+ for (i = 0, m = 0; i < txlen; ) { -+ for (j = 0, tmp = 0; i < txlen && j < 4; i++, j++) -+ p_tmp[j] = txbuf[i]; -+ -+ writel(tmp, snfi->regs + SNFI_GPRAM_DATA + m); -+ m += 4; -+ } -+ -+ writel(txlen, snfi->regs + SNFI_MAC_OUTL); -+ writel(rxlen, snfi->regs + SNFI_MAC_INL); -+ ret = mtk_snfi_mac_op(snfi); -+ if (ret) -+ return ret; -+ -+ /* For NULL input data, this loop will be skipped */ -+ if (rxlen) -+ for (i = 0, m = 0; i < rxlen; ) { -+ reg = readl(snfi->regs + -+ SNFI_GPRAM_DATA + m); -+ for (j = 0; i < rxlen && j < 4; i++, j++, rxbuf++) { -+ if (m == 0 && i == 0) -+ j = i + txlen; -+ *rxbuf = (reg >> (j * 8)) & 0xFF; -+ } -+ m += 4; -+ } -+ -+ return ret; -+} -+ -+/* -+ * mtk_snfi_exec_op - to process command/data to send to the -+ * SPI NAND by mtk controller -+ */ -+static int mtk_snfi_exec_op(struct spi_mem *mem, -+ const struct spi_mem_op *op) -+ -+{ -+ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); -+ struct spinand_device *spinand = spi_mem_get_drvdata(mem); -+ struct mtd_info *mtd = spinand_to_mtd(spinand); -+ struct nand_device *nand = mtd_to_nanddev(mtd); -+ const struct spi_mem_op *read_cache; -+ const struct spi_mem_op *write_cache; -+ const struct spi_mem_op *update_cache; -+ u32 tmpbufsize, txlen = 0, rxlen = 0; -+ u8 *txbuf, *rxbuf = NULL, *buf; -+ int i, ret = 0; -+ -+ ret = mtk_snfi_reset(snfi); -+ if (ret) { -+ dev_warn(snfi->dev, "reset spi memory controller fail\n"); -+ return ret; -+ } -+ -+ /*if bbt initial, framework have detect nand information */ -+ if (nand->bbt.cache) { -+ read_cache = spinand->op_templates.read_cache; -+ write_cache = spinand->op_templates.write_cache; -+ update_cache = spinand->op_templates.update_cache; -+ -+ ret = mtk_snfi_hw_runtime_config(mem); -+ if (ret) -+ return ret; -+ -+ /* For Read/Write with cache, Erase use framework flow */ -+ if (op->cmd.opcode == read_cache->cmd.opcode) { -+ ret = mtk_snfi_read(mem, op); -+ if (ret) -+ dev_warn(snfi->dev, "snfi read fail\n"); -+ -+ return ret; -+ } else if ((op->cmd.opcode == write_cache->cmd.opcode) -+ || (op->cmd.opcode == update_cache->cmd.opcode)) { -+ ret = mtk_snfi_write(mem, op); -+ if (ret) -+ dev_warn(snfi->dev, "snfi write fail\n"); -+ -+ return ret; -+ } -+ } -+ -+ tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + -+ op->dummy.nbytes + op->data.nbytes; -+ -+ txbuf = kzalloc(tmpbufsize, GFP_KERNEL); -+ if (!txbuf) -+ return -ENOMEM; -+ -+ txbuf[txlen++] = op->cmd.opcode; -+ -+ if (op->addr.nbytes) -+ for (i = 0; i < op->addr.nbytes; i++) -+ txbuf[txlen++] = op->addr.val >> -+ (8 * (op->addr.nbytes - i - 1)); -+ -+ txlen += op->dummy.nbytes; -+ -+ if (op->data.dir == SPI_MEM_DATA_OUT) -+ for (i = 0; i < op->data.nbytes; i++) { -+ buf = (u8 *)op->data.buf.out; -+ txbuf[txlen++] = buf[i]; -+ } -+ -+ if (op->data.dir == SPI_MEM_DATA_IN) { -+ rxbuf = (u8 *)op->data.buf.in; -+ rxlen += op->data.nbytes; -+ } -+ -+ ret = mtk_snfi_command_exec(snfi, txbuf, rxbuf, txlen, rxlen); -+ kfree(txbuf); -+ -+ return ret; -+} -+ -+static int mtk_snfi_init(struct mtk_snfi *snfi) -+{ -+ int ret; -+ -+ /* Reset the state machine and data FIFO */ -+ ret = mtk_snfi_reset(snfi); -+ if (ret) { -+ dev_warn(snfi->dev, "MTK reset controller fail\n"); -+ return ret; -+ } -+ -+ snfi->buffer = devm_kzalloc(snfi->dev, 4096 + 256, GFP_KERNEL); -+ if (!snfi->buffer) -+ return -ENOMEM; -+ -+ /* Clear interrupt, read clear. */ -+ readw(snfi->regs + NFI_INTR_STA); -+ writew(0, snfi->regs + NFI_INTR_EN); -+ -+ writel(0, snfi->regs + NFI_CON); -+ writel(0, snfi->regs + NFI_CNFG); -+ -+ /* Change to NFI_SPI mode. */ -+ writel(SNFI_MODE_EN, snfi->regs + SNFI_CNFG); -+ -+ return 0; -+} -+ -+static int mtk_snfi_check_buswidth(u8 width) -+{ -+ switch (width) { -+ case 1: -+ case 2: -+ case 4: -+ return 0; -+ -+ default: -+ break; -+ } -+ -+ return -ENOTSUPP; -+} -+ -+static bool mtk_snfi_supports_op(struct spi_mem *mem, -+ const struct spi_mem_op *op) -+{ -+ int ret = 0; -+ -+ /* For MTK Spi Nand controller, cmd buswidth just support 1 bit*/ -+ if (op->cmd.buswidth != 1) -+ ret = -ENOTSUPP; -+ -+ if (op->addr.nbytes) -+ ret |= mtk_snfi_check_buswidth(op->addr.buswidth); -+ -+ if (op->dummy.nbytes) -+ ret |= mtk_snfi_check_buswidth(op->dummy.buswidth); -+ -+ if (op->data.nbytes) -+ ret |= mtk_snfi_check_buswidth(op->data.buswidth); -+ -+ if (ret) -+ return false; -+ -+ return true; -+} -+ -+static const struct spi_controller_mem_ops mtk_snfi_ops = { -+ .supports_op = mtk_snfi_supports_op, -+ .exec_op = mtk_snfi_exec_op, -+}; -+ -+static const struct mtk_snfi_caps snfi_mt7622 = { -+ .spare_size = spare_size_mt7622, -+ .num_spare_size = 4, -+ .nand_sec_size = 512, -+ .nand_fdm_size = 8, -+ .nand_fdm_ecc_size = 1, -+ .ecc_parity_bits = 13, -+ .pageformat_spare_shift = 4, -+ .bad_mark_swap = 0, -+}; -+ -+static const struct mtk_snfi_caps snfi_mt7629 = { -+ .spare_size = spare_size_mt7622, -+ .num_spare_size = 4, -+ .nand_sec_size = 512, -+ .nand_fdm_size = 8, -+ .nand_fdm_ecc_size = 1, -+ .ecc_parity_bits = 13, -+ .pageformat_spare_shift = 4, -+ .bad_mark_swap = 1, -+}; -+ -+static const struct of_device_id mtk_snfi_id_table[] = { -+ { .compatible = "mediatek,mt7622-snfi", .data = &snfi_mt7622, }, -+ { .compatible = "mediatek,mt7629-snfi", .data = &snfi_mt7629, }, -+ { /* sentinel */ } -+}; -+ -+static int mtk_snfi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct spi_controller *ctlr; -+ struct mtk_snfi *snfi; -+ struct resource *res; -+ int ret = 0, irq; -+ -+ ctlr = spi_alloc_master(&pdev->dev, sizeof(*snfi)); -+ if (!ctlr) -+ return -ENOMEM; -+ -+ snfi = spi_controller_get_devdata(ctlr); -+ snfi->caps = of_device_get_match_data(dev); -+ snfi->dev = dev; -+ -+ snfi->ecc = of_mtk_ecc_get(np); -+ if (IS_ERR_OR_NULL(snfi->ecc)) -+ goto err_put_master; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ snfi->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(snfi->regs)) { -+ ret = PTR_ERR(snfi->regs); -+ goto release_ecc; -+ } -+ -+ /* find the clocks */ -+ snfi->clk.nfi_clk = devm_clk_get(dev, "nfi_clk"); -+ if (IS_ERR(snfi->clk.nfi_clk)) { -+ dev_err(dev, "no nfi clk\n"); -+ ret = PTR_ERR(snfi->clk.nfi_clk); -+ goto release_ecc; -+ } -+ -+ snfi->clk.spi_clk = devm_clk_get(dev, "spi_clk"); -+ if (IS_ERR(snfi->clk.spi_clk)) { -+ dev_err(dev, "no spi clk\n"); -+ ret = PTR_ERR(snfi->clk.spi_clk); -+ goto release_ecc; -+ } -+ -+ ret = mtk_snfi_enable_clk(dev, &snfi->clk); -+ if (ret) -+ goto release_ecc; -+ -+ /* find the irq */ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ dev_err(dev, "no snfi irq resource\n"); -+ ret = -EINVAL; -+ goto clk_disable; -+ } -+ -+ ret = devm_request_irq(dev, irq, mtk_snfi_irq, 0, "mtk-snfi", snfi); -+ if (ret) { -+ dev_err(dev, "failed to request snfi irq\n"); -+ goto clk_disable; -+ } -+ -+ ret = dma_set_mask(dev, DMA_BIT_MASK(32)); -+ if (ret) { -+ dev_err(dev, "failed to set dma mask\n"); -+ goto clk_disable; -+ } -+ -+ ctlr->dev.of_node = np; -+ ctlr->mem_ops = &mtk_snfi_ops; -+ -+ platform_set_drvdata(pdev, snfi); -+ ret = mtk_snfi_init(snfi); -+ if (ret) { -+ dev_err(dev, "failed to init snfi\n"); -+ goto clk_disable; -+ } -+ -+ ret = devm_spi_register_master(dev, ctlr); -+ if (ret) -+ goto clk_disable; -+ -+ return 0; -+ -+clk_disable: -+ mtk_snfi_disable_clk(&snfi->clk); -+ -+release_ecc: -+ mtk_ecc_release(snfi->ecc); -+ -+err_put_master: -+ spi_master_put(ctlr); -+ -+ dev_err(dev, "MediaTek SPI NAND interface probe failed %d\n", ret); -+ return ret; -+} -+ -+static int mtk_snfi_remove(struct platform_device *pdev) -+{ -+ struct mtk_snfi *snfi = platform_get_drvdata(pdev); -+ -+ mtk_snfi_disable_clk(&snfi->clk); -+ -+ return 0; -+} -+ -+static int mtk_snfi_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ struct mtk_snfi *snfi = platform_get_drvdata(pdev); -+ -+ mtk_snfi_disable_clk(&snfi->clk); -+ -+ return 0; -+} -+ -+static int mtk_snfi_resume(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct mtk_snfi *snfi = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = mtk_snfi_enable_clk(dev, &snfi->clk); -+ if (ret) -+ return ret; -+ -+ ret = mtk_snfi_init(snfi); -+ if (ret) -+ dev_err(dev, "failed to init snfi controller\n"); -+ -+ return ret; -+} -+ -+static struct platform_driver mtk_snfi_driver = { -+ .driver = { -+ .name = "mtk-snfi", -+ .of_match_table = mtk_snfi_id_table, -+ }, -+ .probe = mtk_snfi_probe, -+ .remove = mtk_snfi_remove, -+ .suspend = mtk_snfi_suspend, -+ .resume = mtk_snfi_resume, -+}; -+ -+module_platform_driver(mtk_snfi_driver); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Xiangsheng Hou "); -+MODULE_DESCRIPTION("Mediatek SPI Memory Interface Driver"); diff --git a/target/linux/mediatek/patches-5.10/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch b/target/linux/mediatek/patches-5.10/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch deleted file mode 100644 index 3af929e5f0..0000000000 --- a/target/linux/mediatek/patches-5.10/340-mtd-spinand-Add-support-for-the-Fidelix-FM35X1GA.patch +++ /dev/null @@ -1,122 +0,0 @@ -From ea0df4552efcdcc2806fe6eba0540b5f719d80b6 Mon Sep 17 00:00:00 2001 -From: Davide Fioravanti -Date: Fri, 8 Jan 2021 15:35:24 +0100 -Subject: [PATCH 1/1] mtd: spinand: Add support for the Fidelix FM35X1GA - -Datasheet: http://www.hobos.com.cn/upload/datasheet/DS35X1GAXXX_100_rev00.pdf - -Signed-off-by: Davide Fioravanti ---- - drivers/mtd/nand/spi/Makefile | 2 +- - drivers/mtd/nand/spi/core.c | 1 + - drivers/mtd/nand/spi/fidelix.c | 80 ++++++++++++++++++++++++++++++++++ - include/linux/mtd/spinand.h | 1 + - 4 files changed, 83 insertions(+), 1 deletion(-) - create mode 100644 drivers/mtd/nand/spi/fidelix.c - ---- a/drivers/mtd/nand/spi/Makefile -+++ b/drivers/mtd/nand/spi/Makefile -@@ -1,3 +1,3 @@ - # SPDX-License-Identifier: GPL-2.0 --spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o -+spinand-objs := core.o fidelix.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o - obj-$(CONFIG_MTD_SPI_NAND) += spinand.o ---- a/drivers/mtd/nand/spi/core.c -+++ b/drivers/mtd/nand/spi/core.c -@@ -755,6 +755,7 @@ static const struct nand_ops spinand_ops - }; - - static const struct spinand_manufacturer *spinand_manufacturers[] = { -+ &fidelix_spinand_manufacturer, - &gigadevice_spinand_manufacturer, - ¯onix_spinand_manufacturer, - µn_spinand_manufacturer, ---- /dev/null -+++ b/drivers/mtd/nand/spi/fidelix.c -@@ -0,0 +1,76 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2020 Davide Fioravanti -+ */ -+ -+#include -+#include -+#include -+ -+#define SPINAND_MFR_FIDELIX 0xE5 -+#define FIDELIX_ECCSR_MASK 0x0F -+ -+static SPINAND_OP_VARIANTS(read_cache_variants, -+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); -+ -+static SPINAND_OP_VARIANTS(write_cache_variants, -+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), -+ SPINAND_PROG_LOAD(true, 0, NULL, 0)); -+ -+static SPINAND_OP_VARIANTS(update_cache_variants, -+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), -+ SPINAND_PROG_LOAD(false, 0, NULL, 0)); -+ -+static int fm35x1ga_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section > 3) -+ return -ERANGE; -+ -+ region->offset = (16 * section) + 8; -+ region->length = 8; -+ -+ return 0; -+} -+ -+static int fm35x1ga_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section > 3) -+ return -ERANGE; -+ -+ region->offset = (16 * section) + 2; -+ region->length = 6; -+ -+ return 0; -+} -+ -+static const struct mtd_ooblayout_ops fm35x1ga_ooblayout = { -+ .ecc = fm35x1ga_ooblayout_ecc, -+ .free = fm35x1ga_ooblayout_free, -+}; -+ -+static const struct spinand_info fidelix_spinand_table[] = { -+ SPINAND_INFO("FM35X1GA", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71), -+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&fm35x1ga_ooblayout, NULL)), -+}; -+ -+static const struct spinand_manufacturer_ops fidelix_spinand_manuf_ops = { -+}; -+ -+const struct spinand_manufacturer fidelix_spinand_manufacturer = { -+ .id = SPINAND_MFR_FIDELIX, -+ .name = "Fidelix", -+ .chips = fidelix_spinand_table, -+ .nchips = ARRAY_SIZE(fidelix_spinand_table), -+ .ops = &fidelix_spinand_manuf_ops, -+}; ---- a/include/linux/mtd/spinand.h -+++ b/include/linux/mtd/spinand.h -@@ -238,6 +238,7 @@ struct spinand_manufacturer { - }; - - /* SPI NAND manufacturers */ -+extern const struct spinand_manufacturer fidelix_spinand_manufacturer; - extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; - extern const struct spinand_manufacturer macronix_spinand_manufacturer; - extern const struct spinand_manufacturer micron_spinand_manufacturer; From 01b452fe2dace93343d8b568a57317d5fd53aea2 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Tue, 24 Aug 2021 12:04:51 +0800 Subject: [PATCH 32/37] mediatek: change dts to use the new snand driver Signed-off-by: Chuanhong Guo --- .../dts/mt7622-elecom-wrc-2533gent.dts | 83 +++++++--------- .../mediatek/dts/mt7622-linksys-e8450.dtsi | 15 +-- target/linux/mediatek/dts/mt7622-rfb1-ubi.dts | 82 +++++++--------- .../115-dts-bpi64-add-snand-support.patch | 62 +++++------- .../130-dts-mt7629-add-snand-support.patch | 48 +++------ .../131-dts-mt7622-add-snand-support.patch | 97 ++++++++----------- ...dts-fix-wmac-support-for-mt7622-rfb1.patch | 18 ++-- 7 files changed, 160 insertions(+), 245 deletions(-) diff --git a/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts b/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts index 2f3e5b1fb0..867982b061 100644 --- a/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts +++ b/target/linux/mediatek/dts/mt7622-elecom-wrc-2533gent.dts @@ -430,10 +430,6 @@ }; }; -&bch { - status = "okay"; -}; - &btif { status = "disabled"; }; @@ -501,62 +497,55 @@ status = "okay"; }; -&snfi { +&snand { + mediatek,quad-spi; pinctrl-names = "default"; pinctrl-0 = <&serial_nand_pins>; status = "okay"; - spi_nand@0 { + partitions { + compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - compatible = "spi-nand"; - spi-max-frequency = <104000000>; - reg = <0>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; + partition@0 { + label = "Preloader"; + reg = <0x00000 0x0080000>; + read-only; + }; - partition@0 { - label = "Preloader"; - reg = <0x00000 0x0080000>; - read-only; - }; + partition@80000 { + label = "ATF"; + reg = <0x80000 0x0040000>; + read-only; + }; - partition@80000 { - label = "ATF"; - reg = <0x80000 0x0040000>; - read-only; - }; + partition@c0000 { + label = "uboot"; + reg = <0xc0000 0x0080000>; + read-only; + }; - partition@c0000 { - label = "uboot"; - reg = <0xc0000 0x0080000>; - read-only; - }; + partition@140000 { + label = "uboot-env"; + reg = <0x140000 0x0080000>; + read-only; + }; - partition@140000 { - label = "uboot-env"; - reg = <0x140000 0x0080000>; - read-only; - }; + factory: partition@1c0000 { + label = "factory"; + reg = <0x1c0000 0x0040000>; + read-only; + }; - factory: partition@1c0000 { - label = "factory"; - reg = <0x1c0000 0x0040000>; - read-only; - }; + partition@200000 { + label = "firmware"; + reg = <0x200000 0x2000000>; + }; - partition@200000 { - label = "firmware"; - reg = <0x200000 0x2000000>; - }; - - partition@2200000 { - label = "reserved"; - reg = <0x2200000 0x4000000>; - }; + partition@2200000 { + label = "reserved"; + reg = <0x2200000 0x4000000>; }; }; }; diff --git a/target/linux/mediatek/dts/mt7622-linksys-e8450.dtsi b/target/linux/mediatek/dts/mt7622-linksys-e8450.dtsi index 1e367d408f..7358b94a8e 100644 --- a/target/linux/mediatek/dts/mt7622-linksys-e8450.dtsi +++ b/target/linux/mediatek/dts/mt7622-linksys-e8450.dtsi @@ -110,10 +110,6 @@ }; }; -&bch { - status = "okay"; -}; - &btif { status = "okay"; }; @@ -342,18 +338,11 @@ }; }; -&snfi { +&snand { + mediatek,quad-spi; pinctrl-names = "default"; pinctrl-0 = <&serial_nand_pins>; status = "okay"; - - snand: spi_nand@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spi-nand"; - spi-max-frequency = <104000000>; - reg = <0>; - }; }; &spi0 { diff --git a/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts b/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts index a54e710924..3816dcb9cc 100644 --- a/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts +++ b/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts @@ -6,63 +6,51 @@ compatible = "mediatek,mt7622,ubi"; }; -&snfi { - pinctrl-names = "default"; - pinctrl-0 = <&serial_nand_pins>; - status = "okay"; - - spi_nand@0 { +&snand { + partitions { + compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - compatible = "spi-nand"; - spi-max-frequency = <104000000>; - reg = <0>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; + partition@0 { + label = "Preloader"; + reg = <0x00000 0x0080000>; + read-only; + }; - partition@0 { - label = "Preloader"; - reg = <0x00000 0x0080000>; - read-only; - }; + partition@80000 { + label = "ATF"; + reg = <0x80000 0x0040000>; + }; - partition@80000 { - label = "ATF"; - reg = <0x80000 0x0040000>; - }; + partition@c0000 { + label = "Bootloader"; + reg = <0xc0000 0x0080000>; + }; - partition@c0000 { - label = "Bootloader"; - reg = <0xc0000 0x0080000>; - }; + partition@140000 { + label = "Config"; + reg = <0x140000 0x0080000>; + }; - partition@140000 { - label = "Config"; - reg = <0x140000 0x0080000>; - }; + factory: partition@1c0000 { + label = "Factory"; + reg = <0x1c0000 0x0040000>; + }; - factory: partition@1c0000 { - label = "Factory"; - reg = <0x1c0000 0x0040000>; - }; + partition@200000 { + label = "kernel"; + reg = <0x200000 0x400000>; + }; - partition@200000 { - label = "kernel"; - reg = <0x200000 0x400000>; - }; + partition@600000 { + label = "ubi"; + reg = <0x600000 0x1C00000>; + }; - partition@600000 { - label = "ubi"; - reg = <0x600000 0x1C00000>; - }; - - partition@2200000 { - label = "User_data"; - reg = <0x2200000 0x4000000>; - }; + partition@2200000 { + label = "User_data"; + reg = <0x2200000 0x4000000>; }; }; }; diff --git a/target/linux/mediatek/patches-5.10/115-dts-bpi64-add-snand-support.patch b/target/linux/mediatek/patches-5.10/115-dts-bpi64-add-snand-support.patch index 85f7c08c08..39d81bd5d5 100644 --- a/target/linux/mediatek/patches-5.10/115-dts-bpi64-add-snand-support.patch +++ b/target/linux/mediatek/patches-5.10/115-dts-bpi64-add-snand-support.patch @@ -1,56 +1,40 @@ --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts -@@ -114,7 +114,7 @@ - }; - - &bch { -- status = "disabled"; -+ status = "okay"; - }; - - &btif { -@@ -259,14 +259,40 @@ +@@ -259,14 +259,32 @@ status = "disabled"; }; -&nor_flash { -+&snfi { ++&snand { pinctrl-names = "default"; - pinctrl-0 = <&spi_nor_pins>; - status = "disabled"; + pinctrl-0 = <&serial_nand_pins>; ++ mediatek,quad-spi; + status = "okay"; ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2"; ++ reg = <0x0 0x80000>; ++ read-only; ++ }; ++ ++ partition@80000 { ++ label = "fip"; ++ reg = <0x80000 0x200000>; ++ read-only; ++ }; - flash@0 { - compatible = "jedec,spi-nor"; -+ snand: spi_nand@0 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "spi-nand"; -+ spi-max-frequency = <104000000>; - reg = <0>; -+ -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ partition@0 { -+ label = "bl2"; -+ reg = <0x0 0x80000>; -+ read-only; -+ }; -+ -+ partition@80000 { -+ label = "fip"; -+ reg = <0x80000 0x200000>; -+ read-only; -+ }; -+ -+ partition@280000 { -+ label = "ubi"; -+ reg = <0x280000 0x7d80000>; -+ }; +- reg = <0>; ++ partition@280000 { ++ label = "ubi"; ++ reg = <0x280000 0x7d80000>; + }; }; }; diff --git a/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch b/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch index 8febc65d1b..e7c5d9b167 100644 --- a/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch +++ b/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch @@ -11,27 +11,21 @@ Signed-off-by: Xiangsheng Hou --- a/arch/arm/boot/dts/mt7629.dtsi +++ b/arch/arm/boot/dts/mt7629.dtsi -@@ -272,6 +272,28 @@ +@@ -272,6 +272,22 @@ status = "disabled"; }; -+ bch: ecc@1100e000 { -+ compatible = "mediatek,mt7622-ecc"; -+ reg = <0x1100e000 0x1000>; -+ interrupts = ; -+ clocks = <&pericfg CLK_PERI_NFIECC_PD>; -+ clock-names = "nfiecc_clk"; -+ status = "disabled"; -+ }; -+ -+ snfi: spi@1100d000 { -+ compatible = "mediatek,mt7629-snfi"; -+ reg = <0x1100d000 0x1000>; ++ snand: snfi@1100d000 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&serial_nand_pins>; ++ compatible = "mediatek,mt7629-snand"; ++ reg = <0x1100d000 0x1000>, <0x1100e000 0x1000>; ++ reg-names = "nfi", "ecc"; + interrupts = ; + clocks = <&pericfg CLK_PERI_NFI_PD>, -+ <&pericfg CLK_PERI_SNFI_PD>; -+ clock-names = "nfi_clk", "spi_clk"; -+ ecc-engine = <&bch>; ++ <&pericfg CLK_PERI_SNFI_PD>, ++ <&pericfg CLK_PERI_NFIECC_PD>; ++ clock-names = "nfi_clk", "pad_clk", "ecc_clk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; @@ -42,27 +36,15 @@ Signed-off-by: Xiangsheng Hou "mediatek,mt7622-spi"; --- a/arch/arm/boot/dts/mt7629-rfb.dts +++ b/arch/arm/boot/dts/mt7629-rfb.dts -@@ -254,6 +254,52 @@ +@@ -254,6 +254,38 @@ }; }; -+&bch { ++&snand { + status = "okay"; -+}; ++ mediatek,quad-spi; + -+&snfi { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&serial_nand_pins>; -+ status = "okay"; -+ -+ spi_nand@0 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "spi-nand"; -+ spi-max-frequency = <104000000>; -+ reg = <0>; -+ -+ partitions { ++ partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; @@ -87,8 +69,6 @@ Signed-off-by: Xiangsheng Hou + label = "firmware"; + reg = <0x1c0000 0x1000000>; + }; -+ -+ }; + }; +}; + diff --git a/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch b/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch index 5f89d58b06..fe136c2474 100644 --- a/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch +++ b/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch @@ -1,17 +1,18 @@ --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -561,6 +561,19 @@ +@@ -561,6 +561,20 @@ status = "disabled"; }; -+ snfi: spi@1100d000 { -+ compatible = "mediatek,mt7622-snfi"; -+ reg = <0 0x1100d000 0 0x1000>; ++ snand: snfi@1100d000 { ++ compatible = "mediatek,mt7622-snand"; ++ reg = <0 0x1100d000 0 0x1000>, <0 0x1100e000 0 0x1000>; ++ reg-names = "nfi", "ecc"; + interrupts = ; + clocks = <&pericfg CLK_PERI_NFI_PD>, -+ <&pericfg CLK_PERI_SNFI_PD>; -+ clock-names = "nfi_clk", "spi_clk"; -+ ecc-engine = <&bch>; ++ <&pericfg CLK_PERI_SNFI_PD>, ++ <&pericfg CLK_PERI_NFIECC_PD>; ++ clock-names = "nfi_clk", "pad_clk", "ecc_clk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; @@ -22,71 +23,55 @@ "mediatek,mt8173-nor"; --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts -@@ -85,7 +85,7 @@ - }; - - &bch { -- status = "disabled"; -+ status = "okay"; - }; - - &btif { -@@ -529,6 +529,62 @@ +@@ -529,6 +529,55 @@ status = "disabled"; }; -+&snfi { ++&snand { ++ mediatek,quad-spi; + pinctrl-names = "default"; + pinctrl-0 = <&serial_nand_pins>; + status = "okay"; + -+ spi_nand@0 { ++ partitions { ++ compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; -+ compatible = "spi-nand"; -+ spi-max-frequency = <104000000>; -+ reg = <0>; + -+ partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; ++ partition@0 { ++ label = "Preloader"; ++ reg = <0x00000 0x0080000>; ++ read-only; ++ }; + -+ partition@0 { -+ label = "Preloader"; -+ reg = <0x00000 0x0080000>; -+ read-only; -+ }; ++ partition@80000 { ++ label = "ATF"; ++ reg = <0x80000 0x0040000>; ++ }; + -+ partition@80000 { -+ label = "ATF"; -+ reg = <0x80000 0x0040000>; -+ }; ++ partition@c0000 { ++ label = "Bootloader"; ++ reg = <0xc0000 0x0080000>; ++ }; + -+ partition@c0000 { -+ label = "Bootloader"; -+ reg = <0xc0000 0x0080000>; -+ }; ++ partition@140000 { ++ label = "Config"; ++ reg = <0x140000 0x0080000>; ++ }; + -+ partition@140000 { -+ label = "Config"; -+ reg = <0x140000 0x0080000>; -+ }; ++ partition@1c0000 { ++ label = "Factory"; ++ reg = <0x1c0000 0x0100000>; ++ }; + -+ partition@1c0000 { -+ label = "Factory"; -+ reg = <0x1c0000 0x0100000>; -+ }; ++ partition@200000 { ++ label = "firmware"; ++ reg = <0x2c0000 0x2000000>; ++ }; + -+ partition@200000 { -+ label = "firmware"; -+ reg = <0x2c0000 0x2000000>; -+ }; -+ -+ partition@2200000 { -+ label = "User_data"; -+ reg = <0x22c0000 0x4000000>; -+ }; ++ partition@2200000 { ++ label = "User_data"; ++ reg = <0x22c0000 0x4000000>; + }; + }; +}; diff --git a/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch b/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch index d6d471520f..e1e43ce75d 100644 --- a/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch +++ b/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch @@ -1,15 +1,15 @@ --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts -@@ -567,7 +567,7 @@ - reg = <0x140000 0x0080000>; - }; +@@ -561,7 +561,7 @@ + reg = <0x140000 0x0080000>; + }; -- partition@1c0000 { -+ factory: partition@1c0000 { - label = "Factory"; - reg = <0x1c0000 0x0100000>; - }; -@@ -626,5 +626,6 @@ +- partition@1c0000 { ++ factory: partition@1c0000 { + label = "Factory"; + reg = <0x1c0000 0x0100000>; + }; +@@ -619,5 +619,6 @@ }; &wmac { From b600aee3edbbf66e8cc714a7d5f69e4505a7445a Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Fri, 20 Aug 2021 15:21:40 +0800 Subject: [PATCH 33/37] mediatek: attach bmt to the new snand driver Signed-off-by: Chuanhong Guo --- .../patches-5.10/330-mtk-bmt-support.patch | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch index 699870fbd6..ca1e74b863 100644 --- a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch +++ b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch @@ -805,33 +805,6 @@ +MODULE_AUTHOR("Xiangsheng Hou , Felix Fietkau "); +MODULE_DESCRIPTION("Bad Block mapping management v2 for MediaTek NAND Flash Driver"); + ---- a/drivers/mtd/nand/spi/core.c -+++ b/drivers/mtd/nand/spi/core.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - - static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) - { -@@ -1140,6 +1141,8 @@ static int spinand_probe(struct spi_mem - if (ret) - return ret; - -+ mtk_bmt_attach(mtd); -+ - ret = mtd_device_register(mtd, NULL, 0); - if (ret) - goto err_spinand_cleanup; -@@ -1165,6 +1168,7 @@ static int spinand_remove(struct spi_mem - if (ret) - return ret; - -+ mtk_bmt_detach(mtd); - spinand_cleanup(spinand); - - return 0; --- /dev/null +++ b/include/linux/mtd/mtk_bmt.h @@ -0,0 +1,18 @@ @@ -853,3 +826,39 @@ +#endif + +#endif +--- a/drivers/mtd/mtk-snand/mtk-snand-mtd.c ++++ b/drivers/mtd/mtk-snand/mtk-snand-mtd.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -608,6 +609,8 @@ static int mtk_snand_probe(struct platfo + mtd->_block_isbad = mtk_snand_mtd_block_isbad; + mtd->_block_markbad = mtk_snand_mtd_block_markbad; + ++ mtk_bmt_attach(mtd); ++ + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + dev_err(msm->pdev.dev, "failed to register mtd partition\n"); +@@ -619,6 +622,7 @@ static int mtk_snand_probe(struct platfo + return 0; + + errout4: ++ mtk_bmt_detach(mtd); + devm_kfree(msm->pdev.dev, msm->page_cache); + + errout3: +@@ -646,6 +650,8 @@ static int mtk_snand_remove(struct platf + if (ret) + return ret; + ++ mtk_bmt_detach(mtd); ++ + mtk_snand_cleanup(msm->snf); + + if (msm->irq >= 0) From 388127abd139d3ebbe761392403d58d58f5957cd Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Tue, 24 Aug 2021 00:31:17 +0800 Subject: [PATCH 34/37] mediatek: mtk-snand: check request size against chip info mtd->size will be overrided by BMT which makes all mtd requests made by bmt fail in request size checking. this commit changes the driver to check against actual chip size in chip info as a workaround. Signed-off-by: Chuanhong Guo --- .../drivers/mtd/mtk-snand/mtk-snand-mtd.c | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c index b0fcda446d..7e5baf0369 100644 --- a/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c +++ b/target/linux/mediatek/files-5.10/drivers/mtd/mtk-snand/mtk-snand-mtd.c @@ -57,7 +57,7 @@ static int mtk_snand_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) int ret; /* Do not allow write past end of device */ - if ((instr->addr + instr->len) > mtd->size) { + if ((instr->addr + instr->len) > msm->cinfo.chipsize) { dev_err(msm->pdev.dev, "attempt to erase beyond end of device\n"); return -EINVAL; @@ -194,7 +194,7 @@ static int mtk_snand_mtd_read_oob(struct mtd_info *mtd, loff_t from, maxooblen = mtd_oobavail(mtd, ops); /* Do not allow read past end of device */ - if (ops->datbuf && (from + ops->len) > mtd->size) { + if (ops->datbuf && (from + ops->len) > msm->cinfo.chipsize) { dev_err(msm->pdev.dev, "attempt to read beyond end of device\n"); return -EINVAL; @@ -205,9 +205,11 @@ static int mtk_snand_mtd_read_oob(struct mtd_info *mtd, loff_t from, return -EINVAL; } - if (unlikely(from >= mtd->size || - ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) - - (from >> mtd->writesize_shift)) * maxooblen)) { + if (unlikely(from >= msm->cinfo.chipsize || + ops->ooboffs + ops->ooblen > + ((msm->cinfo.chipsize >> mtd->writesize_shift) - + (from >> mtd->writesize_shift)) * + maxooblen)) { dev_err(msm->pdev.dev, "attempt to read beyond end of device\n"); return -EINVAL; @@ -321,7 +323,7 @@ static int mtk_snand_mtd_write_oob(struct mtd_info *mtd, loff_t to, maxooblen = mtd_oobavail(mtd, ops); /* Do not allow write past end of device */ - if (ops->datbuf && (to + ops->len) > mtd->size) { + if (ops->datbuf && (to + ops->len) > msm->cinfo.chipsize) { dev_err(msm->pdev.dev, "attempt to write beyond end of device\n"); return -EINVAL; @@ -333,9 +335,11 @@ static int mtk_snand_mtd_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; } - if (unlikely(to >= mtd->size || - ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) - - (to >> mtd->writesize_shift)) * maxooblen)) { + if (unlikely(to >= msm->cinfo.chipsize || + ops->ooboffs + ops->ooblen > + ((msm->cinfo.chipsize >> mtd->writesize_shift) - + (to >> mtd->writesize_shift)) * + maxooblen)) { dev_err(msm->pdev.dev, "attempt to write beyond end of device\n"); return -EINVAL; From 9abd2fb6c4dd3befa80a5721e7a6bc77506ac778 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Tue, 24 Aug 2021 11:23:21 +0800 Subject: [PATCH 35/37] mediatek: bmt: set default bmt oob offset to 0 there's no driver level remapping of oob data in the new spi-nand driver and bmt oob signature starts at 0x0 of the dumped oob data. change the default value to 0 for the new spi-nand driver. Signed-off-by: Chuanhong Guo --- target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch index ca1e74b863..363d0b857e 100644 --- a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch +++ b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch @@ -700,7 +700,7 @@ + + if (of_property_read_u8(np, "mediatek,bmt-oob-offset", + &bmtd.oob_offset) != 0) -+ bmtd.oob_offset = 8; ++ bmtd.oob_offset = 0; + + if (of_property_read_u32(np, "mediatek,bmt-table-size", + &bmt_table_size) != 0) From 8f2cace0b7f2f9221ce3dd5a01772c17e5244c3e Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Tue, 24 Aug 2021 20:03:52 +0800 Subject: [PATCH 36/37] mediatek: mt7629: build with linux 5.10 Signed-off-by: Chuanhong Guo --- target/linux/mediatek/Makefile | 3 +- target/linux/mediatek/mt7622/target.mk | 1 - target/linux/mediatek/mt7623/target.mk | 1 - .../mt7629/{config-5.4 => config-5.10} | 107 +++--------------- 4 files changed, 16 insertions(+), 96 deletions(-) rename target/linux/mediatek/mt7629/{config-5.4 => config-5.10} (71%) diff --git a/target/linux/mediatek/Makefile b/target/linux/mediatek/Makefile index 0825b8c6ed..94a7dfbdc1 100644 --- a/target/linux/mediatek/Makefile +++ b/target/linux/mediatek/Makefile @@ -8,8 +8,7 @@ BOARDNAME:=MediaTek Ralink ARM SUBTARGETS:=mt7622 mt7623 mt7629 FEATURES:=squashfs nand separate_ramdisk fpu dt-overlay -KERNEL_PATCHVER:=5.4 -KERNEL_TESTING_PATCHVER:=5.10 +KERNEL_PATCHVER:=5.10 include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += \ diff --git a/target/linux/mediatek/mt7622/target.mk b/target/linux/mediatek/mt7622/target.mk index f43a6c4bf4..5403bf5f87 100644 --- a/target/linux/mediatek/mt7622/target.mk +++ b/target/linux/mediatek/mt7622/target.mk @@ -4,7 +4,6 @@ BOARDNAME:=MT7622 CPU_TYPE:=cortex-a53 DEFAULT_PACKAGES += kmod-mt7615e kmod-mt7615-firmware wpad-basic-wolfssl blockdev uboot-envtools KERNELNAME:=Image dtbs -KERNEL_PATCHVER:=5.10 define Target/Description Build firmware images for MediaTek MT7622 ARM based boards. diff --git a/target/linux/mediatek/mt7623/target.mk b/target/linux/mediatek/mt7623/target.mk index 8413acb263..a9d6d2aea1 100644 --- a/target/linux/mediatek/mt7623/target.mk +++ b/target/linux/mediatek/mt7623/target.mk @@ -9,7 +9,6 @@ CPU_TYPE:=cortex-a7 CPU_SUBTYPE:=neon-vfpv4 KERNELNAME:=Image dtbs zImage FEATURES+=usb -KERNEL_PATCHVER:=5.10 DEFAULT_PACKAGES+=blockdev uboot-envtools define Target/Description diff --git a/target/linux/mediatek/mt7629/config-5.4 b/target/linux/mediatek/mt7629/config-5.10 similarity index 71% rename from target/linux/mediatek/mt7629/config-5.4 rename to target/linux/mediatek/mt7629/config-5.10 index 7a77c7aafa..8fca009ec4 100644 --- a/target/linux/mediatek/mt7629/config-5.4 +++ b/target/linux/mediatek/mt7629/config-5.10 @@ -1,22 +1,5 @@ CONFIG_ALIGNMENT_TRAP=y CONFIG_ARCH_32BIT_OFF_T=y -CONFIG_ARCH_CLOCKSOURCE_DATA=y -CONFIG_ARCH_HAS_BINFMT_FLAT=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PHYS_TO_DMA=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MEDIATEK=y @@ -27,17 +10,10 @@ CONFIG_ARCH_MULTI_V7=y CONFIG_ARCH_NR_GPIO=0 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_ARM=y -CONFIG_ARM_ARCH_TIMER=y -CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y CONFIG_ARM_GIC=y CONFIG_ARM_HAS_SG_CHAIN=y CONFIG_ARM_HEAVY_MB=y @@ -45,7 +21,6 @@ CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_L1_CACHE_SHIFT_6=y CONFIG_ARM_PATCH_IDIV=y CONFIG_ARM_PATCH_PHYS_VIRT=y -CONFIG_ARM_PMU=y CONFIG_ARM_THUMB=y CONFIG_ARM_UNWIND=y CONFIG_ARM_VIRT_EXT=y @@ -59,8 +34,6 @@ CONFIG_BLK_SCSI_REQUEST=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_CACHE_L2X0=y -CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED=y -CONFIG_CC_HAS_KASAN_GENERIC=y # CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_CHR_DEV_SCH=y @@ -100,15 +73,10 @@ CONFIG_CPU_THUMB_CAPABLE=y CONFIG_CPU_TLB_V7=y CONFIG_CPU_V7=y CONFIG_CRC16=y -CONFIG_CRYPTO_ACOMP2=y -CONFIG_CRYPTO_AEAD=y -CONFIG_CRYPTO_AEAD2=y CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_GF128MUL=y CONFIG_CRYPTO_HASH_INFO=y CONFIG_CRYPTO_LZO=y -CONFIG_CRYPTO_MANAGER=y -CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_NULL2=y CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_ZSTD=y @@ -116,6 +84,8 @@ CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" CONFIG_DEBUG_MISC=y CONFIG_DEFAULT_HOSTNAME="(mt7629)" +CONFIG_DIMLIB=y +CONFIG_DMA_OPS=y CONFIG_DMA_REMAP=y CONFIG_DTC=y CONFIG_EDAC_ATOMIC_SCRUB=y @@ -131,6 +101,7 @@ CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y CONFIG_GENERIC_CPU_AUTOPROBE=y CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y CONFIG_GENERIC_IDLE_POLL_SETUP=y CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y CONFIG_GENERIC_IRQ_MIGRATION=y @@ -148,6 +119,8 @@ CONFIG_GENERIC_SCHED_CLOCK=y CONFIG_GENERIC_SMP_IDLE_THREAD=y CONFIG_GENERIC_STRNCPY_FROM_USER=y CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_VDSO_32=y CONFIG_GPIOLIB=y CONFIG_HANDLE_DOMAIN_IRQ=y # CONFIG_HARDENED_USERCOPY is not set @@ -156,55 +129,11 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ARM_ARCH_TIMER=y -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_HW_BREAKPOINT=y -CONFIG_HAVE_IDE=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_OPTPROBES=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_PROC_CPU=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_SCHED_AVG_IRQ=y CONFIG_HAVE_SMP=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_UID16=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HOTPLUG_CPU=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MTK=y CONFIG_HZ_FIXED=0 -# CONFIG_I2C_MT65XX is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_IO_URING=y CONFIG_IRQCHIP=y @@ -213,10 +142,9 @@ CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y -# CONFIG_KEYBOARD_MTK_PMIC is not set # CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set -# CONFIG_LEDS_UBNT_LEDBAR is not set CONFIG_LIBFDT=y +CONFIG_LLD_VERSION=0 CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y CONFIG_LZO_COMPRESS=y @@ -230,19 +158,18 @@ CONFIG_MACH_MT7629=y # CONFIG_MACH_MT8135 is not set CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y -# CONFIG_MEDIATEK_MT6577_AUXADC is not set +CONFIG_MDIO_DEVRES=y CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y CONFIG_MFD_SYSCON=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y CONFIG_MIGRATION=y -CONFIG_MODULES_TREE_LOOKUP=y CONFIG_MODULES_USE_ELF_REL=y -CONFIG_MT753X_GSW=y CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_MTK=y -# CONFIG_MTD_NAND_MTK_BMT is not set +CONFIG_MTD_NAND_MTK_BMT=y # CONFIG_MTD_PARSER_TRX is not set CONFIG_MTD_RAW_NAND=y CONFIG_MTD_SPI_NAND=y @@ -258,7 +185,7 @@ CONFIG_MTD_UBI_WL_THRESHOLD=4096 CONFIG_MTK_INFRACFG=y # CONFIG_MTK_PMIC_WRAP is not set CONFIG_MTK_SCPSYS=y -# CONFIG_MTK_THERMAL is not set +CONFIG_MTK_SPI_NAND=y CONFIG_MTK_TIMER=y CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_NEED_DMA_MAP_STATE=y @@ -306,6 +233,7 @@ CONFIG_PHY_MTK_TPHY=y CONFIG_PINCTRL=y CONFIG_PINCTRL_MT7629=y CONFIG_PINCTRL_MTK_MOORE=y +CONFIG_PINCTRL_MTK_V2=y CONFIG_PM=y CONFIG_PM_CLK=y CONFIG_PM_GENERIC_DOMAINS=y @@ -318,7 +246,6 @@ CONFIG_RAS=y CONFIG_RATIONAL=y CONFIG_RCU_NEED_SEGCBLIST=y CONFIG_RCU_STALL_COMMON=y -CONFIG_REFCOUNT_FULL=y CONFIG_REGMAP=y CONFIG_REGMAP_MMIO=y CONFIG_RESET_CONTROLLER=y @@ -337,16 +264,12 @@ CONFIG_SGL_ALLOC=y CONFIG_SG_POOL=y CONFIG_SMP=y CONFIG_SMP_ON_UP=y -# CONFIG_SND_SOC_MT6359 is not set -# CONFIG_SND_SOC_MT6797 is not set -# CONFIG_SND_SOC_MT8183 is not set CONFIG_SPARSE_IRQ=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y CONFIG_SPI_MT65XX=y -# CONFIG_SPI_MTK_NOR is not set -CONFIG_SPI_MTK_SNFI=y +CONFIG_SPI_MTK_NOR=y CONFIG_SRCU=y CONFIG_STACKTRACE=y # CONFIG_SWAP is not set From 472437b93fe01a5cd31ad7c82933fd248b45d082 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Fri, 27 Aug 2021 15:40:27 +0800 Subject: [PATCH 37/37] mediatek: mt7629: manually add missing kconfig These options doesn't show up unless some kernel packages are selected, so they are not covered by kernel_menuconfig. Manually add them so that a build with all kmods can pass without user interaction. Signed-off-by: Chuanhong Guo --- target/linux/mediatek/mt7629/config-5.10 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/linux/mediatek/mt7629/config-5.10 b/target/linux/mediatek/mt7629/config-5.10 index 8fca009ec4..ee70de3a8b 100644 --- a/target/linux/mediatek/mt7629/config-5.10 +++ b/target/linux/mediatek/mt7629/config-5.10 @@ -143,6 +143,7 @@ CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y # CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set +# CONFIG_LEDS_UBNT_LEDBAR is not set CONFIG_LIBFDT=y CONFIG_LLD_VERSION=0 CONFIG_LOCK_DEBUGGING_SUPPORT=y @@ -159,6 +160,7 @@ CONFIG_MACH_MT7629=y CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y +# CONFIG_MEDIATEK_MT6577_AUXADC is not set CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y CONFIG_MFD_SYSCON=y @@ -186,6 +188,7 @@ CONFIG_MTK_INFRACFG=y # CONFIG_MTK_PMIC_WRAP is not set CONFIG_MTK_SCPSYS=y CONFIG_MTK_SPI_NAND=y +# CONFIG_MTK_THERMAL is not set CONFIG_MTK_TIMER=y CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_NEED_DMA_MAP_STATE=y