GNU Linux-libre 4.9.294-gnu1
[releases.git] / drivers / net / wireless / broadcom / brcm80211 / brcmutil / d11.c
1 /*
2  * Copyright (c) 2013 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 /*********************channel spec common functions*********************/
17
18 #include <linux/module.h>
19
20 #include <brcmu_utils.h>
21 #include <brcmu_wifi.h>
22 #include <brcmu_d11.h>
23
24 static u16 d11n_sb(enum brcmu_chan_sb sb)
25 {
26         switch (sb) {
27         case BRCMU_CHAN_SB_NONE:
28                 return BRCMU_CHSPEC_D11N_SB_N;
29         case BRCMU_CHAN_SB_L:
30                 return BRCMU_CHSPEC_D11N_SB_L;
31         case BRCMU_CHAN_SB_U:
32                 return BRCMU_CHSPEC_D11N_SB_U;
33         default:
34                 WARN_ON(1);
35         }
36         return 0;
37 }
38
39 static u16 d11n_bw(enum brcmu_chan_bw bw)
40 {
41         switch (bw) {
42         case BRCMU_CHAN_BW_20:
43                 return BRCMU_CHSPEC_D11N_BW_20;
44         case BRCMU_CHAN_BW_40:
45                 return BRCMU_CHSPEC_D11N_BW_40;
46         default:
47                 WARN_ON(1);
48         }
49         return 0;
50 }
51
52 static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
53 {
54         if (ch->bw == BRCMU_CHAN_BW_20)
55                 ch->sb = BRCMU_CHAN_SB_NONE;
56
57         ch->chspec = 0;
58         brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
59                         BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
60         brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
61                         0, d11n_sb(ch->sb));
62         brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
63                         0, d11n_bw(ch->bw));
64
65         if (ch->chnum <= CH_MAX_2G_CHANNEL)
66                 ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
67         else
68                 ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
69 }
70
71 static u16 d11ac_bw(enum brcmu_chan_bw bw)
72 {
73         switch (bw) {
74         case BRCMU_CHAN_BW_20:
75                 return BRCMU_CHSPEC_D11AC_BW_20;
76         case BRCMU_CHAN_BW_40:
77                 return BRCMU_CHSPEC_D11AC_BW_40;
78         case BRCMU_CHAN_BW_80:
79                 return BRCMU_CHSPEC_D11AC_BW_80;
80         case BRCMU_CHAN_BW_160:
81                 return BRCMU_CHSPEC_D11AC_BW_160;
82         default:
83                 WARN_ON(1);
84         }
85         return 0;
86 }
87
88 static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
89 {
90         if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
91                 ch->sb = BRCMU_CHAN_SB_L;
92
93         brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
94                         BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
95         brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
96                         BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
97         brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
98                         0, d11ac_bw(ch->bw));
99
100         ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
101         if (ch->chnum <= CH_MAX_2G_CHANNEL)
102                 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
103         else
104                 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
105 }
106
107 static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
108 {
109         u16 val;
110
111         ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
112         ch->control_ch_num = ch->chnum;
113
114         switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
115         case BRCMU_CHSPEC_D11N_BW_20:
116                 ch->bw = BRCMU_CHAN_BW_20;
117                 ch->sb = BRCMU_CHAN_SB_NONE;
118                 break;
119         case BRCMU_CHSPEC_D11N_BW_40:
120                 ch->bw = BRCMU_CHAN_BW_40;
121                 val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
122                 if (val == BRCMU_CHSPEC_D11N_SB_L) {
123                         ch->sb = BRCMU_CHAN_SB_L;
124                         ch->control_ch_num -= CH_10MHZ_APART;
125                 } else {
126                         ch->sb = BRCMU_CHAN_SB_U;
127                         ch->control_ch_num += CH_10MHZ_APART;
128                 }
129                 break;
130         default:
131                 WARN_ON_ONCE(1);
132                 break;
133         }
134
135         switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
136         case BRCMU_CHSPEC_D11N_BND_5G:
137                 ch->band = BRCMU_CHAN_BAND_5G;
138                 break;
139         case BRCMU_CHSPEC_D11N_BND_2G:
140                 ch->band = BRCMU_CHAN_BAND_2G;
141                 break;
142         default:
143                 WARN_ON_ONCE(1);
144                 break;
145         }
146 }
147
148 static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
149 {
150         u16 val;
151
152         ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
153         ch->control_ch_num = ch->chnum;
154
155         switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
156         case BRCMU_CHSPEC_D11AC_BW_20:
157                 ch->bw = BRCMU_CHAN_BW_20;
158                 ch->sb = BRCMU_CHAN_SB_NONE;
159                 break;
160         case BRCMU_CHSPEC_D11AC_BW_40:
161                 ch->bw = BRCMU_CHAN_BW_40;
162                 val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
163                 if (val == BRCMU_CHSPEC_D11AC_SB_L) {
164                         ch->sb = BRCMU_CHAN_SB_L;
165                         ch->control_ch_num -= CH_10MHZ_APART;
166                 } else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
167                         ch->sb = BRCMU_CHAN_SB_U;
168                         ch->control_ch_num += CH_10MHZ_APART;
169                 } else {
170                         WARN_ON_ONCE(1);
171                 }
172                 break;
173         case BRCMU_CHSPEC_D11AC_BW_80:
174                 ch->bw = BRCMU_CHAN_BW_80;
175                 ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
176                                          BRCMU_CHSPEC_D11AC_SB_SHIFT);
177                 switch (ch->sb) {
178                 case BRCMU_CHAN_SB_LL:
179                         ch->control_ch_num -= CH_30MHZ_APART;
180                         break;
181                 case BRCMU_CHAN_SB_LU:
182                         ch->control_ch_num -= CH_10MHZ_APART;
183                         break;
184                 case BRCMU_CHAN_SB_UL:
185                         ch->control_ch_num += CH_10MHZ_APART;
186                         break;
187                 case BRCMU_CHAN_SB_UU:
188                         ch->control_ch_num += CH_30MHZ_APART;
189                         break;
190                 default:
191                         WARN_ON_ONCE(1);
192                         break;
193                 }
194                 break;
195         case BRCMU_CHSPEC_D11AC_BW_160:
196                 ch->bw = BRCMU_CHAN_BW_160;
197                 ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
198                                          BRCMU_CHSPEC_D11AC_SB_SHIFT);
199                 switch (ch->sb) {
200                 case BRCMU_CHAN_SB_LLL:
201                         ch->control_ch_num -= CH_70MHZ_APART;
202                         break;
203                 case BRCMU_CHAN_SB_LLU:
204                         ch->control_ch_num -= CH_50MHZ_APART;
205                         break;
206                 case BRCMU_CHAN_SB_LUL:
207                         ch->control_ch_num -= CH_30MHZ_APART;
208                         break;
209                 case BRCMU_CHAN_SB_LUU:
210                         ch->control_ch_num -= CH_10MHZ_APART;
211                         break;
212                 case BRCMU_CHAN_SB_ULL:
213                         ch->control_ch_num += CH_10MHZ_APART;
214                         break;
215                 case BRCMU_CHAN_SB_ULU:
216                         ch->control_ch_num += CH_30MHZ_APART;
217                         break;
218                 case BRCMU_CHAN_SB_UUL:
219                         ch->control_ch_num += CH_50MHZ_APART;
220                         break;
221                 case BRCMU_CHAN_SB_UUU:
222                         ch->control_ch_num += CH_70MHZ_APART;
223                         break;
224                 default:
225                         WARN_ON_ONCE(1);
226                         break;
227                 }
228                 break;
229         case BRCMU_CHSPEC_D11AC_BW_8080:
230         default:
231                 WARN_ON_ONCE(1);
232                 break;
233         }
234
235         switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
236         case BRCMU_CHSPEC_D11AC_BND_5G:
237                 ch->band = BRCMU_CHAN_BAND_5G;
238                 break;
239         case BRCMU_CHSPEC_D11AC_BND_2G:
240                 ch->band = BRCMU_CHAN_BAND_2G;
241                 break;
242         default:
243                 WARN_ON_ONCE(1);
244                 break;
245         }
246 }
247
248 void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
249 {
250         if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
251                 d11inf->encchspec = brcmu_d11n_encchspec;
252                 d11inf->decchspec = brcmu_d11n_decchspec;
253         } else {
254                 d11inf->encchspec = brcmu_d11ac_encchspec;
255                 d11inf->decchspec = brcmu_d11ac_decchspec;
256         }
257 }
258 EXPORT_SYMBOL(brcmu_d11_attach);