248 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2013 Broadcom Corporation4 */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 13static 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 28static 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 41static 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 else57 ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;58}59 60static 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 77static 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 else93 ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;94}95 96static 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 137static 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 237void 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}247EXPORT_SYMBOL(brcmu_d11_attach);248