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 default: 81 WARN_ON(1); 82 } 83 return 0; 84 } 85 86 static void brcmu_d11ac_encchspec(struct brcmu_chan *ch) 87 { 88 if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE) 89 ch->sb = BRCMU_CHAN_SB_L; 90 91 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK, 92 BRCMU_CHSPEC_CH_SHIFT, ch->chnum); 93 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, 94 BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb); 95 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK, 96 0, d11ac_bw(ch->bw)); 97 98 ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK; 99 if (ch->chnum <= CH_MAX_2G_CHANNEL) 100 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G; 101 else 102 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G; 103 } 104 105 static void brcmu_d11n_decchspec(struct brcmu_chan *ch) 106 { 107 u16 val; 108 109 ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); 110 ch->control_ch_num = ch->chnum; 111 112 switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) { 113 case BRCMU_CHSPEC_D11N_BW_20: 114 ch->bw = BRCMU_CHAN_BW_20; 115 ch->sb = BRCMU_CHAN_SB_NONE; 116 break; 117 case BRCMU_CHSPEC_D11N_BW_40: 118 ch->bw = BRCMU_CHAN_BW_40; 119 val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK; 120 if (val == BRCMU_CHSPEC_D11N_SB_L) { 121 ch->sb = BRCMU_CHAN_SB_L; 122 ch->control_ch_num -= CH_10MHZ_APART; 123 } else { 124 ch->sb = BRCMU_CHAN_SB_U; 125 ch->control_ch_num += CH_10MHZ_APART; 126 } 127 break; 128 default: 129 WARN_ON_ONCE(1); 130 break; 131 } 132 133 switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) { 134 case BRCMU_CHSPEC_D11N_BND_5G: 135 ch->band = BRCMU_CHAN_BAND_5G; 136 break; 137 case BRCMU_CHSPEC_D11N_BND_2G: 138 ch->band = BRCMU_CHAN_BAND_2G; 139 break; 140 default: 141 WARN_ON_ONCE(1); 142 break; 143 } 144 } 145 146 static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) 147 { 148 u16 val; 149 150 ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); 151 ch->control_ch_num = ch->chnum; 152 153 switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) { 154 case BRCMU_CHSPEC_D11AC_BW_20: 155 ch->bw = BRCMU_CHAN_BW_20; 156 ch->sb = BRCMU_CHAN_SB_NONE; 157 break; 158 case BRCMU_CHSPEC_D11AC_BW_40: 159 ch->bw = BRCMU_CHAN_BW_40; 160 val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK; 161 if (val == BRCMU_CHSPEC_D11AC_SB_L) { 162 ch->sb = BRCMU_CHAN_SB_L; 163 ch->control_ch_num -= CH_10MHZ_APART; 164 } else if (val == BRCMU_CHSPEC_D11AC_SB_U) { 165 ch->sb = BRCMU_CHAN_SB_U; 166 ch->control_ch_num += CH_10MHZ_APART; 167 } else { 168 WARN_ON_ONCE(1); 169 } 170 break; 171 case BRCMU_CHSPEC_D11AC_BW_80: 172 ch->bw = BRCMU_CHAN_BW_80; 173 ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, 174 BRCMU_CHSPEC_D11AC_SB_SHIFT); 175 switch (ch->sb) { 176 case BRCMU_CHAN_SB_LL: 177 ch->control_ch_num -= CH_30MHZ_APART; 178 break; 179 case BRCMU_CHAN_SB_LU: 180 ch->control_ch_num -= CH_10MHZ_APART; 181 break; 182 case BRCMU_CHAN_SB_UL: 183 ch->control_ch_num += CH_10MHZ_APART; 184 break; 185 case BRCMU_CHAN_SB_UU: 186 ch->control_ch_num += CH_30MHZ_APART; 187 break; 188 default: 189 WARN_ON_ONCE(1); 190 break; 191 } 192 break; 193 case BRCMU_CHSPEC_D11AC_BW_8080: 194 case BRCMU_CHSPEC_D11AC_BW_160: 195 default: 196 WARN_ON_ONCE(1); 197 break; 198 } 199 200 switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) { 201 case BRCMU_CHSPEC_D11AC_BND_5G: 202 ch->band = BRCMU_CHAN_BAND_5G; 203 break; 204 case BRCMU_CHSPEC_D11AC_BND_2G: 205 ch->band = BRCMU_CHAN_BAND_2G; 206 break; 207 default: 208 WARN_ON_ONCE(1); 209 break; 210 } 211 } 212 213 void brcmu_d11_attach(struct brcmu_d11inf *d11inf) 214 { 215 if (d11inf->io_type == BRCMU_D11N_IOTYPE) { 216 d11inf->encchspec = brcmu_d11n_encchspec; 217 d11inf->decchspec = brcmu_d11n_decchspec; 218 } else { 219 d11inf->encchspec = brcmu_d11ac_encchspec; 220 d11inf->decchspec = brcmu_d11ac_decchspec; 221 } 222 } 223 EXPORT_SYMBOL(brcmu_d11_attach); 224