1/******************************************************************************
2 *
3 * Copyright(c) 2009-2010  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 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
16 *
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
21 *
22 * Larry Finger <Larry.Finger@lwfinger.net>
23 *
24 *****************************************************************************/
25
26#include "../wifi.h"
27#include "reg.h"
28#include "def.h"
29#include "phy.h"
30#include "rf.h"
31#include "dm.h"
32
33static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
34
35void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
36{
37	struct rtl_priv *rtlpriv = rtl_priv(hw);
38
39	switch (bandwidth) {
40	case HT_CHANNEL_WIDTH_20:
41		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 3);
42		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 3);
43		break;
44	case HT_CHANNEL_WIDTH_20_40:
45		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 1);
46		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 1);
47		break;
48	case HT_CHANNEL_WIDTH_80:
49		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 0);
50		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 0);
51		break;
52	default:
53		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
54			 "unknown bandwidth: %#X\n", bandwidth);
55		break;
56	}
57}
58
59void rtl8821ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
60					  u8 *ppowerlevel)
61{
62	struct rtl_priv *rtlpriv = rtl_priv(hw);
63	struct rtl_phy *rtlphy = &rtlpriv->phy;
64	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
65	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
66	u32 tx_agc[2] = {0, 0}, tmpval;
67	bool turbo_scanoff = false;
68	u8 idx1, idx2;
69	u8 *ptr;
70	u8 direction;
71	u32 pwrtrac_value;
72
73	if (rtlefuse->eeprom_regulatory != 0)
74		turbo_scanoff = true;
75
76	if (mac->act_scanning) {
77		tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
78		tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
79
80		if (turbo_scanoff) {
81			for (idx1 = RF90_PATH_A;
82				idx1 <= RF90_PATH_B;
83				idx1++) {
84				tx_agc[idx1] = ppowerlevel[idx1] |
85				    (ppowerlevel[idx1] << 8) |
86				    (ppowerlevel[idx1] << 16) |
87				    (ppowerlevel[idx1] << 24);
88			}
89		}
90	} else {
91		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
92			tx_agc[idx1] = ppowerlevel[idx1] |
93			    (ppowerlevel[idx1] << 8) |
94			    (ppowerlevel[idx1] << 16) |
95			    (ppowerlevel[idx1] << 24);
96		}
97
98		if (rtlefuse->eeprom_regulatory == 0) {
99			tmpval =
100			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
101			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
102			     8);
103			tx_agc[RF90_PATH_A] += tmpval;
104
105			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
106			    (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
107			     24);
108			tx_agc[RF90_PATH_B] += tmpval;
109		}
110	}
111
112	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
113		ptr = (u8 *)(&tx_agc[idx1]);
114		for (idx2 = 0; idx2 < 4; idx2++) {
115			if (*ptr > RF6052_MAX_TX_PWR)
116				*ptr = RF6052_MAX_TX_PWR;
117			ptr++;
118		}
119	}
120	rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
121	if (direction == 1) {
122		tx_agc[0] += pwrtrac_value;
123		tx_agc[1] += pwrtrac_value;
124	} else if (direction == 2) {
125		tx_agc[0] -= pwrtrac_value;
126		tx_agc[1] -= pwrtrac_value;
127	}
128	tmpval = tx_agc[RF90_PATH_A];
129	rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKDWORD, tmpval);
130
131	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
132		"CCK PWR 1~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
133		 RTXAGC_A_CCK11_CCK1);
134
135	tmpval = tx_agc[RF90_PATH_B];
136	rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKDWORD, tmpval);
137
138	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
139		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
140		 RTXAGC_B_CCK11_CCK1);
141}
142
143static void rtl8821ae_phy_get_power_base(struct ieee80211_hw *hw,
144					 u8 *ppowerlevel_ofdm,
145					 u8 *ppowerlevel_bw20,
146					 u8 *ppowerlevel_bw40, u8 channel,
147					 u32 *ofdmbase, u32 *mcsbase)
148{
149	struct rtl_priv *rtlpriv = rtl_priv(hw);
150	struct rtl_phy *rtlphy = &rtlpriv->phy;
151	u32 powerbase0, powerbase1;
152	u8 i, powerlevel[2];
153
154	for (i = 0; i < 2; i++) {
155		powerbase0 = ppowerlevel_ofdm[i];
156
157		powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
158		    (powerbase0 << 8) | powerbase0;
159		*(ofdmbase + i) = powerbase0;
160		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
161			" [OFDM power base index rf(%c) = 0x%x]\n",
162			 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
163	}
164
165	for (i = 0; i < 2; i++) {
166		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
167			powerlevel[i] = ppowerlevel_bw20[i];
168		else
169			powerlevel[i] = ppowerlevel_bw40[i];
170
171		powerbase1 = powerlevel[i];
172		powerbase1 = (powerbase1 << 24) |
173		    (powerbase1 << 16) | (powerbase1 << 8) | powerbase1;
174
175		*(mcsbase + i) = powerbase1;
176
177		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
178			" [MCS power base index rf(%c) = 0x%x]\n",
179			 ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
180	}
181}
182
183static void get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
184					       u8 channel, u8 index,
185					       u32 *powerbase0,
186					       u32 *powerbase1,
187					       u32 *p_outwriteval)
188{
189	struct rtl_priv *rtlpriv = rtl_priv(hw);
190	struct rtl_phy *rtlphy = &rtlpriv->phy;
191	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
192	u8 i, chnlgroup = 0, pwr_diff_limit[4], pwr_diff = 0, customer_pwr_diff;
193	u32 writeval, customer_limit, rf;
194
195	for (rf = 0; rf < 2; rf++) {
196		switch (rtlefuse->eeprom_regulatory) {
197		case 0:
198			chnlgroup = 0;
199
200			writeval =
201			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
202							(rf ? 8 : 0)]
203			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
204
205			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
206				"RTK better performance, writeval(%c) = 0x%x\n",
207				 ((rf == 0) ? 'A' : 'B'), writeval);
208			break;
209		case 1:
210			if (rtlphy->pwrgroup_cnt == 1) {
211				chnlgroup = 0;
212			} else {
213				if (channel < 3)
214					chnlgroup = 0;
215				else if (channel < 6)
216					chnlgroup = 1;
217				else if (channel < 9)
218					chnlgroup = 2;
219				else if (channel < 12)
220					chnlgroup = 3;
221				else if (channel < 14)
222					chnlgroup = 4;
223				else if (channel == 14)
224					chnlgroup = 5;
225			}
226
227			writeval =
228			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
229			    [index + (rf ? 8 : 0)] + ((index < 2) ?
230						      powerbase0[rf] :
231						      powerbase1[rf]);
232
233			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
234				"Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
235				 ((rf == 0) ? 'A' : 'B'), writeval);
236
237			break;
238		case 2:
239			writeval =
240			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
241
242			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
243				"Better regulatory, writeval(%c) = 0x%x\n",
244				 ((rf == 0) ? 'A' : 'B'), writeval);
245			break;
246		case 3:
247			chnlgroup = 0;
248
249			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
250				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
251					"customer's limit, 40MHz rf(%c) = 0x%x\n",
252					 ((rf == 0) ? 'A' : 'B'),
253					 rtlefuse->pwrgroup_ht40[rf][channel -
254								     1]);
255			} else {
256				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
257					"customer's limit, 20MHz rf(%c) = 0x%x\n",
258					 ((rf == 0) ? 'A' : 'B'),
259					 rtlefuse->pwrgroup_ht20[rf][channel -
260								     1]);
261			}
262
263			if (index < 2)
264				pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][channel-1];
265			else if (rtlphy->current_chan_bw ==  HT_CHANNEL_WIDTH_20)
266				pwr_diff =
267				  rtlefuse->txpwr_ht20diff[rf][channel-1];
268
269			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
270				customer_pwr_diff =
271				  rtlefuse->pwrgroup_ht40[rf][channel-1];
272			else
273				customer_pwr_diff =
274				  rtlefuse->pwrgroup_ht20[rf][channel-1];
275
276			if (pwr_diff > customer_pwr_diff)
277				pwr_diff = 0;
278			else
279				pwr_diff = customer_pwr_diff - pwr_diff;
280
281			for (i = 0; i < 4; i++) {
282				pwr_diff_limit[i] =
283				    (u8)((rtlphy->mcs_txpwrlevel_origoffset
284				    [chnlgroup][index + (rf ? 8 : 0)] &
285				    (0x7f << (i * 8))) >> (i * 8));
286
287				if (pwr_diff_limit[i] > pwr_diff)
288					pwr_diff_limit[i] = pwr_diff;
289			}
290
291			customer_limit = (pwr_diff_limit[3] << 24) |
292			    (pwr_diff_limit[2] << 16) |
293			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
294
295			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
296				"Customer's limit rf(%c) = 0x%x\n",
297				 ((rf == 0) ? 'A' : 'B'), customer_limit);
298
299			writeval = customer_limit +
300			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
301
302			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
303				"Customer, writeval rf(%c)= 0x%x\n",
304				 ((rf == 0) ? 'A' : 'B'), writeval);
305			break;
306		default:
307			chnlgroup = 0;
308			writeval =
309			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
310			    [index + (rf ? 8 : 0)]
311			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
312
313			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
314				"RTK better performance, writeval rf(%c) = 0x%x\n",
315				 ((rf == 0) ? 'A' : 'B'), writeval);
316			break;
317		}
318
319		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
320			writeval = writeval - 0x06060606;
321		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
322			 TXHIGHPWRLEVEL_BT2)
323			writeval = writeval - 0x0c0c0c0c;
324		*(p_outwriteval + rf) = writeval;
325	}
326}
327
328static void _rtl8821ae_write_ofdm_power_reg(struct ieee80211_hw *hw,
329					    u8 index, u32 *pvalue)
330{
331	struct rtl_priv *rtlpriv = rtl_priv(hw);
332	u16 regoffset_a[6] = {
333		RTXAGC_A_OFDM18_OFDM6, RTXAGC_A_OFDM54_OFDM24,
334		RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
335		RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
336	};
337	u16 regoffset_b[6] = {
338		RTXAGC_B_OFDM18_OFDM6, RTXAGC_B_OFDM54_OFDM24,
339		RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
340		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
341	};
342	u8 i, rf, pwr_val[4];
343	u32 writeval;
344	u16 regoffset;
345
346	for (rf = 0; rf < 2; rf++) {
347		writeval = pvalue[rf];
348		for (i = 0; i < 4; i++) {
349			pwr_val[i] = (u8)((writeval & (0x7f <<
350							(i * 8))) >> (i * 8));
351
352			if (pwr_val[i] > RF6052_MAX_TX_PWR)
353				pwr_val[i] = RF6052_MAX_TX_PWR;
354		}
355		writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
356		    (pwr_val[1] << 8) | pwr_val[0];
357
358		if (rf == 0)
359			regoffset = regoffset_a[index];
360		else
361			regoffset = regoffset_b[index];
362		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
363
364		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
365			"Set 0x%x = %08x\n", regoffset, writeval);
366	}
367}
368
369void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
370					   u8 *ppowerlevel_ofdm,
371					   u8 *ppowerlevel_bw20,
372					   u8 *ppowerlevel_bw40,
373					   u8 channel)
374{
375	u32 writeval[2], powerbase0[2], powerbase1[2];
376	u8 index;
377	u8 direction;
378	u32 pwrtrac_value;
379
380	rtl8821ae_phy_get_power_base(hw, ppowerlevel_ofdm,
381				     ppowerlevel_bw20,
382				     ppowerlevel_bw40,
383				     channel,
384				     &powerbase0[0],
385				     &powerbase1[0]);
386
387	rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
388
389	for (index = 0; index < 6; index++) {
390		get_txpower_writeval_by_regulatory(hw, channel, index,
391						   &powerbase0[0],
392						   &powerbase1[0],
393						   &writeval[0]);
394		if (direction == 1) {
395			writeval[0] += pwrtrac_value;
396			writeval[1] += pwrtrac_value;
397		} else if (direction == 2) {
398			writeval[0] -= pwrtrac_value;
399			writeval[1] -= pwrtrac_value;
400		}
401		_rtl8821ae_write_ofdm_power_reg(hw, index, &writeval[0]);
402	}
403}
404
405bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw)
406{
407	struct rtl_priv *rtlpriv = rtl_priv(hw);
408	struct rtl_phy *rtlphy = &rtlpriv->phy;
409
410	if (rtlphy->rf_type == RF_1T1R)
411		rtlphy->num_total_rfpath = 1;
412	else
413		rtlphy->num_total_rfpath = 2;
414
415	return _rtl8821ae_phy_rf6052_config_parafile(hw);
416}
417
418static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
419{
420	struct rtl_priv *rtlpriv = rtl_priv(hw);
421	struct rtl_phy *rtlphy = &rtlpriv->phy;
422	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
423	u8 rfpath;
424	bool rtstatus = true;
425
426	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
427		switch (rfpath) {
428		case RF90_PATH_A: {
429			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
430				rtstatus =
431				  rtl8812ae_phy_config_rf_with_headerfile(hw,
432							(enum radio_path)rfpath);
433			else
434				rtstatus =
435				  rtl8821ae_phy_config_rf_with_headerfile(hw,
436							(enum radio_path)rfpath);
437			break;
438			}
439		case RF90_PATH_B:
440			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
441				rtstatus =
442				  rtl8812ae_phy_config_rf_with_headerfile(hw,
443							(enum radio_path)rfpath);
444			else
445				rtstatus =
446				  rtl8821ae_phy_config_rf_with_headerfile(hw,
447							(enum radio_path)rfpath);
448			break;
449		case RF90_PATH_C:
450			break;
451		case RF90_PATH_D:
452			break;
453		}
454
455		if (!rtstatus) {
456			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
457				 "Radio[%d] Fail!!", rfpath);
458			return false;
459		}
460	}
461
462	/*put arrays in dm.c*/
463	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
464	return rtstatus;
465}
466