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 {
106134b2d0dSStanislaw Gruszka 	u32 val;
107134b2d0dSStanislaw Gruszka 
108134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_PBF_SYS_CTRL);
109134b2d0dSStanislaw Gruszka 	val &= ~0x2000;
110134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_PBF_SYS_CTRL, val);
111134b2d0dSStanislaw Gruszka 
112134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR |
113134b2d0dSStanislaw Gruszka 					 MT_MAC_SYS_CTRL_RESET_BBP);
114134b2d0dSStanislaw Gruszka 
115134b2d0dSStanislaw Gruszka 	msleep(200);
116134b2d0dSStanislaw Gruszka }
117134b2d0dSStanislaw Gruszka 
118134b2d0dSStanislaw Gruszka static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
119134b2d0dSStanislaw Gruszka {
120134b2d0dSStanislaw Gruszka 	u32 val;
121134b2d0dSStanislaw Gruszka 
122134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_USB_DMA_CFG);
123134b2d0dSStanislaw Gruszka 
1247fd3c60cSLorenzo Bianconi 	val |= MT_USB_DMA_CFG_RX_BULK_EN |
125134b2d0dSStanislaw Gruszka 	       MT_USB_DMA_CFG_TX_BULK_EN;
1267fd3c60cSLorenzo Bianconi 
1277fd3c60cSLorenzo Bianconi 	/* disable AGGR_BULK_RX in order to receive one
1287fd3c60cSLorenzo Bianconi 	 * frame in each rx urb and avoid copies
1297fd3c60cSLorenzo Bianconi 	 */
1307fd3c60cSLorenzo Bianconi 	val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
131134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_USB_DMA_CFG, val);
132134b2d0dSStanislaw Gruszka 
133134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_COM_REG0);
134134b2d0dSStanislaw Gruszka 	if (val & 1)
135134b2d0dSStanislaw Gruszka 		dev_dbg(dev->mt76.dev, "MCU not ready\n");
136134b2d0dSStanislaw Gruszka 
137134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_USB_DMA_CFG);
138134b2d0dSStanislaw Gruszka 
139797ea240SStanislaw Gruszka 	val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
140134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_USB_DMA_CFG, val);
141797ea240SStanislaw Gruszka 	val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
142134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_USB_DMA_CFG, val);
143134b2d0dSStanislaw Gruszka }
144134b2d0dSStanislaw Gruszka 
145134b2d0dSStanislaw Gruszka #define RANDOM_WRITE(dev, tab)			\
14617507157SLorenzo Bianconi 	mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN,	\
147f1638c7cSStanislaw Gruszka 		   tab, ARRAY_SIZE(tab))
148134b2d0dSStanislaw Gruszka 
149134b2d0dSStanislaw Gruszka static int mt76x0_init_bbp(struct mt76x0_dev *dev)
150134b2d0dSStanislaw Gruszka {
151134b2d0dSStanislaw Gruszka 	int ret, i;
152134b2d0dSStanislaw Gruszka 
153134b2d0dSStanislaw Gruszka 	ret = mt76x0_wait_bbp_ready(dev);
154134b2d0dSStanislaw Gruszka 	if (ret)
155134b2d0dSStanislaw Gruszka 		return ret;
156134b2d0dSStanislaw Gruszka 
157134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_bbp_init_tab);
158134b2d0dSStanislaw Gruszka 
159134b2d0dSStanislaw Gruszka 	for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) {
160134b2d0dSStanislaw Gruszka 		const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i];
161134b2d0dSStanislaw Gruszka 		const struct mt76_reg_pair *pair = &item->reg_pair;
162134b2d0dSStanislaw Gruszka 
163134b2d0dSStanislaw Gruszka 		if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20))
164134b2d0dSStanislaw Gruszka 			mt76_wr(dev, pair->reg, pair->value);
165134b2d0dSStanislaw Gruszka 	}
166134b2d0dSStanislaw Gruszka 
167134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_dcoc_tab);
168134b2d0dSStanislaw Gruszka 
169134b2d0dSStanislaw Gruszka 	return 0;
170134b2d0dSStanislaw Gruszka }
171134b2d0dSStanislaw Gruszka 
172134b2d0dSStanislaw Gruszka static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
173134b2d0dSStanislaw Gruszka {
174134b2d0dSStanislaw Gruszka 	u32 reg;
175134b2d0dSStanislaw Gruszka 
176134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, common_mac_reg_table);
177134b2d0dSStanislaw Gruszka 
178a6daf796SLorenzo Bianconi 	mt76x02_set_beacon_offsets(&dev->mt76);
179134b2d0dSStanislaw Gruszka 
180134b2d0dSStanislaw Gruszka 	/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
181134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_mac_reg_table);
182134b2d0dSStanislaw Gruszka 
183134b2d0dSStanislaw Gruszka 	/* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */
184134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_MAC_SYS_CTRL);
185134b2d0dSStanislaw Gruszka 	reg &= ~0x3;
186134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, reg);
187134b2d0dSStanislaw Gruszka 
188134b2d0dSStanislaw Gruszka 	if (is_mt7610e(dev)) {
189134b2d0dSStanislaw Gruszka 		/* Disable COEX_EN */
190134b2d0dSStanislaw Gruszka 		reg = mt76_rr(dev, MT_COEXCFG0);
191134b2d0dSStanislaw Gruszka 		reg &= 0xFFFFFFFE;
192134b2d0dSStanislaw Gruszka 		mt76_wr(dev, MT_COEXCFG0, reg);
193134b2d0dSStanislaw Gruszka 	}
194134b2d0dSStanislaw Gruszka 
195134b2d0dSStanislaw Gruszka 	/* Set 0x141C[15:12]=0xF */
196134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_EXT_CCA_CFG);
197134b2d0dSStanislaw Gruszka 	reg |= 0x0000F000;
198134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_EXT_CCA_CFG, reg);
199134b2d0dSStanislaw Gruszka 
200134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);
201134b2d0dSStanislaw Gruszka 
202134b2d0dSStanislaw Gruszka 	/*
203134b2d0dSStanislaw Gruszka 		TxRing 9 is for Mgmt frame.
204134b2d0dSStanislaw Gruszka 		TxRing 8 is for In-band command frame.
205134b2d0dSStanislaw Gruszka 		WMM_RG0_TXQMA: This register setting is for FCE to define the rule of TxRing 9.
206134b2d0dSStanislaw Gruszka 		WMM_RG1_TXQMA: This register setting is for FCE to define the rule of TxRing 8.
207134b2d0dSStanislaw Gruszka 	*/
208134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_WMM_CTRL);
209134b2d0dSStanislaw Gruszka 	reg &= ~0x000003FF;
210134b2d0dSStanislaw Gruszka 	reg |= 0x00000201;
211134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WMM_CTRL, reg);
212134b2d0dSStanislaw Gruszka 
213134b2d0dSStanislaw Gruszka 	/* TODO: Probably not needed */
214134b2d0dSStanislaw Gruszka 	mt76_wr(dev, 0x7028, 0);
215134b2d0dSStanislaw Gruszka 	mt76_wr(dev, 0x7010, 0);
216134b2d0dSStanislaw Gruszka 	mt76_wr(dev, 0x7024, 0);
217134b2d0dSStanislaw Gruszka 	msleep(10);
218134b2d0dSStanislaw Gruszka }
219134b2d0dSStanislaw Gruszka 
220134b2d0dSStanislaw Gruszka static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev)
221134b2d0dSStanislaw Gruszka {
222134b2d0dSStanislaw Gruszka 	u32 *vals;
223331419b2SStanislaw Gruszka 	int i;
224134b2d0dSStanislaw Gruszka 
22536404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
226134b2d0dSStanislaw Gruszka 	if (!vals)
227134b2d0dSStanislaw Gruszka 		return -ENOMEM;
228134b2d0dSStanislaw Gruszka 
22936404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS; i++)  {
230134b2d0dSStanislaw Gruszka 		vals[i * 2] = 0xffffffff;
231134b2d0dSStanislaw Gruszka 		vals[i * 2 + 1] = 0x00ffffff;
232134b2d0dSStanislaw Gruszka 	}
233134b2d0dSStanislaw Gruszka 
234331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
235134b2d0dSStanislaw Gruszka 	kfree(vals);
236331419b2SStanislaw Gruszka 	return 0;
237134b2d0dSStanislaw Gruszka }
238134b2d0dSStanislaw Gruszka 
239331419b2SStanislaw Gruszka static void mt76x0_init_key_mem(struct mt76x0_dev *dev)
240134b2d0dSStanislaw Gruszka {
241134b2d0dSStanislaw Gruszka 	u32 vals[4] = {};
242134b2d0dSStanislaw Gruszka 
243331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
244134b2d0dSStanislaw Gruszka }
245134b2d0dSStanislaw Gruszka 
246134b2d0dSStanislaw Gruszka static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev)
247134b2d0dSStanislaw Gruszka {
248134b2d0dSStanislaw Gruszka 	u32 *vals;
249331419b2SStanislaw Gruszka 	int i;
250134b2d0dSStanislaw Gruszka 
25136404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
252134b2d0dSStanislaw Gruszka 	if (!vals)
253134b2d0dSStanislaw Gruszka 		return -ENOMEM;
254134b2d0dSStanislaw Gruszka 
25536404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS * 2; i++)
256134b2d0dSStanislaw Gruszka 		vals[i] = 1;
257134b2d0dSStanislaw Gruszka 
258331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
259134b2d0dSStanislaw Gruszka 	kfree(vals);
260331419b2SStanislaw Gruszka 	return 0;
261134b2d0dSStanislaw Gruszka }
262134b2d0dSStanislaw Gruszka 
263134b2d0dSStanislaw Gruszka static void mt76x0_reset_counters(struct mt76x0_dev *dev)
264134b2d0dSStanislaw Gruszka {
265797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_0);
266797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_1);
267797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_2);
268797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_0);
269797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_1);
270797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_2);
271134b2d0dSStanislaw Gruszka }
272134b2d0dSStanislaw Gruszka 
273134b2d0dSStanislaw Gruszka int mt76x0_mac_start(struct mt76x0_dev *dev)
274134b2d0dSStanislaw Gruszka {
275134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
276134b2d0dSStanislaw Gruszka 
2773b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
278134b2d0dSStanislaw Gruszka 		return -ETIMEDOUT;
279134b2d0dSStanislaw Gruszka 
280108a4861SStanislaw Gruszka 	dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
281134b2d0dSStanislaw Gruszka 		MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
282134b2d0dSStanislaw Gruszka 		MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
283134b2d0dSStanislaw Gruszka 		MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
284134b2d0dSStanislaw Gruszka 		MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
285134b2d0dSStanislaw Gruszka 		MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
286134b2d0dSStanislaw Gruszka 		MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
287108a4861SStanislaw Gruszka 	mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
288134b2d0dSStanislaw Gruszka 
289134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL,
290134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
291134b2d0dSStanislaw Gruszka 
2923b11db26SLorenzo Bianconi 	return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
293134b2d0dSStanislaw Gruszka }
294134b2d0dSStanislaw Gruszka 
295134b2d0dSStanislaw Gruszka static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
296134b2d0dSStanislaw Gruszka {
297134b2d0dSStanislaw Gruszka 	int i, ok;
298134b2d0dSStanislaw Gruszka 
299134b2d0dSStanislaw Gruszka 	if (test_bit(MT76_REMOVED, &dev->mt76.state))
300134b2d0dSStanislaw Gruszka 		return;
301134b2d0dSStanislaw Gruszka 
302134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
303134b2d0dSStanislaw Gruszka 		   MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
304134b2d0dSStanislaw Gruszka 		   MT_BEACON_TIME_CFG_BEACON_TX);
305134b2d0dSStanislaw Gruszka 
306134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
307134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n");
308134b2d0dSStanislaw Gruszka 
309134b2d0dSStanislaw Gruszka 	/* Page count on TxQ */
310134b2d0dSStanislaw Gruszka 	i = 200;
311134b2d0dSStanislaw Gruszka 	while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
312134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
313134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
314134b2d0dSStanislaw Gruszka 		msleep(10);
315134b2d0dSStanislaw Gruszka 
316134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
317134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n");
318134b2d0dSStanislaw Gruszka 
319134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
320134b2d0dSStanislaw Gruszka 					 MT_MAC_SYS_CTRL_ENABLE_TX);
321134b2d0dSStanislaw Gruszka 
322134b2d0dSStanislaw Gruszka 	/* Page count on RxQ */
323134b2d0dSStanislaw Gruszka 	ok = 0;
324134b2d0dSStanislaw Gruszka 	i = 200;
325134b2d0dSStanislaw Gruszka 	while (i--) {
326134b2d0dSStanislaw Gruszka 		if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
327134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a30) &&
328134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a34)) {
329134b2d0dSStanislaw Gruszka 			if (ok++ > 5)
330134b2d0dSStanislaw Gruszka 				break;
331134b2d0dSStanislaw Gruszka 			continue;
332134b2d0dSStanislaw Gruszka 		}
333134b2d0dSStanislaw Gruszka 		msleep(1);
334134b2d0dSStanislaw Gruszka 	}
335134b2d0dSStanislaw Gruszka 
336134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
337134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");
338134b2d0dSStanislaw Gruszka 
339134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
340134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n");
341134b2d0dSStanislaw Gruszka }
342134b2d0dSStanislaw Gruszka 
343134b2d0dSStanislaw Gruszka void mt76x0_mac_stop(struct mt76x0_dev *dev)
344134b2d0dSStanislaw Gruszka {
345b680d7fbSLorenzo Bianconi 	cancel_delayed_work_sync(&dev->cal_work);
346b680d7fbSLorenzo Bianconi 	cancel_delayed_work_sync(&dev->mac_work);
347b680d7fbSLorenzo Bianconi 	mt76u_stop_stat_wk(&dev->mt76);
348134b2d0dSStanislaw Gruszka 	mt76x0_mac_stop_hw(dev);
349134b2d0dSStanislaw Gruszka }
350c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
351134b2d0dSStanislaw Gruszka 
352134b2d0dSStanislaw Gruszka int mt76x0_init_hardware(struct mt76x0_dev *dev)
353134b2d0dSStanislaw Gruszka {
354134b2d0dSStanislaw Gruszka 	int ret;
355134b2d0dSStanislaw Gruszka 
3563b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000))
357e30a655eSLorenzo Bianconi 		return -EIO;
358134b2d0dSStanislaw Gruszka 
359134b2d0dSStanislaw Gruszka 	/* Wait for ASIC ready after FW load. */
360e30a655eSLorenzo Bianconi 	if (!mt76x02_wait_for_mac(&dev->mt76))
361e30a655eSLorenzo Bianconi 		return -ETIMEDOUT;
362134b2d0dSStanislaw Gruszka 
363134b2d0dSStanislaw Gruszka 	mt76x0_reset_csr_bbp(dev);
364134b2d0dSStanislaw Gruszka 	mt76x0_init_usb_dma(dev);
365134b2d0dSStanislaw Gruszka 
366134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0);
367134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_TSO_CTRL, 0x0);
368134b2d0dSStanislaw Gruszka 
36928041571SLorenzo Bianconi 	ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false);
370134b2d0dSStanislaw Gruszka 	if (ret)
371e30a655eSLorenzo Bianconi 		return ret;
37230ec9152SLorenzo Bianconi 
373134b2d0dSStanislaw Gruszka 	mt76x0_init_mac_registers(dev);
374134b2d0dSStanislaw Gruszka 
3753b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
376e30a655eSLorenzo Bianconi 		return -EIO;
377134b2d0dSStanislaw Gruszka 
378134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_bbp(dev);
379134b2d0dSStanislaw Gruszka 	if (ret)
380e30a655eSLorenzo Bianconi 		return ret;
381134b2d0dSStanislaw Gruszka 
382134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_mem(dev);
383134b2d0dSStanislaw Gruszka 	if (ret)
384e30a655eSLorenzo Bianconi 		return ret;
385e30a655eSLorenzo Bianconi 
386331419b2SStanislaw Gruszka 	mt76x0_init_key_mem(dev);
387e30a655eSLorenzo Bianconi 
388134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_attr_mem(dev);
389134b2d0dSStanislaw Gruszka 	if (ret)
390e30a655eSLorenzo Bianconi 		return ret;
391134b2d0dSStanislaw Gruszka 
392134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
393134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_SYNC_MODE |
394134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_TBTT_EN |
395134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_BEACON_TX));
396134b2d0dSStanislaw Gruszka 
397134b2d0dSStanislaw Gruszka 	mt76x0_reset_counters(dev);
398134b2d0dSStanislaw Gruszka 
399134b2d0dSStanislaw Gruszka 	mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
400134b2d0dSStanislaw Gruszka 
401134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_TXOP_CTRL_CFG,
402134b2d0dSStanislaw Gruszka 		   FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
403134b2d0dSStanislaw Gruszka 		   FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
404134b2d0dSStanislaw Gruszka 
405134b2d0dSStanislaw Gruszka 	ret = mt76x0_eeprom_init(dev);
406134b2d0dSStanislaw Gruszka 	if (ret)
407e30a655eSLorenzo Bianconi 		return ret;
408134b2d0dSStanislaw Gruszka 
409134b2d0dSStanislaw Gruszka 	mt76x0_phy_init(dev);
410134b2d0dSStanislaw Gruszka 
411e30a655eSLorenzo Bianconi 	return 0;
412134b2d0dSStanislaw Gruszka }
413c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
414134b2d0dSStanislaw Gruszka 
415134b2d0dSStanislaw Gruszka void mt76x0_cleanup(struct mt76x0_dev *dev)
416134b2d0dSStanislaw Gruszka {
417cb722aedSLorenzo Bianconi 	clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
4187c7b1394SLorenzo Bianconi 	mt76x0_chip_onoff(dev, false, false);
41930ec9152SLorenzo Bianconi 	mt76u_queues_deinit(&dev->mt76);
4206f4796b7SLorenzo Bianconi 	mt76u_mcu_deinit(&dev->mt76);
421134b2d0dSStanislaw Gruszka }
422c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_cleanup);
423134b2d0dSStanislaw Gruszka 
424835123b7SStanislaw Gruszka struct mt76x0_dev *
425835123b7SStanislaw Gruszka mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops)
426134b2d0dSStanislaw Gruszka {
427134b2d0dSStanislaw Gruszka 	struct mt76x0_dev *dev;
42895e507d2SLorenzo Bianconi 	struct mt76_dev *mdev;
429134b2d0dSStanislaw Gruszka 
43095e507d2SLorenzo Bianconi 	mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops);
43195e507d2SLorenzo Bianconi 	if (!mdev)
432134b2d0dSStanislaw Gruszka 		return NULL;
433134b2d0dSStanislaw Gruszka 
43495e507d2SLorenzo Bianconi 	mdev->dev = pdev;
435835123b7SStanislaw Gruszka 	mdev->drv = drv_ops;
43695e507d2SLorenzo Bianconi 
43795e507d2SLorenzo Bianconi 	dev = container_of(mdev, struct mt76x0_dev, mt76);
438134b2d0dSStanislaw Gruszka 	mutex_init(&dev->reg_atomic_mutex);
439134b2d0dSStanislaw Gruszka 	mutex_init(&dev->hw_atomic_mutex);
440134b2d0dSStanislaw Gruszka 	spin_lock_init(&dev->mac_lock);
441134b2d0dSStanislaw Gruszka 	spin_lock_init(&dev->con_mon_lock);
442134b2d0dSStanislaw Gruszka 	atomic_set(&dev->avg_ampdu_len, 1);
443134b2d0dSStanislaw Gruszka 
444134b2d0dSStanislaw Gruszka 	return dev;
445134b2d0dSStanislaw Gruszka }
446c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
447134b2d0dSStanislaw Gruszka 
448134b2d0dSStanislaw Gruszka int mt76x0_register_device(struct mt76x0_dev *dev)
449134b2d0dSStanislaw Gruszka {
4501bee323aSLorenzo Bianconi 	struct mt76_dev *mdev = &dev->mt76;
4511bee323aSLorenzo Bianconi 	struct ieee80211_hw *hw = mdev->hw;
452134b2d0dSStanislaw Gruszka 	struct wiphy *wiphy = hw->wiphy;
453134b2d0dSStanislaw Gruszka 	int ret;
454134b2d0dSStanislaw Gruszka 
455e30a655eSLorenzo Bianconi 	ret = mt76x0_init_hardware(dev);
456e30a655eSLorenzo Bianconi 	if (ret)
457e30a655eSLorenzo Bianconi 		return ret;
458e30a655eSLorenzo Bianconi 
459134b2d0dSStanislaw Gruszka 	/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
460134b2d0dSStanislaw Gruszka 	 * entry no. 1 like it does in the vendor driver.
461134b2d0dSStanislaw Gruszka 	 */
4621bee323aSLorenzo Bianconi 	mdev->wcid_mask[0] |= 1;
463134b2d0dSStanislaw Gruszka 
464134b2d0dSStanislaw Gruszka 	/* init fake wcid for monitor interfaces */
4651bee323aSLorenzo Bianconi 	mdev->global_wcid.idx = 0xff;
4661bee323aSLorenzo Bianconi 	mdev->global_wcid.hw_key_idx = -1;
467134b2d0dSStanislaw Gruszka 
4681bee323aSLorenzo Bianconi 	/* init antenna configuration */
4691bee323aSLorenzo Bianconi 	mdev->antenna_mask = 1;
470134b2d0dSStanislaw Gruszka 
471134b2d0dSStanislaw Gruszka 	hw->queues = 4;
472134b2d0dSStanislaw Gruszka 	hw->max_rates = 1;
473134b2d0dSStanislaw Gruszka 	hw->max_report_rates = 7;
474134b2d0dSStanislaw Gruszka 	hw->max_rate_tries = 1;
475493703aaSStanislaw Gruszka 	hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2;
476134b2d0dSStanislaw Gruszka 
47716c8a792SStanislaw Gruszka 	hw->sta_data_size = sizeof(struct mt76x02_sta);
47898ff26e5SStanislaw Gruszka 	hw->vif_data_size = sizeof(struct mt76x02_vif);
479134b2d0dSStanislaw Gruszka 
480134b2d0dSStanislaw Gruszka 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
481134b2d0dSStanislaw Gruszka 
482134b2d0dSStanislaw Gruszka 	INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work);
483134b2d0dSStanislaw Gruszka 
4841bee323aSLorenzo Bianconi 	ret = mt76_register_device(mdev, true, mt76x02_rates,
4851bee323aSLorenzo Bianconi 				   ARRAY_SIZE(mt76x02_rates));
486134b2d0dSStanislaw Gruszka 	if (ret)
487134b2d0dSStanislaw Gruszka 		return ret;
488134b2d0dSStanislaw Gruszka 
4891bee323aSLorenzo Bianconi 	/* overwrite unsupported features */
4901bee323aSLorenzo Bianconi 	if (mdev->cap.has_5ghz)
4911bee323aSLorenzo Bianconi 		mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
4921bee323aSLorenzo Bianconi 
493c6687464SLorenzo Bianconi 	/* check hw sg support in order to enable AMSDU */
4941bee323aSLorenzo Bianconi 	if (mt76u_check_sg(mdev))
495c6687464SLorenzo Bianconi 		hw->max_tx_fragments = MT_SG_MAX_SIZE;
496c6687464SLorenzo Bianconi 	else
497c6687464SLorenzo Bianconi 		hw->max_tx_fragments = 1;
498c6687464SLorenzo Bianconi 
499134b2d0dSStanislaw Gruszka 	mt76x0_init_debugfs(dev);
500134b2d0dSStanislaw Gruszka 
501134b2d0dSStanislaw Gruszka 	return 0;
502134b2d0dSStanislaw Gruszka }
503c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_register_device);
504