1134b2d0dSStanislaw Gruszka /*
2134b2d0dSStanislaw Gruszka  * (c) Copyright 2002-2010, Ralink Technology, Inc.
3134b2d0dSStanislaw Gruszka  * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
4134b2d0dSStanislaw Gruszka  * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
5134b2d0dSStanislaw Gruszka  * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
6134b2d0dSStanislaw Gruszka  *
7134b2d0dSStanislaw Gruszka  * This program is free software; you can redistribute it and/or modify
8134b2d0dSStanislaw Gruszka  * it under the terms of the GNU General Public License version 2
9134b2d0dSStanislaw Gruszka  * as published by the Free Software Foundation
10134b2d0dSStanislaw Gruszka  *
11134b2d0dSStanislaw Gruszka  * This program is distributed in the hope that it will be useful,
12134b2d0dSStanislaw Gruszka  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13134b2d0dSStanislaw Gruszka  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14134b2d0dSStanislaw Gruszka  * GNU General Public License for more details.
15134b2d0dSStanislaw Gruszka  */
16134b2d0dSStanislaw Gruszka 
17134b2d0dSStanislaw Gruszka #include "mt76x0.h"
18134b2d0dSStanislaw Gruszka #include "eeprom.h"
19134b2d0dSStanislaw Gruszka #include "trace.h"
20134b2d0dSStanislaw Gruszka #include "mcu.h"
21f2653a4eSLorenzo Bianconi #include "../mt76x02_util.h"
223b11db26SLorenzo Bianconi #include "../mt76x02_dma.h"
23134b2d0dSStanislaw Gruszka 
24134b2d0dSStanislaw Gruszka #include "initvals.h"
25134b2d0dSStanislaw Gruszka 
261bee323aSLorenzo Bianconi static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
271bee323aSLorenzo Bianconi {
281bee323aSLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
291bee323aSLorenzo Bianconi 	u16 mcs_map = 0;
301bee323aSLorenzo Bianconi 	int i;
311bee323aSLorenzo Bianconi 
321bee323aSLorenzo Bianconi 	vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
331bee323aSLorenzo Bianconi 	for (i = 0; i < 8; i++) {
341bee323aSLorenzo Bianconi 		if (!i)
351bee323aSLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2));
361bee323aSLorenzo Bianconi 		else
371bee323aSLorenzo Bianconi 			mcs_map |=
381bee323aSLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
391bee323aSLorenzo Bianconi 	}
401bee323aSLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
411bee323aSLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
421bee323aSLorenzo Bianconi }
431bee323aSLorenzo Bianconi 
44134b2d0dSStanislaw Gruszka static void
45134b2d0dSStanislaw Gruszka mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
46134b2d0dSStanislaw Gruszka {
475b394355SLorenzo Bianconi 	u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD;
48134b2d0dSStanislaw Gruszka 
49134b2d0dSStanislaw Gruszka 	/* Note: we don't turn off WLAN_CLK because that makes the device
50134b2d0dSStanislaw Gruszka 	 *	 not respond properly on the probe path.
51134b2d0dSStanislaw Gruszka 	 *	 In case anyone (PSM?) wants to use this function we can
52134b2d0dSStanislaw Gruszka 	 *	 bring the clock stuff back and fixup the probe path.
53134b2d0dSStanislaw Gruszka 	 */
54134b2d0dSStanislaw Gruszka 
55134b2d0dSStanislaw Gruszka 	if (enable)
56134b2d0dSStanislaw Gruszka 		val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
57134b2d0dSStanislaw Gruszka 			MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
58134b2d0dSStanislaw Gruszka 	else
59134b2d0dSStanislaw Gruszka 		val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);
60134b2d0dSStanislaw Gruszka 
61134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
62134b2d0dSStanislaw Gruszka 	udelay(20);
63134b2d0dSStanislaw Gruszka 
64134b2d0dSStanislaw Gruszka 	/* Note: vendor driver tries to disable/enable wlan here and retry
65134b2d0dSStanislaw Gruszka 	 *       but the code which does it is so buggy it must have never
66134b2d0dSStanislaw Gruszka 	 *       triggered, so don't bother.
67134b2d0dSStanislaw Gruszka 	 */
685b394355SLorenzo Bianconi 	if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000))
695b394355SLorenzo Bianconi 		dev_err(dev->mt76.dev, "PLL and XTAL check failed\n");
70134b2d0dSStanislaw Gruszka }
71134b2d0dSStanislaw Gruszka 
72369bbecdSStanislaw Gruszka void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
73134b2d0dSStanislaw Gruszka {
74134b2d0dSStanislaw Gruszka 	u32 val;
75134b2d0dSStanislaw Gruszka 
76134b2d0dSStanislaw Gruszka 	mutex_lock(&dev->hw_atomic_mutex);
77134b2d0dSStanislaw Gruszka 
78134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
79134b2d0dSStanislaw Gruszka 
80134b2d0dSStanislaw Gruszka 	if (reset) {
81134b2d0dSStanislaw Gruszka 		val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
82134b2d0dSStanislaw Gruszka 		val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
83134b2d0dSStanislaw Gruszka 
84134b2d0dSStanislaw Gruszka 		if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
85134b2d0dSStanislaw Gruszka 			val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
86134b2d0dSStanislaw Gruszka 				MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
87134b2d0dSStanislaw Gruszka 			mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
88134b2d0dSStanislaw Gruszka 			udelay(20);
89134b2d0dSStanislaw Gruszka 
90134b2d0dSStanislaw Gruszka 			val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
91134b2d0dSStanislaw Gruszka 				 MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
92134b2d0dSStanislaw Gruszka 		}
93134b2d0dSStanislaw Gruszka 	}
94134b2d0dSStanislaw Gruszka 
95134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
96134b2d0dSStanislaw Gruszka 	udelay(20);
97134b2d0dSStanislaw Gruszka 
98134b2d0dSStanislaw Gruszka 	mt76x0_set_wlan_state(dev, val, enable);
99134b2d0dSStanislaw Gruszka 
100134b2d0dSStanislaw Gruszka 	mutex_unlock(&dev->hw_atomic_mutex);
101134b2d0dSStanislaw Gruszka }
102c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
103134b2d0dSStanislaw Gruszka 
104134b2d0dSStanislaw Gruszka static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
105134b2d0dSStanislaw Gruszka {
106512bd4b1SLorenzo Bianconi 	mt76_wr(dev, MT_MAC_SYS_CTRL,
107512bd4b1SLorenzo Bianconi 		MT_MAC_SYS_CTRL_RESET_CSR |
108134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_RESET_BBP);
109134b2d0dSStanislaw Gruszka 	msleep(200);
110134b2d0dSStanislaw Gruszka }
111134b2d0dSStanislaw Gruszka 
112134b2d0dSStanislaw Gruszka static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
113134b2d0dSStanislaw Gruszka {
114134b2d0dSStanislaw Gruszka 	u32 val;
115134b2d0dSStanislaw Gruszka 
116134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_USB_DMA_CFG);
117134b2d0dSStanislaw Gruszka 
1187fd3c60cSLorenzo Bianconi 	val |= MT_USB_DMA_CFG_RX_BULK_EN |
119134b2d0dSStanislaw Gruszka 	       MT_USB_DMA_CFG_TX_BULK_EN;
1207fd3c60cSLorenzo Bianconi 
1217fd3c60cSLorenzo Bianconi 	/* disable AGGR_BULK_RX in order to receive one
1227fd3c60cSLorenzo Bianconi 	 * frame in each rx urb and avoid copies
1237fd3c60cSLorenzo Bianconi 	 */
1247fd3c60cSLorenzo Bianconi 	val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
125134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_USB_DMA_CFG, val);
126134b2d0dSStanislaw Gruszka 
127134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_COM_REG0);
128134b2d0dSStanislaw Gruszka 	if (val & 1)
129134b2d0dSStanislaw Gruszka 		dev_dbg(dev->mt76.dev, "MCU not ready\n");
130134b2d0dSStanislaw Gruszka 
131134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_USB_DMA_CFG);
132134b2d0dSStanislaw Gruszka 
133797ea240SStanislaw Gruszka 	val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
134134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_USB_DMA_CFG, val);
135797ea240SStanislaw Gruszka 	val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
136134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_USB_DMA_CFG, val);
137134b2d0dSStanislaw Gruszka }
138134b2d0dSStanislaw Gruszka 
139134b2d0dSStanislaw Gruszka #define RANDOM_WRITE(dev, tab)			\
14017507157SLorenzo Bianconi 	mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN,	\
141f1638c7cSStanislaw Gruszka 		   tab, ARRAY_SIZE(tab))
142134b2d0dSStanislaw Gruszka 
143134b2d0dSStanislaw Gruszka static int mt76x0_init_bbp(struct mt76x0_dev *dev)
144134b2d0dSStanislaw Gruszka {
145134b2d0dSStanislaw Gruszka 	int ret, i;
146134b2d0dSStanislaw Gruszka 
147134b2d0dSStanislaw Gruszka 	ret = mt76x0_wait_bbp_ready(dev);
148134b2d0dSStanislaw Gruszka 	if (ret)
149134b2d0dSStanislaw Gruszka 		return ret;
150134b2d0dSStanislaw Gruszka 
151134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_bbp_init_tab);
152134b2d0dSStanislaw Gruszka 
153134b2d0dSStanislaw Gruszka 	for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) {
154134b2d0dSStanislaw Gruszka 		const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i];
155134b2d0dSStanislaw Gruszka 		const struct mt76_reg_pair *pair = &item->reg_pair;
156134b2d0dSStanislaw Gruszka 
157134b2d0dSStanislaw Gruszka 		if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20))
158134b2d0dSStanislaw Gruszka 			mt76_wr(dev, pair->reg, pair->value);
159134b2d0dSStanislaw Gruszka 	}
160134b2d0dSStanislaw Gruszka 
161134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_dcoc_tab);
162134b2d0dSStanislaw Gruszka 
163134b2d0dSStanislaw Gruszka 	return 0;
164134b2d0dSStanislaw Gruszka }
165134b2d0dSStanislaw Gruszka 
166134b2d0dSStanislaw Gruszka static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
167134b2d0dSStanislaw Gruszka {
168134b2d0dSStanislaw Gruszka 	u32 reg;
169134b2d0dSStanislaw Gruszka 
170134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, common_mac_reg_table);
171134b2d0dSStanislaw Gruszka 
172a6daf796SLorenzo Bianconi 	mt76x02_set_beacon_offsets(&dev->mt76);
173134b2d0dSStanislaw Gruszka 
174134b2d0dSStanislaw Gruszka 	/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
175134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_mac_reg_table);
176134b2d0dSStanislaw Gruszka 
177134b2d0dSStanislaw Gruszka 	/* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */
178134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_MAC_SYS_CTRL);
179134b2d0dSStanislaw Gruszka 	reg &= ~0x3;
180134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, reg);
181134b2d0dSStanislaw Gruszka 
182134b2d0dSStanislaw Gruszka 	if (is_mt7610e(dev)) {
183134b2d0dSStanislaw Gruszka 		/* Disable COEX_EN */
184134b2d0dSStanislaw Gruszka 		reg = mt76_rr(dev, MT_COEXCFG0);
185134b2d0dSStanislaw Gruszka 		reg &= 0xFFFFFFFE;
186134b2d0dSStanislaw Gruszka 		mt76_wr(dev, MT_COEXCFG0, reg);
187134b2d0dSStanislaw Gruszka 	}
188134b2d0dSStanislaw Gruszka 
189134b2d0dSStanislaw Gruszka 	/* Set 0x141C[15:12]=0xF */
190134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_EXT_CCA_CFG);
191134b2d0dSStanislaw Gruszka 	reg |= 0x0000F000;
192134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_EXT_CCA_CFG, reg);
193134b2d0dSStanislaw Gruszka 
194134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);
195134b2d0dSStanislaw Gruszka 
196134b2d0dSStanislaw Gruszka 	/*
197134b2d0dSStanislaw Gruszka 		TxRing 9 is for Mgmt frame.
198134b2d0dSStanislaw Gruszka 		TxRing 8 is for In-band command frame.
199134b2d0dSStanislaw Gruszka 		WMM_RG0_TXQMA: This register setting is for FCE to define the rule of TxRing 9.
200134b2d0dSStanislaw Gruszka 		WMM_RG1_TXQMA: This register setting is for FCE to define the rule of TxRing 8.
201134b2d0dSStanislaw Gruszka 	*/
202134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_WMM_CTRL);
203134b2d0dSStanislaw Gruszka 	reg &= ~0x000003FF;
204134b2d0dSStanislaw Gruszka 	reg |= 0x00000201;
205134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WMM_CTRL, reg);
206134b2d0dSStanislaw Gruszka 
207134b2d0dSStanislaw Gruszka 	/* TODO: Probably not needed */
208134b2d0dSStanislaw Gruszka 	mt76_wr(dev, 0x7028, 0);
209134b2d0dSStanislaw Gruszka 	mt76_wr(dev, 0x7010, 0);
210134b2d0dSStanislaw Gruszka 	mt76_wr(dev, 0x7024, 0);
211134b2d0dSStanislaw Gruszka 	msleep(10);
212134b2d0dSStanislaw Gruszka }
213134b2d0dSStanislaw Gruszka 
214134b2d0dSStanislaw Gruszka static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev)
215134b2d0dSStanislaw Gruszka {
216134b2d0dSStanislaw Gruszka 	u32 *vals;
217331419b2SStanislaw Gruszka 	int i;
218134b2d0dSStanislaw Gruszka 
21936404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
220134b2d0dSStanislaw Gruszka 	if (!vals)
221134b2d0dSStanislaw Gruszka 		return -ENOMEM;
222134b2d0dSStanislaw Gruszka 
22336404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS; i++)  {
224134b2d0dSStanislaw Gruszka 		vals[i * 2] = 0xffffffff;
225134b2d0dSStanislaw Gruszka 		vals[i * 2 + 1] = 0x00ffffff;
226134b2d0dSStanislaw Gruszka 	}
227134b2d0dSStanislaw Gruszka 
228331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
229134b2d0dSStanislaw Gruszka 	kfree(vals);
230331419b2SStanislaw Gruszka 	return 0;
231134b2d0dSStanislaw Gruszka }
232134b2d0dSStanislaw Gruszka 
233331419b2SStanislaw Gruszka static void mt76x0_init_key_mem(struct mt76x0_dev *dev)
234134b2d0dSStanislaw Gruszka {
235134b2d0dSStanislaw Gruszka 	u32 vals[4] = {};
236134b2d0dSStanislaw Gruszka 
237331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
238134b2d0dSStanislaw Gruszka }
239134b2d0dSStanislaw Gruszka 
240134b2d0dSStanislaw Gruszka static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev)
241134b2d0dSStanislaw Gruszka {
242134b2d0dSStanislaw Gruszka 	u32 *vals;
243331419b2SStanislaw Gruszka 	int i;
244134b2d0dSStanislaw Gruszka 
24536404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
246134b2d0dSStanislaw Gruszka 	if (!vals)
247134b2d0dSStanislaw Gruszka 		return -ENOMEM;
248134b2d0dSStanislaw Gruszka 
24936404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS * 2; i++)
250134b2d0dSStanislaw Gruszka 		vals[i] = 1;
251134b2d0dSStanislaw Gruszka 
252331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
253134b2d0dSStanislaw Gruszka 	kfree(vals);
254331419b2SStanislaw Gruszka 	return 0;
255134b2d0dSStanislaw Gruszka }
256134b2d0dSStanislaw Gruszka 
257134b2d0dSStanislaw Gruszka static void mt76x0_reset_counters(struct mt76x0_dev *dev)
258134b2d0dSStanislaw Gruszka {
259797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_0);
260797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_1);
261797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_2);
262797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_0);
263797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_1);
264797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_2);
265134b2d0dSStanislaw Gruszka }
266134b2d0dSStanislaw Gruszka 
267134b2d0dSStanislaw Gruszka int mt76x0_mac_start(struct mt76x0_dev *dev)
268134b2d0dSStanislaw Gruszka {
269134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
270134b2d0dSStanislaw Gruszka 
2713b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
272134b2d0dSStanislaw Gruszka 		return -ETIMEDOUT;
273134b2d0dSStanislaw Gruszka 
274108a4861SStanislaw Gruszka 	mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
275134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL,
276134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
277134b2d0dSStanislaw Gruszka 
2783b11db26SLorenzo Bianconi 	return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
279134b2d0dSStanislaw Gruszka }
280134b2d0dSStanislaw Gruszka 
281134b2d0dSStanislaw Gruszka static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
282134b2d0dSStanislaw Gruszka {
283134b2d0dSStanislaw Gruszka 	int i, ok;
284134b2d0dSStanislaw Gruszka 
285134b2d0dSStanislaw Gruszka 	if (test_bit(MT76_REMOVED, &dev->mt76.state))
286134b2d0dSStanislaw Gruszka 		return;
287134b2d0dSStanislaw Gruszka 
288134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
289134b2d0dSStanislaw Gruszka 		   MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
290134b2d0dSStanislaw Gruszka 		   MT_BEACON_TIME_CFG_BEACON_TX);
291134b2d0dSStanislaw Gruszka 
292134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
293134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n");
294134b2d0dSStanislaw Gruszka 
295134b2d0dSStanislaw Gruszka 	/* Page count on TxQ */
296134b2d0dSStanislaw Gruszka 	i = 200;
297134b2d0dSStanislaw Gruszka 	while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
298134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
299134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
300134b2d0dSStanislaw Gruszka 		msleep(10);
301134b2d0dSStanislaw Gruszka 
302134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
303134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n");
304134b2d0dSStanislaw Gruszka 
305134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
306134b2d0dSStanislaw Gruszka 					 MT_MAC_SYS_CTRL_ENABLE_TX);
307134b2d0dSStanislaw Gruszka 
308134b2d0dSStanislaw Gruszka 	/* Page count on RxQ */
309134b2d0dSStanislaw Gruszka 	ok = 0;
310134b2d0dSStanislaw Gruszka 	i = 200;
311134b2d0dSStanislaw Gruszka 	while (i--) {
312134b2d0dSStanislaw Gruszka 		if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
313134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a30) &&
314134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a34)) {
315134b2d0dSStanislaw Gruszka 			if (ok++ > 5)
316134b2d0dSStanislaw Gruszka 				break;
317134b2d0dSStanislaw Gruszka 			continue;
318134b2d0dSStanislaw Gruszka 		}
319134b2d0dSStanislaw Gruszka 		msleep(1);
320134b2d0dSStanislaw Gruszka 	}
321134b2d0dSStanislaw Gruszka 
322134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
323134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");
324134b2d0dSStanislaw Gruszka 
325134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
326134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n");
327134b2d0dSStanislaw Gruszka }
328134b2d0dSStanislaw Gruszka 
329134b2d0dSStanislaw Gruszka void mt76x0_mac_stop(struct mt76x0_dev *dev)
330134b2d0dSStanislaw Gruszka {
331b680d7fbSLorenzo Bianconi 	cancel_delayed_work_sync(&dev->cal_work);
332b680d7fbSLorenzo Bianconi 	cancel_delayed_work_sync(&dev->mac_work);
333b680d7fbSLorenzo Bianconi 	mt76u_stop_stat_wk(&dev->mt76);
334134b2d0dSStanislaw Gruszka 	mt76x0_mac_stop_hw(dev);
335134b2d0dSStanislaw Gruszka }
336c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
337134b2d0dSStanislaw Gruszka 
338134b2d0dSStanislaw Gruszka int mt76x0_init_hardware(struct mt76x0_dev *dev)
339134b2d0dSStanislaw Gruszka {
340134b2d0dSStanislaw Gruszka 	int ret;
341134b2d0dSStanislaw Gruszka 
3423b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000))
343e30a655eSLorenzo Bianconi 		return -EIO;
344134b2d0dSStanislaw Gruszka 
345134b2d0dSStanislaw Gruszka 	/* Wait for ASIC ready after FW load. */
346e30a655eSLorenzo Bianconi 	if (!mt76x02_wait_for_mac(&dev->mt76))
347e30a655eSLorenzo Bianconi 		return -ETIMEDOUT;
348134b2d0dSStanislaw Gruszka 
349134b2d0dSStanislaw Gruszka 	mt76x0_reset_csr_bbp(dev);
350134b2d0dSStanislaw Gruszka 	mt76x0_init_usb_dma(dev);
351134b2d0dSStanislaw Gruszka 
35228041571SLorenzo Bianconi 	ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false);
353134b2d0dSStanislaw Gruszka 	if (ret)
354e30a655eSLorenzo Bianconi 		return ret;
35530ec9152SLorenzo Bianconi 
356134b2d0dSStanislaw Gruszka 	mt76x0_init_mac_registers(dev);
357134b2d0dSStanislaw Gruszka 
3583b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
359e30a655eSLorenzo Bianconi 		return -EIO;
360134b2d0dSStanislaw Gruszka 
361134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_bbp(dev);
362134b2d0dSStanislaw Gruszka 	if (ret)
363e30a655eSLorenzo Bianconi 		return ret;
364134b2d0dSStanislaw Gruszka 
365a31821abSLorenzo Bianconi 	dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
366a31821abSLorenzo Bianconi 
367134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_mem(dev);
368134b2d0dSStanislaw Gruszka 	if (ret)
369e30a655eSLorenzo Bianconi 		return ret;
370e30a655eSLorenzo Bianconi 
371331419b2SStanislaw Gruszka 	mt76x0_init_key_mem(dev);
372e30a655eSLorenzo Bianconi 
373134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_attr_mem(dev);
374134b2d0dSStanislaw Gruszka 	if (ret)
375e30a655eSLorenzo Bianconi 		return ret;
376134b2d0dSStanislaw Gruszka 
377134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
378134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_SYNC_MODE |
379134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_TBTT_EN |
380134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_BEACON_TX));
381134b2d0dSStanislaw Gruszka 
382134b2d0dSStanislaw Gruszka 	mt76x0_reset_counters(dev);
383134b2d0dSStanislaw Gruszka 
384134b2d0dSStanislaw Gruszka 	mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
385134b2d0dSStanislaw Gruszka 
386134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_TXOP_CTRL_CFG,
387134b2d0dSStanislaw Gruszka 		   FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
388134b2d0dSStanislaw Gruszka 		   FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
389134b2d0dSStanislaw Gruszka 
390134b2d0dSStanislaw Gruszka 	ret = mt76x0_eeprom_init(dev);
391134b2d0dSStanislaw Gruszka 	if (ret)
392e30a655eSLorenzo Bianconi 		return ret;
393134b2d0dSStanislaw Gruszka 
394134b2d0dSStanislaw Gruszka 	mt76x0_phy_init(dev);
395134b2d0dSStanislaw Gruszka 
396e30a655eSLorenzo Bianconi 	return 0;
397134b2d0dSStanislaw Gruszka }
398c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
399134b2d0dSStanislaw Gruszka 
400134b2d0dSStanislaw Gruszka void mt76x0_cleanup(struct mt76x0_dev *dev)
401134b2d0dSStanislaw Gruszka {
402cb722aedSLorenzo Bianconi 	clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
4037c7b1394SLorenzo Bianconi 	mt76x0_chip_onoff(dev, false, false);
40430ec9152SLorenzo Bianconi 	mt76u_queues_deinit(&dev->mt76);
4056f4796b7SLorenzo Bianconi 	mt76u_mcu_deinit(&dev->mt76);
406134b2d0dSStanislaw Gruszka }
407c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_cleanup);
408134b2d0dSStanislaw Gruszka 
409835123b7SStanislaw Gruszka struct mt76x0_dev *
410835123b7SStanislaw Gruszka mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops)
411134b2d0dSStanislaw Gruszka {
412134b2d0dSStanislaw Gruszka 	struct mt76x0_dev *dev;
41395e507d2SLorenzo Bianconi 	struct mt76_dev *mdev;
414134b2d0dSStanislaw Gruszka 
41595e507d2SLorenzo Bianconi 	mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops);
41695e507d2SLorenzo Bianconi 	if (!mdev)
417134b2d0dSStanislaw Gruszka 		return NULL;
418134b2d0dSStanislaw Gruszka 
41995e507d2SLorenzo Bianconi 	mdev->dev = pdev;
420835123b7SStanislaw Gruszka 	mdev->drv = drv_ops;
42195e507d2SLorenzo Bianconi 
42295e507d2SLorenzo Bianconi 	dev = container_of(mdev, struct mt76x0_dev, mt76);
423134b2d0dSStanislaw Gruszka 	mutex_init(&dev->reg_atomic_mutex);
424134b2d0dSStanislaw Gruszka 	mutex_init(&dev->hw_atomic_mutex);
425134b2d0dSStanislaw Gruszka 	spin_lock_init(&dev->mac_lock);
426134b2d0dSStanislaw Gruszka 	spin_lock_init(&dev->con_mon_lock);
427134b2d0dSStanislaw Gruszka 	atomic_set(&dev->avg_ampdu_len, 1);
428134b2d0dSStanislaw Gruszka 
429134b2d0dSStanislaw Gruszka 	return dev;
430134b2d0dSStanislaw Gruszka }
431c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
432134b2d0dSStanislaw Gruszka 
433134b2d0dSStanislaw Gruszka int mt76x0_register_device(struct mt76x0_dev *dev)
434134b2d0dSStanislaw Gruszka {
4351bee323aSLorenzo Bianconi 	struct mt76_dev *mdev = &dev->mt76;
4361bee323aSLorenzo Bianconi 	struct ieee80211_hw *hw = mdev->hw;
437134b2d0dSStanislaw Gruszka 	struct wiphy *wiphy = hw->wiphy;
438134b2d0dSStanislaw Gruszka 	int ret;
439134b2d0dSStanislaw Gruszka 
440e30a655eSLorenzo Bianconi 	ret = mt76x0_init_hardware(dev);
441e30a655eSLorenzo Bianconi 	if (ret)
442e30a655eSLorenzo Bianconi 		return ret;
443e30a655eSLorenzo Bianconi 
444134b2d0dSStanislaw Gruszka 	/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
445134b2d0dSStanislaw Gruszka 	 * entry no. 1 like it does in the vendor driver.
446134b2d0dSStanislaw Gruszka 	 */
4471bee323aSLorenzo Bianconi 	mdev->wcid_mask[0] |= 1;
448134b2d0dSStanislaw Gruszka 
449134b2d0dSStanislaw Gruszka 	/* init fake wcid for monitor interfaces */
4501bee323aSLorenzo Bianconi 	mdev->global_wcid.idx = 0xff;
4511bee323aSLorenzo Bianconi 	mdev->global_wcid.hw_key_idx = -1;
452134b2d0dSStanislaw Gruszka 
4531bee323aSLorenzo Bianconi 	/* init antenna configuration */
4541bee323aSLorenzo Bianconi 	mdev->antenna_mask = 1;
455134b2d0dSStanislaw Gruszka 
456134b2d0dSStanislaw Gruszka 	hw->queues = 4;
457134b2d0dSStanislaw Gruszka 	hw->max_rates = 1;
458134b2d0dSStanislaw Gruszka 	hw->max_report_rates = 7;
459134b2d0dSStanislaw Gruszka 	hw->max_rate_tries = 1;
460493703aaSStanislaw Gruszka 	hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2;
461134b2d0dSStanislaw Gruszka 
46216c8a792SStanislaw Gruszka 	hw->sta_data_size = sizeof(struct mt76x02_sta);
46398ff26e5SStanislaw Gruszka 	hw->vif_data_size = sizeof(struct mt76x02_vif);
464134b2d0dSStanislaw Gruszka 
465134b2d0dSStanislaw Gruszka 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
466134b2d0dSStanislaw Gruszka 
467134b2d0dSStanislaw Gruszka 	INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work);
468134b2d0dSStanislaw Gruszka 
4691bee323aSLorenzo Bianconi 	ret = mt76_register_device(mdev, true, mt76x02_rates,
4701bee323aSLorenzo Bianconi 				   ARRAY_SIZE(mt76x02_rates));
471134b2d0dSStanislaw Gruszka 	if (ret)
472134b2d0dSStanislaw Gruszka 		return ret;
473134b2d0dSStanislaw Gruszka 
4741bee323aSLorenzo Bianconi 	/* overwrite unsupported features */
4751bee323aSLorenzo Bianconi 	if (mdev->cap.has_5ghz)
4761bee323aSLorenzo Bianconi 		mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
4771bee323aSLorenzo Bianconi 
478c6687464SLorenzo Bianconi 	/* check hw sg support in order to enable AMSDU */
4791bee323aSLorenzo Bianconi 	if (mt76u_check_sg(mdev))
480c6687464SLorenzo Bianconi 		hw->max_tx_fragments = MT_SG_MAX_SIZE;
481c6687464SLorenzo Bianconi 	else
482c6687464SLorenzo Bianconi 		hw->max_tx_fragments = 1;
483c6687464SLorenzo Bianconi 
484134b2d0dSStanislaw Gruszka 	mt76x0_init_debugfs(dev);
485134b2d0dSStanislaw Gruszka 
486134b2d0dSStanislaw Gruszka 	return 0;
487134b2d0dSStanislaw Gruszka }
488c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_register_device);
489