162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2013 Broadcom Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*********************channel spec common functions*********************/
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <brcmu_utils.h>
1062306a36Sopenharmony_ci#include <brcmu_wifi.h>
1162306a36Sopenharmony_ci#include <brcmu_d11.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic u16 d11n_sb(enum brcmu_chan_sb sb)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	switch (sb) {
1662306a36Sopenharmony_ci	case BRCMU_CHAN_SB_NONE:
1762306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11N_SB_N;
1862306a36Sopenharmony_ci	case BRCMU_CHAN_SB_L:
1962306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11N_SB_L;
2062306a36Sopenharmony_ci	case BRCMU_CHAN_SB_U:
2162306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11N_SB_U;
2262306a36Sopenharmony_ci	default:
2362306a36Sopenharmony_ci		WARN_ON(1);
2462306a36Sopenharmony_ci	}
2562306a36Sopenharmony_ci	return 0;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic u16 d11n_bw(enum brcmu_chan_bw bw)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	switch (bw) {
3162306a36Sopenharmony_ci	case BRCMU_CHAN_BW_20:
3262306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11N_BW_20;
3362306a36Sopenharmony_ci	case BRCMU_CHAN_BW_40:
3462306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11N_BW_40;
3562306a36Sopenharmony_ci	default:
3662306a36Sopenharmony_ci		WARN_ON(1);
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci	return 0;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void brcmu_d11n_encchspec(struct brcmu_chan *ch)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	if (ch->bw == BRCMU_CHAN_BW_20)
4462306a36Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_NONE;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	ch->chspec = 0;
4762306a36Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
4862306a36Sopenharmony_ci			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
4962306a36Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK,
5062306a36Sopenharmony_ci			0, d11n_sb(ch->sb));
5162306a36Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK,
5262306a36Sopenharmony_ci			0, d11n_bw(ch->bw));
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (ch->chnum <= CH_MAX_2G_CHANNEL)
5562306a36Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
5662306a36Sopenharmony_ci	else
5762306a36Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic u16 d11ac_bw(enum brcmu_chan_bw bw)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	switch (bw) {
6362306a36Sopenharmony_ci	case BRCMU_CHAN_BW_20:
6462306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_20;
6562306a36Sopenharmony_ci	case BRCMU_CHAN_BW_40:
6662306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_40;
6762306a36Sopenharmony_ci	case BRCMU_CHAN_BW_80:
6862306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_80;
6962306a36Sopenharmony_ci	case BRCMU_CHAN_BW_160:
7062306a36Sopenharmony_ci		return BRCMU_CHSPEC_D11AC_BW_160;
7162306a36Sopenharmony_ci	default:
7262306a36Sopenharmony_ci		WARN_ON(1);
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE)
8062306a36Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_L;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK,
8362306a36Sopenharmony_ci			BRCMU_CHSPEC_CH_SHIFT, ch->chnum);
8462306a36Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
8562306a36Sopenharmony_ci			BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb);
8662306a36Sopenharmony_ci	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK,
8762306a36Sopenharmony_ci			0, d11ac_bw(ch->bw));
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;
9062306a36Sopenharmony_ci	if (ch->chnum <= CH_MAX_2G_CHANNEL)
9162306a36Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
9262306a36Sopenharmony_ci	else
9362306a36Sopenharmony_ci		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void brcmu_d11n_decchspec(struct brcmu_chan *ch)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	u16 val;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
10162306a36Sopenharmony_ci	ch->control_ch_num = ch->chnum;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
10462306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BW_20:
10562306a36Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_20;
10662306a36Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_NONE;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BW_40:
10962306a36Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_40;
11062306a36Sopenharmony_ci		val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
11162306a36Sopenharmony_ci		if (val == BRCMU_CHSPEC_D11N_SB_L) {
11262306a36Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_L;
11362306a36Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
11462306a36Sopenharmony_ci		} else {
11562306a36Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_U;
11662306a36Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci		break;
11962306a36Sopenharmony_ci	default:
12062306a36Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
12162306a36Sopenharmony_ci		break;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
12562306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BND_5G:
12662306a36Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_5G;
12762306a36Sopenharmony_ci		break;
12862306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11N_BND_2G:
12962306a36Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_2G;
13062306a36Sopenharmony_ci		break;
13162306a36Sopenharmony_ci	default:
13262306a36Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
13362306a36Sopenharmony_ci		break;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	u16 val;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
14262306a36Sopenharmony_ci	ch->control_ch_num = ch->chnum;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
14562306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_20:
14662306a36Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_20;
14762306a36Sopenharmony_ci		ch->sb = BRCMU_CHAN_SB_NONE;
14862306a36Sopenharmony_ci		break;
14962306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_40:
15062306a36Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_40;
15162306a36Sopenharmony_ci		val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
15262306a36Sopenharmony_ci		if (val == BRCMU_CHSPEC_D11AC_SB_L) {
15362306a36Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_L;
15462306a36Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
15562306a36Sopenharmony_ci		} else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
15662306a36Sopenharmony_ci			ch->sb = BRCMU_CHAN_SB_U;
15762306a36Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
15862306a36Sopenharmony_ci		} else {
15962306a36Sopenharmony_ci			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_80:
16362306a36Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_80;
16462306a36Sopenharmony_ci		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
16562306a36Sopenharmony_ci					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
16662306a36Sopenharmony_ci		switch (ch->sb) {
16762306a36Sopenharmony_ci		case BRCMU_CHAN_SB_LL:
16862306a36Sopenharmony_ci			ch->control_ch_num -= CH_30MHZ_APART;
16962306a36Sopenharmony_ci			break;
17062306a36Sopenharmony_ci		case BRCMU_CHAN_SB_LU:
17162306a36Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
17262306a36Sopenharmony_ci			break;
17362306a36Sopenharmony_ci		case BRCMU_CHAN_SB_UL:
17462306a36Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
17562306a36Sopenharmony_ci			break;
17662306a36Sopenharmony_ci		case BRCMU_CHAN_SB_UU:
17762306a36Sopenharmony_ci			ch->control_ch_num += CH_30MHZ_APART;
17862306a36Sopenharmony_ci			break;
17962306a36Sopenharmony_ci		default:
18062306a36Sopenharmony_ci			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
18162306a36Sopenharmony_ci			break;
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_160:
18562306a36Sopenharmony_ci		ch->bw = BRCMU_CHAN_BW_160;
18662306a36Sopenharmony_ci		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK,
18762306a36Sopenharmony_ci					 BRCMU_CHSPEC_D11AC_SB_SHIFT);
18862306a36Sopenharmony_ci		switch (ch->sb) {
18962306a36Sopenharmony_ci		case BRCMU_CHAN_SB_LLL:
19062306a36Sopenharmony_ci			ch->control_ch_num -= CH_70MHZ_APART;
19162306a36Sopenharmony_ci			break;
19262306a36Sopenharmony_ci		case BRCMU_CHAN_SB_LLU:
19362306a36Sopenharmony_ci			ch->control_ch_num -= CH_50MHZ_APART;
19462306a36Sopenharmony_ci			break;
19562306a36Sopenharmony_ci		case BRCMU_CHAN_SB_LUL:
19662306a36Sopenharmony_ci			ch->control_ch_num -= CH_30MHZ_APART;
19762306a36Sopenharmony_ci			break;
19862306a36Sopenharmony_ci		case BRCMU_CHAN_SB_LUU:
19962306a36Sopenharmony_ci			ch->control_ch_num -= CH_10MHZ_APART;
20062306a36Sopenharmony_ci			break;
20162306a36Sopenharmony_ci		case BRCMU_CHAN_SB_ULL:
20262306a36Sopenharmony_ci			ch->control_ch_num += CH_10MHZ_APART;
20362306a36Sopenharmony_ci			break;
20462306a36Sopenharmony_ci		case BRCMU_CHAN_SB_ULU:
20562306a36Sopenharmony_ci			ch->control_ch_num += CH_30MHZ_APART;
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		case BRCMU_CHAN_SB_UUL:
20862306a36Sopenharmony_ci			ch->control_ch_num += CH_50MHZ_APART;
20962306a36Sopenharmony_ci			break;
21062306a36Sopenharmony_ci		case BRCMU_CHAN_SB_UUU:
21162306a36Sopenharmony_ci			ch->control_ch_num += CH_70MHZ_APART;
21262306a36Sopenharmony_ci			break;
21362306a36Sopenharmony_ci		default:
21462306a36Sopenharmony_ci			WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
21562306a36Sopenharmony_ci			break;
21662306a36Sopenharmony_ci		}
21762306a36Sopenharmony_ci		break;
21862306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BW_8080:
21962306a36Sopenharmony_ci	default:
22062306a36Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
22162306a36Sopenharmony_ci		break;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
22562306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BND_5G:
22662306a36Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_5G;
22762306a36Sopenharmony_ci		break;
22862306a36Sopenharmony_ci	case BRCMU_CHSPEC_D11AC_BND_2G:
22962306a36Sopenharmony_ci		ch->band = BRCMU_CHAN_BAND_2G;
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci	default:
23262306a36Sopenharmony_ci		WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec);
23362306a36Sopenharmony_ci		break;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_civoid brcmu_d11_attach(struct brcmu_d11inf *d11inf)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
24062306a36Sopenharmony_ci		d11inf->encchspec = brcmu_d11n_encchspec;
24162306a36Sopenharmony_ci		d11inf->decchspec = brcmu_d11n_decchspec;
24262306a36Sopenharmony_ci	} else {
24362306a36Sopenharmony_ci		d11inf->encchspec = brcmu_d11ac_encchspec;
24462306a36Sopenharmony_ci		d11inf->decchspec = brcmu_d11ac_decchspec;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ciEXPORT_SYMBOL(brcmu_d11_attach);
248