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 "mcu.h"
20134b2d0dSStanislaw Gruszka #include "initvals.h"
21134b2d0dSStanislaw Gruszka 
221bee323aSLorenzo Bianconi static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
231bee323aSLorenzo Bianconi {
241bee323aSLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
251bee323aSLorenzo Bianconi 	u16 mcs_map = 0;
261bee323aSLorenzo Bianconi 	int i;
271bee323aSLorenzo Bianconi 
281bee323aSLorenzo Bianconi 	vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
291bee323aSLorenzo Bianconi 	for (i = 0; i < 8; i++) {
301bee323aSLorenzo Bianconi 		if (!i)
311bee323aSLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2));
321bee323aSLorenzo Bianconi 		else
331bee323aSLorenzo Bianconi 			mcs_map |=
341bee323aSLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
351bee323aSLorenzo Bianconi 	}
361bee323aSLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
371bee323aSLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
381bee323aSLorenzo Bianconi }
391bee323aSLorenzo Bianconi 
40134b2d0dSStanislaw Gruszka static void
41b2d871c0SLorenzo Bianconi mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable)
42134b2d0dSStanislaw Gruszka {
435b394355SLorenzo Bianconi 	u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD;
44134b2d0dSStanislaw Gruszka 
45134b2d0dSStanislaw Gruszka 	/* Note: we don't turn off WLAN_CLK because that makes the device
46134b2d0dSStanislaw Gruszka 	 *	 not respond properly on the probe path.
47134b2d0dSStanislaw Gruszka 	 *	 In case anyone (PSM?) wants to use this function we can
48134b2d0dSStanislaw Gruszka 	 *	 bring the clock stuff back and fixup the probe path.
49134b2d0dSStanislaw Gruszka 	 */
50134b2d0dSStanislaw Gruszka 
51134b2d0dSStanislaw Gruszka 	if (enable)
52134b2d0dSStanislaw Gruszka 		val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
53134b2d0dSStanislaw Gruszka 			MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
54134b2d0dSStanislaw Gruszka 	else
55134b2d0dSStanislaw Gruszka 		val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);
56134b2d0dSStanislaw Gruszka 
57134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
58134b2d0dSStanislaw Gruszka 	udelay(20);
59134b2d0dSStanislaw Gruszka 
60134b2d0dSStanislaw Gruszka 	/* Note: vendor driver tries to disable/enable wlan here and retry
61134b2d0dSStanislaw Gruszka 	 *       but the code which does it is so buggy it must have never
62134b2d0dSStanislaw Gruszka 	 *       triggered, so don't bother.
63134b2d0dSStanislaw Gruszka 	 */
645b394355SLorenzo Bianconi 	if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000))
655b394355SLorenzo Bianconi 		dev_err(dev->mt76.dev, "PLL and XTAL check failed\n");
66134b2d0dSStanislaw Gruszka }
67134b2d0dSStanislaw Gruszka 
68b2d871c0SLorenzo Bianconi void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset)
69134b2d0dSStanislaw Gruszka {
70134b2d0dSStanislaw Gruszka 	u32 val;
71134b2d0dSStanislaw Gruszka 
72134b2d0dSStanislaw Gruszka 	val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
73134b2d0dSStanislaw Gruszka 
74134b2d0dSStanislaw Gruszka 	if (reset) {
75134b2d0dSStanislaw Gruszka 		val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
76134b2d0dSStanislaw Gruszka 		val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
77134b2d0dSStanislaw Gruszka 
78134b2d0dSStanislaw Gruszka 		if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
79134b2d0dSStanislaw Gruszka 			val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
80134b2d0dSStanislaw Gruszka 				MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
81134b2d0dSStanislaw Gruszka 			mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
82134b2d0dSStanislaw Gruszka 			udelay(20);
83134b2d0dSStanislaw Gruszka 
84134b2d0dSStanislaw Gruszka 			val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
85134b2d0dSStanislaw Gruszka 				 MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
86134b2d0dSStanislaw Gruszka 		}
87134b2d0dSStanislaw Gruszka 	}
88134b2d0dSStanislaw Gruszka 
89134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
90134b2d0dSStanislaw Gruszka 	udelay(20);
91134b2d0dSStanislaw Gruszka 
92134b2d0dSStanislaw Gruszka 	mt76x0_set_wlan_state(dev, val, enable);
93134b2d0dSStanislaw Gruszka }
94c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
95134b2d0dSStanislaw Gruszka 
96b2d871c0SLorenzo Bianconi static void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev)
97134b2d0dSStanislaw Gruszka {
98512bd4b1SLorenzo Bianconi 	mt76_wr(dev, MT_MAC_SYS_CTRL,
99512bd4b1SLorenzo Bianconi 		MT_MAC_SYS_CTRL_RESET_CSR |
100134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_RESET_BBP);
101134b2d0dSStanislaw Gruszka 	msleep(200);
1022b2cb40bSLorenzo Bianconi 	mt76_clear(dev, MT_MAC_SYS_CTRL,
1032b2cb40bSLorenzo Bianconi 		   MT_MAC_SYS_CTRL_RESET_CSR |
1042b2cb40bSLorenzo Bianconi 		   MT_MAC_SYS_CTRL_RESET_BBP);
105134b2d0dSStanislaw Gruszka }
106134b2d0dSStanislaw Gruszka 
107134b2d0dSStanislaw Gruszka #define RANDOM_WRITE(dev, tab)			\
10817507157SLorenzo Bianconi 	mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN,	\
109f1638c7cSStanislaw Gruszka 		   tab, ARRAY_SIZE(tab))
110134b2d0dSStanislaw Gruszka 
111b2d871c0SLorenzo Bianconi static int mt76x0_init_bbp(struct mt76x02_dev *dev)
112134b2d0dSStanislaw Gruszka {
113134b2d0dSStanislaw Gruszka 	int ret, i;
114134b2d0dSStanislaw Gruszka 
1159c410782SLorenzo Bianconi 	ret = mt76x0_phy_wait_bbp_ready(dev);
116134b2d0dSStanislaw Gruszka 	if (ret)
117134b2d0dSStanislaw Gruszka 		return ret;
118134b2d0dSStanislaw Gruszka 
119134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_bbp_init_tab);
120134b2d0dSStanislaw Gruszka 
121134b2d0dSStanislaw Gruszka 	for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) {
122134b2d0dSStanislaw Gruszka 		const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i];
123134b2d0dSStanislaw Gruszka 		const struct mt76_reg_pair *pair = &item->reg_pair;
124134b2d0dSStanislaw Gruszka 
125134b2d0dSStanislaw Gruszka 		if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20))
126134b2d0dSStanislaw Gruszka 			mt76_wr(dev, pair->reg, pair->value);
127134b2d0dSStanislaw Gruszka 	}
128134b2d0dSStanislaw Gruszka 
129134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_dcoc_tab);
130134b2d0dSStanislaw Gruszka 
131134b2d0dSStanislaw Gruszka 	return 0;
132134b2d0dSStanislaw Gruszka }
133134b2d0dSStanislaw Gruszka 
134b2d871c0SLorenzo Bianconi static void mt76x0_init_mac_registers(struct mt76x02_dev *dev)
135134b2d0dSStanislaw Gruszka {
136134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, common_mac_reg_table);
137134b2d0dSStanislaw Gruszka 
138d87cf75fSLorenzo Bianconi 	mt76x02_set_beacon_offsets(dev);
139134b2d0dSStanislaw Gruszka 
140134b2d0dSStanislaw Gruszka 	/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
141134b2d0dSStanislaw Gruszka 	RANDOM_WRITE(dev, mt76x0_mac_reg_table);
142134b2d0dSStanislaw Gruszka 
143134b2d0dSStanislaw Gruszka 	/* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */
14400eccdd6SLorenzo Bianconi 	mt76_clear(dev, MT_MAC_SYS_CTRL, 0x3);
145134b2d0dSStanislaw Gruszka 
146134b2d0dSStanislaw Gruszka 	/* Set 0x141C[15:12]=0xF */
14700eccdd6SLorenzo Bianconi 	mt76_set(dev, MT_EXT_CCA_CFG, 0xf000);
148134b2d0dSStanislaw Gruszka 
149134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);
150134b2d0dSStanislaw Gruszka 
151134b2d0dSStanislaw Gruszka 	/*
15200eccdd6SLorenzo Bianconi 	 * tx_ring 9 is for mgmt frame
15300eccdd6SLorenzo Bianconi 	 * tx_ring 8 is for in-band command frame.
15400eccdd6SLorenzo Bianconi 	 * WMM_RG0_TXQMA: this register setting is for FCE to
15500eccdd6SLorenzo Bianconi 	 *		  define the rule of tx_ring 9
15600eccdd6SLorenzo Bianconi 	 * WMM_RG1_TXQMA: this register setting is for FCE to
15700eccdd6SLorenzo Bianconi 	 *		  define the rule of tx_ring 8
158134b2d0dSStanislaw Gruszka 	 */
15900eccdd6SLorenzo Bianconi 	mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201);
160134b2d0dSStanislaw Gruszka }
161134b2d0dSStanislaw Gruszka 
162b2d871c0SLorenzo Bianconi static int mt76x0_init_wcid_mem(struct mt76x02_dev *dev)
163134b2d0dSStanislaw Gruszka {
164134b2d0dSStanislaw Gruszka 	u32 *vals;
165331419b2SStanislaw Gruszka 	int i;
166134b2d0dSStanislaw Gruszka 
16736404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
168134b2d0dSStanislaw Gruszka 	if (!vals)
169134b2d0dSStanislaw Gruszka 		return -ENOMEM;
170134b2d0dSStanislaw Gruszka 
17136404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS; i++)  {
172134b2d0dSStanislaw Gruszka 		vals[i * 2] = 0xffffffff;
173134b2d0dSStanislaw Gruszka 		vals[i * 2 + 1] = 0x00ffffff;
174134b2d0dSStanislaw Gruszka 	}
175134b2d0dSStanislaw Gruszka 
176331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
177134b2d0dSStanislaw Gruszka 	kfree(vals);
178331419b2SStanislaw Gruszka 	return 0;
179134b2d0dSStanislaw Gruszka }
180134b2d0dSStanislaw Gruszka 
181b2d871c0SLorenzo Bianconi static void mt76x0_init_key_mem(struct mt76x02_dev *dev)
182134b2d0dSStanislaw Gruszka {
183134b2d0dSStanislaw Gruszka 	u32 vals[4] = {};
184134b2d0dSStanislaw Gruszka 
185331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
186134b2d0dSStanislaw Gruszka }
187134b2d0dSStanislaw Gruszka 
188b2d871c0SLorenzo Bianconi static int mt76x0_init_wcid_attr_mem(struct mt76x02_dev *dev)
189134b2d0dSStanislaw Gruszka {
190134b2d0dSStanislaw Gruszka 	u32 *vals;
191331419b2SStanislaw Gruszka 	int i;
192134b2d0dSStanislaw Gruszka 
19336404c06SStanislaw Gruszka 	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
194134b2d0dSStanislaw Gruszka 	if (!vals)
195134b2d0dSStanislaw Gruszka 		return -ENOMEM;
196134b2d0dSStanislaw Gruszka 
19736404c06SStanislaw Gruszka 	for (i = 0; i < MT76_N_WCIDS * 2; i++)
198134b2d0dSStanislaw Gruszka 		vals[i] = 1;
199134b2d0dSStanislaw Gruszka 
200331419b2SStanislaw Gruszka 	mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
201134b2d0dSStanislaw Gruszka 	kfree(vals);
202331419b2SStanislaw Gruszka 	return 0;
203134b2d0dSStanislaw Gruszka }
204134b2d0dSStanislaw Gruszka 
205b2d871c0SLorenzo Bianconi static void mt76x0_reset_counters(struct mt76x02_dev *dev)
206134b2d0dSStanislaw Gruszka {
207797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_0);
208797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_1);
209797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_RX_STAT_2);
210797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_0);
211797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_1);
212797ea240SStanislaw Gruszka 	mt76_rr(dev, MT_TX_STA_2);
213134b2d0dSStanislaw Gruszka }
214134b2d0dSStanislaw Gruszka 
215b2d871c0SLorenzo Bianconi int mt76x0_mac_start(struct mt76x02_dev *dev)
216134b2d0dSStanislaw Gruszka {
217134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
218134b2d0dSStanislaw Gruszka 
2193b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
220134b2d0dSStanislaw Gruszka 		return -ETIMEDOUT;
221134b2d0dSStanislaw Gruszka 
222108a4861SStanislaw Gruszka 	mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
223134b2d0dSStanislaw Gruszka 	mt76_wr(dev, MT_MAC_SYS_CTRL,
224134b2d0dSStanislaw Gruszka 		MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
225134b2d0dSStanislaw Gruszka 
2263b11db26SLorenzo Bianconi 	return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
227134b2d0dSStanislaw Gruszka }
228b11e1969SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x0_mac_start);
229134b2d0dSStanislaw Gruszka 
230b2d871c0SLorenzo Bianconi void mt76x0_mac_stop(struct mt76x02_dev *dev)
231134b2d0dSStanislaw Gruszka {
232b11e1969SLorenzo Bianconi 	int i = 200, ok = 0;
233134b2d0dSStanislaw Gruszka 
234134b2d0dSStanislaw Gruszka 	/* Page count on TxQ */
235134b2d0dSStanislaw Gruszka 	while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
236134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
237134b2d0dSStanislaw Gruszka 		       (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
238134b2d0dSStanislaw Gruszka 		msleep(10);
239134b2d0dSStanislaw Gruszka 
240134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
241134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n");
242134b2d0dSStanislaw Gruszka 
243134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
244134b2d0dSStanislaw Gruszka 					 MT_MAC_SYS_CTRL_ENABLE_TX);
245134b2d0dSStanislaw Gruszka 
246134b2d0dSStanislaw Gruszka 	/* Page count on RxQ */
247b11e1969SLorenzo Bianconi 	for (i = 0; i < 200; i++) {
248134b2d0dSStanislaw Gruszka 		if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
249134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a30) &&
250134b2d0dSStanislaw Gruszka 		    !mt76_rr(dev, 0x0a34)) {
251134b2d0dSStanislaw Gruszka 			if (ok++ > 5)
252134b2d0dSStanislaw Gruszka 				break;
253134b2d0dSStanislaw Gruszka 			continue;
254134b2d0dSStanislaw Gruszka 		}
255134b2d0dSStanislaw Gruszka 		msleep(1);
256134b2d0dSStanislaw Gruszka 	}
257134b2d0dSStanislaw Gruszka 
258134b2d0dSStanislaw Gruszka 	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
259134b2d0dSStanislaw Gruszka 		dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");
260134b2d0dSStanislaw Gruszka }
261c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
262134b2d0dSStanislaw Gruszka 
263b2d871c0SLorenzo Bianconi int mt76x0_init_hardware(struct mt76x02_dev *dev)
264134b2d0dSStanislaw Gruszka {
265134b2d0dSStanislaw Gruszka 	int ret;
266134b2d0dSStanislaw Gruszka 
2673b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000))
268e30a655eSLorenzo Bianconi 		return -EIO;
269134b2d0dSStanislaw Gruszka 
270134b2d0dSStanislaw Gruszka 	/* Wait for ASIC ready after FW load. */
271e30a655eSLorenzo Bianconi 	if (!mt76x02_wait_for_mac(&dev->mt76))
272e30a655eSLorenzo Bianconi 		return -ETIMEDOUT;
273134b2d0dSStanislaw Gruszka 
274134b2d0dSStanislaw Gruszka 	mt76x0_reset_csr_bbp(dev);
275499cd0aaSLorenzo Bianconi 	ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false);
276134b2d0dSStanislaw Gruszka 	if (ret)
277e30a655eSLorenzo Bianconi 		return ret;
27830ec9152SLorenzo Bianconi 
279134b2d0dSStanislaw Gruszka 	mt76x0_init_mac_registers(dev);
280134b2d0dSStanislaw Gruszka 
2813b11db26SLorenzo Bianconi 	if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
282e30a655eSLorenzo Bianconi 		return -EIO;
283134b2d0dSStanislaw Gruszka 
284134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_bbp(dev);
285134b2d0dSStanislaw Gruszka 	if (ret)
286e30a655eSLorenzo Bianconi 		return ret;
287134b2d0dSStanislaw Gruszka 
288a31821abSLorenzo Bianconi 	dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
289a31821abSLorenzo Bianconi 
290134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_mem(dev);
291134b2d0dSStanislaw Gruszka 	if (ret)
292e30a655eSLorenzo Bianconi 		return ret;
293e30a655eSLorenzo Bianconi 
294331419b2SStanislaw Gruszka 	mt76x0_init_key_mem(dev);
295e30a655eSLorenzo Bianconi 
296134b2d0dSStanislaw Gruszka 	ret = mt76x0_init_wcid_attr_mem(dev);
297134b2d0dSStanislaw Gruszka 	if (ret)
298e30a655eSLorenzo Bianconi 		return ret;
299134b2d0dSStanislaw Gruszka 
300134b2d0dSStanislaw Gruszka 	mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
301134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_SYNC_MODE |
302134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_TBTT_EN |
303134b2d0dSStanislaw Gruszka 					     MT_BEACON_TIME_CFG_BEACON_TX));
304134b2d0dSStanislaw Gruszka 
305134b2d0dSStanislaw Gruszka 	mt76x0_reset_counters(dev);
306134b2d0dSStanislaw Gruszka 
307134b2d0dSStanislaw Gruszka 	ret = mt76x0_eeprom_init(dev);
308134b2d0dSStanislaw Gruszka 	if (ret)
309e30a655eSLorenzo Bianconi 		return ret;
310134b2d0dSStanislaw Gruszka 
311134b2d0dSStanislaw Gruszka 	mt76x0_phy_init(dev);
312134b2d0dSStanislaw Gruszka 
313e30a655eSLorenzo Bianconi 	return 0;
314134b2d0dSStanislaw Gruszka }
315c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
316134b2d0dSStanislaw Gruszka 
317b2d871c0SLorenzo Bianconi struct mt76x02_dev *
318b11e1969SLorenzo Bianconi mt76x0_alloc_device(struct device *pdev,
319b11e1969SLorenzo Bianconi 		    const struct mt76_driver_ops *drv_ops,
320b11e1969SLorenzo Bianconi 		    const struct ieee80211_ops *ops)
321134b2d0dSStanislaw Gruszka {
322b2d871c0SLorenzo Bianconi 	struct mt76x02_dev *dev;
32395e507d2SLorenzo Bianconi 	struct mt76_dev *mdev;
324134b2d0dSStanislaw Gruszka 
325b11e1969SLorenzo Bianconi 	mdev = mt76_alloc_device(sizeof(*dev), ops);
32695e507d2SLorenzo Bianconi 	if (!mdev)
327134b2d0dSStanislaw Gruszka 		return NULL;
328134b2d0dSStanislaw Gruszka 
32995e507d2SLorenzo Bianconi 	mdev->dev = pdev;
330835123b7SStanislaw Gruszka 	mdev->drv = drv_ops;
33195e507d2SLorenzo Bianconi 
332b2d871c0SLorenzo Bianconi 	dev = container_of(mdev, struct mt76x02_dev, mt76);
333b2d871c0SLorenzo Bianconi 	mutex_init(&dev->phy_mutex);
334134b2d0dSStanislaw Gruszka 
335134b2d0dSStanislaw Gruszka 	return dev;
336134b2d0dSStanislaw Gruszka }
337c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
338134b2d0dSStanislaw Gruszka 
339b2d871c0SLorenzo Bianconi int mt76x0_register_device(struct mt76x02_dev *dev)
340134b2d0dSStanislaw Gruszka {
3411bee323aSLorenzo Bianconi 	struct mt76_dev *mdev = &dev->mt76;
3421bee323aSLorenzo Bianconi 	struct ieee80211_hw *hw = mdev->hw;
343134b2d0dSStanislaw Gruszka 	struct wiphy *wiphy = hw->wiphy;
344134b2d0dSStanislaw Gruszka 	int ret;
345134b2d0dSStanislaw Gruszka 
346134b2d0dSStanislaw Gruszka 	/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
347134b2d0dSStanislaw Gruszka 	 * entry no. 1 like it does in the vendor driver.
348134b2d0dSStanislaw Gruszka 	 */
3491bee323aSLorenzo Bianconi 	mdev->wcid_mask[0] |= 1;
350134b2d0dSStanislaw Gruszka 
351134b2d0dSStanislaw Gruszka 	/* init fake wcid for monitor interfaces */
3521bee323aSLorenzo Bianconi 	mdev->global_wcid.idx = 0xff;
3531bee323aSLorenzo Bianconi 	mdev->global_wcid.hw_key_idx = -1;
354134b2d0dSStanislaw Gruszka 
3551bee323aSLorenzo Bianconi 	/* init antenna configuration */
3561bee323aSLorenzo Bianconi 	mdev->antenna_mask = 1;
357134b2d0dSStanislaw Gruszka 
358134b2d0dSStanislaw Gruszka 	hw->queues = 4;
359134b2d0dSStanislaw Gruszka 	hw->max_rates = 1;
360134b2d0dSStanislaw Gruszka 	hw->max_report_rates = 7;
361134b2d0dSStanislaw Gruszka 	hw->max_rate_tries = 1;
362f3727daeSStanislaw Gruszka 	hw->extra_tx_headroom = 2;
363f3727daeSStanislaw Gruszka 	if (mt76_is_usb(dev))
364f3727daeSStanislaw Gruszka 		hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
365f3727daeSStanislaw Gruszka 					 MT_DMA_HDR_LEN;
366134b2d0dSStanislaw Gruszka 
36716c8a792SStanislaw Gruszka 	hw->sta_data_size = sizeof(struct mt76x02_sta);
36898ff26e5SStanislaw Gruszka 	hw->vif_data_size = sizeof(struct mt76x02_vif);
369134b2d0dSStanislaw Gruszka 
370134b2d0dSStanislaw Gruszka 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
371134b2d0dSStanislaw Gruszka 
37273556561SLorenzo Bianconi 	INIT_DELAYED_WORK(&dev->mac_work, mt76x02_mac_work);
373134b2d0dSStanislaw Gruszka 
3741bee323aSLorenzo Bianconi 	ret = mt76_register_device(mdev, true, mt76x02_rates,
3751bee323aSLorenzo Bianconi 				   ARRAY_SIZE(mt76x02_rates));
376134b2d0dSStanislaw Gruszka 	if (ret)
377134b2d0dSStanislaw Gruszka 		return ret;
378134b2d0dSStanislaw Gruszka 
3791bee323aSLorenzo Bianconi 	/* overwrite unsupported features */
3801bee323aSLorenzo Bianconi 	if (mdev->cap.has_5ghz)
3811bee323aSLorenzo Bianconi 		mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
3821bee323aSLorenzo Bianconi 
38363f15d94SLorenzo Bianconi 	mt76x02_init_debugfs(dev);
384134b2d0dSStanislaw Gruszka 
385134b2d0dSStanislaw Gruszka 	return 0;
386134b2d0dSStanislaw Gruszka }
387c2a4d9fbSStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76x0_register_device);
388