brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · 5a49360 Raw
508 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2009-2012  Realtek Corporation.*/3 4#include "../wifi.h"5#include "reg.h"6#include "def.h"7#include "phy.h"8#include "rf.h"9#include "dm.h"10 11 12static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,13				  u8 chnl, u32 *ofdmbase, u32 *mcsbase,14				  u8 *p_final_pwridx)15{16	struct rtl_priv *rtlpriv = rtl_priv(hw);17	struct rtl_phy *rtlphy = &(rtlpriv->phy);18	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));19	u32 pwrbase0, pwrbase1;20	u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;21	u8 i, pwrlevel[4];22 23	for (i = 0; i < 2; i++)24		pwrlevel[i] = p_pwrlevel[i];25 26	/* We only care about the path A for legacy. */27	if (rtlefuse->eeprom_version < 2) {28		pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_ht_txpowerdiff & 0xf);29	} else {30		legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff31						[RF90_PATH_A][chnl - 1];32 33		/* For legacy OFDM, tx pwr always > HT OFDM pwr.34		 * We do not care Path B35		 * legacy OFDM pwr diff. NO BB register36		 * to notify HW. */37		pwrbase0 = pwrlevel[0] + legacy_pwrdiff;38	}39 40	pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) |41		    pwrbase0;42	*ofdmbase = pwrbase0;43 44	/* MCS rates */45	if (rtlefuse->eeprom_version >= 2) {46		/* Check HT20 to HT40 diff	*/47		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {48			for (i = 0; i < 2; i++) {49				/* rf-A, rf-B */50				/* HT 20<->40 pwr diff */51				ht20_pwrdiff = rtlefuse->txpwr_ht20diff52							[i][chnl - 1];53 54				if (ht20_pwrdiff < 8) /* 0~+7 */55					pwrlevel[i] += ht20_pwrdiff;56				else /* index8-15=-8~-1 */57					pwrlevel[i] -= (16 - ht20_pwrdiff);58			}59		}60	}61 62	/* use index of rf-A */63	pwrbase1 = pwrlevel[0];64	pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) |65				pwrbase1;66	*mcsbase = pwrbase1;67 68	/* The following is for Antenna69	 * diff from Ant-B to Ant-A */70	p_final_pwridx[0] = pwrlevel[0];71	p_final_pwridx[1] = pwrlevel[1];72 73	switch (rtlefuse->eeprom_regulatory) {74	case 3:75		/* The following is for calculation76		 * of the power diff for Ant-B to Ant-A. */77		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {78			p_final_pwridx[0] += rtlefuse->pwrgroup_ht4079						[RF90_PATH_A][80						chnl - 1];81			p_final_pwridx[1] += rtlefuse->pwrgroup_ht4082						[RF90_PATH_B][83						chnl - 1];84		} else {85			p_final_pwridx[0] += rtlefuse->pwrgroup_ht2086						[RF90_PATH_A][87						chnl - 1];88			p_final_pwridx[1] += rtlefuse->pwrgroup_ht2089						[RF90_PATH_B][90						chnl - 1];91		}92		break;93	default:94		break;95	}96 97	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {98		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,99			"40MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",100			p_final_pwridx[0], p_final_pwridx[1]);101	} else {102		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,103			"20MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",104			p_final_pwridx[0], p_final_pwridx[1]);105	}106}107 108static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw,109				    u8 *p_final_pwridx)110{111	struct rtl_priv *rtlpriv = rtl_priv(hw);112	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));113	struct rtl_phy *rtlphy = &(rtlpriv->phy);114	s8 ant_pwr_diff = 0;115	u32	u4reg_val = 0;116 117	if (rtlphy->rf_type == RF_2T2R) {118		ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0];119 120		/* range is from 7~-8,121		 * index = 0x0~0xf */122		if (ant_pwr_diff > 7)123			ant_pwr_diff = 7;124		if (ant_pwr_diff < -8)125			ant_pwr_diff = -8;126 127		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,128			"Antenna Diff from RF-B to RF-A = %d (0x%x)\n",129			ant_pwr_diff, ant_pwr_diff & 0xf);130 131		ant_pwr_diff &= 0xf;132	}133 134	/* Antenna TX power difference */135	rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */136	rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */137	rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff);	/* RF-B */138 139	u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 |140				rtlefuse->antenna_txpwdiff[1] << 4 |141				rtlefuse->antenna_txpwdiff[0];142 143	rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC),144		      u4reg_val);145 146	rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n",147		RFPGA0_TXGAINSTAGE, u4reg_val);148}149 150static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,151						      u8 chnl, u8 index,152						      u32 pwrbase0,153						      u32 pwrbase1,154						      u32 *p_outwrite_val)155{156	struct rtl_priv *rtlpriv = rtl_priv(hw);157	struct rtl_phy *rtlphy = &(rtlpriv->phy);158	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));159	u8 i, chnlgroup, pwrdiff_limit[4];160	u32 writeval, customer_limit;161 162	/* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */163	switch (rtlefuse->eeprom_regulatory) {164	case 0:165		/* Realtek better performance increase power diff166		 * defined by Realtek for large power */167		chnlgroup = 0;168 169		writeval = rtlphy->mcs_offset[chnlgroup][index] +170				((index < 2) ? pwrbase0 : pwrbase1);171 172		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,173			"RTK better performance, writeval = 0x%x\n", writeval);174		break;175	case 1:176		/* Realtek regulatory increase power diff defined177		 * by Realtek for regulatory */178		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {179			writeval = ((index < 2) ? pwrbase0 : pwrbase1);180 181			rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,182				"Realtek regulatory, 40MHz, writeval = 0x%x\n",183				writeval);184		} else {185			chnlgroup = 0;186 187			if (rtlphy->pwrgroup_cnt >= 3) {188				if (chnl <= 3)189					chnlgroup = 0;190				else if (chnl >= 4 && chnl <= 8)191					chnlgroup = 1;192				else if (chnl > 8)193					chnlgroup = 2;194				if (rtlphy->pwrgroup_cnt == 4)195					chnlgroup++;196			}197 198			writeval = rtlphy->mcs_offset[chnlgroup][index]199					+ ((index < 2) ?200					pwrbase0 : pwrbase1);201 202			rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,203				"Realtek regulatory, 20MHz, writeval = 0x%x\n",204				writeval);205		}206		break;207	case 2:208		/* Better regulatory don't increase any power diff */209		writeval = ((index < 2) ? pwrbase0 : pwrbase1);210		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,211			"Better regulatory, writeval = 0x%x\n", writeval);212		break;213	case 3:214		/* Customer defined power diff. increase power diff215		  defined by customer. */216		chnlgroup = 0;217 218		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {219			rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,220				"customer's limit, 40MHz = 0x%x\n",221				rtlefuse->pwrgroup_ht40222				[RF90_PATH_A][chnl - 1]);223		} else {224			rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,225				"customer's limit, 20MHz = 0x%x\n",226				rtlefuse->pwrgroup_ht20227				[RF90_PATH_A][chnl - 1]);228		}229 230		for (i = 0; i < 4; i++) {231			pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset232				[chnlgroup][index] & (0x7f << (i * 8)))233				>> (i * 8));234 235			if (rtlphy->current_chan_bw ==236			    HT_CHANNEL_WIDTH_20_40) {237				if (pwrdiff_limit[i] >238				    rtlefuse->pwrgroup_ht40239				    [RF90_PATH_A][chnl - 1]) {240					pwrdiff_limit[i] =241					  rtlefuse->pwrgroup_ht40242					  [RF90_PATH_A][chnl - 1];243				}244			} else {245				if (pwrdiff_limit[i] >246				    rtlefuse->pwrgroup_ht20247				    [RF90_PATH_A][chnl - 1]) {248					pwrdiff_limit[i] =249					    rtlefuse->pwrgroup_ht20250					    [RF90_PATH_A][chnl - 1];251				}252			}253		}254 255		customer_limit = (pwrdiff_limit[3] << 24) |256				(pwrdiff_limit[2] << 16) |257				(pwrdiff_limit[1] << 8) |258				(pwrdiff_limit[0]);259		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,260			"Customer's limit = 0x%x\n", customer_limit);261 262		writeval = customer_limit + ((index < 2) ?263					     pwrbase0 : pwrbase1);264		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,265			"Customer, writeval = 0x%x\n", writeval);266		break;267	default:268		chnlgroup = 0;269		writeval = rtlphy->mcs_offset[chnlgroup][index] +270				((index < 2) ? pwrbase0 : pwrbase1);271		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,272			"RTK better performance, writeval = 0x%x\n", writeval);273		break;274	}275 276	if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1)277		writeval = 0x10101010;278	else if (rtlpriv->dm.dynamic_txhighpower_lvl ==279		 TX_HIGH_PWR_LEVEL_LEVEL2)280		writeval = 0x0;281 282	*p_outwrite_val = writeval;283 284}285 286static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw,287					u8 index, u32 val)288{289	struct rtl_priv *rtlpriv = rtl_priv(hw);290	struct rtl_phy *rtlphy = &(rtlpriv->phy);291	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));292	u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};293	u8 i, rfa_pwr[4];294	u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0;295	u32 writeval = val;296 297	/* If path A and Path B coexist, we must limit Path A tx power.298	 * Protect Path B pwr over or under flow. We need to calculate299	 * upper and lower bound of path A tx power. */300	if (rtlphy->rf_type == RF_2T2R) {301		rf_pwr_diff = rtlefuse->antenna_txpwdiff[0];302 303		/* Diff=-8~-1 */304		if (rf_pwr_diff >= 8) {305			/* Prevent underflow!! */306			rfa_lower_bound = 0x10 - rf_pwr_diff;307		/* if (rf_pwr_diff >= 0) Diff = 0-7 */308		} else {309			rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff;310		}311	}312 313	for (i = 0; i < 4; i++) {314		rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8));315		if (rfa_pwr[i]  > RF6052_MAX_TX_PWR)316			rfa_pwr[i]  = RF6052_MAX_TX_PWR;317 318		/* If path A and Path B coexist, we must limit Path A tx power.319		 * Protect Path B pwr over or under flow. We need to calculate320		 * upper and lower bound of path A tx power. */321		if (rtlphy->rf_type == RF_2T2R) {322			/* Diff=-8~-1 */323			if (rf_pwr_diff >= 8) {324				/* Prevent underflow!! */325				if (rfa_pwr[i] < rfa_lower_bound)326					rfa_pwr[i] = rfa_lower_bound;327			/* Diff = 0-7 */328			} else if (rf_pwr_diff >= 1) {329				/* Prevent overflow */330				if (rfa_pwr[i] > rfa_upper_bound)331					rfa_pwr[i] = rfa_upper_bound;332			}333		}334 335	}336 337	writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) |338				rfa_pwr[0];339 340	rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval);341}342 343void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,344				       u8 *p_pwrlevel, u8 chnl)345{346	u32 writeval, pwrbase0, pwrbase1;347	u8 index = 0;348	u8 finalpwr_idx[4];349 350	_rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1,351			&finalpwr_idx[0]);352	_rtl92s_set_antennadiff(hw, &finalpwr_idx[0]);353 354	for (index = 0; index < 6; index++) {355		_rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index,356				pwrbase0, pwrbase1, &writeval);357 358		_rtl92s_write_ofdm_powerreg(hw, index, writeval);359	}360}361 362void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel)363{364	struct rtl_priv *rtlpriv = rtl_priv(hw);365	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));366	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));367	u32 txagc = 0;368	bool dont_inc_cck_or_turboscanoff = false;369 370	if (((rtlefuse->eeprom_version >= 2) &&371	      (rtlefuse->txpwr_safetyflag == 1)) ||372	      ((rtlefuse->eeprom_version >= 2) &&373	      (rtlefuse->eeprom_regulatory != 0)))374		dont_inc_cck_or_turboscanoff = true;375 376	if (mac->act_scanning) {377		txagc = 0x3f;378		if (dont_inc_cck_or_turboscanoff)379			txagc = pwrlevel;380	} else {381		txagc = pwrlevel;382 383		if (rtlpriv->dm.dynamic_txhighpower_lvl ==384		    TX_HIGH_PWR_LEVEL_LEVEL1)385			txagc = 0x10;386		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==387			TX_HIGH_PWR_LEVEL_LEVEL2)388			txagc = 0x0;389	}390 391	if (txagc > RF6052_MAX_TX_PWR)392		txagc = RF6052_MAX_TX_PWR;393 394	rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc);395 396}397 398bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw)399{400	struct rtl_priv *rtlpriv = rtl_priv(hw);401	struct rtl_phy *rtlphy = &(rtlpriv->phy);402	u32 u4reg_val = 0;403	u8 rfpath;404	bool rtstatus = true;405	struct bb_reg_def *pphyreg;406 407	/* Initialize RF */408	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {409 410		pphyreg = &rtlphy->phyreg_def[rfpath];411 412		/* Store original RFENV control type */413		switch (rfpath) {414		case RF90_PATH_A:415		case RF90_PATH_C:416			u4reg_val = rtl92s_phy_query_bb_reg(hw,417							    pphyreg->rfintfs,418							    BRFSI_RFENV);419			break;420		case RF90_PATH_B:421		case RF90_PATH_D:422			u4reg_val = rtl92s_phy_query_bb_reg(hw,423							    pphyreg->rfintfs,424							    BRFSI_RFENV << 16);425			break;426		}427 428		/* Set RF_ENV enable */429		rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe,430				      BRFSI_RFENV << 16, 0x1);431 432		/* Set RF_ENV output high */433		rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);434 435		/* Set bit number of Address and Data for RF register */436		rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,437				B3WIRE_ADDRESSLENGTH, 0x0);438		rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,439				B3WIRE_DATALENGTH, 0x0);440 441		/* Initialize RF fom connfiguration file */442		switch (rfpath) {443		case RF90_PATH_A:444			rtstatus = rtl92s_phy_config_rf(hw,445						(enum radio_path)rfpath);446			break;447		case RF90_PATH_B:448			rtstatus = rtl92s_phy_config_rf(hw,449						(enum radio_path)rfpath);450			break;451		case RF90_PATH_C:452			break;453		case RF90_PATH_D:454			break;455		}456 457		/* Restore RFENV control type */458		switch (rfpath) {459		case RF90_PATH_A:460		case RF90_PATH_C:461			rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV,462					      u4reg_val);463			break;464		case RF90_PATH_B:465		case RF90_PATH_D:466			rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs,467					      BRFSI_RFENV << 16,468					      u4reg_val);469			break;470		}471 472		if (!rtstatus) {473			pr_err("Radio[%d] Fail!!\n", rfpath);474			goto fail;475		}476 477	}478 479	return rtstatus;480 481fail:482	return rtstatus;483}484 485void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)486{487	struct rtl_priv *rtlpriv = rtl_priv(hw);488	struct rtl_phy *rtlphy = &(rtlpriv->phy);489 490	switch (bandwidth) {491	case HT_CHANNEL_WIDTH_20:492		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &493					   0xfffff3ff) | 0x0400);494		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,495					rtlphy->rfreg_chnlval[0]);496		break;497	case HT_CHANNEL_WIDTH_20_40:498		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &499					    0xfffff3ff));500		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,501					rtlphy->rfreg_chnlval[0]);502		break;503	default:504		pr_err("unknown bandwidth: %#X\n", bandwidth);505		break;506	}507}508