1*afe06f82SArend van Spriel // SPDX-License-Identifier: ISC
205491d2cSKalle Valo /*
305491d2cSKalle Valo * Copyright (c) 2013 Broadcom Corporation
405491d2cSKalle Valo */
505491d2cSKalle Valo /*********************channel spec common functions*********************/
605491d2cSKalle Valo
705491d2cSKalle Valo #include <linux/module.h>
805491d2cSKalle Valo
905491d2cSKalle Valo #include <brcmu_utils.h>
1005491d2cSKalle Valo #include <brcmu_wifi.h>
1105491d2cSKalle Valo #include <brcmu_d11.h>
1205491d2cSKalle Valo
d11n_sb(enum brcmu_chan_sb sb)1305491d2cSKalle Valo static u16 d11n_sb(enum brcmu_chan_sb sb)
1405491d2cSKalle Valo {
1505491d2cSKalle Valo switch (sb) {
1605491d2cSKalle Valo case BRCMU_CHAN_SB_NONE:
1705491d2cSKalle Valo return BRCMU_CHSPEC_D11N_SB_N;
1805491d2cSKalle Valo case BRCMU_CHAN_SB_L:
1905491d2cSKalle Valo return BRCMU_CHSPEC_D11N_SB_L;
2005491d2cSKalle Valo case BRCMU_CHAN_SB_U:
2105491d2cSKalle Valo return BRCMU_CHSPEC_D11N_SB_U;
2205491d2cSKalle Valo default:
2305491d2cSKalle Valo WARN_ON(1);
2405491d2cSKalle Valo }
2505491d2cSKalle Valo return 0;
2605491d2cSKalle Valo }
2705491d2cSKalle Valo
d11n_bw(enum brcmu_chan_bw bw)2805491d2cSKalle Valo static u16 d11n_bw(enum brcmu_chan_bw bw)
2905491d2cSKalle Valo {
3005491d2cSKalle Valo switch (bw) {
3105491d2cSKalle Valo case BRCMU_CHAN_BW_20:
3205491d2cSKalle Valo return BRCMU_CHSPEC_D11N_BW_20;
3305491d2cSKalle Valo case BRCMU_CHAN_BW_40:
3405491d2cSKalle Valo return BRCMU_CHSPEC_D11N_BW_40;
3505491d2cSKalle Valo default:
3605491d2cSKalle Valo WARN_ON(1);
3705491d2cSKalle Valo }
3805491d2cSKalle Valo return 0;
3905491d2cSKalle Valo }
4005491d2cSKalle Valo
brcmu_d11n_encchspec(struct brcmu_chan * ch)4105491d2cSKalle Valo static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
4205491d2cSKalle Valo {
4305491d2cSKalle Valo if (ch->bw == BRCMU_CHAN_BW_20)
4405491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_NONE;
4505491d2cSKalle Valo
4605491d2cSKalle Valo ch->chspec = 0;
4705491d2cSKalle Valo brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
4805491d2cSKalle Valo BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
4905491d2cSKalle Valo brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
5005491d2cSKalle Valo 0, d11n_sb(ch->sb));
5105491d2cSKalle Valo brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
5205491d2cSKalle Valo 0, d11n_bw(ch->bw));
5305491d2cSKalle Valo
5405491d2cSKalle Valo if (ch->chnum <= CH_MAX_2G_CHANNEL)
5505491d2cSKalle Valo ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
5605491d2cSKalle Valo else
5705491d2cSKalle Valo ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
5805491d2cSKalle Valo }
5905491d2cSKalle Valo
d11ac_bw(enum brcmu_chan_bw bw)6005491d2cSKalle Valo static u16 d11ac_bw(enum brcmu_chan_bw bw)
6105491d2cSKalle Valo {
6205491d2cSKalle Valo switch (bw) {
6305491d2cSKalle Valo case BRCMU_CHAN_BW_20:
6405491d2cSKalle Valo return BRCMU_CHSPEC_D11AC_BW_20;
6505491d2cSKalle Valo case BRCMU_CHAN_BW_40:
6605491d2cSKalle Valo return BRCMU_CHSPEC_D11AC_BW_40;
6705491d2cSKalle Valo case BRCMU_CHAN_BW_80:
6805491d2cSKalle Valo return BRCMU_CHSPEC_D11AC_BW_80;
69330994e8SArend van Spriel case BRCMU_CHAN_BW_160:
70330994e8SArend van Spriel return BRCMU_CHSPEC_D11AC_BW_160;
7105491d2cSKalle Valo default:
7205491d2cSKalle Valo WARN_ON(1);
7305491d2cSKalle Valo }
7405491d2cSKalle Valo return 0;
7505491d2cSKalle Valo }
7605491d2cSKalle Valo
brcmu_d11ac_encchspec(struct brcmu_chan * ch)7705491d2cSKalle Valo static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
7805491d2cSKalle Valo {
7905491d2cSKalle Valo if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
8005491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_L;
8105491d2cSKalle Valo
8205491d2cSKalle Valo brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
8305491d2cSKalle Valo BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
8405491d2cSKalle Valo brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
8505491d2cSKalle Valo BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
8605491d2cSKalle Valo brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
8705491d2cSKalle Valo 0, d11ac_bw(ch->bw));
8805491d2cSKalle Valo
8905491d2cSKalle Valo ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
9005491d2cSKalle Valo if (ch->chnum <= CH_MAX_2G_CHANNEL)
9105491d2cSKalle Valo ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
9205491d2cSKalle Valo else
9305491d2cSKalle Valo ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
9405491d2cSKalle Valo }
9505491d2cSKalle Valo
brcmu_d11n_decchspec(struct brcmu_chan * ch)9605491d2cSKalle Valo static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
9705491d2cSKalle Valo {
9805491d2cSKalle Valo u16 val;
9905491d2cSKalle Valo
10005491d2cSKalle Valo ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
1014712d88aSRafał Miłecki ch->control_ch_num = ch->chnum;
10205491d2cSKalle Valo
10305491d2cSKalle Valo switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
10405491d2cSKalle Valo case BRCMU_CHSPEC_D11N_BW_20:
10505491d2cSKalle Valo ch->bw = BRCMU_CHAN_BW_20;
10605491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_NONE;
10705491d2cSKalle Valo break;
10805491d2cSKalle Valo case BRCMU_CHSPEC_D11N_BW_40:
10905491d2cSKalle Valo ch->bw = BRCMU_CHAN_BW_40;
11005491d2cSKalle Valo val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
11105491d2cSKalle Valo if (val == BRCMU_CHSPEC_D11N_SB_L) {
11205491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_L;
1134712d88aSRafał Miłecki ch->control_ch_num -= CH_10MHZ_APART;
11405491d2cSKalle Valo } else {
11505491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_U;
1164712d88aSRafał Miłecki ch->control_ch_num += CH_10MHZ_APART;
11705491d2cSKalle Valo }
11805491d2cSKalle Valo break;
11905491d2cSKalle Valo default:
120ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
12105491d2cSKalle Valo break;
12205491d2cSKalle Valo }
12305491d2cSKalle Valo
12405491d2cSKalle Valo switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
12505491d2cSKalle Valo case BRCMU_CHSPEC_D11N_BND_5G:
12605491d2cSKalle Valo ch->band = BRCMU_CHAN_BAND_5G;
12705491d2cSKalle Valo break;
12805491d2cSKalle Valo case BRCMU_CHSPEC_D11N_BND_2G:
12905491d2cSKalle Valo ch->band = BRCMU_CHAN_BAND_2G;
13005491d2cSKalle Valo break;
13105491d2cSKalle Valo default:
132ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
13305491d2cSKalle Valo break;
13405491d2cSKalle Valo }
13505491d2cSKalle Valo }
13605491d2cSKalle Valo
brcmu_d11ac_decchspec(struct brcmu_chan * ch)13705491d2cSKalle Valo static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
13805491d2cSKalle Valo {
13905491d2cSKalle Valo u16 val;
14005491d2cSKalle Valo
14105491d2cSKalle Valo ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
1424712d88aSRafał Miłecki ch->control_ch_num = ch->chnum;
14305491d2cSKalle Valo
14405491d2cSKalle Valo switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
14505491d2cSKalle Valo case BRCMU_CHSPEC_D11AC_BW_20:
14605491d2cSKalle Valo ch->bw = BRCMU_CHAN_BW_20;
14705491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_NONE;
14805491d2cSKalle Valo break;
14905491d2cSKalle Valo case BRCMU_CHSPEC_D11AC_BW_40:
15005491d2cSKalle Valo ch->bw = BRCMU_CHAN_BW_40;
15105491d2cSKalle Valo val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
15205491d2cSKalle Valo if (val == BRCMU_CHSPEC_D11AC_SB_L) {
15305491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_L;
1544712d88aSRafał Miłecki ch->control_ch_num -= CH_10MHZ_APART;
15505491d2cSKalle Valo } else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
15605491d2cSKalle Valo ch->sb = BRCMU_CHAN_SB_U;
1574712d88aSRafał Miłecki ch->control_ch_num += CH_10MHZ_APART;
15805491d2cSKalle Valo } else {
159ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
16005491d2cSKalle Valo }
16105491d2cSKalle Valo break;
16205491d2cSKalle Valo case BRCMU_CHSPEC_D11AC_BW_80:
16305491d2cSKalle Valo ch->bw = BRCMU_CHAN_BW_80;
16405491d2cSKalle Valo ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
16505491d2cSKalle Valo BRCMU_CHSPEC_D11AC_SB_SHIFT);
16605491d2cSKalle Valo switch (ch->sb) {
16705491d2cSKalle Valo case BRCMU_CHAN_SB_LL:
1684712d88aSRafał Miłecki ch->control_ch_num -= CH_30MHZ_APART;
16905491d2cSKalle Valo break;
17005491d2cSKalle Valo case BRCMU_CHAN_SB_LU:
1714712d88aSRafał Miłecki ch->control_ch_num -= CH_10MHZ_APART;
17205491d2cSKalle Valo break;
17305491d2cSKalle Valo case BRCMU_CHAN_SB_UL:
1744712d88aSRafał Miłecki ch->control_ch_num += CH_10MHZ_APART;
17505491d2cSKalle Valo break;
17605491d2cSKalle Valo case BRCMU_CHAN_SB_UU:
1774712d88aSRafał Miłecki ch->control_ch_num += CH_30MHZ_APART;
17805491d2cSKalle Valo break;
17905491d2cSKalle Valo default:
180ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
18105491d2cSKalle Valo break;
18205491d2cSKalle Valo }
18305491d2cSKalle Valo break;
18405491d2cSKalle Valo case BRCMU_CHSPEC_D11AC_BW_160:
1853401d42cSRafał Miłecki ch->bw = BRCMU_CHAN_BW_160;
1863401d42cSRafał Miłecki ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
1873401d42cSRafał Miłecki BRCMU_CHSPEC_D11AC_SB_SHIFT);
188330994e8SArend van Spriel switch (ch->sb) {
189330994e8SArend van Spriel case BRCMU_CHAN_SB_LLL:
190330994e8SArend van Spriel ch->control_ch_num -= CH_70MHZ_APART;
191330994e8SArend van Spriel break;
192330994e8SArend van Spriel case BRCMU_CHAN_SB_LLU:
193330994e8SArend van Spriel ch->control_ch_num -= CH_50MHZ_APART;
194330994e8SArend van Spriel break;
195330994e8SArend van Spriel case BRCMU_CHAN_SB_LUL:
196330994e8SArend van Spriel ch->control_ch_num -= CH_30MHZ_APART;
197330994e8SArend van Spriel break;
198330994e8SArend van Spriel case BRCMU_CHAN_SB_LUU:
199330994e8SArend van Spriel ch->control_ch_num -= CH_10MHZ_APART;
200330994e8SArend van Spriel break;
201330994e8SArend van Spriel case BRCMU_CHAN_SB_ULL:
202330994e8SArend van Spriel ch->control_ch_num += CH_10MHZ_APART;
203330994e8SArend van Spriel break;
204330994e8SArend van Spriel case BRCMU_CHAN_SB_ULU:
205330994e8SArend van Spriel ch->control_ch_num += CH_30MHZ_APART;
206330994e8SArend van Spriel break;
207330994e8SArend van Spriel case BRCMU_CHAN_SB_UUL:
208330994e8SArend van Spriel ch->control_ch_num += CH_50MHZ_APART;
209330994e8SArend van Spriel break;
210330994e8SArend van Spriel case BRCMU_CHAN_SB_UUU:
211330994e8SArend van Spriel ch->control_ch_num += CH_70MHZ_APART;
212330994e8SArend van Spriel break;
213330994e8SArend van Spriel default:
214ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
215330994e8SArend van Spriel break;
216330994e8SArend van Spriel }
217330994e8SArend van Spriel break;
218330994e8SArend van Spriel case BRCMU_CHSPEC_D11AC_BW_8080:
21905491d2cSKalle Valo default:
220ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
22105491d2cSKalle Valo break;
22205491d2cSKalle Valo }
22305491d2cSKalle Valo
22405491d2cSKalle Valo switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
22505491d2cSKalle Valo case BRCMU_CHSPEC_D11AC_BND_5G:
22605491d2cSKalle Valo ch->band = BRCMU_CHAN_BAND_5G;
22705491d2cSKalle Valo break;
22805491d2cSKalle Valo case BRCMU_CHSPEC_D11AC_BND_2G:
22905491d2cSKalle Valo ch->band = BRCMU_CHAN_BAND_2G;
23005491d2cSKalle Valo break;
23105491d2cSKalle Valo default:
232ae5848cbSRafał Miłecki WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
23305491d2cSKalle Valo break;
23405491d2cSKalle Valo }
23505491d2cSKalle Valo }
23605491d2cSKalle Valo
brcmu_d11_attach(struct brcmu_d11inf * d11inf)23705491d2cSKalle Valo void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
23805491d2cSKalle Valo {
23905491d2cSKalle Valo if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
24005491d2cSKalle Valo d11inf->encchspec = brcmu_d11n_encchspec;
24105491d2cSKalle Valo d11inf->decchspec = brcmu_d11n_decchspec;
24205491d2cSKalle Valo } else {
24305491d2cSKalle Valo d11inf->encchspec = brcmu_d11ac_encchspec;
24405491d2cSKalle Valo d11inf->decchspec = brcmu_d11ac_decchspec;
24505491d2cSKalle Valo }
24605491d2cSKalle Valo }
24705491d2cSKalle Valo EXPORT_SYMBOL(brcmu_d11_attach);
248