1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2013 Broadcom Corporation
5 /*********************channel spec common functions*********************/
7 #include <linux/module.h>
9 #include <brcmu_utils.h>
10 #include <brcmu_wifi.h>
11 #include <brcmu_d11.h>
13 static u16 d11n_sb(enum brcmu_chan_sb sb)
16 case BRCMU_CHAN_SB_NONE:
17 return BRCMU_CHSPEC_D11N_SB_N;
19 return BRCMU_CHSPEC_D11N_SB_L;
21 return BRCMU_CHSPEC_D11N_SB_U;
28 static u16 d11n_bw(enum brcmu_chan_bw bw)
31 case BRCMU_CHAN_BW_20:
32 return BRCMU_CHSPEC_D11N_BW_20;
33 case BRCMU_CHAN_BW_40:
34 return BRCMU_CHSPEC_D11N_BW_40;
41 static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
43 if (ch->bw == BRCMU_CHAN_BW_20)
44 ch->sb = BRCMU_CHAN_SB_NONE;
47 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
48 BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
49 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
51 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
54 if (ch->chnum <= CH_MAX_2G_CHANNEL)
55 ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
57 ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
60 static u16 d11ac_bw(enum brcmu_chan_bw bw)
63 case BRCMU_CHAN_BW_20:
64 return BRCMU_CHSPEC_D11AC_BW_20;
65 case BRCMU_CHAN_BW_40:
66 return BRCMU_CHSPEC_D11AC_BW_40;
67 case BRCMU_CHAN_BW_80:
68 return BRCMU_CHSPEC_D11AC_BW_80;
69 case BRCMU_CHAN_BW_160:
70 return BRCMU_CHSPEC_D11AC_BW_160;
77 static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
79 if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
80 ch->sb = BRCMU_CHAN_SB_L;
82 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
83 BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
84 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
85 BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
86 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
89 ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
90 if (ch->chnum <= CH_MAX_2G_CHANNEL)
91 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
93 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
96 static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
100 ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
101 ch->control_ch_num = ch->chnum;
103 switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
104 case BRCMU_CHSPEC_D11N_BW_20:
105 ch->bw = BRCMU_CHAN_BW_20;
106 ch->sb = BRCMU_CHAN_SB_NONE;
108 case BRCMU_CHSPEC_D11N_BW_40:
109 ch->bw = BRCMU_CHAN_BW_40;
110 val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
111 if (val == BRCMU_CHSPEC_D11N_SB_L) {
112 ch->sb = BRCMU_CHAN_SB_L;
113 ch->control_ch_num -= CH_10MHZ_APART;
115 ch->sb = BRCMU_CHAN_SB_U;
116 ch->control_ch_num += CH_10MHZ_APART;
120 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
124 switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
125 case BRCMU_CHSPEC_D11N_BND_5G:
126 ch->band = BRCMU_CHAN_BAND_5G;
128 case BRCMU_CHSPEC_D11N_BND_2G:
129 ch->band = BRCMU_CHAN_BAND_2G;
132 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
137 static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
141 ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
142 ch->control_ch_num = ch->chnum;
144 switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
145 case BRCMU_CHSPEC_D11AC_BW_20:
146 ch->bw = BRCMU_CHAN_BW_20;
147 ch->sb = BRCMU_CHAN_SB_NONE;
149 case BRCMU_CHSPEC_D11AC_BW_40:
150 ch->bw = BRCMU_CHAN_BW_40;
151 val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
152 if (val == BRCMU_CHSPEC_D11AC_SB_L) {
153 ch->sb = BRCMU_CHAN_SB_L;
154 ch->control_ch_num -= CH_10MHZ_APART;
155 } else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
156 ch->sb = BRCMU_CHAN_SB_U;
157 ch->control_ch_num += CH_10MHZ_APART;
159 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
162 case BRCMU_CHSPEC_D11AC_BW_80:
163 ch->bw = BRCMU_CHAN_BW_80;
164 ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
165 BRCMU_CHSPEC_D11AC_SB_SHIFT);
167 case BRCMU_CHAN_SB_LL:
168 ch->control_ch_num -= CH_30MHZ_APART;
170 case BRCMU_CHAN_SB_LU:
171 ch->control_ch_num -= CH_10MHZ_APART;
173 case BRCMU_CHAN_SB_UL:
174 ch->control_ch_num += CH_10MHZ_APART;
176 case BRCMU_CHAN_SB_UU:
177 ch->control_ch_num += CH_30MHZ_APART;
180 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
184 case BRCMU_CHSPEC_D11AC_BW_160:
185 ch->bw = BRCMU_CHAN_BW_160;
186 ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
187 BRCMU_CHSPEC_D11AC_SB_SHIFT);
189 case BRCMU_CHAN_SB_LLL:
190 ch->control_ch_num -= CH_70MHZ_APART;
192 case BRCMU_CHAN_SB_LLU:
193 ch->control_ch_num -= CH_50MHZ_APART;
195 case BRCMU_CHAN_SB_LUL:
196 ch->control_ch_num -= CH_30MHZ_APART;
198 case BRCMU_CHAN_SB_LUU:
199 ch->control_ch_num -= CH_10MHZ_APART;
201 case BRCMU_CHAN_SB_ULL:
202 ch->control_ch_num += CH_10MHZ_APART;
204 case BRCMU_CHAN_SB_ULU:
205 ch->control_ch_num += CH_30MHZ_APART;
207 case BRCMU_CHAN_SB_UUL:
208 ch->control_ch_num += CH_50MHZ_APART;
210 case BRCMU_CHAN_SB_UUU:
211 ch->control_ch_num += CH_70MHZ_APART;
214 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
218 case BRCMU_CHSPEC_D11AC_BW_8080:
220 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
224 switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
225 case BRCMU_CHSPEC_D11AC_BND_5G:
226 ch->band = BRCMU_CHAN_BAND_5G;
228 case BRCMU_CHSPEC_D11AC_BND_2G:
229 ch->band = BRCMU_CHAN_BAND_2G;
232 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
237 void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
239 if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
240 d11inf->encchspec = brcmu_d11n_encchspec;
241 d11inf->decchspec = brcmu_d11n_decchspec;
243 d11inf->encchspec = brcmu_d11ac_encchspec;
244 d11inf->decchspec = brcmu_d11ac_decchspec;
247 EXPORT_SYMBOL(brcmu_d11_attach);