init.c 16.4 KB
Newer Older
S
Stanislaw Gruszka 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * (c) Copyright 2002-2010, Ralink Technology, Inc.
 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
 * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
 * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "mt76x0.h"
#include "eeprom.h"
#include "trace.h"
#include "mcu.h"
#include "usb.h"
22
#include "../mt76x02_util.h"
S
Stanislaw Gruszka 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

#include "initvals.h"

static void
mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
{
	int i;

	/* Note: we don't turn off WLAN_CLK because that makes the device
	 *	 not respond properly on the probe path.
	 *	 In case anyone (PSM?) wants to use this function we can
	 *	 bring the clock stuff back and fixup the probe path.
	 */

	if (enable)
		val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
			MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
	else
		val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);

	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
	udelay(20);

	if (!enable)
		return;

	for (i = 200; i; i--) {
		val = mt76_rr(dev, MT_CMB_CTRL);

		if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD)
			break;

		udelay(20);
	}

	/* Note: vendor driver tries to disable/enable wlan here and retry
	 *       but the code which does it is so buggy it must have never
	 *       triggered, so don't bother.
	 */
	if (!i)
		dev_err(dev->mt76.dev, "Error: PLL and XTAL check failed!\n");
}

66
void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
S
Stanislaw Gruszka 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
{
	u32 val;

	mutex_lock(&dev->hw_atomic_mutex);

	val = mt76_rr(dev, MT_WLAN_FUN_CTRL);

	if (reset) {
		val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
		val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;

		if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
			val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
				MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
			mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
			udelay(20);

			val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
				 MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
		}
	}

	mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
	udelay(20);

	mt76x0_set_wlan_state(dev, val, enable);

	mutex_unlock(&dev->hw_atomic_mutex);
}

static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
{
	u32 val;

	val = mt76_rr(dev, MT_PBF_SYS_CTRL);
	val &= ~0x2000;
	mt76_wr(dev, MT_PBF_SYS_CTRL, val);

	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR |
					 MT_MAC_SYS_CTRL_RESET_BBP);

	msleep(200);
}

static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
{
	u32 val;

	val = mt76_rr(dev, MT_USB_DMA_CFG);

117
	val |= MT_USB_DMA_CFG_RX_BULK_EN |
S
Stanislaw Gruszka 已提交
118
	       MT_USB_DMA_CFG_TX_BULK_EN;
119 120 121 122 123

	/* disable AGGR_BULK_RX in order to receive one
	 * frame in each rx urb and avoid copies
	 */
	val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
S
Stanislaw Gruszka 已提交
124 125 126 127 128 129 130 131
	mt76_wr(dev, MT_USB_DMA_CFG, val);

	val = mt76_rr(dev, MT_COM_REG0);
	if (val & 1)
		dev_dbg(dev->mt76.dev, "MCU not ready\n");

	val = mt76_rr(dev, MT_USB_DMA_CFG);

132
	val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
S
Stanislaw Gruszka 已提交
133
	mt76_wr(dev, MT_USB_DMA_CFG, val);
134
	val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
S
Stanislaw Gruszka 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	mt76_wr(dev, MT_USB_DMA_CFG, val);
}

#define RANDOM_WRITE(dev, tab) \
	mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, tab, ARRAY_SIZE(tab));

static int mt76x0_init_bbp(struct mt76x0_dev *dev)
{
	int ret, i;

	ret = mt76x0_wait_bbp_ready(dev);
	if (ret)
		return ret;

	RANDOM_WRITE(dev, mt76x0_bbp_init_tab);

	for (i = 0; i < ARRAY_SIZE(mt76x0_bbp_switch_tab); i++) {
		const struct mt76x0_bbp_switch_item *item = &mt76x0_bbp_switch_tab[i];
		const struct mt76_reg_pair *pair = &item->reg_pair;

		if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20))
			mt76_wr(dev, pair->reg, pair->value);
	}

	RANDOM_WRITE(dev, mt76x0_dcoc_tab);

	return 0;
}

static void
mt76_init_beacon_offsets(struct mt76x0_dev *dev)
{
	u16 base = MT_BEACON_BASE;
	u32 regs[4] = {};
	int i;

	for (i = 0; i < 16; i++) {
		u16 addr = dev->beacon_offsets[i];

		regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
	}

	for (i = 0; i < 4; i++)
		mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
}

static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
{
	u32 reg;

	RANDOM_WRITE(dev, common_mac_reg_table);

	mt76_init_beacon_offsets(dev);

	/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
	RANDOM_WRITE(dev, mt76x0_mac_reg_table);

	/* Release BBP and MAC reset MAC_SYS_CTRL[1:0] = 0x0 */
	reg = mt76_rr(dev, MT_MAC_SYS_CTRL);
	reg &= ~0x3;
	mt76_wr(dev, MT_MAC_SYS_CTRL, reg);

	if (is_mt7610e(dev)) {
		/* Disable COEX_EN */
		reg = mt76_rr(dev, MT_COEXCFG0);
		reg &= 0xFFFFFFFE;
		mt76_wr(dev, MT_COEXCFG0, reg);
	}

	/* Set 0x141C[15:12]=0xF */
	reg = mt76_rr(dev, MT_EXT_CCA_CFG);
	reg |= 0x0000F000;
	mt76_wr(dev, MT_EXT_CCA_CFG, reg);

	mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);

	/*
		TxRing 9 is for Mgmt frame.
		TxRing 8 is for In-band command frame.
		WMM_RG0_TXQMA: This register setting is for FCE to define the rule of TxRing 9.
		WMM_RG1_TXQMA: This register setting is for FCE to define the rule of TxRing 8.
	*/
	reg = mt76_rr(dev, MT_WMM_CTRL);
	reg &= ~0x000003FF;
	reg |= 0x00000201;
	mt76_wr(dev, MT_WMM_CTRL, reg);

	/* TODO: Probably not needed */
	mt76_wr(dev, 0x7028, 0);
	mt76_wr(dev, 0x7010, 0);
	mt76_wr(dev, 0x7024, 0);
	msleep(10);
}

static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev)
{
	u32 *vals;
	int i, ret;

234
	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
S
Stanislaw Gruszka 已提交
235 236 237
	if (!vals)
		return -ENOMEM;

238
	for (i = 0; i < MT76_N_WCIDS; i++)  {
S
Stanislaw Gruszka 已提交
239 240 241 242 243
		vals[i * 2] = 0xffffffff;
		vals[i * 2 + 1] = 0x00ffffff;
	}

	ret = mt76x0_burst_write_regs(dev, MT_WCID_ADDR_BASE,
244
				      vals, MT76_N_WCIDS * 2);
S
Stanislaw Gruszka 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
	kfree(vals);

	return ret;
}

static int mt76x0_init_key_mem(struct mt76x0_dev *dev)
{
	u32 vals[4] = {};

	return mt76x0_burst_write_regs(dev, MT_SKEY_MODE_BASE_0,
					vals, ARRAY_SIZE(vals));
}

static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev)
{
	u32 *vals;
	int i, ret;

263
	vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
S
Stanislaw Gruszka 已提交
264 265 266
	if (!vals)
		return -ENOMEM;

267
	for (i = 0; i < MT76_N_WCIDS * 2; i++)
S
Stanislaw Gruszka 已提交
268 269 270
		vals[i] = 1;

	ret = mt76x0_burst_write_regs(dev, MT_WCID_ATTR_BASE,
271
				      vals, MT76_N_WCIDS * 2);
S
Stanislaw Gruszka 已提交
272 273 274 275 276 277 278
	kfree(vals);

	return ret;
}

static void mt76x0_reset_counters(struct mt76x0_dev *dev)
{
279 280 281 282 283 284
	mt76_rr(dev, MT_RX_STAT_0);
	mt76_rr(dev, MT_RX_STAT_1);
	mt76_rr(dev, MT_RX_STAT_2);
	mt76_rr(dev, MT_TX_STA_0);
	mt76_rr(dev, MT_TX_STA_1);
	mt76_rr(dev, MT_TX_STA_2);
S
Stanislaw Gruszka 已提交
285 286 287 288 289 290 291 292 293 294
}

int mt76x0_mac_start(struct mt76x0_dev *dev)
{
	mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);

	if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
		       MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000))
		return -ETIMEDOUT;

295
	dev->mt76.rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
S
Stanislaw Gruszka 已提交
296 297 298 299 300 301
		MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
		MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
		MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
		MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
		MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
		MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
302
	mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
S
Stanislaw Gruszka 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363

	mt76_wr(dev, MT_MAC_SYS_CTRL,
		   MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);

	if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
		       MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50))
		return -ETIMEDOUT;

	return 0;
}

static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
{
	int i, ok;

	if (test_bit(MT76_REMOVED, &dev->mt76.state))
		return;

	mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
		   MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
		   MT_BEACON_TIME_CFG_BEACON_TX);

	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n");

	/* Page count on TxQ */
	i = 200;
	while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
		       (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
		       (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
		msleep(10);

	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: MAC TX did not stop!\n");

	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
					 MT_MAC_SYS_CTRL_ENABLE_TX);

	/* Page count on RxQ */
	ok = 0;
	i = 200;
	while (i--) {
		if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
		    !mt76_rr(dev, 0x0a30) &&
		    !mt76_rr(dev, 0x0a34)) {
			if (ok++ > 5)
				break;
			continue;
		}
		msleep(1);
	}

	if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");

	if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
		dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n");
}

void mt76x0_mac_stop(struct mt76x0_dev *dev)
{
364 365 366
	cancel_delayed_work_sync(&dev->cal_work);
	cancel_delayed_work_sync(&dev->mac_work);
	mt76u_stop_stat_wk(&dev->mt76);
S
Stanislaw Gruszka 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	mt76x0_mac_stop_hw(dev);
}

int mt76x0_init_hardware(struct mt76x0_dev *dev)
{
	static const u16 beacon_offsets[16] = {
		/* 512 byte per beacon */
		0xc000,	0xc200,	0xc400,	0xc600,
		0xc800,	0xca00,	0xcc00,	0xce00,
		0xd000,	0xd200,	0xd400,	0xd600,
		0xd800,	0xda00,	0xdc00,	0xde00
	};
	int ret;

	dev->beacon_offsets = beacon_offsets;

	mt76x0_chip_onoff(dev, true, true);

S
Stanislaw Gruszka 已提交
385 386
	if (!mt76x02_wait_for_mac(&dev->mt76)) {
		ret = -ETIMEDOUT;
S
Stanislaw Gruszka 已提交
387
		goto err;
S
Stanislaw Gruszka 已提交
388 389
	}

S
Stanislaw Gruszka 已提交
390 391 392 393 394 395 396 397 398 399 400 401
	ret = mt76x0_mcu_init(dev);
	if (ret)
		goto err;

	if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
			    MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
			    MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) {
		ret = -EIO;
		goto err;
	}

	/* Wait for ASIC ready after FW load. */
S
Stanislaw Gruszka 已提交
402 403
	if (!mt76x02_wait_for_mac(&dev->mt76)) {
		ret = -ETIMEDOUT;
S
Stanislaw Gruszka 已提交
404
		goto err;
S
Stanislaw Gruszka 已提交
405
	}
S
Stanislaw Gruszka 已提交
406 407 408 409 410 411 412 413 414 415

	mt76x0_reset_csr_bbp(dev);
	mt76x0_init_usb_dma(dev);

	mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0);
	mt76_wr(dev, MT_TSO_CTRL, 0x0);

	ret = mt76x0_mcu_cmd_init(dev);
	if (ret)
		goto err;
416 417 418

	ret = mt76u_alloc_queues(&dev->mt76);
	if (ret < 0)
S
Stanislaw Gruszka 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
		goto err_mcu;

	mt76x0_init_mac_registers(dev);

	if (!mt76_poll_msec(dev, MT_MAC_STATUS,
			    MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000)) {
		ret = -EIO;
		goto err_rx;
	}

	ret = mt76x0_init_bbp(dev);
	if (ret)
		goto err_rx;

	ret = mt76x0_init_wcid_mem(dev);
	if (ret)
		goto err_rx;
	ret = mt76x0_init_key_mem(dev);
	if (ret)
		goto err_rx;
	ret = mt76x0_init_wcid_attr_mem(dev);
	if (ret)
		goto err_rx;

	mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
					     MT_BEACON_TIME_CFG_SYNC_MODE |
					     MT_BEACON_TIME_CFG_TBTT_EN |
					     MT_BEACON_TIME_CFG_BEACON_TX));

	mt76x0_reset_counters(dev);

	mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);

	mt76_wr(dev, MT_TXOP_CTRL_CFG,
		   FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
		   FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));

	ret = mt76x0_eeprom_init(dev);
	if (ret)
		goto err_rx;

	mt76x0_phy_init(dev);
	return 0;

err_rx:
464
	mt76u_queues_deinit(&dev->mt76);
S
Stanislaw Gruszka 已提交
465
err_mcu:
466
	mt76u_mcu_deinit(&dev->mt76);
S
Stanislaw Gruszka 已提交
467 468 469 470 471 472 473
err:
	mt76x0_chip_onoff(dev, false, false);
	return ret;
}

void mt76x0_cleanup(struct mt76x0_dev *dev)
{
474
	clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
475
	mt76x0_chip_onoff(dev, false, false);
476
	mt76u_queues_deinit(&dev->mt76);
477
	mt76u_mcu_deinit(&dev->mt76);
S
Stanislaw Gruszka 已提交
478 479 480 481
}

struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev)
{
482 483 484 485 486 487
	static const struct mt76_driver_ops drv_ops = {
		.tx_prepare_skb = mt76x0_tx_prepare_skb,
		.tx_complete_skb = mt76x02_tx_complete_skb,
		.tx_status_data = mt76x02_tx_status_data,
		.rx_skb = mt76x0_queue_rx_skb,
	};
S
Stanislaw Gruszka 已提交
488
	struct mt76x0_dev *dev;
489
	struct mt76_dev *mdev;
S
Stanislaw Gruszka 已提交
490

491 492
	mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops);
	if (!mdev)
S
Stanislaw Gruszka 已提交
493 494
		return NULL;

495 496 497 498
	mdev->dev = pdev;
	mdev->drv = &drv_ops;

	dev = container_of(mdev, struct mt76x0_dev, mt76);
S
Stanislaw Gruszka 已提交
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
	mutex_init(&dev->reg_atomic_mutex);
	mutex_init(&dev->hw_atomic_mutex);
	spin_lock_init(&dev->mac_lock);
	spin_lock_init(&dev->con_mon_lock);
	atomic_set(&dev->avg_ampdu_len, 1);

	return dev;
}

#define CHAN2G(_idx, _freq) {			\
	.band = NL80211_BAND_2GHZ,		\
	.center_freq = (_freq),			\
	.hw_value = (_idx),			\
	.max_power = 30,			\
}

static const struct ieee80211_channel mt76_channels_2ghz[] = {
	CHAN2G(1, 2412),
	CHAN2G(2, 2417),
	CHAN2G(3, 2422),
	CHAN2G(4, 2427),
	CHAN2G(5, 2432),
	CHAN2G(6, 2437),
	CHAN2G(7, 2442),
	CHAN2G(8, 2447),
	CHAN2G(9, 2452),
	CHAN2G(10, 2457),
	CHAN2G(11, 2462),
	CHAN2G(12, 2467),
	CHAN2G(13, 2472),
	CHAN2G(14, 2484),
};

#define CHAN5G(_idx, _freq) {			\
	.band = NL80211_BAND_5GHZ,		\
	.center_freq = (_freq),			\
	.hw_value = (_idx),			\
	.max_power = 30,			\
}

static const struct ieee80211_channel mt76_channels_5ghz[] = {
	CHAN5G(36, 5180),
	CHAN5G(40, 5200),
	CHAN5G(44, 5220),
	CHAN5G(46, 5230),
	CHAN5G(48, 5240),
	CHAN5G(52, 5260),
	CHAN5G(56, 5280),
	CHAN5G(60, 5300),
	CHAN5G(64, 5320),

	CHAN5G(100, 5500),
	CHAN5G(104, 5520),
	CHAN5G(108, 5540),
	CHAN5G(112, 5560),
	CHAN5G(116, 5580),
	CHAN5G(120, 5600),
	CHAN5G(124, 5620),
	CHAN5G(128, 5640),
	CHAN5G(132, 5660),
	CHAN5G(136, 5680),
	CHAN5G(140, 5700),
};

static int
mt76_init_sband(struct mt76x0_dev *dev, struct ieee80211_supported_band *sband,
		const struct ieee80211_channel *chan, int n_chan,
		struct ieee80211_rate *rates, int n_rates)
{
	struct ieee80211_sta_ht_cap *ht_cap;
	void *chanlist;
	int size;

	size = n_chan * sizeof(*chan);
	chanlist = devm_kmemdup(dev->mt76.dev, chan, size, GFP_KERNEL);
	if (!chanlist)
		return -ENOMEM;

	sband->channels = chanlist;
	sband->n_channels = n_chan;
	sband->bitrates = rates;
	sband->n_bitrates = n_rates;

	ht_cap = &sband->ht_cap;
	ht_cap->ht_supported = true;
	ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
		      IEEE80211_HT_CAP_GRN_FLD |
		      IEEE80211_HT_CAP_SGI_20 |
		      IEEE80211_HT_CAP_SGI_40 |
		      (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);

	ht_cap->mcs.rx_mask[0] = 0xff;
	ht_cap->mcs.rx_mask[4] = 0x1;
	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2;

	return 0;
}

static int
mt76_init_sband_2g(struct mt76x0_dev *dev)
{
	dev->mt76.hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->mt76.sband_2g.sband;

	WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num >
		ARRAY_SIZE(mt76_channels_2ghz));


	return mt76_init_sband(dev, &dev->mt76.sband_2g.sband,
			       mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz),
610
			       mt76x02_rates, ARRAY_SIZE(mt76x02_rates));
S
Stanislaw Gruszka 已提交
611 612 613 614 615 616 617 618 619
}

static int
mt76_init_sband_5g(struct mt76x0_dev *dev)
{
	dev->mt76.hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->mt76.sband_5g.sband;

	return mt76_init_sband(dev, &dev->mt76.sband_5g.sband,
			       mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz),
620
			       mt76x02_rates + 4, ARRAY_SIZE(mt76x02_rates) - 4);
S
Stanislaw Gruszka 已提交
621 622 623 624 625 626 627 628 629 630 631 632
}


int mt76x0_register_device(struct mt76x0_dev *dev)
{
	struct ieee80211_hw *hw = dev->mt76.hw;
	struct wiphy *wiphy = hw->wiphy;
	int ret;

	/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
	 * entry no. 1 like it does in the vendor driver.
	 */
633
	dev->mt76.wcid_mask[0] |= 1;
S
Stanislaw Gruszka 已提交
634 635

	/* init fake wcid for monitor interfaces */
636 637
	dev->mt76.global_wcid.idx = 0xff;
	dev->mt76.global_wcid.hw_key_idx = -1;
S
Stanislaw Gruszka 已提交
638 639 640 641 642 643 644 645 646

	SET_IEEE80211_DEV(hw, dev->mt76.dev);

	hw->queues = 4;
	ieee80211_hw_set(hw, SIGNAL_DBM);
	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
	ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
L
Lorenzo Bianconi 已提交
647 648 649 650 651 652 653
	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
	ieee80211_hw_set(hw, TX_AMSDU);
	ieee80211_hw_set(hw, TX_FRAG_LIST);
	ieee80211_hw_set(hw, MFP_CAPABLE);

S
Stanislaw Gruszka 已提交
654 655 656
	hw->max_rates = 1;
	hw->max_report_rates = 7;
	hw->max_rate_tries = 1;
657
	hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2;
S
Stanislaw Gruszka 已提交
658

659
	hw->sta_data_size = sizeof(struct mt76x02_sta);
660
	hw->vif_data_size = sizeof(struct mt76x02_vif);
S
Stanislaw Gruszka 已提交
661

662 663 664
	hw->txq_data_size = sizeof(struct mt76_txq);
	hw->max_tx_fragments = 16;

S
Stanislaw Gruszka 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);

	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);

	if (dev->ee->has_2ghz) {
		ret = mt76_init_sband_2g(dev);
		if (ret)
			return ret;
	}

	if (dev->ee->has_5ghz) {
		ret = mt76_init_sband_5g(dev);
		if (ret)
			return ret;
	}

	dev->mt76.chandef.chan = &dev->mt76.sband_2g.sband.channels[0];

	INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work);

	ret = ieee80211_register_hw(hw);
	if (ret)
		return ret;

690 691 692 693 694 695
	/* check hw sg support in order to enable AMSDU */
	if (mt76u_check_sg(&dev->mt76))
		hw->max_tx_fragments = MT_SG_MAX_SIZE;
	else
		hw->max_tx_fragments = 1;

S
Stanislaw Gruszka 已提交
696 697 698 699
	mt76x0_init_debugfs(dev);

	return 0;
}