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"
21134b2d0dSStanislaw Gruszka #include "initvals.h"
22134b2d0dSStanislaw Gruszka 
231bee323aSLorenzo Bianconi static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
241bee323aSLorenzo Bianconi {
251bee323aSLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
261bee323aSLorenzo Bianconi 	u16 mcs_map = 0;
271bee323aSLorenzo Bianconi 	int i;
281bee323aSLorenzo Bianconi 
291bee323aSLorenzo Bianconi 	vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
301bee323aSLorenzo Bianconi 	for (i = 0; i < 8; i++) {
311bee323aSLorenzo Bianconi 		if (!i)
321bee323aSLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2));
331bee323aSLorenzo Bianconi 		else
341bee323aSLorenzo Bianconi 			mcs_map |=
351bee323aSLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
361bee323aSLorenzo Bianconi 	}
371bee323aSLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
381bee323aSLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
391bee323aSLorenzo Bianconi }
401bee323aSLorenzo Bianconi 
41134b2d0dSStanislaw Gruszka static void
42b2d871c0SLorenzo Bianconi mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable)
43134b2d0dSStanislaw Gruszka {
445b394355SLorenzo Bianconi 	u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD;
45134b2d0dSStanislaw Gruszka 
46134b2d0dSStanislaw Gruszka 	/* Note: we don't turn off WLAN_CLK because that makes the device
47134b2d0dSStanislaw Gruszka 	 *	 not respond properly on the probe path.
48134b2d0dSStanislaw Gruszka 	 *	 In case anyone (PSM?) wants to use this function we can
49134b2d0dSStanislaw Gruszka 	 *	 bring the clock stuff back and fixup the probe path.
50134b2d0dSStanislaw Gruszka 	 */
51134b2d0dSStanislaw Gruszka 
52134b2d0dSStanislaw Gruszka 	if (enable)
53134b2d0dSStanislaw Gruszka 		val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
54134b2d0dSStanislaw Gruszka 			MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
55134b2d0dSStanislaw Gruszka 	else
56134b2d0dSStanislaw Gruszka 		val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);
57134b2d0dSStanislaw Gruszka 
58134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
59134b2d0dSStanislaw Gruszka 	udelay(20);
60134b2d0dSStanislaw Gruszka 
61134b2d0dSStanislaw Gruszka 	/* Note: vendor driver tries to disable/enable wlan here and retry
62134b2d0dSStanislaw Gruszka 	 *       but the code which does it is so buggy it must have never
63134b2d0dSStanislaw Gruszka 	 *       triggered, so don't bother.
64134b2d0dSStanislaw Gruszka 	 */
655b394355SLorenzo Bianconi 	if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000))
665b394355SLorenzo Bianconi 		dev_err(dev->mt76.dev, "PLL and XTAL check failed\n");
67134b2d0dSStanislaw Gruszka }
68134b2d0dSStanislaw Gruszka 
69b2d871c0SLorenzo Bianconi void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset)
70134b2d0dSStanislaw Gruszka {
71134b2d0dSStanislaw Gruszka 	u32 val;
72134b2d0dSStanislaw Gruszka 
73134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
74134b2d0dSStanislaw Gruszka 
75134b2d0dSStanislaw Gruszka 	if (reset) {
76134b2d0dSStanislaw Gruszka 		val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
77134b2d0dSStanislaw Gruszka 		val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
78134b2d0dSStanislaw Gruszka 
79134b2d0dSStanislaw Gruszka 		if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
80134b2d0dSStanislaw Gruszka 			val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
81134b2d0dSStanislaw Gruszka 				MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
82134b2d0dSStanislaw Gruszka 			mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
83134b2d0dSStanislaw Gruszka 			udelay(20);
84134b2d0dSStanislaw Gruszka 
85134b2d0dSStanislaw Gruszka 			val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
86134b2d0dSStanislaw Gruszka 				 MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
87134b2d0dSStanislaw Gruszka 		}
88134b2d0dSStanislaw Gruszka 	}
89134b2d0dSStanislaw Gruszka 
90134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
91134b2d0dSStanislaw Gruszka 	udelay(20);
92134b2d0dSStanislaw Gruszka 
93134b2d0dSStanislaw Gruszka 	mt76x0_set_wlan_state(dev, val, enable);
94134b2d0dSStanislaw Gruszka }
95c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
96134b2d0dSStanislaw Gruszka 
97b2d871c0SLorenzo Bianconi static void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev)
98134b2d0dSStanislaw Gruszka {
99512bd4b1SLorenzo Bianconi 	mt76_wr(dev, MT_MAC_SYS_CTRL,
100512bd4b1SLorenzo Bianconi 		MT_MAC_SYS_CTRL_RESET_CSR |
101134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_RESET_BBP);
102134b2d0dSStanislaw Gruszka 	msleep(200);
1032b2cb40bSLorenzo Bianconi 	mt76_clear(dev, MT_MAC_SYS_CTRL,
1042b2cb40bSLorenzo Bianconi 		   MT_MAC_SYS_CTRL_RESET_CSR |
1052b2cb40bSLorenzo Bianconi 		   MT_MAC_SYS_CTRL_RESET_BBP);
106134b2d0dSStanislaw Gruszka }
107134b2d0dSStanislaw Gruszka 
108134b2d0dSStanislaw Gruszka #define RANDOM_WRITE(dev, tab)			\
10917507157SLorenzo Bianconi 	mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN,	\
110f1638c7cSStanislaw Gruszka 		   tab, ARRAY_SIZE(tab))
111134b2d0dSStanislaw Gruszka 
112b2d871c0SLorenzo Bianconi static int mt76x0_init_bbp(struct mt76x02_dev *dev)
113134b2d0dSStanislaw Gruszka {
114134b2d0dSStanislaw Gruszka 	int ret, i;
115134b2d0dSStanislaw Gruszka 
1169c410782SLorenzo Bianconi 	ret = mt76x0_phy_wait_bbp_ready(dev);
117134b2d0dSStanislaw Gruszka 	if (ret)
118134b2d0dSStanislaw Gruszka 		return ret;
119134b2d0dSStanislaw Gruszka 
120134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_bbp_init_tab);
121134b2d0dSStanislaw Gruszka 
122134b2d0dSStanislaw Gruszka 	for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) {
123134b2d0dSStanislaw Gruszka 		const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i];
124134b2d0dSStanislaw Gruszka 		const struct mt76_reg_pair *pair = &item->reg_pair;
125134b2d0dSStanislaw Gruszka 
126134b2d0dSStanislaw Gruszka 		if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20))
127134b2d0dSStanislaw Gruszka 			mt76_wr(dev, pair->reg, pair->value);
128134b2d0dSStanislaw Gruszka 	}
129134b2d0dSStanislaw Gruszka 
130134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_dcoc_tab);
131134b2d0dSStanislaw Gruszka 
132134b2d0dSStanislaw Gruszka 	return 0;
133134b2d0dSStanislaw Gruszka }
134134b2d0dSStanislaw Gruszka 
135b2d871c0SLorenzo Bianconi static void mt76x0_init_mac_registers(struct mt76x02_dev *dev)
136134b2d0dSStanislaw Gruszka {
137134b2d0dSStanislaw Gruszka 	u32 reg;
138134b2d0dSStanislaw Gruszka 
139134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, common_mac_reg_table);
140134b2d0dSStanislaw Gruszka 
141d87cf75fSLorenzo Bianconi 	mt76x02_set_beacon_offsets(dev);
142134b2d0dSStanislaw Gruszka 
143134b2d0dSStanislaw Gruszka 	/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
144134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_mac_reg_table);
145134b2d0dSStanislaw Gruszka 
146134b2d0dSStanislaw Gruszka 	/* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */
147134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_MAC_SYS_CTRL);
148134b2d0dSStanislaw Gruszka 	reg &= ~0x3;
149134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, reg);
150134b2d0dSStanislaw Gruszka 
151134b2d0dSStanislaw Gruszka 	/* Set 0x141C[15:12]=0xF */
152134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_EXT_CCA_CFG);
153134b2d0dSStanislaw Gruszka 	reg |= 0x0000F000;
154134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_EXT_CCA_CFG, reg);
155134b2d0dSStanislaw Gruszka 
156134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);
157134b2d0dSStanislaw Gruszka 
158134b2d0dSStanislaw Gruszka 	/*
159134b2d0dSStanislaw Gruszka 		TxRing 9 is for Mgmt frame.
160134b2d0dSStanislaw Gruszka 		TxRing 8 is for In-band command frame.
161134b2d0dSStanislaw Gruszka 		WMM_RG0_TXQMA: This register setting is for FCE to define the rule of TxRing 9.
162134b2d0dSStanislaw Gruszka 		WMM_RG1_TXQMA: This register setting is for FCE to define the rule of TxRing 8.
163134b2d0dSStanislaw Gruszka 	*/
164134b2d0dSStanislaw Gruszka 	reg = mt76_rr(dev, MT_WMM_CTRL);
165134b2d0dSStanislaw Gruszka 	reg &= ~0x000003FF;
166134b2d0dSStanislaw Gruszka 	reg |= 0x00000201;
167134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WMM_CTRL, reg);
168134b2d0dSStanislaw Gruszka }
169134b2d0dSStanislaw Gruszka 
170b2d871c0SLorenzo Bianconi static int mt76x0_init_wcid_mem(struct mt76x02_dev *dev)
171134b2d0dSStanislaw Gruszka {
172134b2d0dSStanislaw Gruszka 	u32 *vals;
173331419b2SStanislaw Gruszka 	int i;
174134b2d0dSStanislaw Gruszka 
17536404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
176134b2d0dSStanislaw Gruszka 	if (!vals)
177134b2d0dSStanislaw Gruszka 		return -ENOMEM;
178134b2d0dSStanislaw Gruszka 
17936404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS; i++)  {
180134b2d0dSStanislaw Gruszka 		vals[i * 2] = 0xffffffff;
181134b2d0dSStanislaw Gruszka 		vals[i * 2 + 1] = 0x00ffffff;
182134b2d0dSStanislaw Gruszka 	}
183134b2d0dSStanislaw Gruszka 
184331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
185134b2d0dSStanislaw Gruszka 	kfree(vals);
186331419b2SStanislaw Gruszka 	return 0;
187134b2d0dSStanislaw Gruszka }
188134b2d0dSStanislaw Gruszka 
189b2d871c0SLorenzo Bianconi static void mt76x0_init_key_mem(struct mt76x02_dev *dev)
190134b2d0dSStanislaw Gruszka {
191134b2d0dSStanislaw Gruszka 	u32 vals[4] = {};
192134b2d0dSStanislaw Gruszka 
193331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
194134b2d0dSStanislaw Gruszka }
195134b2d0dSStanislaw Gruszka 
196b2d871c0SLorenzo Bianconi static int mt76x0_init_wcid_attr_mem(struct mt76x02_dev *dev)
197134b2d0dSStanislaw Gruszka {
198134b2d0dSStanislaw Gruszka 	u32 *vals;
199331419b2SStanislaw Gruszka 	int i;
200134b2d0dSStanislaw Gruszka 
20136404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
202134b2d0dSStanislaw Gruszka 	if (!vals)
203134b2d0dSStanislaw Gruszka 		return -ENOMEM;
204134b2d0dSStanislaw Gruszka 
20536404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS * 2; i++)
206134b2d0dSStanislaw Gruszka 		vals[i] = 1;
207134b2d0dSStanislaw Gruszka 
208331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
209134b2d0dSStanislaw Gruszka 	kfree(vals);
210331419b2SStanislaw Gruszka 	return 0;
211134b2d0dSStanislaw Gruszka }
212134b2d0dSStanislaw Gruszka 
213b2d871c0SLorenzo Bianconi static void mt76x0_reset_counters(struct mt76x02_dev *dev)
214134b2d0dSStanislaw Gruszka {
215797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_0);
216797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_1);
217797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_2);
218797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_0);
219797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_1);
220797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_2);
221134b2d0dSStanislaw Gruszka }
222134b2d0dSStanislaw Gruszka 
223b2d871c0SLorenzo Bianconi int mt76x0_mac_start(struct mt76x02_dev *dev)
224134b2d0dSStanislaw Gruszka {
225134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
226134b2d0dSStanislaw Gruszka 
2273b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
228134b2d0dSStanislaw Gruszka 		return -ETIMEDOUT;
229134b2d0dSStanislaw Gruszka 
230108a4861SStanislaw Gruszka 	mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
231134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL,
232134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
233134b2d0dSStanislaw Gruszka 
2343b11db26SLorenzo Bianconi 	return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
235134b2d0dSStanislaw Gruszka }
236b11e1969SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x0_mac_start);
237134b2d0dSStanislaw Gruszka 
238b2d871c0SLorenzo Bianconi void mt76x0_mac_stop(struct mt76x02_dev *dev)
239134b2d0dSStanislaw Gruszka {
240b11e1969SLorenzo Bianconi 	int i = 200, ok = 0;
241134b2d0dSStanislaw Gruszka 
242134b2d0dSStanislaw Gruszka 	/* Page count on TxQ */
243134b2d0dSStanislaw Gruszka 	while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
244134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
245134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
246134b2d0dSStanislaw Gruszka 		msleep(10);
247134b2d0dSStanislaw Gruszka 
248134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
249134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n");
250134b2d0dSStanislaw Gruszka 
251134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
252134b2d0dSStanislaw Gruszka 					 MT_MAC_SYS_CTRL_ENABLE_TX);
253134b2d0dSStanislaw Gruszka 
254134b2d0dSStanislaw Gruszka 	/* Page count on RxQ */
255b11e1969SLorenzo Bianconi 	for (i = 0; i < 200; i++) {
256134b2d0dSStanislaw Gruszka 		if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
257134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a30) &&
258134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a34)) {
259134b2d0dSStanislaw Gruszka 			if (ok++ > 5)
260134b2d0dSStanislaw Gruszka 				break;
261134b2d0dSStanislaw Gruszka 			continue;
262134b2d0dSStanislaw Gruszka 		}
263134b2d0dSStanislaw Gruszka 		msleep(1);
264134b2d0dSStanislaw Gruszka 	}
265134b2d0dSStanislaw Gruszka 
266134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
267134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");
268134b2d0dSStanislaw Gruszka }
269c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
270134b2d0dSStanislaw Gruszka 
271b2d871c0SLorenzo Bianconi int mt76x0_init_hardware(struct mt76x02_dev *dev)
272134b2d0dSStanislaw Gruszka {
273134b2d0dSStanislaw Gruszka 	int ret;
274134b2d0dSStanislaw Gruszka 
2753b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000))
276e30a655eSLorenzo Bianconi 		return -EIO;
277134b2d0dSStanislaw Gruszka 
278134b2d0dSStanislaw Gruszka 	/* Wait for ASIC ready after FW load. */
279e30a655eSLorenzo Bianconi 	if (!mt76x02_wait_for_mac(&dev->mt76))
280e30a655eSLorenzo Bianconi 		return -ETIMEDOUT;
281134b2d0dSStanislaw Gruszka 
282134b2d0dSStanislaw Gruszka 	mt76x0_reset_csr_bbp(dev);
283499cd0aaSLorenzo Bianconi 	ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false);
284134b2d0dSStanislaw Gruszka 	if (ret)
285e30a655eSLorenzo Bianconi 		return ret;
28630ec9152SLorenzo Bianconi 
287134b2d0dSStanislaw Gruszka 	mt76x0_init_mac_registers(dev);
288134b2d0dSStanislaw Gruszka 
2893b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
290e30a655eSLorenzo Bianconi 		return -EIO;
291134b2d0dSStanislaw Gruszka 
292134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_bbp(dev);
293134b2d0dSStanislaw Gruszka 	if (ret)
294e30a655eSLorenzo Bianconi 		return ret;
295134b2d0dSStanislaw Gruszka 
296a31821abSLorenzo Bianconi 	dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
297a31821abSLorenzo Bianconi 
298134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_mem(dev);
299134b2d0dSStanislaw Gruszka 	if (ret)
300e30a655eSLorenzo Bianconi 		return ret;
301e30a655eSLorenzo Bianconi 
302331419b2SStanislaw Gruszka 	mt76x0_init_key_mem(dev);
303e30a655eSLorenzo Bianconi 
304134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_attr_mem(dev);
305134b2d0dSStanislaw Gruszka 	if (ret)
306e30a655eSLorenzo Bianconi 		return ret;
307134b2d0dSStanislaw Gruszka 
308134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
309134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_SYNC_MODE |
310134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_TBTT_EN |
311134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_BEACON_TX));
312134b2d0dSStanislaw Gruszka 
313134b2d0dSStanislaw Gruszka 	mt76x0_reset_counters(dev);
314134b2d0dSStanislaw Gruszka 
315134b2d0dSStanislaw Gruszka 	ret = mt76x0_eeprom_init(dev);
316134b2d0dSStanislaw Gruszka 	if (ret)
317e30a655eSLorenzo Bianconi 		return ret;
318134b2d0dSStanislaw Gruszka 
319134b2d0dSStanislaw Gruszka 	mt76x0_phy_init(dev);
320134b2d0dSStanislaw Gruszka 
321e30a655eSLorenzo Bianconi 	return 0;
322134b2d0dSStanislaw Gruszka }
323c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
324134b2d0dSStanislaw Gruszka 
325b2d871c0SLorenzo Bianconi struct mt76x02_dev *
326b11e1969SLorenzo Bianconi mt76x0_alloc_device(struct device *pdev,
327b11e1969SLorenzo Bianconi 		    const struct mt76_driver_ops *drv_ops,
328b11e1969SLorenzo Bianconi 		    const struct ieee80211_ops *ops)
329134b2d0dSStanislaw Gruszka {
330b2d871c0SLorenzo Bianconi 	struct mt76x02_dev *dev;
33195e507d2SLorenzo Bianconi 	struct mt76_dev *mdev;
332134b2d0dSStanislaw Gruszka 
333b11e1969SLorenzo Bianconi 	mdev = mt76_alloc_device(sizeof(*dev), ops);
33495e507d2SLorenzo Bianconi 	if (!mdev)
335134b2d0dSStanislaw Gruszka 		return NULL;
336134b2d0dSStanislaw Gruszka 
33795e507d2SLorenzo Bianconi 	mdev->dev = pdev;
338835123b7SStanislaw Gruszka 	mdev->drv = drv_ops;
33995e507d2SLorenzo Bianconi 
340b2d871c0SLorenzo Bianconi 	dev = container_of(mdev, struct mt76x02_dev, mt76);
341b2d871c0SLorenzo Bianconi 	mutex_init(&dev->phy_mutex);
342134b2d0dSStanislaw Gruszka 
343134b2d0dSStanislaw Gruszka 	return dev;
344134b2d0dSStanislaw Gruszka }
345c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
346134b2d0dSStanislaw Gruszka 
347b2d871c0SLorenzo Bianconi int mt76x0_register_device(struct mt76x02_dev *dev)
348134b2d0dSStanislaw Gruszka {
3491bee323aSLorenzo Bianconi 	struct mt76_dev *mdev = &dev->mt76;
3501bee323aSLorenzo Bianconi 	struct ieee80211_hw *hw = mdev->hw;
351134b2d0dSStanislaw Gruszka 	struct wiphy *wiphy = hw->wiphy;
352134b2d0dSStanislaw Gruszka 	int ret;
353134b2d0dSStanislaw Gruszka 
354134b2d0dSStanislaw Gruszka 	/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
355134b2d0dSStanislaw Gruszka 	 * entry no. 1 like it does in the vendor driver.
356134b2d0dSStanislaw Gruszka 	 */
3571bee323aSLorenzo Bianconi 	mdev->wcid_mask[0] |= 1;
358134b2d0dSStanislaw Gruszka 
359134b2d0dSStanislaw Gruszka 	/* init fake wcid for monitor interfaces */
3601bee323aSLorenzo Bianconi 	mdev->global_wcid.idx = 0xff;
3611bee323aSLorenzo Bianconi 	mdev->global_wcid.hw_key_idx = -1;
362134b2d0dSStanislaw Gruszka 
3631bee323aSLorenzo Bianconi 	/* init antenna configuration */
3641bee323aSLorenzo Bianconi 	mdev->antenna_mask = 1;
365134b2d0dSStanislaw Gruszka 
366134b2d0dSStanislaw Gruszka 	hw->queues = 4;
367134b2d0dSStanislaw Gruszka 	hw->max_rates = 1;
368134b2d0dSStanislaw Gruszka 	hw->max_report_rates = 7;
369134b2d0dSStanislaw Gruszka 	hw->max_rate_tries = 1;
370f3727daeSStanislaw Gruszka 	hw->extra_tx_headroom = 2;
371f3727daeSStanislaw Gruszka 	if (mt76_is_usb(dev))
372f3727daeSStanislaw Gruszka 		hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
373f3727daeSStanislaw Gruszka 					 MT_DMA_HDR_LEN;
374134b2d0dSStanislaw Gruszka 
37516c8a792SStanislaw Gruszka 	hw->sta_data_size = sizeof(struct mt76x02_sta);
37698ff26e5SStanislaw Gruszka 	hw->vif_data_size = sizeof(struct mt76x02_vif);
377134b2d0dSStanislaw Gruszka 
378134b2d0dSStanislaw Gruszka 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
379134b2d0dSStanislaw Gruszka 
38073556561SLorenzo Bianconi 	INIT_DELAYED_WORK(&dev->mac_work, mt76x02_mac_work);
381134b2d0dSStanislaw Gruszka 
3821bee323aSLorenzo Bianconi 	ret = mt76_register_device(mdev, true, mt76x02_rates,
3831bee323aSLorenzo Bianconi 				   ARRAY_SIZE(mt76x02_rates));
384134b2d0dSStanislaw Gruszka 	if (ret)
385134b2d0dSStanislaw Gruszka 		return ret;
386134b2d0dSStanislaw Gruszka 
3871bee323aSLorenzo Bianconi 	/* overwrite unsupported features */
3881bee323aSLorenzo Bianconi 	if (mdev->cap.has_5ghz)
3891bee323aSLorenzo Bianconi 		mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
3901bee323aSLorenzo Bianconi 
39163f15d94SLorenzo Bianconi 	mt76x02_init_debugfs(dev);
392134b2d0dSStanislaw Gruszka 
393134b2d0dSStanislaw Gruszka 	return 0;
394134b2d0dSStanislaw Gruszka }
395c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_register_device);
396