xref: /freebsd/sys/contrib/dev/broadcom/brcm80211/brcmutil/d11.c (revision b4c3e9b5b09c829b4135aff738bd2893ed052377)
1*b4c3e9b5SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2*b4c3e9b5SBjoern A. Zeeb /*
3*b4c3e9b5SBjoern A. Zeeb  * Copyright (c) 2013 Broadcom Corporation
4*b4c3e9b5SBjoern A. Zeeb  */
5*b4c3e9b5SBjoern A. Zeeb /*********************channel spec common functions*********************/
6*b4c3e9b5SBjoern A. Zeeb 
7*b4c3e9b5SBjoern A. Zeeb #include <linux/module.h>
8*b4c3e9b5SBjoern A. Zeeb 
9*b4c3e9b5SBjoern A. Zeeb #include <brcmu_utils.h>
10*b4c3e9b5SBjoern A. Zeeb #include <brcmu_wifi.h>
11*b4c3e9b5SBjoern A. Zeeb #include <brcmu_d11.h>
12*b4c3e9b5SBjoern A. Zeeb 
d11n_sb(enum brcmu_chan_sb sb)13*b4c3e9b5SBjoern A. Zeeb static u16 d11n_sb(enum brcmu_chan_sb sb)
14*b4c3e9b5SBjoern A. Zeeb {
15*b4c3e9b5SBjoern A. Zeeb 	switch (sb) {
16*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_SB_NONE:
17*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11N_SB_N;
18*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_SB_L:
19*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11N_SB_L;
20*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_SB_U:
21*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11N_SB_U;
22*b4c3e9b5SBjoern A. Zeeb 	default:
23*b4c3e9b5SBjoern A. Zeeb 		WARN_ON(1);
24*b4c3e9b5SBjoern A. Zeeb 	}
25*b4c3e9b5SBjoern A. Zeeb 	return 0;
26*b4c3e9b5SBjoern A. Zeeb }
27*b4c3e9b5SBjoern A. Zeeb 
d11n_bw(enum brcmu_chan_bw bw)28*b4c3e9b5SBjoern A. Zeeb static u16 d11n_bw(enum brcmu_chan_bw bw)
29*b4c3e9b5SBjoern A. Zeeb {
30*b4c3e9b5SBjoern A. Zeeb 	switch (bw) {
31*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_BW_20:
32*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11N_BW_20;
33*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_BW_40:
34*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11N_BW_40;
35*b4c3e9b5SBjoern A. Zeeb 	default:
36*b4c3e9b5SBjoern A. Zeeb 		WARN_ON(1);
37*b4c3e9b5SBjoern A. Zeeb 	}
38*b4c3e9b5SBjoern A. Zeeb 	return 0;
39*b4c3e9b5SBjoern A. Zeeb }
40*b4c3e9b5SBjoern A. Zeeb 
brcmu_d11n_encchspec(struct brcmu_chan * ch)41*b4c3e9b5SBjoern A. Zeeb static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
42*b4c3e9b5SBjoern A. Zeeb {
43*b4c3e9b5SBjoern A. Zeeb 	if (ch->bw == BRCMU_CHAN_BW_20)
44*b4c3e9b5SBjoern A. Zeeb 		ch->sb = BRCMU_CHAN_SB_NONE;
45*b4c3e9b5SBjoern A. Zeeb 
46*b4c3e9b5SBjoern A. Zeeb 	ch->chspec = 0;
47*b4c3e9b5SBjoern A. Zeeb 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
48*b4c3e9b5SBjoern A. Zeeb 			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
49*b4c3e9b5SBjoern A. Zeeb 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
50*b4c3e9b5SBjoern A. Zeeb 			0, d11n_sb(ch->sb));
51*b4c3e9b5SBjoern A. Zeeb 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
52*b4c3e9b5SBjoern A. Zeeb 			0, d11n_bw(ch->bw));
53*b4c3e9b5SBjoern A. Zeeb 
54*b4c3e9b5SBjoern A. Zeeb 	if (ch->chnum <= CH_MAX_2G_CHANNEL)
55*b4c3e9b5SBjoern A. Zeeb 		ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
56*b4c3e9b5SBjoern A. Zeeb 	else
57*b4c3e9b5SBjoern A. Zeeb 		ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
58*b4c3e9b5SBjoern A. Zeeb }
59*b4c3e9b5SBjoern A. Zeeb 
d11ac_bw(enum brcmu_chan_bw bw)60*b4c3e9b5SBjoern A. Zeeb static u16 d11ac_bw(enum brcmu_chan_bw bw)
61*b4c3e9b5SBjoern A. Zeeb {
62*b4c3e9b5SBjoern A. Zeeb 	switch (bw) {
63*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_BW_20:
64*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11AC_BW_20;
65*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_BW_40:
66*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11AC_BW_40;
67*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_BW_80:
68*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11AC_BW_80;
69*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHAN_BW_160:
70*b4c3e9b5SBjoern A. Zeeb 		return BRCMU_CHSPEC_D11AC_BW_160;
71*b4c3e9b5SBjoern A. Zeeb 	default:
72*b4c3e9b5SBjoern A. Zeeb 		WARN_ON(1);
73*b4c3e9b5SBjoern A. Zeeb 	}
74*b4c3e9b5SBjoern A. Zeeb 	return 0;
75*b4c3e9b5SBjoern A. Zeeb }
76*b4c3e9b5SBjoern A. Zeeb 
brcmu_d11ac_encchspec(struct brcmu_chan * ch)77*b4c3e9b5SBjoern A. Zeeb static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
78*b4c3e9b5SBjoern A. Zeeb {
79*b4c3e9b5SBjoern A. Zeeb 	if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
80*b4c3e9b5SBjoern A. Zeeb 		ch->sb = BRCMU_CHAN_SB_L;
81*b4c3e9b5SBjoern A. Zeeb 
82*b4c3e9b5SBjoern A. Zeeb 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
83*b4c3e9b5SBjoern A. Zeeb 			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
84*b4c3e9b5SBjoern A. Zeeb 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
85*b4c3e9b5SBjoern A. Zeeb 			BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
86*b4c3e9b5SBjoern A. Zeeb 	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
87*b4c3e9b5SBjoern A. Zeeb 			0, d11ac_bw(ch->bw));
88*b4c3e9b5SBjoern A. Zeeb 
89*b4c3e9b5SBjoern A. Zeeb 	ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
90*b4c3e9b5SBjoern A. Zeeb 	if (ch->chnum <= CH_MAX_2G_CHANNEL)
91*b4c3e9b5SBjoern A. Zeeb 		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
92*b4c3e9b5SBjoern A. Zeeb 	else
93*b4c3e9b5SBjoern A. Zeeb 		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
94*b4c3e9b5SBjoern A. Zeeb }
95*b4c3e9b5SBjoern A. Zeeb 
brcmu_d11n_decchspec(struct brcmu_chan * ch)96*b4c3e9b5SBjoern A. Zeeb static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
97*b4c3e9b5SBjoern A. Zeeb {
98*b4c3e9b5SBjoern A. Zeeb 	u16 val;
99*b4c3e9b5SBjoern A. Zeeb 
100*b4c3e9b5SBjoern A. Zeeb 	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
101*b4c3e9b5SBjoern A. Zeeb 	ch->control_ch_num = ch->chnum;
102*b4c3e9b5SBjoern A. Zeeb 
103*b4c3e9b5SBjoern A. Zeeb 	switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
104*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11N_BW_20:
105*b4c3e9b5SBjoern A. Zeeb 		ch->bw = BRCMU_CHAN_BW_20;
106*b4c3e9b5SBjoern A. Zeeb 		ch->sb = BRCMU_CHAN_SB_NONE;
107*b4c3e9b5SBjoern A. Zeeb 		break;
108*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11N_BW_40:
109*b4c3e9b5SBjoern A. Zeeb 		ch->bw = BRCMU_CHAN_BW_40;
110*b4c3e9b5SBjoern A. Zeeb 		val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
111*b4c3e9b5SBjoern A. Zeeb 		if (val == BRCMU_CHSPEC_D11N_SB_L) {
112*b4c3e9b5SBjoern A. Zeeb 			ch->sb = BRCMU_CHAN_SB_L;
113*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_10MHZ_APART;
114*b4c3e9b5SBjoern A. Zeeb 		} else {
115*b4c3e9b5SBjoern A. Zeeb 			ch->sb = BRCMU_CHAN_SB_U;
116*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_10MHZ_APART;
117*b4c3e9b5SBjoern A. Zeeb 		}
118*b4c3e9b5SBjoern A. Zeeb 		break;
119*b4c3e9b5SBjoern A. Zeeb 	default:
120*b4c3e9b5SBjoern A. Zeeb 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
121*b4c3e9b5SBjoern A. Zeeb 		break;
122*b4c3e9b5SBjoern A. Zeeb 	}
123*b4c3e9b5SBjoern A. Zeeb 
124*b4c3e9b5SBjoern A. Zeeb 	switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
125*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11N_BND_5G:
126*b4c3e9b5SBjoern A. Zeeb 		ch->band = BRCMU_CHAN_BAND_5G;
127*b4c3e9b5SBjoern A. Zeeb 		break;
128*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11N_BND_2G:
129*b4c3e9b5SBjoern A. Zeeb 		ch->band = BRCMU_CHAN_BAND_2G;
130*b4c3e9b5SBjoern A. Zeeb 		break;
131*b4c3e9b5SBjoern A. Zeeb 	default:
132*b4c3e9b5SBjoern A. Zeeb 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
133*b4c3e9b5SBjoern A. Zeeb 		break;
134*b4c3e9b5SBjoern A. Zeeb 	}
135*b4c3e9b5SBjoern A. Zeeb }
136*b4c3e9b5SBjoern A. Zeeb 
brcmu_d11ac_decchspec(struct brcmu_chan * ch)137*b4c3e9b5SBjoern A. Zeeb static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
138*b4c3e9b5SBjoern A. Zeeb {
139*b4c3e9b5SBjoern A. Zeeb 	u16 val;
140*b4c3e9b5SBjoern A. Zeeb 
141*b4c3e9b5SBjoern A. Zeeb 	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
142*b4c3e9b5SBjoern A. Zeeb 	ch->control_ch_num = ch->chnum;
143*b4c3e9b5SBjoern A. Zeeb 
144*b4c3e9b5SBjoern A. Zeeb 	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
145*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BW_20:
146*b4c3e9b5SBjoern A. Zeeb 		ch->bw = BRCMU_CHAN_BW_20;
147*b4c3e9b5SBjoern A. Zeeb 		ch->sb = BRCMU_CHAN_SB_NONE;
148*b4c3e9b5SBjoern A. Zeeb 		break;
149*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BW_40:
150*b4c3e9b5SBjoern A. Zeeb 		ch->bw = BRCMU_CHAN_BW_40;
151*b4c3e9b5SBjoern A. Zeeb 		val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
152*b4c3e9b5SBjoern A. Zeeb 		if (val == BRCMU_CHSPEC_D11AC_SB_L) {
153*b4c3e9b5SBjoern A. Zeeb 			ch->sb = BRCMU_CHAN_SB_L;
154*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_10MHZ_APART;
155*b4c3e9b5SBjoern A. Zeeb 		} else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
156*b4c3e9b5SBjoern A. Zeeb 			ch->sb = BRCMU_CHAN_SB_U;
157*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_10MHZ_APART;
158*b4c3e9b5SBjoern A. Zeeb 		} else {
159*b4c3e9b5SBjoern A. Zeeb 			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
160*b4c3e9b5SBjoern A. Zeeb 		}
161*b4c3e9b5SBjoern A. Zeeb 		break;
162*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BW_80:
163*b4c3e9b5SBjoern A. Zeeb 		ch->bw = BRCMU_CHAN_BW_80;
164*b4c3e9b5SBjoern A. Zeeb 		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
165*b4c3e9b5SBjoern A. Zeeb 					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
166*b4c3e9b5SBjoern A. Zeeb 		switch (ch->sb) {
167*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_LL:
168*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_30MHZ_APART;
169*b4c3e9b5SBjoern A. Zeeb 			break;
170*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_LU:
171*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_10MHZ_APART;
172*b4c3e9b5SBjoern A. Zeeb 			break;
173*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_UL:
174*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_10MHZ_APART;
175*b4c3e9b5SBjoern A. Zeeb 			break;
176*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_UU:
177*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_30MHZ_APART;
178*b4c3e9b5SBjoern A. Zeeb 			break;
179*b4c3e9b5SBjoern A. Zeeb 		default:
180*b4c3e9b5SBjoern A. Zeeb 			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
181*b4c3e9b5SBjoern A. Zeeb 			break;
182*b4c3e9b5SBjoern A. Zeeb 		}
183*b4c3e9b5SBjoern A. Zeeb 		break;
184*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BW_160:
185*b4c3e9b5SBjoern A. Zeeb 		ch->bw = BRCMU_CHAN_BW_160;
186*b4c3e9b5SBjoern A. Zeeb 		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
187*b4c3e9b5SBjoern A. Zeeb 					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
188*b4c3e9b5SBjoern A. Zeeb 		switch (ch->sb) {
189*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_LLL:
190*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_70MHZ_APART;
191*b4c3e9b5SBjoern A. Zeeb 			break;
192*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_LLU:
193*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_50MHZ_APART;
194*b4c3e9b5SBjoern A. Zeeb 			break;
195*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_LUL:
196*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_30MHZ_APART;
197*b4c3e9b5SBjoern A. Zeeb 			break;
198*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_LUU:
199*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num -= CH_10MHZ_APART;
200*b4c3e9b5SBjoern A. Zeeb 			break;
201*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_ULL:
202*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_10MHZ_APART;
203*b4c3e9b5SBjoern A. Zeeb 			break;
204*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_ULU:
205*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_30MHZ_APART;
206*b4c3e9b5SBjoern A. Zeeb 			break;
207*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_UUL:
208*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_50MHZ_APART;
209*b4c3e9b5SBjoern A. Zeeb 			break;
210*b4c3e9b5SBjoern A. Zeeb 		case BRCMU_CHAN_SB_UUU:
211*b4c3e9b5SBjoern A. Zeeb 			ch->control_ch_num += CH_70MHZ_APART;
212*b4c3e9b5SBjoern A. Zeeb 			break;
213*b4c3e9b5SBjoern A. Zeeb 		default:
214*b4c3e9b5SBjoern A. Zeeb 			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
215*b4c3e9b5SBjoern A. Zeeb 			break;
216*b4c3e9b5SBjoern A. Zeeb 		}
217*b4c3e9b5SBjoern A. Zeeb 		break;
218*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BW_8080:
219*b4c3e9b5SBjoern A. Zeeb 	default:
220*b4c3e9b5SBjoern A. Zeeb 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
221*b4c3e9b5SBjoern A. Zeeb 		break;
222*b4c3e9b5SBjoern A. Zeeb 	}
223*b4c3e9b5SBjoern A. Zeeb 
224*b4c3e9b5SBjoern A. Zeeb 	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
225*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BND_5G:
226*b4c3e9b5SBjoern A. Zeeb 		ch->band = BRCMU_CHAN_BAND_5G;
227*b4c3e9b5SBjoern A. Zeeb 		break;
228*b4c3e9b5SBjoern A. Zeeb 	case BRCMU_CHSPEC_D11AC_BND_2G:
229*b4c3e9b5SBjoern A. Zeeb 		ch->band = BRCMU_CHAN_BAND_2G;
230*b4c3e9b5SBjoern A. Zeeb 		break;
231*b4c3e9b5SBjoern A. Zeeb 	default:
232*b4c3e9b5SBjoern A. Zeeb 		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
233*b4c3e9b5SBjoern A. Zeeb 		break;
234*b4c3e9b5SBjoern A. Zeeb 	}
235*b4c3e9b5SBjoern A. Zeeb }
236*b4c3e9b5SBjoern A. Zeeb 
brcmu_d11_attach(struct brcmu_d11inf * d11inf)237*b4c3e9b5SBjoern A. Zeeb void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
238*b4c3e9b5SBjoern A. Zeeb {
239*b4c3e9b5SBjoern A. Zeeb 	if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
240*b4c3e9b5SBjoern A. Zeeb 		d11inf->encchspec = brcmu_d11n_encchspec;
241*b4c3e9b5SBjoern A. Zeeb 		d11inf->decchspec = brcmu_d11n_decchspec;
242*b4c3e9b5SBjoern A. Zeeb 	} else {
243*b4c3e9b5SBjoern A. Zeeb 		d11inf->encchspec = brcmu_d11ac_encchspec;
244*b4c3e9b5SBjoern A. Zeeb 		d11inf->decchspec = brcmu_d11ac_decchspec;
245*b4c3e9b5SBjoern A. Zeeb 	}
246*b4c3e9b5SBjoern A. Zeeb }
247*b4c3e9b5SBjoern A. Zeeb EXPORT_SYMBOL(brcmu_d11_attach);
248