1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (c) 2013 Broadcom Corporation 4 */ 5 /*********************channel spec common functions*********************/ 6 7 #include <linux/module.h> 8 9 #include <brcmu_utils.h> 10 #include <brcmu_wifi.h> 11 #include <brcmu_d11.h> 12 13 static u16 d11n_sb(enum brcmu_chan_sb sb) 14 { 15 switch (sb) { 16 case BRCMU_CHAN_SB_NONE: 17 return BRCMU_CHSPEC_D11N_SB_N; 18 case BRCMU_CHAN_SB_L: 19 return BRCMU_CHSPEC_D11N_SB_L; 20 case BRCMU_CHAN_SB_U: 21 return BRCMU_CHSPEC_D11N_SB_U; 22 default: 23 WARN_ON(1); 24 } 25 return 0; 26 } 27 28 static u16 d11n_bw(enum brcmu_chan_bw bw) 29 { 30 switch (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; 35 default: 36 WARN_ON(1); 37 } 38 return 0; 39 } 40 41 static void brcmu_d11n_encchspec(struct brcmu_chan *ch) 42 { 43 if (ch->bw == BRCMU_CHAN_BW_20) 44 ch->sb = BRCMU_CHAN_SB_NONE; 45 46 ch->chspec = 0; 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, 50 0, d11n_sb(ch->sb)); 51 brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK, 52 0, d11n_bw(ch->bw)); 53 54 if (ch->chnum <= CH_MAX_2G_CHANNEL) 55 ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G; 56 else 57 ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G; 58 } 59 60 static u16 d11ac_bw(enum brcmu_chan_bw bw) 61 { 62 switch (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; 71 default: 72 WARN_ON(1); 73 } 74 return 0; 75 } 76 77 static void brcmu_d11ac_encchspec(struct brcmu_chan *ch) 78 { 79 if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE) 80 ch->sb = BRCMU_CHAN_SB_L; 81 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, 87 0, d11ac_bw(ch->bw)); 88 89 ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK; 90 if (ch->chnum <= CH_MAX_2G_CHANNEL) 91 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G; 92 else 93 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G; 94 } 95 96 static void brcmu_d11n_decchspec(struct brcmu_chan *ch) 97 { 98 u16 val; 99 100 ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); 101 ch->control_ch_num = ch->chnum; 102 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; 107 break; 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; 114 } else { 115 ch->sb = BRCMU_CHAN_SB_U; 116 ch->control_ch_num += CH_10MHZ_APART; 117 } 118 break; 119 default: 120 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 121 break; 122 } 123 124 switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) { 125 case BRCMU_CHSPEC_D11N_BND_5G: 126 ch->band = BRCMU_CHAN_BAND_5G; 127 break; 128 case BRCMU_CHSPEC_D11N_BND_2G: 129 ch->band = BRCMU_CHAN_BAND_2G; 130 break; 131 default: 132 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 133 break; 134 } 135 } 136 137 static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) 138 { 139 u16 val; 140 141 ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); 142 ch->control_ch_num = ch->chnum; 143 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; 148 break; 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; 158 } else { 159 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 160 } 161 break; 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); 166 switch (ch->sb) { 167 case BRCMU_CHAN_SB_LL: 168 ch->control_ch_num -= CH_30MHZ_APART; 169 break; 170 case BRCMU_CHAN_SB_LU: 171 ch->control_ch_num -= CH_10MHZ_APART; 172 break; 173 case BRCMU_CHAN_SB_UL: 174 ch->control_ch_num += CH_10MHZ_APART; 175 break; 176 case BRCMU_CHAN_SB_UU: 177 ch->control_ch_num += CH_30MHZ_APART; 178 break; 179 default: 180 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 181 break; 182 } 183 break; 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); 188 switch (ch->sb) { 189 case BRCMU_CHAN_SB_LLL: 190 ch->control_ch_num -= CH_70MHZ_APART; 191 break; 192 case BRCMU_CHAN_SB_LLU: 193 ch->control_ch_num -= CH_50MHZ_APART; 194 break; 195 case BRCMU_CHAN_SB_LUL: 196 ch->control_ch_num -= CH_30MHZ_APART; 197 break; 198 case BRCMU_CHAN_SB_LUU: 199 ch->control_ch_num -= CH_10MHZ_APART; 200 break; 201 case BRCMU_CHAN_SB_ULL: 202 ch->control_ch_num += CH_10MHZ_APART; 203 break; 204 case BRCMU_CHAN_SB_ULU: 205 ch->control_ch_num += CH_30MHZ_APART; 206 break; 207 case BRCMU_CHAN_SB_UUL: 208 ch->control_ch_num += CH_50MHZ_APART; 209 break; 210 case BRCMU_CHAN_SB_UUU: 211 ch->control_ch_num += CH_70MHZ_APART; 212 break; 213 default: 214 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 215 break; 216 } 217 break; 218 case BRCMU_CHSPEC_D11AC_BW_8080: 219 default: 220 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 221 break; 222 } 223 224 switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) { 225 case BRCMU_CHSPEC_D11AC_BND_5G: 226 ch->band = BRCMU_CHAN_BAND_5G; 227 break; 228 case BRCMU_CHSPEC_D11AC_BND_2G: 229 ch->band = BRCMU_CHAN_BAND_2G; 230 break; 231 default: 232 WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 233 break; 234 } 235 } 236 237 void brcmu_d11_attach(struct brcmu_d11inf *d11inf) 238 { 239 if (d11inf->io_type == BRCMU_D11N_IOTYPE) { 240 d11inf->encchspec = brcmu_d11n_encchspec; 241 d11inf->decchspec = brcmu_d11n_decchspec; 242 } else { 243 d11inf->encchspec = brcmu_d11ac_encchspec; 244 d11inf->decchspec = brcmu_d11ac_decchspec; 245 } 246 } 247 EXPORT_SYMBOL(brcmu_d11_attach); 248