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		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
89			tx_agc[idx1] = ppowerlevel[idx1] |
90			    (ppowerlevel[idx1] << 8) |
91			    (ppowerlevel[idx1] << 16) |
92			    (ppowerlevel[idx1] << 24);
93			if (rtlhal->interface == INTF_USB) {
94				if (tx_agc[idx1] > 0x20 &&
95				    rtlefuse->external_pa)
96					tx_agc[idx1] = 0x20;
97			}
98		}
99	} else {
100		if (rtlpriv->dm.dynamic_txhighpower_lvl ==
101		    TXHIGHPWRLEVEL_LEVEL1) {
102			tx_agc[RF90_PATH_A] = 0x10101010;
103			tx_agc[RF90_PATH_B] = 0x10101010;
104		} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
105			   TXHIGHPWRLEVEL_LEVEL2) {
106			tx_agc[RF90_PATH_A] = 0x00000000;
107			tx_agc[RF90_PATH_B] = 0x00000000;
108		} else {
109			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
110				tx_agc[idx1] = ppowerlevel[idx1] |
111				    (ppowerlevel[idx1] << 8) |
112				    (ppowerlevel[idx1] << 16) |
113				    (ppowerlevel[idx1] << 24);
114			}
115			if (rtlefuse->eeprom_regulatory == 0) {
116				tmpval = (rtlphy->mcs_offset[0][6]) +
117					(rtlphy->mcs_offset[0][7] <<  8);
118				tx_agc[RF90_PATH_A] += tmpval;
119				tmpval = (rtlphy->mcs_offset[0][14]) +
120					(rtlphy->mcs_offset[0][15] << 24);
121				tx_agc[RF90_PATH_B] += tmpval;
122			}
123		}
124	}
125	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
126		ptr = (u8 *) (&(tx_agc[idx1]));
127		for (idx2 = 0; idx2 < 4; idx2++) {
128			if (*ptr > RF6052_MAX_TX_PWR)
129				*ptr = RF6052_MAX_TX_PWR;
130			ptr++;
131		}
132	}
133	tmpval = tx_agc[RF90_PATH_A] & 0xff;
134	rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
135
136	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
137		"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",
138		tmpval, RTXAGC_A_CCK1_MCS32);
139
140	tmpval = tx_agc[RF90_PATH_A] >> 8;
141	if (mac->mode == WIRELESS_MODE_B)
142		tmpval = tmpval & 0xff00ffff;
143	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
144	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
145		"CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",
146		tmpval, RTXAGC_B_CCK11_A_CCK2_11);
147	tmpval = tx_agc[RF90_PATH_B] >> 24;
148	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
149	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
150		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",
151		tmpval, RTXAGC_B_CCK11_A_CCK2_11);
152	tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
153	rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
154	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
155		"CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n",
156		tmpval, RTXAGC_B_CCK1_55_MCS32);
157}
158
159static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw,
160				      u8 *ppowerlevel, u8 channel,
161				      u32 *ofdmbase, u32 *mcsbase)
162{
163	struct rtl_priv *rtlpriv = rtl_priv(hw);
164	struct rtl_phy *rtlphy = &(rtlpriv->phy);
165	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
166	u32 powerBase0, powerBase1;
167	u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
168	u8 i, powerlevel[2];
169
170	for (i = 0; i < 2; i++) {
171		powerlevel[i] = ppowerlevel[i];
172		legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];
173		powerBase0 = powerlevel[i] + legacy_pwrdiff;
174		powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
175		    (powerBase0 << 8) | powerBase0;
176		*(ofdmbase + i) = powerBase0;
177		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
178			" [OFDM power base index rf(%c) = 0x%x]\n",
179			i == 0 ? 'A' : 'B', *(ofdmbase + i));
180	}
181	for (i = 0; i < 2; i++) {
182		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
183			ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];
184			powerlevel[i] += ht20_pwrdiff;
185		}
186		powerBase1 = powerlevel[i];
187		powerBase1 = (powerBase1 << 24) |
188		    (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
189		*(mcsbase + i) = powerBase1;
190		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
191			" [MCS power base index rf(%c) = 0x%x]\n",
192			i == 0 ? 'A' : 'B', *(mcsbase + i));
193	}
194}
195
196static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
197						       u8 channel, u8 index,
198						       u32 *powerBase0,
199						       u32 *powerBase1,
200						       u32 *p_outwriteval)
201{
202	struct rtl_priv *rtlpriv = rtl_priv(hw);
203	struct rtl_phy *rtlphy = &(rtlpriv->phy);
204	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
205	u8 i, chnlgroup = 0, pwr_diff_limit[4];
206	u32 writeVal, customer_limit, rf;
207
208	for (rf = 0; rf < 2; rf++) {
209		switch (rtlefuse->eeprom_regulatory) {
210		case 0:
211			chnlgroup = 0;
212			writeVal = rtlphy->mcs_offset
213			    [chnlgroup][index + (rf ? 8 : 0)]
214			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
215			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
216				"RTK better performance,writeVal(%c) = 0x%x\n",
217				rf == 0 ? 'A' : 'B', writeVal);
218			break;
219		case 1:
220			if (rtlphy->pwrgroup_cnt == 1)
221				chnlgroup = 0;
222			if (rtlphy->pwrgroup_cnt >= 3) {
223				if (channel <= 3)
224					chnlgroup = 0;
225				else if (channel >= 4 && channel <= 9)
226					chnlgroup = 1;
227				else if (channel > 9)
228					chnlgroup = 2;
229				if (rtlphy->current_chan_bw ==
230				    HT_CHANNEL_WIDTH_20)
231					chnlgroup++;
232				else
233					chnlgroup += 4;
234			}
235			writeVal = rtlphy->mcs_offset[chnlgroup][index +
236					(rf ? 8 : 0)] +
237					((index < 2) ? powerBase0[rf] :
238					powerBase1[rf]);
239			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
240				"Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n",
241				rf == 0 ? 'A' : 'B', writeVal);
242			break;
243		case 2:
244			writeVal = ((index < 2) ? powerBase0[rf] :
245				   powerBase1[rf]);
246			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
247				"Better regulatory,writeVal(%c) = 0x%x\n",
248				rf == 0 ? 'A' : 'B', writeVal);
249			break;
250		case 3:
251			chnlgroup = 0;
252			if (rtlphy->current_chan_bw ==
253			    HT_CHANNEL_WIDTH_20_40) {
254				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
255					"customer's limit, 40MHzrf(%c) = 0x%x\n",
256					rf == 0 ? 'A' : 'B',
257					rtlefuse->pwrgroup_ht40[rf]
258					[channel - 1]);
259			} else {
260				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
261					"customer's limit, 20MHz rf(%c) = 0x%x\n",
262					rf == 0 ? 'A' : 'B',
263					rtlefuse->pwrgroup_ht20[rf]
264					[channel - 1]);
265			}
266			for (i = 0; i < 4; i++) {
267				pwr_diff_limit[i] = (u8) ((rtlphy->mcs_offset
268				    [chnlgroup][index + (rf ? 8 : 0)]
269				    & (0x7f << (i * 8))) >> (i * 8));
270				if (rtlphy->current_chan_bw ==
271				    HT_CHANNEL_WIDTH_20_40) {
272					if (pwr_diff_limit[i] >
273					    rtlefuse->pwrgroup_ht40[rf]
274						[channel - 1])
275						pwr_diff_limit[i] = rtlefuse->
276						    pwrgroup_ht40[rf]
277						    [channel - 1];
278				} else {
279					if (pwr_diff_limit[i] >
280					    rtlefuse->pwrgroup_ht20[rf]
281						[channel - 1])
282						pwr_diff_limit[i] =
283						    rtlefuse->pwrgroup_ht20[rf]
284						    [channel - 1];
285				}
286			}
287			customer_limit = (pwr_diff_limit[3] << 24) |
288			    (pwr_diff_limit[2] << 16) |
289			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
290			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
291				"Customer's limit rf(%c) = 0x%x\n",
292				rf == 0 ? 'A' : 'B', customer_limit);
293			writeVal = customer_limit + ((index < 2) ?
294				   powerBase0[rf] : powerBase1[rf]);
295			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
296				"Customer, writeVal rf(%c)= 0x%x\n",
297				rf == 0 ? 'A' : 'B', writeVal);
298			break;
299		default:
300			chnlgroup = 0;
301			writeVal = rtlphy->mcs_offset[chnlgroup]
302				   [index + (rf ? 8 : 0)] + ((index < 2) ?
303				   powerBase0[rf] : powerBase1[rf]);
304			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
305				"RTK better performance, writeValrf(%c) = 0x%x\n",
306				rf == 0 ? 'A' : 'B', writeVal);
307			break;
308		}
309		if (rtlpriv->dm.dynamic_txhighpower_lvl ==
310		    TXHIGHPWRLEVEL_LEVEL1)
311			writeVal = 0x14141414;
312		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
313			 TXHIGHPWRLEVEL_LEVEL2)
314			writeVal = 0x00000000;
315		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
316			writeVal = writeVal - 0x06060606;
317		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
318			 TXHIGHPWRLEVEL_BT2)
319			writeVal = writeVal;
320		*(p_outwriteval + rf) = writeVal;
321	}
322}
323
324static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
325					 u8 index, u32 *pValue)
326{
327	struct rtl_priv *rtlpriv = rtl_priv(hw);
328	struct rtl_phy *rtlphy = &(rtlpriv->phy);
329	u16 regoffset_a[6] = {
330		RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
331		RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
332		RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
333	};
334	u16 regoffset_b[6] = {
335		RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
336		RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
337		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
338	};
339	u8 i, rf, pwr_val[4];
340	u32 writeVal;
341	u16 regoffset;
342
343	for (rf = 0; rf < 2; rf++) {
344		writeVal = pValue[rf];
345		for (i = 0; i < 4; i++) {
346			pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >>
347					  (i * 8));
348			if (pwr_val[i] > RF6052_MAX_TX_PWR)
349				pwr_val[i] = RF6052_MAX_TX_PWR;
350		}
351		writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
352		    (pwr_val[1] << 8) | pwr_val[0];
353		if (rf == 0)
354			regoffset = regoffset_a[index];
355		else
356			regoffset = regoffset_b[index];
357		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal);
358		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
359			"Set 0x%x = %08x\n", regoffset, writeVal);
360		if (((get_rf_type(rtlphy) == RF_2T2R) &&
361		     (regoffset == RTXAGC_A_MCS15_MCS12 ||
362		      regoffset == RTXAGC_B_MCS15_MCS12)) ||
363		    ((get_rf_type(rtlphy) != RF_2T2R) &&
364		     (regoffset == RTXAGC_A_MCS07_MCS04 ||
365		      regoffset == RTXAGC_B_MCS07_MCS04))) {
366			writeVal = pwr_val[3];
367			if (regoffset == RTXAGC_A_MCS15_MCS12 ||
368			    regoffset == RTXAGC_A_MCS07_MCS04)
369				regoffset = 0xc90;
370			if (regoffset == RTXAGC_B_MCS15_MCS12 ||
371			    regoffset == RTXAGC_B_MCS07_MCS04)
372				regoffset = 0xc98;
373			for (i = 0; i < 3; i++) {
374				if (i != 2)
375					writeVal = (writeVal > 8) ?
376						   (writeVal - 8) : 0;
377				else
378					writeVal = (writeVal > 6) ?
379						   (writeVal - 6) : 0;
380				rtl_write_byte(rtlpriv, (u32)(regoffset + i),
381					      (u8)writeVal);
382			}
383		}
384	}
385}
386
387void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
388					 u8 *ppowerlevel, u8 channel)
389{
390	u32 writeVal[2], powerBase0[2], powerBase1[2];
391	u8 index = 0;
392
393	rtl92c_phy_get_power_base(hw, ppowerlevel,
394				  channel, &powerBase0[0], &powerBase1[0]);
395	for (index = 0; index < 6; index++) {
396		_rtl92c_get_txpower_writeval_by_regulatory(hw,
397							   channel, index,
398							   &powerBase0[0],
399							   &powerBase1[0],
400							   &writeVal[0]);
401		_rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]);
402	}
403}
404
405bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw)
406{
407	struct rtl_priv *rtlpriv = rtl_priv(hw);
408	struct rtl_phy *rtlphy = &(rtlpriv->phy);
409	bool rtstatus = true;
410	u8 b_reg_hwparafile = 1;
411
412	if (rtlphy->rf_type == RF_1T1R)
413		rtlphy->num_total_rfpath = 1;
414	else
415		rtlphy->num_total_rfpath = 2;
416	if (b_reg_hwparafile == 1)
417		rtstatus = _rtl92c_phy_rf6052_config_parafile(hw);
418	return rtstatus;
419}
420
421static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
422{
423	struct rtl_priv *rtlpriv = rtl_priv(hw);
424	struct rtl_phy *rtlphy = &(rtlpriv->phy);
425	u32 u4_regvalue = 0;
426	u8 rfpath;
427	bool rtstatus = true;
428	struct bb_reg_def *pphyreg;
429
430	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
431		pphyreg = &rtlphy->phyreg_def[rfpath];
432		switch (rfpath) {
433		case RF90_PATH_A:
434		case RF90_PATH_C:
435			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
436						    BRFSI_RFENV);
437			break;
438		case RF90_PATH_B:
439		case RF90_PATH_D:
440			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
441						    BRFSI_RFENV << 16);
442			break;
443		}
444		rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
445		udelay(1);
446		rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
447		udelay(1);
448		rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
449			      B3WIREADDREAALENGTH, 0x0);
450		udelay(1);
451		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
452		udelay(1);
453		switch (rfpath) {
454		case RF90_PATH_A:
455			rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
456					(enum radio_path) rfpath);
457			break;
458		case RF90_PATH_B:
459			rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
460					(enum radio_path) rfpath);
461			break;
462		case RF90_PATH_C:
463			break;
464		case RF90_PATH_D:
465			break;
466		}
467		switch (rfpath) {
468		case RF90_PATH_A:
469		case RF90_PATH_C:
470			rtl_set_bbreg(hw, pphyreg->rfintfs,
471				      BRFSI_RFENV, u4_regvalue);
472			break;
473		case RF90_PATH_B:
474		case RF90_PATH_D:
475			rtl_set_bbreg(hw, pphyreg->rfintfs,
476				      BRFSI_RFENV << 16, u4_regvalue);
477			break;
478		}
479		if (!rtstatus) {
480			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
481				 "Radio[%d] Fail!!", rfpath);
482			goto phy_rf_cfg_fail;
483		}
484	}
485	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");
486	return rtstatus;
487phy_rf_cfg_fail:
488	return rtstatus;
489}
490