]>
Commit | Line | Data |
---|---|---|
90520afb LB |
1 | // SPDX-License-Identifier: ISC |
2 | /* Copyright (C) 2020 MediaTek Inc. | |
3 | * | |
4 | * Author: Lorenzo Bianconi <lorenzo@kernel.org> | |
5 | * Sean Wang <sean.wang@mediatek.com> | |
6 | */ | |
7 | ||
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/usb.h> | |
11 | ||
12 | #include "mt7615.h" | |
13 | #include "mac.h" | |
14 | #include "mcu.h" | |
15 | #include "regs.h" | |
16 | ||
17 | const u32 mt7663_usb_sdio_reg_map[] = { | |
18 | [MT_TOP_CFG_BASE] = 0x80020000, | |
19 | [MT_HW_BASE] = 0x80000000, | |
20 | [MT_DMA_SHDL_BASE] = 0x5000a000, | |
21 | [MT_HIF_BASE] = 0x50000000, | |
22 | [MT_CSR_BASE] = 0x40000000, | |
23 | [MT_EFUSE_ADDR_BASE] = 0x78011000, | |
24 | [MT_TOP_MISC_BASE] = 0x81020000, | |
25 | [MT_PLE_BASE] = 0x82060000, | |
26 | [MT_PSE_BASE] = 0x82068000, | |
a66cbdd6 | 27 | [MT_PP_BASE] = 0x8206c000, |
90520afb LB |
28 | [MT_WTBL_BASE_ADDR] = 0x820e0000, |
29 | [MT_CFG_BASE] = 0x820f0000, | |
30 | [MT_AGG_BASE] = 0x820f2000, | |
31 | [MT_ARB_BASE] = 0x820f3000, | |
32 | [MT_TMAC_BASE] = 0x820f4000, | |
33 | [MT_RMAC_BASE] = 0x820f5000, | |
34 | [MT_DMA_BASE] = 0x820f7000, | |
35 | [MT_PF_BASE] = 0x820f8000, | |
36 | [MT_WTBL_BASE_ON] = 0x820f9000, | |
37 | [MT_WTBL_BASE_OFF] = 0x820f9800, | |
38 | [MT_LPON_BASE] = 0x820fb000, | |
39 | [MT_MIB_BASE] = 0x820fd000, | |
40 | }; | |
41 | EXPORT_SYMBOL_GPL(mt7663_usb_sdio_reg_map); | |
42 | ||
43 | static void | |
44 | mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, | |
45 | enum mt76_txq_id qid, struct ieee80211_sta *sta, | |
46 | struct sk_buff *skb) | |
47 | { | |
48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
49 | struct ieee80211_key_conf *key = info->control.hw_key; | |
50 | __le32 *txwi; | |
51 | int pid; | |
52 | ||
53 | if (!wcid) | |
54 | wcid = &dev->mt76.global_wcid; | |
55 | ||
56 | pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); | |
57 | ||
58 | txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); | |
59 | memset(txwi, 0, MT_USB_TXD_SIZE); | |
60 | mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); | |
61 | skb_push(skb, MT_USB_TXD_SIZE); | |
62 | } | |
63 | ||
d927ebb9 LB |
64 | static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev, |
65 | struct mt7615_wtbl_rate_desc *wrd) | |
90520afb | 66 | { |
d927ebb9 LB |
67 | struct mt7615_rate_desc *rate = &wrd->rate; |
68 | struct mt7615_sta *sta = wrd->sta; | |
90520afb LB |
69 | u32 w5, w27, addr, val; |
70 | ||
71 | lockdep_assert_held(&dev->mt76.mutex); | |
72 | ||
73 | if (!sta) | |
74 | return -EINVAL; | |
75 | ||
76 | if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) | |
77 | return -ETIMEDOUT; | |
78 | ||
79 | addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); | |
80 | ||
81 | w27 = mt76_rr(dev, addr + 27 * 4); | |
82 | w27 &= ~MT_WTBL_W27_CC_BW_SEL; | |
83 | w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); | |
84 | ||
85 | w5 = mt76_rr(dev, addr + 5 * 4); | |
86 | w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | | |
87 | MT_WTBL_W5_MPDU_OK_COUNT | | |
88 | MT_WTBL_W5_MPDU_FAIL_COUNT | | |
89 | MT_WTBL_W5_RATE_IDX); | |
90 | w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | | |
91 | FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, | |
92 | rate->bw_idx ? rate->bw_idx - 1 : 7); | |
93 | ||
94 | mt76_wr(dev, MT_WTBL_RIUCR0, w5); | |
95 | ||
96 | mt76_wr(dev, MT_WTBL_RIUCR1, | |
97 | FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | | |
98 | FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | | |
99 | FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); | |
100 | ||
101 | mt76_wr(dev, MT_WTBL_RIUCR2, | |
102 | FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | | |
103 | FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | | |
104 | FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | | |
105 | FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); | |
106 | ||
107 | mt76_wr(dev, MT_WTBL_RIUCR3, | |
108 | FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | | |
109 | FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | | |
110 | FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); | |
111 | ||
112 | mt76_wr(dev, MT_WTBL_UPDATE, | |
113 | FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | | |
114 | MT_WTBL_UPDATE_RATE_UPDATE | | |
115 | MT_WTBL_UPDATE_TX_COUNT_CLEAR); | |
116 | ||
117 | mt76_wr(dev, addr + 27 * 4, w27); | |
118 | ||
119 | sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1; | |
120 | ||
121 | mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ | |
122 | val = mt76_rr(dev, MT_LPON_UTTR0); | |
123 | sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; | |
124 | ||
125 | if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) | |
126 | mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); | |
127 | ||
128 | sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; | |
129 | sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; | |
130 | ||
131 | return 0; | |
132 | } | |
133 | ||
d927ebb9 | 134 | static void mt7663_usb_sdio_rate_work(struct work_struct *work) |
90520afb | 135 | { |
d927ebb9 LB |
136 | struct mt7615_wtbl_rate_desc *wrd, *wrd_next; |
137 | struct list_head wrd_list; | |
90520afb LB |
138 | struct mt7615_dev *dev; |
139 | ||
140 | dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, | |
d927ebb9 | 141 | rate_work); |
90520afb | 142 | |
d927ebb9 | 143 | INIT_LIST_HEAD(&wrd_list); |
90520afb | 144 | spin_lock_bh(&dev->mt76.lock); |
d927ebb9 | 145 | list_splice_init(&dev->wrd_head, &wrd_list); |
90520afb LB |
146 | spin_unlock_bh(&dev->mt76.lock); |
147 | ||
d927ebb9 LB |
148 | list_for_each_entry_safe(wrd, wrd_next, &wrd_list, node) { |
149 | list_del(&wrd->node); | |
90520afb LB |
150 | |
151 | mt7615_mutex_acquire(dev); | |
d927ebb9 | 152 | mt7663_usb_sdio_set_rates(dev, wrd); |
90520afb LB |
153 | mt7615_mutex_release(dev); |
154 | ||
d927ebb9 | 155 | kfree(wrd); |
90520afb LB |
156 | } |
157 | } | |
90520afb LB |
158 | |
159 | bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) | |
160 | { | |
161 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); | |
162 | ||
163 | mt7615_mutex_acquire(dev); | |
164 | mt7615_mac_sta_poll(dev); | |
165 | mt7615_mutex_release(dev); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data); | |
170 | ||
171 | void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, | |
90520afb LB |
172 | struct mt76_queue_entry *e) |
173 | { | |
174 | unsigned int headroom = MT_USB_TXD_SIZE; | |
175 | ||
176 | if (mt76_is_usb(mdev)) | |
177 | headroom += MT_USB_HDR_SIZE; | |
178 | skb_pull(e->skb, headroom); | |
179 | ||
e1378e52 | 180 | mt76_tx_complete_skb(mdev, e->wcid, e->skb); |
90520afb LB |
181 | } |
182 | EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_complete_skb); | |
183 | ||
184 | int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, | |
185 | enum mt76_txq_id qid, struct mt76_wcid *wcid, | |
186 | struct ieee80211_sta *sta, | |
187 | struct mt76_tx_info *tx_info) | |
188 | { | |
90520afb LB |
189 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); |
190 | struct sk_buff *skb = tx_info->skb; | |
191 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
51c0975d | 192 | struct mt7615_sta *msta; |
e98e6df6 | 193 | int pad; |
90520afb | 194 | |
51c0975d | 195 | msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; |
90520afb | 196 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && |
51c0975d | 197 | msta && !msta->rate_probe) { |
90520afb LB |
198 | /* request to configure sampling rate */ |
199 | spin_lock_bh(&dev->mt76.lock); | |
200 | mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], | |
201 | msta->rates); | |
202 | spin_unlock_bh(&dev->mt76.lock); | |
203 | } | |
204 | ||
205 | mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, skb); | |
8da40d69 LB |
206 | if (mt76_is_usb(mdev)) { |
207 | u32 len = skb->len; | |
208 | ||
209 | put_unaligned_le32(len, skb_push(skb, sizeof(len))); | |
e98e6df6 LB |
210 | pad = round_up(skb->len, 4) + 4 - skb->len; |
211 | } else { | |
212 | pad = round_up(skb->len, 4) - skb->len; | |
8da40d69 | 213 | } |
90520afb | 214 | |
e98e6df6 | 215 | return mt76_skb_adjust_pad(skb, pad); |
90520afb LB |
216 | } |
217 | EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb); | |
218 | ||
219 | static int mt7663u_dma_sched_init(struct mt7615_dev *dev) | |
220 | { | |
221 | int i; | |
222 | ||
223 | mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), | |
224 | MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, | |
225 | FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | | |
226 | FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); | |
227 | ||
228 | /* disable refill group 5 - group 15 and raise group 2 | |
229 | * and 3 as high priority. | |
230 | */ | |
231 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); | |
232 | mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); | |
233 | ||
234 | for (i = 0; i < 5; i++) | |
235 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), | |
236 | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | | |
237 | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); | |
238 | ||
239 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); | |
240 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); | |
241 | ||
242 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); | |
243 | ||
244 | /* group pririority from high to low: | |
245 | * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. | |
246 | */ | |
247 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); | |
248 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); | |
249 | mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); | |
250 | ||
251 | mt76_wr(dev, MT_UDMA_WLCFG_1, | |
252 | FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | | |
253 | FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); | |
254 | ||
255 | /* setup UDMA Rx Flush */ | |
256 | mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); | |
257 | /* hif reset */ | |
258 | mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); | |
259 | ||
260 | mt76_set(dev, MT_UDMA_WLCFG_0, | |
261 | MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | | |
262 | MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | | |
263 | MT_WL_TX_TMOUT_FUNC_EN); | |
264 | mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, | |
265 | FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | | |
266 | FIELD_PREP(MT_WL_RX_AGG_TO, 100)); | |
267 | ||
268 | return 0; | |
269 | } | |
270 | ||
271 | static int mt7663_usb_sdio_init_hardware(struct mt7615_dev *dev) | |
272 | { | |
273 | int ret, idx; | |
274 | ||
275 | ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); | |
276 | if (ret < 0) | |
277 | return ret; | |
278 | ||
279 | if (mt76_is_usb(&dev->mt76)) { | |
280 | ret = mt7663u_dma_sched_init(dev); | |
281 | if (ret) | |
282 | return ret; | |
283 | } | |
284 | ||
285 | set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); | |
286 | ||
287 | /* Beacon and mgmt frames should occupy wcid 0 */ | |
288 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); | |
289 | if (idx) | |
290 | return -ENOSPC; | |
291 | ||
292 | dev->mt76.global_wcid.idx = idx; | |
293 | dev->mt76.global_wcid.hw_key_idx = -1; | |
294 | rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
299 | int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) | |
300 | { | |
301 | struct ieee80211_hw *hw = mt76_hw(dev); | |
302 | int err; | |
303 | ||
d927ebb9 LB |
304 | INIT_WORK(&dev->rate_work, mt7663_usb_sdio_rate_work); |
305 | INIT_LIST_HEAD(&dev->wrd_head); | |
90520afb LB |
306 | mt7615_init_device(dev); |
307 | ||
308 | err = mt7663_usb_sdio_init_hardware(dev); | |
309 | if (err) | |
310 | return err; | |
311 | ||
90520afb | 312 | hw->extra_tx_headroom += MT_USB_TXD_SIZE; |
b9b852b9 | 313 | if (mt76_is_usb(&dev->mt76)) { |
90520afb | 314 | hw->extra_tx_headroom += MT_USB_HDR_SIZE; |
b9b852b9 LB |
315 | /* check hw sg support in order to enable AMSDU */ |
316 | if (dev->mt76.usb.sg_en) | |
317 | hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM; | |
318 | else | |
319 | hw->max_tx_fragments = 1; | |
320 | } | |
90520afb LB |
321 | |
322 | err = mt76_register_device(&dev->mt76, true, mt7615_rates, | |
323 | ARRAY_SIZE(mt7615_rates)); | |
324 | if (err < 0) | |
325 | return err; | |
326 | ||
327 | if (!dev->mt76.usb.sg_en) { | |
328 | struct ieee80211_sta_vht_cap *vht_cap; | |
329 | ||
330 | /* decrease max A-MSDU size if SG is not supported */ | |
331 | vht_cap = &dev->mphy.sband_5g.sband.vht_cap; | |
332 | vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; | |
333 | } | |
334 | ||
335 | ieee80211_queue_work(hw, &dev->mcu_work); | |
336 | mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); | |
337 | mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); | |
338 | ||
339 | return mt7615_init_debugfs(dev); | |
340 | } | |
341 | EXPORT_SYMBOL_GPL(mt7663_usb_sdio_register_device); | |
342 | ||
343 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); | |
344 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); | |
345 | MODULE_LICENSE("Dual BSD/GPL"); |