Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/******************************************************************************
  2 *
  3 * Copyright(c) 2009-2012  Realtek Corporation.
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of version 2 of the GNU General Public License as
  7 * published by the Free Software Foundation.
  8 *
  9 * This program is distributed in the hope that it will be useful, but WITHOUT
 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 12 * more details.
 13 *
 14 * You should have received a copy of the GNU General Public License along with
 15 * this program; if not, write to the Free Software Foundation, Inc.,
 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 17 *
 18 * The full GNU General Public License is included in this distribution in the
 19 * file called LICENSE.
 20 *
 21 * Contact Information:
 22 * wlanfae <wlanfae@realtek.com>
 23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
 24 * Hsinchu 300, Taiwan.
 25 *
 26 * Larry Finger <Larry.Finger@lwfinger.net>
 27 *
 28 *****************************************************************************/
 29
 30#include "../wifi.h"
 31#include "reg.h"
 32#include "def.h"
 33#include "phy.h"
 34#include "rf.h"
 35#include "dm.h"
 36
 37static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
 38
 39void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 40{
 41	struct rtl_priv *rtlpriv = rtl_priv(hw);
 42	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 43
 44	switch (bandwidth) {
 45	case HT_CHANNEL_WIDTH_20:
 46		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
 47					     0xfffff3ff) | 0x0400);
 48		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
 49			      rtlphy->rfreg_chnlval[0]);
 50		break;
 51	case HT_CHANNEL_WIDTH_20_40:
 52		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
 53					     0xfffff3ff));
 54		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
 55			      rtlphy->rfreg_chnlval[0]);
 56		break;
 57	default:
 58		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 59			 "unknown bandwidth: %#X\n", bandwidth);
 60		break;
 61	}
 62}
 63
 64void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
 65					u8 *ppowerlevel)
 66{
 67	struct rtl_priv *rtlpriv = rtl_priv(hw);
 68	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 69	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 70	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 71	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 72	u32 tx_agc[2] = { 0, 0 }, tmpval = 0;
 73	bool turbo_scanoff = false;
 74	u8 idx1, idx2;
 75	u8 *ptr;
 76
 77	if (rtlhal->interface == INTF_PCI) {
 78		if (rtlefuse->eeprom_regulatory != 0)
 79			turbo_scanoff = true;
 80	} else {
 81		if ((rtlefuse->eeprom_regulatory != 0) ||
 82		    (rtlefuse->external_pa))
 83			turbo_scanoff = true;
 84	}
 85	if (mac->act_scanning) {
 86		tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
 87		tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
 88		if (turbo_scanoff) {
 89			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
 90				tx_agc[idx1] = ppowerlevel[idx1] |
 91				    (ppowerlevel[idx1] << 8) |
 92				    (ppowerlevel[idx1] << 16) |
 93				    (ppowerlevel[idx1] << 24);
 94				if (rtlhal->interface == INTF_USB) {
 95					if (tx_agc[idx1] > 0x20 &&
 96					    rtlefuse->external_pa)
 97						tx_agc[idx1] = 0x20;
 98				}
 99			}
100		}
101	} else {
102		if (rtlpriv->dm.dynamic_txhighpower_lvl ==
103		    TXHIGHPWRLEVEL_LEVEL1) {
104			tx_agc[RF90_PATH_A] = 0x10101010;
105			tx_agc[RF90_PATH_B] = 0x10101010;
106		} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
107			   TXHIGHPWRLEVEL_LEVEL1) {
108			tx_agc[RF90_PATH_A] = 0x00000000;
109			tx_agc[RF90_PATH_B] = 0x00000000;
110		} else{
111			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
112				tx_agc[idx1] = ppowerlevel[idx1] |
113				    (ppowerlevel[idx1] << 8) |
114				    (ppowerlevel[idx1] << 16) |
115				    (ppowerlevel[idx1] << 24);
116			}
117			if (rtlefuse->eeprom_regulatory == 0) {
118				tmpval = (rtlphy->mcs_txpwrlevel_origoffset
119					[0][6]) +
120					(rtlphy->mcs_txpwrlevel_origoffset
121					[0][7] <<  8);
122				tx_agc[RF90_PATH_A] += tmpval;
123				tmpval = (rtlphy->mcs_txpwrlevel_origoffset
124					[0][14]) +
125					(rtlphy->mcs_txpwrlevel_origoffset
126					[0][15] << 24);
127				tx_agc[RF90_PATH_B] += tmpval;
128			}
129		}
130	}
131	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
132		ptr = (u8 *) (&(tx_agc[idx1]));
133		for (idx2 = 0; idx2 < 4; idx2++) {
134			if (*ptr > RF6052_MAX_TX_PWR)
135				*ptr = RF6052_MAX_TX_PWR;
136			ptr++;
137		}
138	}
139	tmpval = tx_agc[RF90_PATH_A] & 0xff;
140	rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
141
142	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
143		"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",
144		tmpval, RTXAGC_A_CCK1_MCS32);
145
146	tmpval = tx_agc[RF90_PATH_A] >> 8;
147	if (mac->mode == WIRELESS_MODE_B)
148		tmpval = tmpval & 0xff00ffff;
149	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
150	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
151		"CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",
152		tmpval, RTXAGC_B_CCK11_A_CCK2_11);
153	tmpval = tx_agc[RF90_PATH_B] >> 24;
154	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
155	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
156		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",
157		tmpval, RTXAGC_B_CCK11_A_CCK2_11);
158	tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
159	rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
160	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
161		"CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n",
162		tmpval, RTXAGC_B_CCK1_55_MCS32);
163}
164
165static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw,
166				      u8 *ppowerlevel, u8 channel,
167				      u32 *ofdmbase, u32 *mcsbase)
168{
169	struct rtl_priv *rtlpriv = rtl_priv(hw);
170	struct rtl_phy *rtlphy = &(rtlpriv->phy);
171	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
172	u32 powerBase0, powerBase1;
173	u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
174	u8 i, powerlevel[2];
175
176	for (i = 0; i < 2; i++) {
177		powerlevel[i] = ppowerlevel[i];
178		legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];
179		powerBase0 = powerlevel[i] + legacy_pwrdiff;
180		powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
181		    (powerBase0 << 8) | powerBase0;
182		*(ofdmbase + i) = powerBase0;
183		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
184			" [OFDM power base index rf(%c) = 0x%x]\n",
185			i == 0 ? 'A' : 'B', *(ofdmbase + i));
186	}
187	for (i = 0; i < 2; i++) {
188		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
189			ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];
190			powerlevel[i] += ht20_pwrdiff;
191		}
192		powerBase1 = powerlevel[i];
193		powerBase1 = (powerBase1 << 24) |
194		    (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
195		*(mcsbase + i) = powerBase1;
196		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
197			" [MCS power base index rf(%c) = 0x%x]\n",
198			i == 0 ? 'A' : 'B', *(mcsbase + i));
199	}
200}
201
202static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
203						       u8 channel, u8 index,
204						       u32 *powerBase0,
205						       u32 *powerBase1,
206						       u32 *p_outwriteval)
207{
208	struct rtl_priv *rtlpriv = rtl_priv(hw);
209	struct rtl_phy *rtlphy = &(rtlpriv->phy);
210	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
211	u8 i, chnlgroup = 0, pwr_diff_limit[4];
212	u32 writeVal, customer_limit, rf;
213
214	for (rf = 0; rf < 2; rf++) {
215		switch (rtlefuse->eeprom_regulatory) {
216		case 0:
217			chnlgroup = 0;
218			writeVal = rtlphy->mcs_txpwrlevel_origoffset
219			    [chnlgroup][index + (rf ? 8 : 0)]
220			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
221			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
222				"RTK better performance,writeVal(%c) = 0x%x\n",
223				rf == 0 ? 'A' : 'B', writeVal);
224			break;
225		case 1:
226			if (rtlphy->pwrgroup_cnt == 1)
227				chnlgroup = 0;
228			if (rtlphy->pwrgroup_cnt >= 3) {
229				if (channel <= 3)
230					chnlgroup = 0;
231				else if (channel >= 4 && channel <= 9)
232					chnlgroup = 1;
233				else if (channel > 9)
234					chnlgroup = 2;
235				if (rtlphy->current_chan_bw ==
236				    HT_CHANNEL_WIDTH_20)
237					chnlgroup++;
238				else
239					chnlgroup += 4;
240			}
241			writeVal = rtlphy->mcs_txpwrlevel_origoffset
242					[chnlgroup][index +
243					(rf ? 8 : 0)] +
244					((index < 2) ? powerBase0[rf] :
245					powerBase1[rf]);
246			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
247				"Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n",
248				rf == 0 ? 'A' : 'B', writeVal);
249			break;
250		case 2:
251			writeVal = ((index < 2) ? powerBase0[rf] :
252				   powerBase1[rf]);
253			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
254				"Better regulatory,writeVal(%c) = 0x%x\n",
255				rf == 0 ? 'A' : 'B', writeVal);
256			break;
257		case 3:
258			chnlgroup = 0;
259			if (rtlphy->current_chan_bw ==
260			    HT_CHANNEL_WIDTH_20_40) {
261				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
262					"customer's limit, 40MHzrf(%c) = 0x%x\n",
263					rf == 0 ? 'A' : 'B',
264					rtlefuse->pwrgroup_ht40[rf]
265					[channel - 1]);
266			} else {
267				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
268					"customer's limit, 20MHz rf(%c) = 0x%x\n",
269					rf == 0 ? 'A' : 'B',
270					rtlefuse->pwrgroup_ht20[rf]
271					[channel - 1]);
272			}
273			for (i = 0; i < 4; i++) {
274				pwr_diff_limit[i] =
275				    (u8) ((rtlphy->mcs_txpwrlevel_origoffset
276				    [chnlgroup][index + (rf ? 8 : 0)]
277				    & (0x7f << (i * 8))) >> (i * 8));
278				if (rtlphy->current_chan_bw ==
279				    HT_CHANNEL_WIDTH_20_40) {
280					if (pwr_diff_limit[i] >
281					    rtlefuse->pwrgroup_ht40[rf]
282						[channel - 1])
283						pwr_diff_limit[i] = rtlefuse->
284						    pwrgroup_ht40[rf]
285						    [channel - 1];
286				} else {
287					if (pwr_diff_limit[i] >
288					    rtlefuse->pwrgroup_ht20[rf]
289						[channel - 1])
290						pwr_diff_limit[i] =
291						    rtlefuse->pwrgroup_ht20[rf]
292						    [channel - 1];
293				}
294			}
295			customer_limit = (pwr_diff_limit[3] << 24) |
296			    (pwr_diff_limit[2] << 16) |
297			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
298			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
299				"Customer's limit rf(%c) = 0x%x\n",
300				rf == 0 ? 'A' : 'B', customer_limit);
301			writeVal = customer_limit + ((index < 2) ?
302				   powerBase0[rf] : powerBase1[rf]);
303			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
304				"Customer, writeVal rf(%c)= 0x%x\n",
305				rf == 0 ? 'A' : 'B', writeVal);
306			break;
307		default:
308			chnlgroup = 0;
309			writeVal = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
310				   [index + (rf ? 8 : 0)] + ((index < 2) ?
311				   powerBase0[rf] : powerBase1[rf]);
312			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
313				"RTK better performance, writeValrf(%c) = 0x%x\n",
314				rf == 0 ? 'A' : 'B', writeVal);
315			break;
316		}
317		if (rtlpriv->dm.dynamic_txhighpower_lvl ==
318		    TXHIGHPWRLEVEL_LEVEL1)
319			writeVal = 0x14141414;
320		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
321			 TXHIGHPWRLEVEL_LEVEL2)
322			writeVal = 0x00000000;
323		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
324			writeVal = writeVal - 0x06060606;
325		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
326			 TXHIGHPWRLEVEL_BT2)
327			writeVal = writeVal;
328		*(p_outwriteval + rf) = writeVal;
329	}
330}
331
332static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
333					 u8 index, u32 *pValue)
334{
335	struct rtl_priv *rtlpriv = rtl_priv(hw);
336	struct rtl_phy *rtlphy = &(rtlpriv->phy);
337	u16 regoffset_a[6] = {
338		RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
339		RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
340		RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
341	};
342	u16 regoffset_b[6] = {
343		RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
344		RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
345		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
346	};
347	u8 i, rf, pwr_val[4];
348	u32 writeVal;
349	u16 regoffset;
350
351	for (rf = 0; rf < 2; rf++) {
352		writeVal = pValue[rf];
353		for (i = 0; i < 4; i++) {
354			pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >>
355					  (i * 8));
356			if (pwr_val[i] > RF6052_MAX_TX_PWR)
357				pwr_val[i] = RF6052_MAX_TX_PWR;
358		}
359		writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
360		    (pwr_val[1] << 8) | pwr_val[0];
361		if (rf == 0)
362			regoffset = regoffset_a[index];
363		else
364			regoffset = regoffset_b[index];
365		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal);
366		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
367			"Set 0x%x = %08x\n", regoffset, writeVal);
368		if (((get_rf_type(rtlphy) == RF_2T2R) &&
369		     (regoffset == RTXAGC_A_MCS15_MCS12 ||
370		      regoffset == RTXAGC_B_MCS15_MCS12)) ||
371		    ((get_rf_type(rtlphy) != RF_2T2R) &&
372		     (regoffset == RTXAGC_A_MCS07_MCS04 ||
373		      regoffset == RTXAGC_B_MCS07_MCS04))) {
374			writeVal = pwr_val[3];
375			if (regoffset == RTXAGC_A_MCS15_MCS12 ||
376			    regoffset == RTXAGC_A_MCS07_MCS04)
377				regoffset = 0xc90;
378			if (regoffset == RTXAGC_B_MCS15_MCS12 ||
379			    regoffset == RTXAGC_B_MCS07_MCS04)
380				regoffset = 0xc98;
381			for (i = 0; i < 3; i++) {
382				writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
383				rtl_write_byte(rtlpriv, (u32)(regoffset + i),
384					      (u8)writeVal);
385			}
386		}
387	}
388}
389
390void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
391					 u8 *ppowerlevel, u8 channel)
392{
393	u32 writeVal[2], powerBase0[2], powerBase1[2];
394	u8 index = 0;
395
396	rtl92c_phy_get_power_base(hw, ppowerlevel,
397				  channel, &powerBase0[0], &powerBase1[0]);
398	for (index = 0; index < 6; index++) {
399		_rtl92c_get_txpower_writeval_by_regulatory(hw,
400							   channel, index,
401							   &powerBase0[0],
402							   &powerBase1[0],
403							   &writeVal[0]);
404		_rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]);
405	}
406}
407
408bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw)
409{
410	struct rtl_priv *rtlpriv = rtl_priv(hw);
411	struct rtl_phy *rtlphy = &(rtlpriv->phy);
412	bool rtstatus = true;
413	u8 b_reg_hwparafile = 1;
414
415	if (rtlphy->rf_type == RF_1T1R)
416		rtlphy->num_total_rfpath = 1;
417	else
418		rtlphy->num_total_rfpath = 2;
419	if (b_reg_hwparafile == 1)
420		rtstatus = _rtl92c_phy_rf6052_config_parafile(hw);
421	return rtstatus;
422}
423
424static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
425{
426	struct rtl_priv *rtlpriv = rtl_priv(hw);
427	struct rtl_phy *rtlphy = &(rtlpriv->phy);
428	u32 u4_regvalue = 0;
429	u8 rfpath;
430	bool rtstatus = true;
431	struct bb_reg_def *pphyreg;
432
433	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
434		pphyreg = &rtlphy->phyreg_def[rfpath];
435		switch (rfpath) {
436		case RF90_PATH_A:
437		case RF90_PATH_C:
438			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
439						    BRFSI_RFENV);
440			break;
441		case RF90_PATH_B:
442		case RF90_PATH_D:
443			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
444						    BRFSI_RFENV << 16);
445			break;
446		}
447		rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
448		udelay(1);
449		rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
450		udelay(1);
451		rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
452			      B3WIREADDREAALENGTH, 0x0);
453		udelay(1);
454		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
455		udelay(1);
456		switch (rfpath) {
457		case RF90_PATH_A:
458			rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
459					(enum radio_path) rfpath);
460			break;
461		case RF90_PATH_B:
462			rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
463					(enum radio_path) rfpath);
464			break;
465		case RF90_PATH_C:
466			break;
467		case RF90_PATH_D:
468			break;
469		}
470		switch (rfpath) {
471		case RF90_PATH_A:
472		case RF90_PATH_C:
473			rtl_set_bbreg(hw, pphyreg->rfintfs,
474				      BRFSI_RFENV, u4_regvalue);
475			break;
476		case RF90_PATH_B:
477		case RF90_PATH_D:
478			rtl_set_bbreg(hw, pphyreg->rfintfs,
479				      BRFSI_RFENV << 16, u4_regvalue);
480			break;
481		}
482		if (!rtstatus) {
483			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
484				 "Radio[%d] Fail!!", rfpath);
485			goto phy_rf_cfg_fail;
486		}
487	}
488	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");
489	return rtstatus;
490phy_rf_cfg_fail:
491	return rtstatus;
492}