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