18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2013 Broadcom Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci/*********************channel spec common functions*********************/ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <brcmu_utils.h> 108c2ecf20Sopenharmony_ci#include <brcmu_wifi.h> 118c2ecf20Sopenharmony_ci#include <brcmu_d11.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic u16 d11n_sb(enum brcmu_chan_sb sb) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci switch (sb) { 168c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_NONE: 178c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11N_SB_N; 188c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_L: 198c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11N_SB_L; 208c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_U: 218c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11N_SB_U; 228c2ecf20Sopenharmony_ci default: 238c2ecf20Sopenharmony_ci WARN_ON(1); 248c2ecf20Sopenharmony_ci } 258c2ecf20Sopenharmony_ci return 0; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u16 d11n_bw(enum brcmu_chan_bw bw) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci switch (bw) { 318c2ecf20Sopenharmony_ci case BRCMU_CHAN_BW_20: 328c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11N_BW_20; 338c2ecf20Sopenharmony_ci case BRCMU_CHAN_BW_40: 348c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11N_BW_40; 358c2ecf20Sopenharmony_ci default: 368c2ecf20Sopenharmony_ci WARN_ON(1); 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void brcmu_d11n_encchspec(struct brcmu_chan *ch) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci if (ch->bw == BRCMU_CHAN_BW_20) 448c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_NONE; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ch->chspec = 0; 478c2ecf20Sopenharmony_ci brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK, 488c2ecf20Sopenharmony_ci BRCMU_CHSPEC_CH_SHIFT, ch->chnum); 498c2ecf20Sopenharmony_ci brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK, 508c2ecf20Sopenharmony_ci 0, d11n_sb(ch->sb)); 518c2ecf20Sopenharmony_ci brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK, 528c2ecf20Sopenharmony_ci 0, d11n_bw(ch->bw)); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (ch->chnum <= CH_MAX_2G_CHANNEL) 558c2ecf20Sopenharmony_ci ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G; 568c2ecf20Sopenharmony_ci else 578c2ecf20Sopenharmony_ci ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic u16 d11ac_bw(enum brcmu_chan_bw bw) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci switch (bw) { 638c2ecf20Sopenharmony_ci case BRCMU_CHAN_BW_20: 648c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11AC_BW_20; 658c2ecf20Sopenharmony_ci case BRCMU_CHAN_BW_40: 668c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11AC_BW_40; 678c2ecf20Sopenharmony_ci case BRCMU_CHAN_BW_80: 688c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11AC_BW_80; 698c2ecf20Sopenharmony_ci case BRCMU_CHAN_BW_160: 708c2ecf20Sopenharmony_ci return BRCMU_CHSPEC_D11AC_BW_160; 718c2ecf20Sopenharmony_ci default: 728c2ecf20Sopenharmony_ci WARN_ON(1); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void brcmu_d11ac_encchspec(struct brcmu_chan *ch) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE) 808c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_L; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK, 838c2ecf20Sopenharmony_ci BRCMU_CHSPEC_CH_SHIFT, ch->chnum); 848c2ecf20Sopenharmony_ci brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, 858c2ecf20Sopenharmony_ci BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb); 868c2ecf20Sopenharmony_ci brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK, 878c2ecf20Sopenharmony_ci 0, d11ac_bw(ch->bw)); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK; 908c2ecf20Sopenharmony_ci if (ch->chnum <= CH_MAX_2G_CHANNEL) 918c2ecf20Sopenharmony_ci ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G; 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void brcmu_d11n_decchspec(struct brcmu_chan *ch) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci u16 val; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); 1018c2ecf20Sopenharmony_ci ch->control_ch_num = ch->chnum; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) { 1048c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11N_BW_20: 1058c2ecf20Sopenharmony_ci ch->bw = BRCMU_CHAN_BW_20; 1068c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_NONE; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11N_BW_40: 1098c2ecf20Sopenharmony_ci ch->bw = BRCMU_CHAN_BW_40; 1108c2ecf20Sopenharmony_ci val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK; 1118c2ecf20Sopenharmony_ci if (val == BRCMU_CHSPEC_D11N_SB_L) { 1128c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_L; 1138c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_10MHZ_APART; 1148c2ecf20Sopenharmony_ci } else { 1158c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_U; 1168c2ecf20Sopenharmony_ci ch->control_ch_num += CH_10MHZ_APART; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci default: 1208c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) { 1258c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11N_BND_5G: 1268c2ecf20Sopenharmony_ci ch->band = BRCMU_CHAN_BAND_5G; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11N_BND_2G: 1298c2ecf20Sopenharmony_ci ch->band = BRCMU_CHAN_BAND_2G; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci default: 1328c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void brcmu_d11ac_decchspec(struct brcmu_chan *ch) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci u16 val; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); 1428c2ecf20Sopenharmony_ci ch->control_ch_num = ch->chnum; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) { 1458c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BW_20: 1468c2ecf20Sopenharmony_ci ch->bw = BRCMU_CHAN_BW_20; 1478c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_NONE; 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BW_40: 1508c2ecf20Sopenharmony_ci ch->bw = BRCMU_CHAN_BW_40; 1518c2ecf20Sopenharmony_ci val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK; 1528c2ecf20Sopenharmony_ci if (val == BRCMU_CHSPEC_D11AC_SB_L) { 1538c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_L; 1548c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_10MHZ_APART; 1558c2ecf20Sopenharmony_ci } else if (val == BRCMU_CHSPEC_D11AC_SB_U) { 1568c2ecf20Sopenharmony_ci ch->sb = BRCMU_CHAN_SB_U; 1578c2ecf20Sopenharmony_ci ch->control_ch_num += CH_10MHZ_APART; 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BW_80: 1638c2ecf20Sopenharmony_ci ch->bw = BRCMU_CHAN_BW_80; 1648c2ecf20Sopenharmony_ci ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, 1658c2ecf20Sopenharmony_ci BRCMU_CHSPEC_D11AC_SB_SHIFT); 1668c2ecf20Sopenharmony_ci switch (ch->sb) { 1678c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_LL: 1688c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_30MHZ_APART; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_LU: 1718c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_10MHZ_APART; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_UL: 1748c2ecf20Sopenharmony_ci ch->control_ch_num += CH_10MHZ_APART; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_UU: 1778c2ecf20Sopenharmony_ci ch->control_ch_num += CH_30MHZ_APART; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci default: 1808c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BW_160: 1858c2ecf20Sopenharmony_ci ch->bw = BRCMU_CHAN_BW_160; 1868c2ecf20Sopenharmony_ci ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, 1878c2ecf20Sopenharmony_ci BRCMU_CHSPEC_D11AC_SB_SHIFT); 1888c2ecf20Sopenharmony_ci switch (ch->sb) { 1898c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_LLL: 1908c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_70MHZ_APART; 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_LLU: 1938c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_50MHZ_APART; 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_LUL: 1968c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_30MHZ_APART; 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_LUU: 1998c2ecf20Sopenharmony_ci ch->control_ch_num -= CH_10MHZ_APART; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_ULL: 2028c2ecf20Sopenharmony_ci ch->control_ch_num += CH_10MHZ_APART; 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_ULU: 2058c2ecf20Sopenharmony_ci ch->control_ch_num += CH_30MHZ_APART; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_UUL: 2088c2ecf20Sopenharmony_ci ch->control_ch_num += CH_50MHZ_APART; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case BRCMU_CHAN_SB_UUU: 2118c2ecf20Sopenharmony_ci ch->control_ch_num += CH_70MHZ_APART; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci default: 2148c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BW_8080: 2198c2ecf20Sopenharmony_ci default: 2208c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) { 2258c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BND_5G: 2268c2ecf20Sopenharmony_ci ch->band = BRCMU_CHAN_BAND_5G; 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case BRCMU_CHSPEC_D11AC_BND_2G: 2298c2ecf20Sopenharmony_ci ch->band = BRCMU_CHAN_BAND_2G; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci default: 2328c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid chanspec 0x%04x\n", ch->chspec); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_civoid brcmu_d11_attach(struct brcmu_d11inf *d11inf) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci if (d11inf->io_type == BRCMU_D11N_IOTYPE) { 2408c2ecf20Sopenharmony_ci d11inf->encchspec = brcmu_d11n_encchspec; 2418c2ecf20Sopenharmony_ci d11inf->decchspec = brcmu_d11n_decchspec; 2428c2ecf20Sopenharmony_ci } else { 2438c2ecf20Sopenharmony_ci d11inf->encchspec = brcmu_d11ac_encchspec; 2448c2ecf20Sopenharmony_ci d11inf->decchspec = brcmu_d11ac_decchspec; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(brcmu_d11_attach); 248