xref: /openbmc/linux/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
1*afe06f82SArend van Spriel // SPDX-License-Identifier: ISC
205491d2cSKalle Valo /*
305491d2cSKalle Valo  * Copyright (c) 2013 Broadcom Corporation
405491d2cSKalle Valo  */
505491d2cSKalle Valo /*********************channel spec common functions*********************/
605491d2cSKalle Valo 
705491d2cSKalle Valo #include <linux/module.h>
805491d2cSKalle Valo 
905491d2cSKalle Valo #include <brcmu_utils.h>
1005491d2cSKalle Valo #include <brcmu_wifi.h>
1105491d2cSKalle Valo #include <brcmu_d11.h>
1205491d2cSKalle Valo 
d11n_sb(enum brcmu_chan_sb sb)1305491d2cSKalle Valo static u16 d11n_sb(enum brcmu_chan_sb sb)
1405491d2cSKalle Valo {
1505491d2cSKalle Valo 	switch (sb) {
1605491d2cSKalle Valo 	case BRCMU_CHAN_SB_NONE:
1705491d2cSKalle Valo 		return BRCMU_CHSPEC_D11N_SB_N;
1805491d2cSKalle Valo 	case BRCMU_CHAN_SB_L:
1905491d2cSKalle Valo 		return BRCMU_CHSPEC_D11N_SB_L;
2005491d2cSKalle Valo 	case BRCMU_CHAN_SB_U:
2105491d2cSKalle Valo 		return BRCMU_CHSPEC_D11N_SB_U;
2205491d2cSKalle Valo 	default:
2305491d2cSKalle Valo 		WARN_ON(1);
2405491d2cSKalle Valo 	}
2505491d2cSKalle Valo 	return 0;
2605491d2cSKalle Valo }
2705491d2cSKalle Valo 
d11n_bw(enum brcmu_chan_bw bw)2805491d2cSKalle Valo static u16 d11n_bw(enum brcmu_chan_bw bw)
2905491d2cSKalle Valo {
3005491d2cSKalle Valo 	switch (bw) {
3105491d2cSKalle Valo 	case BRCMU_CHAN_BW_20:
3205491d2cSKalle Valo 		return BRCMU_CHSPEC_D11N_BW_20;
3305491d2cSKalle Valo 	case BRCMU_CHAN_BW_40:
3405491d2cSKalle Valo 		return BRCMU_CHSPEC_D11N_BW_40;
3505491d2cSKalle Valo 	default:
3605491d2cSKalle Valo 		WARN_ON(1);
3705491d2cSKalle Valo 	}
3805491d2cSKalle Valo 	return 0;
3905491d2cSKalle Valo }
4005491d2cSKalle Valo 
brcmu_d11n_encchspec(struct brcmu_chan * ch)4105491d2cSKalle Valo static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
4205491d2cSKalle Valo {
4305491d2cSKalle Valo 	if (ch->bw == BRCMU_CHAN_BW_20)
4405491d2cSKalle Valo 		ch->sb = BRCMU_CHAN_SB_NONE;
4505491d2cSKalle Valo 
4605491d2cSKalle Valo 	ch->chspec = 0;
4705491d2cSKalle Valo 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
4805491d2cSKalle Valo 			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
4905491d2cSKalle Valo 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
5005491d2cSKalle Valo 			0, d11n_sb(ch->sb));
5105491d2cSKalle Valo 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
5205491d2cSKalle Valo 			0, d11n_bw(ch->bw));
5305491d2cSKalle Valo 
5405491d2cSKalle Valo 	if (ch->chnum <= CH_MAX_2G_CHANNEL)
5505491d2cSKalle Valo 		ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
5605491d2cSKalle Valo 	else
5705491d2cSKalle Valo 		ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
5805491d2cSKalle Valo }
5905491d2cSKalle Valo 
d11ac_bw(enum brcmu_chan_bw bw)6005491d2cSKalle Valo static u16 d11ac_bw(enum brcmu_chan_bw bw)
6105491d2cSKalle Valo {
6205491d2cSKalle Valo 	switch (bw) {
6305491d2cSKalle Valo 	case BRCMU_CHAN_BW_20:
6405491d2cSKalle Valo 		return BRCMU_CHSPEC_D11AC_BW_20;
6505491d2cSKalle Valo 	case BRCMU_CHAN_BW_40:
6605491d2cSKalle Valo 		return BRCMU_CHSPEC_D11AC_BW_40;
6705491d2cSKalle Valo 	case BRCMU_CHAN_BW_80:
6805491d2cSKalle Valo 		return BRCMU_CHSPEC_D11AC_BW_80;
69330994e8SArend van Spriel 	case BRCMU_CHAN_BW_160:
70330994e8SArend van Spriel 		return BRCMU_CHSPEC_D11AC_BW_160;
7105491d2cSKalle Valo 	default:
7205491d2cSKalle Valo 		WARN_ON(1);
7305491d2cSKalle Valo 	}
7405491d2cSKalle Valo 	return 0;
7505491d2cSKalle Valo }
7605491d2cSKalle Valo 
brcmu_d11ac_encchspec(struct brcmu_chan * ch)7705491d2cSKalle Valo static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
7805491d2cSKalle Valo {
7905491d2cSKalle Valo 	if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
8005491d2cSKalle Valo 		ch->sb = BRCMU_CHAN_SB_L;
8105491d2cSKalle Valo 
8205491d2cSKalle Valo 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
8305491d2cSKalle Valo 			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
8405491d2cSKalle Valo 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
8505491d2cSKalle Valo 			BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
8605491d2cSKalle Valo 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
8705491d2cSKalle Valo 			0, d11ac_bw(ch->bw));
8805491d2cSKalle Valo 
8905491d2cSKalle Valo 	ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
9005491d2cSKalle Valo 	if (ch->chnum <= CH_MAX_2G_CHANNEL)
9105491d2cSKalle Valo 		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
9205491d2cSKalle Valo 	else
9305491d2cSKalle Valo 		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
9405491d2cSKalle Valo }
9505491d2cSKalle Valo 
brcmu_d11n_decchspec(struct brcmu_chan * ch)9605491d2cSKalle Valo static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
9705491d2cSKalle Valo {
9805491d2cSKalle Valo 	u16 val;
9905491d2cSKalle Valo 
10005491d2cSKalle Valo 	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
1014712d88aSRafał Miłecki 	ch->control_ch_num = ch->chnum;
10205491d2cSKalle Valo 
10305491d2cSKalle Valo 	switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
10405491d2cSKalle Valo 	case BRCMU_CHSPEC_D11N_BW_20:
10505491d2cSKalle Valo 		ch->bw = BRCMU_CHAN_BW_20;
10605491d2cSKalle Valo 		ch->sb = BRCMU_CHAN_SB_NONE;
10705491d2cSKalle Valo 		break;
10805491d2cSKalle Valo 	case BRCMU_CHSPEC_D11N_BW_40:
10905491d2cSKalle Valo 		ch->bw = BRCMU_CHAN_BW_40;
11005491d2cSKalle Valo 		val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
11105491d2cSKalle Valo 		if (val == BRCMU_CHSPEC_D11N_SB_L) {
11205491d2cSKalle Valo 			ch->sb = BRCMU_CHAN_SB_L;
1134712d88aSRafał Miłecki 			ch->control_ch_num -= CH_10MHZ_APART;
11405491d2cSKalle Valo 		} else {
11505491d2cSKalle Valo 			ch->sb = BRCMU_CHAN_SB_U;
1164712d88aSRafał Miłecki 			ch->control_ch_num += CH_10MHZ_APART;
11705491d2cSKalle Valo 		}
11805491d2cSKalle Valo 		break;
11905491d2cSKalle Valo 	default:
120ae5848cbSRafał Miłecki 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
12105491d2cSKalle Valo 		break;
12205491d2cSKalle Valo 	}
12305491d2cSKalle Valo 
12405491d2cSKalle Valo 	switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
12505491d2cSKalle Valo 	case BRCMU_CHSPEC_D11N_BND_5G:
12605491d2cSKalle Valo 		ch->band = BRCMU_CHAN_BAND_5G;
12705491d2cSKalle Valo 		break;
12805491d2cSKalle Valo 	case BRCMU_CHSPEC_D11N_BND_2G:
12905491d2cSKalle Valo 		ch->band = BRCMU_CHAN_BAND_2G;
13005491d2cSKalle Valo 		break;
13105491d2cSKalle Valo 	default:
132ae5848cbSRafał Miłecki 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
13305491d2cSKalle Valo 		break;
13405491d2cSKalle Valo 	}
13505491d2cSKalle Valo }
13605491d2cSKalle Valo 
brcmu_d11ac_decchspec(struct brcmu_chan * ch)13705491d2cSKalle Valo static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
13805491d2cSKalle Valo {
13905491d2cSKalle Valo 	u16 val;
14005491d2cSKalle Valo 
14105491d2cSKalle Valo 	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
1424712d88aSRafał Miłecki 	ch->control_ch_num = ch->chnum;
14305491d2cSKalle Valo 
14405491d2cSKalle Valo 	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
14505491d2cSKalle Valo 	case BRCMU_CHSPEC_D11AC_BW_20:
14605491d2cSKalle Valo 		ch->bw = BRCMU_CHAN_BW_20;
14705491d2cSKalle Valo 		ch->sb = BRCMU_CHAN_SB_NONE;
14805491d2cSKalle Valo 		break;
14905491d2cSKalle Valo 	case BRCMU_CHSPEC_D11AC_BW_40:
15005491d2cSKalle Valo 		ch->bw = BRCMU_CHAN_BW_40;
15105491d2cSKalle Valo 		val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
15205491d2cSKalle Valo 		if (val == BRCMU_CHSPEC_D11AC_SB_L) {
15305491d2cSKalle Valo 			ch->sb = BRCMU_CHAN_SB_L;
1544712d88aSRafał Miłecki 			ch->control_ch_num -= CH_10MHZ_APART;
15505491d2cSKalle Valo 		} else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
15605491d2cSKalle Valo 			ch->sb = BRCMU_CHAN_SB_U;
1574712d88aSRafał Miłecki 			ch->control_ch_num += CH_10MHZ_APART;
15805491d2cSKalle Valo 		} else {
159ae5848cbSRafał Miłecki 			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
16005491d2cSKalle Valo 		}
16105491d2cSKalle Valo 		break;
16205491d2cSKalle Valo 	case BRCMU_CHSPEC_D11AC_BW_80:
16305491d2cSKalle Valo 		ch->bw = BRCMU_CHAN_BW_80;
16405491d2cSKalle Valo 		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
16505491d2cSKalle Valo 					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
16605491d2cSKalle Valo 		switch (ch->sb) {
16705491d2cSKalle Valo 		case BRCMU_CHAN_SB_LL:
1684712d88aSRafał Miłecki 			ch->control_ch_num -= CH_30MHZ_APART;
16905491d2cSKalle Valo 			break;
17005491d2cSKalle Valo 		case BRCMU_CHAN_SB_LU:
1714712d88aSRafał Miłecki 			ch->control_ch_num -= CH_10MHZ_APART;
17205491d2cSKalle Valo 			break;
17305491d2cSKalle Valo 		case BRCMU_CHAN_SB_UL:
1744712d88aSRafał Miłecki 			ch->control_ch_num += CH_10MHZ_APART;
17505491d2cSKalle Valo 			break;
17605491d2cSKalle Valo 		case BRCMU_CHAN_SB_UU:
1774712d88aSRafał Miłecki 			ch->control_ch_num += CH_30MHZ_APART;
17805491d2cSKalle Valo 			break;
17905491d2cSKalle Valo 		default:
180ae5848cbSRafał Miłecki 			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
18105491d2cSKalle Valo 			break;
18205491d2cSKalle Valo 		}
18305491d2cSKalle Valo 		break;
18405491d2cSKalle Valo 	case BRCMU_CHSPEC_D11AC_BW_160:
1853401d42cSRafał Miłecki 		ch->bw = BRCMU_CHAN_BW_160;
1863401d42cSRafał Miłecki 		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
1873401d42cSRafał Miłecki 					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
188330994e8SArend van Spriel 		switch (ch->sb) {
189330994e8SArend van Spriel 		case BRCMU_CHAN_SB_LLL:
190330994e8SArend van Spriel 			ch->control_ch_num -= CH_70MHZ_APART;
191330994e8SArend van Spriel 			break;
192330994e8SArend van Spriel 		case BRCMU_CHAN_SB_LLU:
193330994e8SArend van Spriel 			ch->control_ch_num -= CH_50MHZ_APART;
194330994e8SArend van Spriel 			break;
195330994e8SArend van Spriel 		case BRCMU_CHAN_SB_LUL:
196330994e8SArend van Spriel 			ch->control_ch_num -= CH_30MHZ_APART;
197330994e8SArend van Spriel 			break;
198330994e8SArend van Spriel 		case BRCMU_CHAN_SB_LUU:
199330994e8SArend van Spriel 			ch->control_ch_num -= CH_10MHZ_APART;
200330994e8SArend van Spriel 			break;
201330994e8SArend van Spriel 		case BRCMU_CHAN_SB_ULL:
202330994e8SArend van Spriel 			ch->control_ch_num += CH_10MHZ_APART;
203330994e8SArend van Spriel 			break;
204330994e8SArend van Spriel 		case BRCMU_CHAN_SB_ULU:
205330994e8SArend van Spriel 			ch->control_ch_num += CH_30MHZ_APART;
206330994e8SArend van Spriel 			break;
207330994e8SArend van Spriel 		case BRCMU_CHAN_SB_UUL:
208330994e8SArend van Spriel 			ch->control_ch_num += CH_50MHZ_APART;
209330994e8SArend van Spriel 			break;
210330994e8SArend van Spriel 		case BRCMU_CHAN_SB_UUU:
211330994e8SArend van Spriel 			ch->control_ch_num += CH_70MHZ_APART;
212330994e8SArend van Spriel 			break;
213330994e8SArend van Spriel 		default:
214ae5848cbSRafał Miłecki 			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
215330994e8SArend van Spriel 			break;
216330994e8SArend van Spriel 		}
217330994e8SArend van Spriel 		break;
218330994e8SArend van Spriel 	case BRCMU_CHSPEC_D11AC_BW_8080:
21905491d2cSKalle Valo 	default:
220ae5848cbSRafał Miłecki 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
22105491d2cSKalle Valo 		break;
22205491d2cSKalle Valo 	}
22305491d2cSKalle Valo 
22405491d2cSKalle Valo 	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
22505491d2cSKalle Valo 	case BRCMU_CHSPEC_D11AC_BND_5G:
22605491d2cSKalle Valo 		ch->band = BRCMU_CHAN_BAND_5G;
22705491d2cSKalle Valo 		break;
22805491d2cSKalle Valo 	case BRCMU_CHSPEC_D11AC_BND_2G:
22905491d2cSKalle Valo 		ch->band = BRCMU_CHAN_BAND_2G;
23005491d2cSKalle Valo 		break;
23105491d2cSKalle Valo 	default:
232ae5848cbSRafał Miłecki 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
23305491d2cSKalle Valo 		break;
23405491d2cSKalle Valo 	}
23505491d2cSKalle Valo }
23605491d2cSKalle Valo 
brcmu_d11_attach(struct brcmu_d11inf * d11inf)23705491d2cSKalle Valo void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
23805491d2cSKalle Valo {
23905491d2cSKalle Valo 	if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
24005491d2cSKalle Valo 		d11inf->encchspec = brcmu_d11n_encchspec;
24105491d2cSKalle Valo 		d11inf->decchspec = brcmu_d11n_decchspec;
24205491d2cSKalle Valo 	} else {
24305491d2cSKalle Valo 		d11inf->encchspec = brcmu_d11ac_encchspec;
24405491d2cSKalle Valo 		d11inf->decchspec = brcmu_d11ac_decchspec;
24505491d2cSKalle Valo 	}
24605491d2cSKalle Valo }
24705491d2cSKalle Valo EXPORT_SYMBOL(brcmu_d11_attach);
248