18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2013 Broadcom Corporation
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci/*********************channel spec common functions*********************/
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <brcmu_utils.h>
108c2ecf20Sopenharmony_ci#include <brcmu_wifi.h>
118c2ecf20Sopenharmony_ci#include <brcmu_d11.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic u16 d11n_sb(enum brcmu_chan_sb sb)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	switch (sb) {
168c2ecf20Sopenharmony_ci	case BRCMU_CHAN_SB_NONE:
178c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11N_SB_N;
188c2ecf20Sopenharmony_ci	case BRCMU_CHAN_SB_L:
198c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11N_SB_L;
208c2ecf20Sopenharmony_ci	case BRCMU_CHAN_SB_U:
218c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11N_SB_U;
228c2ecf20Sopenharmony_ci	default:
238c2ecf20Sopenharmony_ci		WARN_ON(1);
248c2ecf20Sopenharmony_ci	}
258c2ecf20Sopenharmony_ci	return 0;
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic u16 d11n_bw(enum brcmu_chan_bw bw)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	switch (bw) {
318c2ecf20Sopenharmony_ci	case BRCMU_CHAN_BW_20:
328c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11N_BW_20;
338c2ecf20Sopenharmony_ci	case BRCMU_CHAN_BW_40:
348c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11N_BW_40;
358c2ecf20Sopenharmony_ci	default:
368c2ecf20Sopenharmony_ci		WARN_ON(1);
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci	return 0;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic void brcmu_d11n_encchspec(struct brcmu_chan *ch)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	if (ch->bw == BRCMU_CHAN_BW_20)
448c2ecf20Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_NONE;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	ch->chspec = 0;
478c2ecf20Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
488c2ecf20Sopenharmony_ci			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
498c2ecf20Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
508c2ecf20Sopenharmony_ci			0, d11n_sb(ch->sb));
518c2ecf20Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
528c2ecf20Sopenharmony_ci			0, d11n_bw(ch->bw));
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (ch->chnum <= CH_MAX_2G_CHANNEL)
558c2ecf20Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
568c2ecf20Sopenharmony_ci	else
578c2ecf20Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic u16 d11ac_bw(enum brcmu_chan_bw bw)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	switch (bw) {
638c2ecf20Sopenharmony_ci	case BRCMU_CHAN_BW_20:
648c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_20;
658c2ecf20Sopenharmony_ci	case BRCMU_CHAN_BW_40:
668c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_40;
678c2ecf20Sopenharmony_ci	case BRCMU_CHAN_BW_80:
688c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_80;
698c2ecf20Sopenharmony_ci	case BRCMU_CHAN_BW_160:
708c2ecf20Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_160;
718c2ecf20Sopenharmony_ci	default:
728c2ecf20Sopenharmony_ci		WARN_ON(1);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
808c2ecf20Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_L;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
838c2ecf20Sopenharmony_ci			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
848c2ecf20Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
858c2ecf20Sopenharmony_ci			BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
868c2ecf20Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
878c2ecf20Sopenharmony_ci			0, d11ac_bw(ch->bw));
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
908c2ecf20Sopenharmony_ci	if (ch->chnum <= CH_MAX_2G_CHANNEL)
918c2ecf20Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
928c2ecf20Sopenharmony_ci	else
938c2ecf20Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic void brcmu_d11n_decchspec(struct brcmu_chan *ch)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	u16 val;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
1018c2ecf20Sopenharmony_ci	ch->control_ch_num = ch->chnum;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
1048c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BW_20:
1058c2ecf20Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_20;
1068c2ecf20Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_NONE;
1078c2ecf20Sopenharmony_ci		break;
1088c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BW_40:
1098c2ecf20Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_40;
1108c2ecf20Sopenharmony_ci		val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
1118c2ecf20Sopenharmony_ci		if (val == BRCMU_CHSPEC_D11N_SB_L) {
1128c2ecf20Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_L;
1138c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
1148c2ecf20Sopenharmony_ci		} else {
1158c2ecf20Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_U;
1168c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
1178c2ecf20Sopenharmony_ci		}
1188c2ecf20Sopenharmony_ci		break;
1198c2ecf20Sopenharmony_ci	default:
1208c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
1258c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BND_5G:
1268c2ecf20Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_5G;
1278c2ecf20Sopenharmony_ci		break;
1288c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BND_2G:
1298c2ecf20Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_2G;
1308c2ecf20Sopenharmony_ci		break;
1318c2ecf20Sopenharmony_ci	default:
1328c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	u16 val;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
1428c2ecf20Sopenharmony_ci	ch->control_ch_num = ch->chnum;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
1458c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_20:
1468c2ecf20Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_20;
1478c2ecf20Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_NONE;
1488c2ecf20Sopenharmony_ci		break;
1498c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_40:
1508c2ecf20Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_40;
1518c2ecf20Sopenharmony_ci		val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
1528c2ecf20Sopenharmony_ci		if (val == BRCMU_CHSPEC_D11AC_SB_L) {
1538c2ecf20Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_L;
1548c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
1558c2ecf20Sopenharmony_ci		} else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
1568c2ecf20Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_U;
1578c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
1588c2ecf20Sopenharmony_ci		} else {
1598c2ecf20Sopenharmony_ci			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
1608c2ecf20Sopenharmony_ci		}
1618c2ecf20Sopenharmony_ci		break;
1628c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_80:
1638c2ecf20Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_80;
1648c2ecf20Sopenharmony_ci		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
1658c2ecf20Sopenharmony_ci					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
1668c2ecf20Sopenharmony_ci		switch (ch->sb) {
1678c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_LL:
1688c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_30MHZ_APART;
1698c2ecf20Sopenharmony_ci			break;
1708c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_LU:
1718c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
1728c2ecf20Sopenharmony_ci			break;
1738c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_UL:
1748c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
1758c2ecf20Sopenharmony_ci			break;
1768c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_UU:
1778c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_30MHZ_APART;
1788c2ecf20Sopenharmony_ci			break;
1798c2ecf20Sopenharmony_ci		default:
1808c2ecf20Sopenharmony_ci			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
1818c2ecf20Sopenharmony_ci			break;
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci		break;
1848c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_160:
1858c2ecf20Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_160;
1868c2ecf20Sopenharmony_ci		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
1878c2ecf20Sopenharmony_ci					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
1888c2ecf20Sopenharmony_ci		switch (ch->sb) {
1898c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_LLL:
1908c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_70MHZ_APART;
1918c2ecf20Sopenharmony_ci			break;
1928c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_LLU:
1938c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_50MHZ_APART;
1948c2ecf20Sopenharmony_ci			break;
1958c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_LUL:
1968c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_30MHZ_APART;
1978c2ecf20Sopenharmony_ci			break;
1988c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_LUU:
1998c2ecf20Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
2008c2ecf20Sopenharmony_ci			break;
2018c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_ULL:
2028c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
2038c2ecf20Sopenharmony_ci			break;
2048c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_ULU:
2058c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_30MHZ_APART;
2068c2ecf20Sopenharmony_ci			break;
2078c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_UUL:
2088c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_50MHZ_APART;
2098c2ecf20Sopenharmony_ci			break;
2108c2ecf20Sopenharmony_ci		case BRCMU_CHAN_SB_UUU:
2118c2ecf20Sopenharmony_ci			ch->control_ch_num += CH_70MHZ_APART;
2128c2ecf20Sopenharmony_ci			break;
2138c2ecf20Sopenharmony_ci		default:
2148c2ecf20Sopenharmony_ci			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
2158c2ecf20Sopenharmony_ci			break;
2168c2ecf20Sopenharmony_ci		}
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_8080:
2198c2ecf20Sopenharmony_ci	default:
2208c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
2218c2ecf20Sopenharmony_ci		break;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
2258c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BND_5G:
2268c2ecf20Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_5G;
2278c2ecf20Sopenharmony_ci		break;
2288c2ecf20Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BND_2G:
2298c2ecf20Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_2G;
2308c2ecf20Sopenharmony_ci		break;
2318c2ecf20Sopenharmony_ci	default:
2328c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
2338c2ecf20Sopenharmony_ci		break;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_civoid brcmu_d11_attach(struct brcmu_d11inf *d11inf)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
2408c2ecf20Sopenharmony_ci		d11inf->encchspec = brcmu_d11n_encchspec;
2418c2ecf20Sopenharmony_ci		d11inf->decchspec = brcmu_d11n_decchspec;
2428c2ecf20Sopenharmony_ci	} else {
2438c2ecf20Sopenharmony_ci		d11inf->encchspec = brcmu_d11ac_encchspec;
2448c2ecf20Sopenharmony_ci		d11inf->decchspec = brcmu_d11ac_decchspec;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(brcmu_d11_attach);
248