xref: /linux/drivers/net/wireless/realtek/rtl8xxxu/8188e.c (revision 1260ed77798502de9c98020040d2995008de10cc)
13dfb8e84SJes Sorensen // SPDX-License-Identifier: GPL-2.0-only
23dfb8e84SJes Sorensen /*
33dfb8e84SJes Sorensen  * RTL8XXXU mac80211 USB driver - 8188e specific subdriver
43dfb8e84SJes Sorensen  *
53dfb8e84SJes Sorensen  * Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@gmail.com>
63dfb8e84SJes Sorensen  *
73dfb8e84SJes Sorensen  * Portions, notably calibration code:
83dfb8e84SJes Sorensen  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
93dfb8e84SJes Sorensen  *
103dfb8e84SJes Sorensen  * This driver was written as a replacement for the vendor provided
113dfb8e84SJes Sorensen  * rtl8723au driver. As the Realtek 8xxx chips are very similar in
123dfb8e84SJes Sorensen  * their programming interface, I have started adding support for
133dfb8e84SJes Sorensen  * additional 8xxx chips like the 8192cu, 8188cus, etc.
143dfb8e84SJes Sorensen  */
153dfb8e84SJes Sorensen 
16028fa281SKalle Valo #include "regs.h"
17949f6f3aSPing-Ke Shih #include "rtl8xxxu.h"
183dfb8e84SJes Sorensen 
193dfb8e84SJes Sorensen static const struct rtl8xxxu_reg8val rtl8188e_mac_init_table[] = {
203dfb8e84SJes Sorensen 	{0x026, 0x41}, {0x027, 0x35}, {0x040, 0x00}, {0x421, 0x0f},
213dfb8e84SJes Sorensen 	{0x428, 0x0a}, {0x429, 0x10}, {0x430, 0x00}, {0x431, 0x01},
223dfb8e84SJes Sorensen 	{0x432, 0x02}, {0x433, 0x04}, {0x434, 0x05}, {0x435, 0x06},
233dfb8e84SJes Sorensen 	{0x436, 0x07}, {0x437, 0x08}, {0x438, 0x00}, {0x439, 0x00},
243dfb8e84SJes Sorensen 	{0x43a, 0x01}, {0x43b, 0x02}, {0x43c, 0x04}, {0x43d, 0x05},
253dfb8e84SJes Sorensen 	{0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01},
263dfb8e84SJes Sorensen 	{0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f},
273dfb8e84SJes Sorensen 	{0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72},
283dfb8e84SJes Sorensen 	{0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x480, 0x08},
293dfb8e84SJes Sorensen 	{0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff}, {0x4cd, 0xff},
303dfb8e84SJes Sorensen 	{0x4ce, 0x01}, {0x4d3, 0x01}, {0x500, 0x26}, {0x501, 0xa2},
313dfb8e84SJes Sorensen 	{0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3},
323dfb8e84SJes Sorensen 	{0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4},
333dfb8e84SJes Sorensen 	{0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4},
343dfb8e84SJes Sorensen 	{0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a},
353dfb8e84SJes Sorensen 	{0x516, 0x0a}, {0x525, 0x4f}, {0x550, 0x10}, {0x551, 0x10},
363dfb8e84SJes Sorensen 	{0x559, 0x02}, {0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e},
373dfb8e84SJes Sorensen 	{0x609, 0x2a}, {0x620, 0xff}, {0x621, 0xff}, {0x622, 0xff},
383dfb8e84SJes Sorensen 	{0x623, 0xff}, {0x624, 0xff}, {0x625, 0xff}, {0x626, 0xff},
393dfb8e84SJes Sorensen 	{0x627, 0xff}, {0x63c, 0x08}, {0x63d, 0x08}, {0x63e, 0x0c},
403dfb8e84SJes Sorensen 	{0x63f, 0x0c}, {0x640, 0x40}, {0x652, 0x20}, {0x66e, 0x05},
413dfb8e84SJes Sorensen 	{0x700, 0x21}, {0x701, 0x43}, {0x702, 0x65}, {0x703, 0x87},
423dfb8e84SJes Sorensen 	{0x708, 0x21}, {0x709, 0x43}, {0x70a, 0x65}, {0x70b, 0x87},
433dfb8e84SJes Sorensen 	{0xffff, 0xff},
443dfb8e84SJes Sorensen };
453dfb8e84SJes Sorensen 
463dfb8e84SJes Sorensen static const struct rtl8xxxu_reg32val rtl8188eu_phy_init_table[] = {
473dfb8e84SJes Sorensen 	{0x800, 0x80040000}, {0x804, 0x00000003},
483dfb8e84SJes Sorensen 	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
493dfb8e84SJes Sorensen 	{0x810, 0x10001331}, {0x814, 0x020c3d10},
503dfb8e84SJes Sorensen 	{0x818, 0x02200385}, {0x81c, 0x00000000},
513dfb8e84SJes Sorensen 	{0x820, 0x01000100}, {0x824, 0x00390204},
523dfb8e84SJes Sorensen 	{0x828, 0x00000000}, {0x82c, 0x00000000},
533dfb8e84SJes Sorensen 	{0x830, 0x00000000}, {0x834, 0x00000000},
543dfb8e84SJes Sorensen 	{0x838, 0x00000000}, {0x83c, 0x00000000},
553dfb8e84SJes Sorensen 	{0x840, 0x00010000}, {0x844, 0x00000000},
563dfb8e84SJes Sorensen 	{0x848, 0x00000000}, {0x84c, 0x00000000},
573dfb8e84SJes Sorensen 	{0x850, 0x00000000}, {0x854, 0x00000000},
583dfb8e84SJes Sorensen 	{0x858, 0x569a11a9}, {0x85c, 0x01000014},
593dfb8e84SJes Sorensen 	{0x860, 0x66f60110}, {0x864, 0x061f0649},
603dfb8e84SJes Sorensen 	{0x868, 0x00000000}, {0x86c, 0x27272700},
613dfb8e84SJes Sorensen 	{0x870, 0x07000760}, {0x874, 0x25004000},
623dfb8e84SJes Sorensen 	{0x878, 0x00000808}, {0x87c, 0x00000000},
633dfb8e84SJes Sorensen 	{0x880, 0xb0000c1c}, {0x884, 0x00000001},
643dfb8e84SJes Sorensen 	{0x888, 0x00000000}, {0x88c, 0xccc000c0},
653dfb8e84SJes Sorensen 	{0x890, 0x00000800}, {0x894, 0xfffffffe},
663dfb8e84SJes Sorensen 	{0x898, 0x40302010}, {0x89c, 0x00706050},
673dfb8e84SJes Sorensen 	{0x900, 0x00000000}, {0x904, 0x00000023},
683dfb8e84SJes Sorensen 	{0x908, 0x00000000}, {0x90c, 0x81121111},
693dfb8e84SJes Sorensen 	{0x910, 0x00000002}, {0x914, 0x00000201},
703dfb8e84SJes Sorensen 	{0xa00, 0x00d047c8}, {0xa04, 0x80ff800c},
713dfb8e84SJes Sorensen 	{0xa08, 0x8c838300}, {0xa0c, 0x2e7f120f},
723dfb8e84SJes Sorensen 	{0xa10, 0x9500bb7e}, {0xa14, 0x1114d028},
733dfb8e84SJes Sorensen 	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
743dfb8e84SJes Sorensen 	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
753dfb8e84SJes Sorensen 	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
763dfb8e84SJes Sorensen 	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
773dfb8e84SJes Sorensen 	{0xa78, 0x00000900}, {0xa7c, 0x225b0606},
783dfb8e84SJes Sorensen 	{0xa80, 0x218075b1}, {0xb2c, 0x80000000},
793dfb8e84SJes Sorensen 	{0xc00, 0x48071d40}, {0xc04, 0x03a05611},
803dfb8e84SJes Sorensen 	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
813dfb8e84SJes Sorensen 	{0xc10, 0x08800000}, {0xc14, 0x40000100},
823dfb8e84SJes Sorensen 	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
833dfb8e84SJes Sorensen 	{0xc20, 0x00000000}, {0xc24, 0x00000000},
843dfb8e84SJes Sorensen 	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
853dfb8e84SJes Sorensen 	{0xc30, 0x69e9ac47}, {0xc34, 0x469652af},
863dfb8e84SJes Sorensen 	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
873dfb8e84SJes Sorensen 	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
883dfb8e84SJes Sorensen 	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
893dfb8e84SJes Sorensen 	{0xc50, 0x69553420}, {0xc54, 0x43bc0094},
903dfb8e84SJes Sorensen 	{0xc58, 0x00013169}, {0xc5c, 0x00250492},
913dfb8e84SJes Sorensen 	{0xc60, 0x00000000}, {0xc64, 0x7112848b},
923dfb8e84SJes Sorensen 	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
933dfb8e84SJes Sorensen 	{0xc70, 0x2c7f000d}, {0xc74, 0x020610db},
943dfb8e84SJes Sorensen 	{0xc78, 0x0000001f}, {0xc7c, 0x00b91612},
953dfb8e84SJes Sorensen 	{0xc80, 0x390000e4}, {0xc84, 0x21f60000},
963dfb8e84SJes Sorensen 	{0xc88, 0x40000100}, {0xc8c, 0x20200000},
973dfb8e84SJes Sorensen 	{0xc90, 0x00091521}, {0xc94, 0x00000000},
983dfb8e84SJes Sorensen 	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
993dfb8e84SJes Sorensen 	{0xca0, 0x00000000}, {0xca4, 0x000300a0},
1003dfb8e84SJes Sorensen 	{0xca8, 0x00000000}, {0xcac, 0x00000000},
1013dfb8e84SJes Sorensen 	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
1023dfb8e84SJes Sorensen 	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
1033dfb8e84SJes Sorensen 	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
1043dfb8e84SJes Sorensen 	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
1053dfb8e84SJes Sorensen 	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
1063dfb8e84SJes Sorensen 	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
1073dfb8e84SJes Sorensen 	{0xce0, 0x00222222}, {0xce4, 0x00000000},
1083dfb8e84SJes Sorensen 	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
1093dfb8e84SJes Sorensen 	{0xd00, 0x00000740}, {0xd04, 0x00020401},
1103dfb8e84SJes Sorensen 	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
1113dfb8e84SJes Sorensen 	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
1123dfb8e84SJes Sorensen 	{0xd18, 0x7a8f5b6f}, {0xd2c, 0xcc979975},
1133dfb8e84SJes Sorensen 	{0xd30, 0x00000000}, {0xd34, 0x80608000},
1143dfb8e84SJes Sorensen 	{0xd38, 0x00000000}, {0xd3c, 0x00127353},
1153dfb8e84SJes Sorensen 	{0xd40, 0x00000000}, {0xd44, 0x00000000},
1163dfb8e84SJes Sorensen 	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
1173dfb8e84SJes Sorensen 	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
1183dfb8e84SJes Sorensen 	{0xd58, 0x00000282}, {0xd5c, 0x30032064},
1193dfb8e84SJes Sorensen 	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
1203dfb8e84SJes Sorensen 	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
1213dfb8e84SJes Sorensen 	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
1223dfb8e84SJes Sorensen 	{0xd78, 0x000e3c24}, {0xe00, 0x2d2d2d2d},
1233dfb8e84SJes Sorensen 	{0xe04, 0x2d2d2d2d}, {0xe08, 0x0390272d},
1243dfb8e84SJes Sorensen 	{0xe10, 0x2d2d2d2d}, {0xe14, 0x2d2d2d2d},
1253dfb8e84SJes Sorensen 	{0xe18, 0x2d2d2d2d}, {0xe1c, 0x2d2d2d2d},
1263dfb8e84SJes Sorensen 	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
1273dfb8e84SJes Sorensen 	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
1283dfb8e84SJes Sorensen 	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
1293dfb8e84SJes Sorensen 	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
1303dfb8e84SJes Sorensen 	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
1313dfb8e84SJes Sorensen 	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
1323dfb8e84SJes Sorensen 	{0xe5c, 0x28160d05}, {0xe60, 0x00000048},
1333dfb8e84SJes Sorensen 	{0xe68, 0x001b25a4}, {0xe6c, 0x00c00014},
1343dfb8e84SJes Sorensen 	{0xe70, 0x00c00014}, {0xe74, 0x01000014},
1353dfb8e84SJes Sorensen 	{0xe78, 0x01000014}, {0xe7c, 0x01000014},
1363dfb8e84SJes Sorensen 	{0xe80, 0x01000014}, {0xe84, 0x00c00014},
1373dfb8e84SJes Sorensen 	{0xe88, 0x01000014}, {0xe8c, 0x00c00014},
1383dfb8e84SJes Sorensen 	{0xed0, 0x00c00014}, {0xed4, 0x00c00014},
1393dfb8e84SJes Sorensen 	{0xed8, 0x00c00014}, {0xedc, 0x00000014},
1403dfb8e84SJes Sorensen 	{0xee0, 0x00000014}, {0xee8, 0x21555448},
1413dfb8e84SJes Sorensen 	{0xeec, 0x01c00014}, {0xf14, 0x00000003},
1423dfb8e84SJes Sorensen 	{0xf4c, 0x00000000}, {0xf00, 0x00000300},
1433dfb8e84SJes Sorensen 	{0xffff, 0xffffffff},
1443dfb8e84SJes Sorensen };
1453dfb8e84SJes Sorensen 
1463dfb8e84SJes Sorensen static const struct rtl8xxxu_reg32val rtl8188e_agc_table[] = {
1473dfb8e84SJes Sorensen 	{0xc78, 0xfb000001}, {0xc78, 0xfb010001},
1483dfb8e84SJes Sorensen 	{0xc78, 0xfb020001}, {0xc78, 0xfb030001},
1493dfb8e84SJes Sorensen 	{0xc78, 0xfb040001}, {0xc78, 0xfb050001},
1503dfb8e84SJes Sorensen 	{0xc78, 0xfa060001}, {0xc78, 0xf9070001},
1513dfb8e84SJes Sorensen 	{0xc78, 0xf8080001}, {0xc78, 0xf7090001},
1523dfb8e84SJes Sorensen 	{0xc78, 0xf60a0001}, {0xc78, 0xf50b0001},
1533dfb8e84SJes Sorensen 	{0xc78, 0xf40c0001}, {0xc78, 0xf30d0001},
1543dfb8e84SJes Sorensen 	{0xc78, 0xf20e0001}, {0xc78, 0xf10f0001},
1553dfb8e84SJes Sorensen 	{0xc78, 0xf0100001}, {0xc78, 0xef110001},
1563dfb8e84SJes Sorensen 	{0xc78, 0xee120001}, {0xc78, 0xed130001},
1573dfb8e84SJes Sorensen 	{0xc78, 0xec140001}, {0xc78, 0xeb150001},
1583dfb8e84SJes Sorensen 	{0xc78, 0xea160001}, {0xc78, 0xe9170001},
1593dfb8e84SJes Sorensen 	{0xc78, 0xe8180001}, {0xc78, 0xe7190001},
1603dfb8e84SJes Sorensen 	{0xc78, 0xe61a0001}, {0xc78, 0xe51b0001},
1613dfb8e84SJes Sorensen 	{0xc78, 0xe41c0001}, {0xc78, 0xe31d0001},
1623dfb8e84SJes Sorensen 	{0xc78, 0xe21e0001}, {0xc78, 0xe11f0001},
1633dfb8e84SJes Sorensen 	{0xc78, 0x8a200001}, {0xc78, 0x89210001},
1643dfb8e84SJes Sorensen 	{0xc78, 0x88220001}, {0xc78, 0x87230001},
1653dfb8e84SJes Sorensen 	{0xc78, 0x86240001}, {0xc78, 0x85250001},
1663dfb8e84SJes Sorensen 	{0xc78, 0x84260001}, {0xc78, 0x83270001},
1673dfb8e84SJes Sorensen 	{0xc78, 0x82280001}, {0xc78, 0x6b290001},
1683dfb8e84SJes Sorensen 	{0xc78, 0x6a2a0001}, {0xc78, 0x692b0001},
1693dfb8e84SJes Sorensen 	{0xc78, 0x682c0001}, {0xc78, 0x672d0001},
1703dfb8e84SJes Sorensen 	{0xc78, 0x662e0001}, {0xc78, 0x652f0001},
1713dfb8e84SJes Sorensen 	{0xc78, 0x64300001}, {0xc78, 0x63310001},
1723dfb8e84SJes Sorensen 	{0xc78, 0x62320001}, {0xc78, 0x61330001},
1733dfb8e84SJes Sorensen 	{0xc78, 0x46340001}, {0xc78, 0x45350001},
1743dfb8e84SJes Sorensen 	{0xc78, 0x44360001}, {0xc78, 0x43370001},
1753dfb8e84SJes Sorensen 	{0xc78, 0x42380001}, {0xc78, 0x41390001},
1763dfb8e84SJes Sorensen 	{0xc78, 0x403a0001}, {0xc78, 0x403b0001},
1773dfb8e84SJes Sorensen 	{0xc78, 0x403c0001}, {0xc78, 0x403d0001},
1783dfb8e84SJes Sorensen 	{0xc78, 0x403e0001}, {0xc78, 0x403f0001},
1793dfb8e84SJes Sorensen 	{0xc78, 0xfb400001}, {0xc78, 0xfb410001},
1803dfb8e84SJes Sorensen 	{0xc78, 0xfb420001}, {0xc78, 0xfb430001},
1813dfb8e84SJes Sorensen 	{0xc78, 0xfb440001}, {0xc78, 0xfb450001},
1823dfb8e84SJes Sorensen 	{0xc78, 0xfb460001}, {0xc78, 0xfb470001},
1833dfb8e84SJes Sorensen 	{0xc78, 0xfb480001}, {0xc78, 0xfa490001},
1843dfb8e84SJes Sorensen 	{0xc78, 0xf94a0001}, {0xc78, 0xf84b0001},
1853dfb8e84SJes Sorensen 	{0xc78, 0xf74c0001}, {0xc78, 0xf64d0001},
1863dfb8e84SJes Sorensen 	{0xc78, 0xf54e0001}, {0xc78, 0xf44f0001},
1873dfb8e84SJes Sorensen 	{0xc78, 0xf3500001}, {0xc78, 0xf2510001},
1883dfb8e84SJes Sorensen 	{0xc78, 0xf1520001}, {0xc78, 0xf0530001},
1893dfb8e84SJes Sorensen 	{0xc78, 0xef540001}, {0xc78, 0xee550001},
1903dfb8e84SJes Sorensen 	{0xc78, 0xed560001}, {0xc78, 0xec570001},
1913dfb8e84SJes Sorensen 	{0xc78, 0xeb580001}, {0xc78, 0xea590001},
1923dfb8e84SJes Sorensen 	{0xc78, 0xe95a0001}, {0xc78, 0xe85b0001},
1933dfb8e84SJes Sorensen 	{0xc78, 0xe75c0001}, {0xc78, 0xe65d0001},
1943dfb8e84SJes Sorensen 	{0xc78, 0xe55e0001}, {0xc78, 0xe45f0001},
1953dfb8e84SJes Sorensen 	{0xc78, 0xe3600001}, {0xc78, 0xe2610001},
1963dfb8e84SJes Sorensen 	{0xc78, 0xc3620001}, {0xc78, 0xc2630001},
1973dfb8e84SJes Sorensen 	{0xc78, 0xc1640001}, {0xc78, 0x8b650001},
1983dfb8e84SJes Sorensen 	{0xc78, 0x8a660001}, {0xc78, 0x89670001},
1993dfb8e84SJes Sorensen 	{0xc78, 0x88680001}, {0xc78, 0x87690001},
2003dfb8e84SJes Sorensen 	{0xc78, 0x866a0001}, {0xc78, 0x856b0001},
2013dfb8e84SJes Sorensen 	{0xc78, 0x846c0001}, {0xc78, 0x676d0001},
2023dfb8e84SJes Sorensen 	{0xc78, 0x666e0001}, {0xc78, 0x656f0001},
2033dfb8e84SJes Sorensen 	{0xc78, 0x64700001}, {0xc78, 0x63710001},
2043dfb8e84SJes Sorensen 	{0xc78, 0x62720001}, {0xc78, 0x61730001},
2053dfb8e84SJes Sorensen 	{0xc78, 0x60740001}, {0xc78, 0x46750001},
2063dfb8e84SJes Sorensen 	{0xc78, 0x45760001}, {0xc78, 0x44770001},
2073dfb8e84SJes Sorensen 	{0xc78, 0x43780001}, {0xc78, 0x42790001},
2083dfb8e84SJes Sorensen 	{0xc78, 0x417a0001}, {0xc78, 0x407b0001},
2093dfb8e84SJes Sorensen 	{0xc78, 0x407c0001}, {0xc78, 0x407d0001},
2103dfb8e84SJes Sorensen 	{0xc78, 0x407e0001}, {0xc78, 0x407f0001},
2113dfb8e84SJes Sorensen 	{0xc50, 0x69553422}, {0xc50, 0x69553420},
2123dfb8e84SJes Sorensen 	{0xffff, 0xffffffff}
2133dfb8e84SJes Sorensen };
2143dfb8e84SJes Sorensen 
2153dfb8e84SJes Sorensen static const struct rtl8xxxu_rfregval rtl8188eu_radioa_init_table[] = {
2163dfb8e84SJes Sorensen 	{0x00, 0x00030000}, {0x08, 0x00084000},
2173dfb8e84SJes Sorensen 	{0x18, 0x00000407}, {0x19, 0x00000012},
2183dfb8e84SJes Sorensen 	{0x1e, 0x00080009}, {0x1f, 0x00000880},
2193dfb8e84SJes Sorensen 	{0x2f, 0x0001a060}, {0x3f, 0x00000000},
2203dfb8e84SJes Sorensen 	{0x42, 0x000060c0}, {0x57, 0x000d0000},
2213dfb8e84SJes Sorensen 	{0x58, 0x000be180}, {0x67, 0x00001552},
2223dfb8e84SJes Sorensen 	{0x83, 0x00000000}, {0xb0, 0x000ff8fc},
2233dfb8e84SJes Sorensen 	{0xb1, 0x00054400}, {0xb2, 0x000ccc19},
2243dfb8e84SJes Sorensen 	{0xb4, 0x00043003}, {0xb6, 0x0004953e},
2253dfb8e84SJes Sorensen 	{0xb7, 0x0001c718}, {0xb8, 0x000060ff},
2263dfb8e84SJes Sorensen 	{0xb9, 0x00080001}, {0xba, 0x00040000},
2273dfb8e84SJes Sorensen 	{0xbb, 0x00000400}, {0xbf, 0x000c0000},
2283dfb8e84SJes Sorensen 	{0xc2, 0x00002400}, {0xc3, 0x00000009},
2293dfb8e84SJes Sorensen 	{0xc4, 0x00040c91}, {0xc5, 0x00099999},
2303dfb8e84SJes Sorensen 	{0xc6, 0x000000a3}, {0xc7, 0x00088820},
2313dfb8e84SJes Sorensen 	{0xc8, 0x00076c06}, {0xc9, 0x00000000},
2323dfb8e84SJes Sorensen 	{0xca, 0x00080000}, {0xdf, 0x00000180},
2333dfb8e84SJes Sorensen 	{0xef, 0x000001a0}, {0x51, 0x0006b27d},
2343dfb8e84SJes Sorensen 	{0x52, 0x0007e49d},	/* Set to 0x0007e4dd for SDIO */
2353dfb8e84SJes Sorensen 	{0x53, 0x00000073}, {0x56, 0x00051ff3},
2363dfb8e84SJes Sorensen 	{0x35, 0x00000086}, {0x35, 0x00000186},
2373dfb8e84SJes Sorensen 	{0x35, 0x00000286}, {0x36, 0x00001c25},
2383dfb8e84SJes Sorensen 	{0x36, 0x00009c25}, {0x36, 0x00011c25},
2393dfb8e84SJes Sorensen 	{0x36, 0x00019c25}, {0xb6, 0x00048538},
2403dfb8e84SJes Sorensen 	{0x18, 0x00000c07}, {0x5a, 0x0004bd00},
2413dfb8e84SJes Sorensen 	{0x19, 0x000739d0}, {0x34, 0x0000adf3},
2423dfb8e84SJes Sorensen 	{0x34, 0x00009df0}, {0x34, 0x00008ded},
2433dfb8e84SJes Sorensen 	{0x34, 0x00007dea}, {0x34, 0x00006de7},
2443dfb8e84SJes Sorensen 	{0x34, 0x000054ee}, {0x34, 0x000044eb},
2453dfb8e84SJes Sorensen 	{0x34, 0x000034e8}, {0x34, 0x0000246b},
2463dfb8e84SJes Sorensen 	{0x34, 0x00001468}, {0x34, 0x0000006d},
2473dfb8e84SJes Sorensen 	{0x00, 0x00030159}, {0x84, 0x00068200},
2483dfb8e84SJes Sorensen 	{0x86, 0x000000ce}, {0x87, 0x00048a00},
2493dfb8e84SJes Sorensen 	{0x8e, 0x00065540}, {0x8f, 0x00088000},
2503dfb8e84SJes Sorensen 	{0xef, 0x000020a0}, {0x3b, 0x000f02b0},
2513dfb8e84SJes Sorensen 	{0x3b, 0x000ef7b0}, {0x3b, 0x000d4fb0},
2523dfb8e84SJes Sorensen 	{0x3b, 0x000cf060}, {0x3b, 0x000b0090},
2533dfb8e84SJes Sorensen 	{0x3b, 0x000a0080}, {0x3b, 0x00090080},
2543dfb8e84SJes Sorensen 	{0x3b, 0x0008f780}, {0x3b, 0x000722b0},
2553dfb8e84SJes Sorensen 	{0x3b, 0x0006f7b0}, {0x3b, 0x00054fb0},
2563dfb8e84SJes Sorensen 	{0x3b, 0x0004f060}, {0x3b, 0x00030090},
2573dfb8e84SJes Sorensen 	{0x3b, 0x00020080}, {0x3b, 0x00010080},
2583dfb8e84SJes Sorensen 	{0x3b, 0x0000f780}, {0xef, 0x000000a0},
2593dfb8e84SJes Sorensen 	{0x00, 0x00010159}, {0x18, 0x0000f407},
2603dfb8e84SJes Sorensen 	{0xFE, 0x00000000}, {0xFE, 0x00000000},
2613dfb8e84SJes Sorensen 	{0x1F, 0x00080003}, {0xFE, 0x00000000},
2623dfb8e84SJes Sorensen 	{0xFE, 0x00000000}, {0x1E, 0x00000001},
2633dfb8e84SJes Sorensen 	{0x1F, 0x00080000}, {0x00, 0x00033e60},
2643dfb8e84SJes Sorensen 	{0xff, 0xffffffff}
2653dfb8e84SJes Sorensen };
2663dfb8e84SJes Sorensen 
2678b9754b2SBitterblue Smith #define PERENTRY		23
2688b9754b2SBitterblue Smith #define RETRYSIZE		5
2698b9754b2SBitterblue Smith #define RATESIZE		28
2708b9754b2SBitterblue Smith #define TX_RPT2_ITEM_SIZE	8
2718b9754b2SBitterblue Smith 
2728b9754b2SBitterblue Smith static const u8 retry_penalty[PERENTRY][RETRYSIZE + 1] = {
2738b9754b2SBitterblue Smith 	{5, 4, 3, 2, 0, 3}, /* 92 , idx=0 */
2748b9754b2SBitterblue Smith 	{6, 5, 4, 3, 0, 4}, /* 86 , idx=1 */
2758b9754b2SBitterblue Smith 	{6, 5, 4, 2, 0, 4}, /* 81 , idx=2 */
2768b9754b2SBitterblue Smith 	{8, 7, 6, 4, 0, 6}, /* 75 , idx=3 */
2778b9754b2SBitterblue Smith 	{10, 9, 8, 6, 0, 8}, /* 71 , idx=4 */
2788b9754b2SBitterblue Smith 	{10, 9, 8, 4, 0, 8}, /* 66 , idx=5 */
2798b9754b2SBitterblue Smith 	{10, 9, 8, 2, 0, 8}, /* 62 , idx=6 */
2808b9754b2SBitterblue Smith 	{10, 9, 8, 0, 0, 8}, /* 59 , idx=7 */
2818b9754b2SBitterblue Smith 	{18, 17, 16, 8, 0, 16}, /* 53 , idx=8 */
2828b9754b2SBitterblue Smith 	{26, 25, 24, 16, 0, 24}, /* 50 , idx=9 */
2838b9754b2SBitterblue Smith 	{34, 33, 32, 24, 0, 32}, /* 47 , idx=0x0a */
2848b9754b2SBitterblue Smith 	{34, 31, 28, 20, 0, 32}, /* 43 , idx=0x0b */
2858b9754b2SBitterblue Smith 	{34, 31, 27, 18, 0, 32}, /* 40 , idx=0x0c */
2868b9754b2SBitterblue Smith 	{34, 31, 26, 16, 0, 32}, /* 37 , idx=0x0d */
2878b9754b2SBitterblue Smith 	{34, 30, 22, 16, 0, 32}, /* 32 , idx=0x0e */
2888b9754b2SBitterblue Smith 	{34, 30, 24, 16, 0, 32}, /* 26 , idx=0x0f */
2898b9754b2SBitterblue Smith 	{49, 46, 40, 16, 0, 48}, /* 20 , idx=0x10 */
2908b9754b2SBitterblue Smith 	{49, 45, 32, 0, 0, 48}, /* 17 , idx=0x11 */
2918b9754b2SBitterblue Smith 	{49, 45, 22, 18, 0, 48}, /* 15 , idx=0x12 */
2928b9754b2SBitterblue Smith 	{49, 40, 24, 16, 0, 48}, /* 12 , idx=0x13 */
2938b9754b2SBitterblue Smith 	{49, 32, 18, 12, 0, 48}, /* 9 , idx=0x14 */
2948b9754b2SBitterblue Smith 	{49, 22, 18, 14, 0, 48}, /* 6 , idx=0x15 */
2958b9754b2SBitterblue Smith 	{49, 16, 16, 0, 0, 48} /* 3, idx=0x16 */
2968b9754b2SBitterblue Smith };
2978b9754b2SBitterblue Smith 
2988b9754b2SBitterblue Smith static const u8 pt_penalty[RETRYSIZE + 1] = {34, 31, 30, 24, 0, 32};
2998b9754b2SBitterblue Smith 
3008b9754b2SBitterblue Smith static const u8 retry_penalty_idx_normal[2][RATESIZE] = {
3018b9754b2SBitterblue Smith 	{ /* RSSI>TH */
3028b9754b2SBitterblue Smith 		4, 4, 4, 5,
3038b9754b2SBitterblue Smith 		4, 4, 5, 7, 7, 7, 8, 0x0a,
3048b9754b2SBitterblue Smith 		4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d,
3058b9754b2SBitterblue Smith 		5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f
3068b9754b2SBitterblue Smith 	},
3078b9754b2SBitterblue Smith 	{ /* RSSI<TH */
3088b9754b2SBitterblue Smith 		0x0a, 0x0a, 0x0b, 0x0c,
3098b9754b2SBitterblue Smith 		0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13,
3108b9754b2SBitterblue Smith 		0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x13,
3118b9754b2SBitterblue Smith 		9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13
3128b9754b2SBitterblue Smith 	}
3138b9754b2SBitterblue Smith };
3148b9754b2SBitterblue Smith 
3158b9754b2SBitterblue Smith static const u8 retry_penalty_idx_cut_i[2][RATESIZE] = {
3168b9754b2SBitterblue Smith 	{ /* RSSI>TH */
3178b9754b2SBitterblue Smith 		4, 4, 4, 5,
3188b9754b2SBitterblue Smith 		4, 4, 5, 7, 7, 7, 8, 0x0a,
3198b9754b2SBitterblue Smith 		4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d,
3208b9754b2SBitterblue Smith 		5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f
3218b9754b2SBitterblue Smith 	},
3228b9754b2SBitterblue Smith 	{ /* RSSI<TH */
3238b9754b2SBitterblue Smith 		0x0a, 0x0a, 0x0b, 0x0c,
3248b9754b2SBitterblue Smith 		0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13,
3258b9754b2SBitterblue Smith 		0x06, 0x07, 0x08, 0x0d, 0x0e, 0x11, 0x11, 0x11,
3268b9754b2SBitterblue Smith 		9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13
3278b9754b2SBitterblue Smith 	}
3288b9754b2SBitterblue Smith };
3298b9754b2SBitterblue Smith 
3308b9754b2SBitterblue Smith static const u8 retry_penalty_up_idx_normal[RATESIZE] = {
3318b9754b2SBitterblue Smith 	0x0c, 0x0d, 0x0d, 0x0f,
3328b9754b2SBitterblue Smith 	0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14,
3338b9754b2SBitterblue Smith 	0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15,
3348b9754b2SBitterblue Smith 	0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15
3358b9754b2SBitterblue Smith };
3368b9754b2SBitterblue Smith 
3378b9754b2SBitterblue Smith static const u8 retry_penalty_up_idx_cut_i[RATESIZE] = {
3388b9754b2SBitterblue Smith 	0x0c, 0x0d, 0x0d, 0x0f,
3398b9754b2SBitterblue Smith 	0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14,
3408b9754b2SBitterblue Smith 	0x0b, 0x0b, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12,
3418b9754b2SBitterblue Smith 	0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15
3428b9754b2SBitterblue Smith };
3438b9754b2SBitterblue Smith 
3448b9754b2SBitterblue Smith static const u8 rssi_threshold[RATESIZE] = {
3458b9754b2SBitterblue Smith 	0, 0, 0, 0,
3468b9754b2SBitterblue Smith 	0, 0, 0, 0, 0, 0x24, 0x26, 0x2a,
3478b9754b2SBitterblue Smith 	0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a,
3488b9754b2SBitterblue Smith 	0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c
3498b9754b2SBitterblue Smith };
3508b9754b2SBitterblue Smith 
3518b9754b2SBitterblue Smith static const u16 n_threshold_high[RATESIZE] = {
3528b9754b2SBitterblue Smith 	4, 4, 8, 16,
3538b9754b2SBitterblue Smith 	24, 36, 48, 72, 96, 144, 192, 216,
3548b9754b2SBitterblue Smith 	60, 80, 100, 160, 240, 400, 600, 800,
3558b9754b2SBitterblue Smith 	300, 320, 480, 720, 1000, 1200, 1600, 2000
3568b9754b2SBitterblue Smith };
3578b9754b2SBitterblue Smith 
3588b9754b2SBitterblue Smith static const u16 n_threshold_low[RATESIZE] = {
3598b9754b2SBitterblue Smith 	2, 2, 4, 8,
3608b9754b2SBitterblue Smith 	12, 18, 24, 36, 48, 72, 96, 108,
3618b9754b2SBitterblue Smith 	30, 40, 50, 80, 120, 200, 300, 400,
3628b9754b2SBitterblue Smith 	150, 160, 240, 360, 500, 600, 800, 1000
3638b9754b2SBitterblue Smith };
3648b9754b2SBitterblue Smith 
3658b9754b2SBitterblue Smith static const u8 dropping_necessary[RATESIZE] = {
3668b9754b2SBitterblue Smith 	1, 1, 1, 1,
3678b9754b2SBitterblue Smith 	1, 2, 3, 4, 5, 6, 7, 8,
3688b9754b2SBitterblue Smith 	1, 2, 3, 4, 5, 6, 7, 8,
3698b9754b2SBitterblue Smith 	5, 6, 7, 8, 9, 10, 11, 12
3708b9754b2SBitterblue Smith };
3718b9754b2SBitterblue Smith 
3728b9754b2SBitterblue Smith static const u8 pending_for_rate_up_fail[5] = {2, 10, 24, 40, 60};
3738b9754b2SBitterblue Smith 
3748b9754b2SBitterblue Smith static const u16 dynamic_tx_rpt_timing[6] = {
3758b9754b2SBitterblue Smith 	0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12, 0x927c /* 200ms-1200ms */
3768b9754b2SBitterblue Smith };
3778b9754b2SBitterblue Smith 
3788b9754b2SBitterblue Smith enum rtl8188e_tx_rpt_timing {
3798b9754b2SBitterblue Smith 	DEFAULT_TIMING = 0,
3808b9754b2SBitterblue Smith 	INCREASE_TIMING,
3818b9754b2SBitterblue Smith 	DECREASE_TIMING
3828b9754b2SBitterblue Smith };
3838b9754b2SBitterblue Smith 
rtl8188eu_identify_chip(struct rtl8xxxu_priv * priv)3843dfb8e84SJes Sorensen static int rtl8188eu_identify_chip(struct rtl8xxxu_priv *priv)
3853dfb8e84SJes Sorensen {
3863dfb8e84SJes Sorensen 	struct device *dev = &priv->udev->dev;
3873dfb8e84SJes Sorensen 	u32 sys_cfg, vendor;
3883dfb8e84SJes Sorensen 	int ret = 0;
3893dfb8e84SJes Sorensen 
3903dfb8e84SJes Sorensen 	strscpy(priv->chip_name, "8188EU", sizeof(priv->chip_name));
3913dfb8e84SJes Sorensen 	priv->rtl_chip = RTL8188E;
3923dfb8e84SJes Sorensen 	priv->rf_paths = 1;
3933dfb8e84SJes Sorensen 	priv->rx_paths = 1;
3943dfb8e84SJes Sorensen 	priv->tx_paths = 1;
3953dfb8e84SJes Sorensen 	priv->has_wifi = 1;
3963dfb8e84SJes Sorensen 
3973dfb8e84SJes Sorensen 	sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG);
3983dfb8e84SJes Sorensen 	priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK);
3993dfb8e84SJes Sorensen 	if (sys_cfg & SYS_CFG_TRP_VAUX_EN) {
4003dfb8e84SJes Sorensen 		dev_info(dev, "Unsupported test chip\n");
4013dfb8e84SJes Sorensen 		return -EOPNOTSUPP;
4023dfb8e84SJes Sorensen 	}
4033dfb8e84SJes Sorensen 
4043dfb8e84SJes Sorensen 	/*
4053dfb8e84SJes Sorensen 	 * TODO: At a glance, I cut requires a different firmware,
4063dfb8e84SJes Sorensen 	 * different initialisation tables, and no software rate
4073dfb8e84SJes Sorensen 	 * control. The vendor driver is not configured to handle
4083dfb8e84SJes Sorensen 	 * I cut chips by default. Are there any in the wild?
4093dfb8e84SJes Sorensen 	 */
4103dfb8e84SJes Sorensen 	if (priv->chip_cut == 8) {
4113dfb8e84SJes Sorensen 		dev_info(dev, "RTL8188EU cut I is not supported. Please complain about it at linux-wireless@vger.kernel.org.\n");
4123dfb8e84SJes Sorensen 		return -EOPNOTSUPP;
4133dfb8e84SJes Sorensen 	}
4143dfb8e84SJes Sorensen 
4153dfb8e84SJes Sorensen 	vendor = sys_cfg & SYS_CFG_VENDOR_ID;
4163dfb8e84SJes Sorensen 	rtl8xxxu_identify_vendor_1bit(priv, vendor);
4173dfb8e84SJes Sorensen 
4183dfb8e84SJes Sorensen 	ret = rtl8xxxu_config_endpoints_no_sie(priv);
4193dfb8e84SJes Sorensen 
4203dfb8e84SJes Sorensen 	return ret;
4213dfb8e84SJes Sorensen }
4223dfb8e84SJes Sorensen 
rtl8188eu_config_channel(struct ieee80211_hw * hw)4233dfb8e84SJes Sorensen static void rtl8188eu_config_channel(struct ieee80211_hw *hw)
4243dfb8e84SJes Sorensen {
4253dfb8e84SJes Sorensen 	struct rtl8xxxu_priv *priv = hw->priv;
4263dfb8e84SJes Sorensen 	u32 val32, rsr;
4273dfb8e84SJes Sorensen 	u8 opmode;
4283dfb8e84SJes Sorensen 	int sec_ch_above, channel;
4293dfb8e84SJes Sorensen 	int i;
4303dfb8e84SJes Sorensen 
4313dfb8e84SJes Sorensen 	opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE);
4323dfb8e84SJes Sorensen 	rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
4333dfb8e84SJes Sorensen 	channel = hw->conf.chandef.chan->hw_value;
4343dfb8e84SJes Sorensen 
4353dfb8e84SJes Sorensen 	switch (hw->conf.chandef.width) {
4363dfb8e84SJes Sorensen 	case NL80211_CHAN_WIDTH_20_NOHT:
4373dfb8e84SJes Sorensen 	case NL80211_CHAN_WIDTH_20:
4383dfb8e84SJes Sorensen 		opmode |= BW_OPMODE_20MHZ;
4393dfb8e84SJes Sorensen 		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
4403dfb8e84SJes Sorensen 
4413dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
4423dfb8e84SJes Sorensen 		val32 &= ~FPGA_RF_MODE;
4433dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
4443dfb8e84SJes Sorensen 
4453dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
4463dfb8e84SJes Sorensen 		val32 &= ~FPGA_RF_MODE;
4473dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
4483dfb8e84SJes Sorensen 		break;
4493dfb8e84SJes Sorensen 	case NL80211_CHAN_WIDTH_40:
4503dfb8e84SJes Sorensen 		if (hw->conf.chandef.center_freq1 >
4513dfb8e84SJes Sorensen 		    hw->conf.chandef.chan->center_freq) {
4523dfb8e84SJes Sorensen 			sec_ch_above = 1;
4533dfb8e84SJes Sorensen 			channel += 2;
4543dfb8e84SJes Sorensen 		} else {
4553dfb8e84SJes Sorensen 			sec_ch_above = 0;
4563dfb8e84SJes Sorensen 			channel -= 2;
4573dfb8e84SJes Sorensen 		}
4583dfb8e84SJes Sorensen 
4593dfb8e84SJes Sorensen 		opmode &= ~BW_OPMODE_20MHZ;
4603dfb8e84SJes Sorensen 		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
4613dfb8e84SJes Sorensen 		rsr &= ~RSR_RSC_BANDWIDTH_40M;
4623dfb8e84SJes Sorensen 		if (sec_ch_above)
4633dfb8e84SJes Sorensen 			rsr |= RSR_RSC_LOWER_SUB_CHANNEL;
4643dfb8e84SJes Sorensen 		else
4653dfb8e84SJes Sorensen 			rsr |= RSR_RSC_UPPER_SUB_CHANNEL;
4663dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr);
4673dfb8e84SJes Sorensen 
4683dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
4693dfb8e84SJes Sorensen 		val32 |= FPGA_RF_MODE;
4703dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
4713dfb8e84SJes Sorensen 
4723dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
4733dfb8e84SJes Sorensen 		val32 |= FPGA_RF_MODE;
4743dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
4753dfb8e84SJes Sorensen 
4763dfb8e84SJes Sorensen 		/*
4773dfb8e84SJes Sorensen 		 * Set Control channel to upper or lower. These settings
4783dfb8e84SJes Sorensen 		 * are required only for 40MHz
4793dfb8e84SJes Sorensen 		 */
4803dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM);
4813dfb8e84SJes Sorensen 		val32 &= ~CCK0_SIDEBAND;
4823dfb8e84SJes Sorensen 		if (!sec_ch_above)
4833dfb8e84SJes Sorensen 			val32 |= CCK0_SIDEBAND;
4843dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32);
4853dfb8e84SJes Sorensen 
4863dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
4873dfb8e84SJes Sorensen 		val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */
4883dfb8e84SJes Sorensen 		if (sec_ch_above)
4893dfb8e84SJes Sorensen 			val32 |= OFDM_LSTF_PRIME_CH_LOW;
4903dfb8e84SJes Sorensen 		else
4913dfb8e84SJes Sorensen 			val32 |= OFDM_LSTF_PRIME_CH_HIGH;
4923dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
4933dfb8e84SJes Sorensen 
4943dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
4953dfb8e84SJes Sorensen 		val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL);
4963dfb8e84SJes Sorensen 		if (sec_ch_above)
4973dfb8e84SJes Sorensen 			val32 |= FPGA0_PS_UPPER_CHANNEL;
4983dfb8e84SJes Sorensen 		else
4993dfb8e84SJes Sorensen 			val32 |= FPGA0_PS_LOWER_CHANNEL;
5003dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
5013dfb8e84SJes Sorensen 		break;
5023dfb8e84SJes Sorensen 
5033dfb8e84SJes Sorensen 	default:
5043dfb8e84SJes Sorensen 		break;
5053dfb8e84SJes Sorensen 	}
5063dfb8e84SJes Sorensen 
5073dfb8e84SJes Sorensen 	for (i = RF_A; i < priv->rf_paths; i++) {
5083dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
5093dfb8e84SJes Sorensen 		u32p_replace_bits(&val32, channel, MODE_AG_CHANNEL_MASK);
5103dfb8e84SJes Sorensen 		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
5113dfb8e84SJes Sorensen 	}
5123dfb8e84SJes Sorensen 
5133dfb8e84SJes Sorensen 	for (i = RF_A; i < priv->rf_paths; i++) {
5143dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
5153dfb8e84SJes Sorensen 		val32 &= ~MODE_AG_BW_MASK;
5163dfb8e84SJes Sorensen 		if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40)
5173dfb8e84SJes Sorensen 			val32 |= MODE_AG_BW_40MHZ_8723B;
5183dfb8e84SJes Sorensen 		else
5193dfb8e84SJes Sorensen 			val32 |= MODE_AG_BW_20MHZ_8723B;
5203dfb8e84SJes Sorensen 		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
5213dfb8e84SJes Sorensen 	}
5223dfb8e84SJes Sorensen }
5233dfb8e84SJes Sorensen 
rtl8188eu_init_aggregation(struct rtl8xxxu_priv * priv)5243dfb8e84SJes Sorensen static void rtl8188eu_init_aggregation(struct rtl8xxxu_priv *priv)
5253dfb8e84SJes Sorensen {
5263dfb8e84SJes Sorensen 	u8 agg_ctrl, usb_spec;
5273dfb8e84SJes Sorensen 
5283dfb8e84SJes Sorensen 	usb_spec = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION);
5293dfb8e84SJes Sorensen 	usb_spec &= ~USB_SPEC_USB_AGG_ENABLE;
5303dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, usb_spec);
5313dfb8e84SJes Sorensen 
5323dfb8e84SJes Sorensen 	agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL);
5333dfb8e84SJes Sorensen 	agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN;
5343dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl);
5353dfb8e84SJes Sorensen }
5363dfb8e84SJes Sorensen 
rtl8188eu_parse_efuse(struct rtl8xxxu_priv * priv)5373dfb8e84SJes Sorensen static int rtl8188eu_parse_efuse(struct rtl8xxxu_priv *priv)
5383dfb8e84SJes Sorensen {
5393dfb8e84SJes Sorensen 	struct rtl8188eu_efuse *efuse = &priv->efuse_wifi.efuse8188eu;
5403dfb8e84SJes Sorensen 
5413dfb8e84SJes Sorensen 	if (efuse->rtl_id != cpu_to_le16(0x8129))
5423dfb8e84SJes Sorensen 		return -EINVAL;
5433dfb8e84SJes Sorensen 
5443dfb8e84SJes Sorensen 	ether_addr_copy(priv->mac_addr, efuse->mac_addr);
5453dfb8e84SJes Sorensen 
5463dfb8e84SJes Sorensen 	memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base,
5473dfb8e84SJes Sorensen 	       sizeof(efuse->tx_power_index_A.cck_base));
5483dfb8e84SJes Sorensen 
5493dfb8e84SJes Sorensen 	memcpy(priv->ht40_1s_tx_power_index_A,
5503dfb8e84SJes Sorensen 	       efuse->tx_power_index_A.ht40_base,
5513dfb8e84SJes Sorensen 	       sizeof(efuse->tx_power_index_A.ht40_base));
5523dfb8e84SJes Sorensen 
5533dfb8e84SJes Sorensen 	priv->default_crystal_cap = efuse->xtal_k & 0x3f;
5543dfb8e84SJes Sorensen 
5553dfb8e84SJes Sorensen 	return 0;
5563dfb8e84SJes Sorensen }
5573dfb8e84SJes Sorensen 
rtl8188eu_reset_8051(struct rtl8xxxu_priv * priv)5583dfb8e84SJes Sorensen static void rtl8188eu_reset_8051(struct rtl8xxxu_priv *priv)
5593dfb8e84SJes Sorensen {
5603dfb8e84SJes Sorensen 	u16 sys_func;
5613dfb8e84SJes Sorensen 
5623dfb8e84SJes Sorensen 	sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC);
5633dfb8e84SJes Sorensen 	sys_func &= ~SYS_FUNC_CPU_ENABLE;
5643dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func);
5653dfb8e84SJes Sorensen 
5663dfb8e84SJes Sorensen 	sys_func |= SYS_FUNC_CPU_ENABLE;
5673dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func);
5683dfb8e84SJes Sorensen }
5693dfb8e84SJes Sorensen 
rtl8188eu_load_firmware(struct rtl8xxxu_priv * priv)5703dfb8e84SJes Sorensen static int rtl8188eu_load_firmware(struct rtl8xxxu_priv *priv)
5713dfb8e84SJes Sorensen {
5723dfb8e84SJes Sorensen 	const char *fw_name;
5733dfb8e84SJes Sorensen 	int ret;
5743dfb8e84SJes Sorensen 
5753dfb8e84SJes Sorensen 	fw_name = "rtlwifi/rtl8188eufw.bin";
5763dfb8e84SJes Sorensen 
5773dfb8e84SJes Sorensen 	ret = rtl8xxxu_load_firmware(priv, fw_name);
5783dfb8e84SJes Sorensen 
5793dfb8e84SJes Sorensen 	return ret;
5803dfb8e84SJes Sorensen }
5813dfb8e84SJes Sorensen 
rtl8188eu_init_phy_bb(struct rtl8xxxu_priv * priv)5823dfb8e84SJes Sorensen static void rtl8188eu_init_phy_bb(struct rtl8xxxu_priv *priv)
5833dfb8e84SJes Sorensen {
5843dfb8e84SJes Sorensen 	u8 val8;
5853dfb8e84SJes Sorensen 	u16 val16;
5863dfb8e84SJes Sorensen 
5873dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
5883dfb8e84SJes Sorensen 	val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB | SYS_FUNC_DIO_RF;
5893dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
5903dfb8e84SJes Sorensen 
5913dfb8e84SJes Sorensen 	/*
5923dfb8e84SJes Sorensen 	 * Per vendor driver, run power sequence before init of RF
5933dfb8e84SJes Sorensen 	 */
5943dfb8e84SJes Sorensen 	val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
5953dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
5963dfb8e84SJes Sorensen 
5973dfb8e84SJes Sorensen 	val8 = SYS_FUNC_USBA | SYS_FUNC_USBD |
5983dfb8e84SJes Sorensen 	       SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
5993dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
6003dfb8e84SJes Sorensen 
6013dfb8e84SJes Sorensen 	rtl8xxxu_init_phy_regs(priv, rtl8188eu_phy_init_table);
6023dfb8e84SJes Sorensen 	rtl8xxxu_init_phy_regs(priv, rtl8188e_agc_table);
6033dfb8e84SJes Sorensen }
6043dfb8e84SJes Sorensen 
rtl8188eu_init_phy_rf(struct rtl8xxxu_priv * priv)6053dfb8e84SJes Sorensen static int rtl8188eu_init_phy_rf(struct rtl8xxxu_priv *priv)
6063dfb8e84SJes Sorensen {
6073dfb8e84SJes Sorensen 	return rtl8xxxu_init_phy_rf(priv, rtl8188eu_radioa_init_table, RF_A);
6083dfb8e84SJes Sorensen }
6093dfb8e84SJes Sorensen 
rtl8188eu_iqk_path_a(struct rtl8xxxu_priv * priv)6103dfb8e84SJes Sorensen static int rtl8188eu_iqk_path_a(struct rtl8xxxu_priv *priv)
6113dfb8e84SJes Sorensen {
6123dfb8e84SJes Sorensen 	u32 reg_eac, reg_e94, reg_e9c;
6133dfb8e84SJes Sorensen 	int result = 0;
6143dfb8e84SJes Sorensen 
6153dfb8e84SJes Sorensen 	/* Path A IQK setting */
6163dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1c);
6173dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x30008c1c);
6183dfb8e84SJes Sorensen 
6193dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x8214032a);
6203dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000);
6213dfb8e84SJes Sorensen 
6223dfb8e84SJes Sorensen 	/* LO calibration setting */
6233dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00462911);
6243dfb8e84SJes Sorensen 
6253dfb8e84SJes Sorensen 	/* One shot, path A LOK & IQK */
6263dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
6273dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
6283dfb8e84SJes Sorensen 
6293dfb8e84SJes Sorensen 	mdelay(10);
6303dfb8e84SJes Sorensen 
6313dfb8e84SJes Sorensen 	/* Check failed */
6323dfb8e84SJes Sorensen 	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
6333dfb8e84SJes Sorensen 	reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
6343dfb8e84SJes Sorensen 	reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
6353dfb8e84SJes Sorensen 
6363dfb8e84SJes Sorensen 	if (!(reg_eac & BIT(28)) &&
6373dfb8e84SJes Sorensen 	    ((reg_e94 & 0x03ff0000) != 0x01420000) &&
6383dfb8e84SJes Sorensen 	    ((reg_e9c & 0x03ff0000) != 0x00420000))
6393dfb8e84SJes Sorensen 		result |= 0x01;
6403dfb8e84SJes Sorensen 
6413dfb8e84SJes Sorensen 	return result;
6423dfb8e84SJes Sorensen }
6433dfb8e84SJes Sorensen 
rtl8188eu_rx_iqk_path_a(struct rtl8xxxu_priv * priv)6443dfb8e84SJes Sorensen static int rtl8188eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv)
6453dfb8e84SJes Sorensen {
6463dfb8e84SJes Sorensen 	u32 reg_ea4, reg_eac, reg_e94, reg_e9c, val32;
6473dfb8e84SJes Sorensen 	int result = 0;
6483dfb8e84SJes Sorensen 
6493dfb8e84SJes Sorensen 	/* Leave IQK mode */
6503dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
6513dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0, 0xffffff00);
6523dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
6533dfb8e84SJes Sorensen 
6543dfb8e84SJes Sorensen 	/* Enable path A PA in TX IQK mode */
6553dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
6563dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
6573dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
6583dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf117b);
6593dfb8e84SJes Sorensen 
6603dfb8e84SJes Sorensen 	/* Enter IQK mode */
6613dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
6623dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0x808000, 0xffffff00);
6633dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
6643dfb8e84SJes Sorensen 
6653dfb8e84SJes Sorensen 	/* TX IQK setting */
6663dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
6673dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK, 0x81004800);
6683dfb8e84SJes Sorensen 
6693dfb8e84SJes Sorensen 	/* path-A IQK setting */
6703dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1c);
6713dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x30008c1c);
6723dfb8e84SJes Sorensen 
6733dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160804);
6743dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000);
6753dfb8e84SJes Sorensen 
6763dfb8e84SJes Sorensen 	/* LO calibration setting */
6773dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
6783dfb8e84SJes Sorensen 
6793dfb8e84SJes Sorensen 	/* One shot, path A LOK & IQK */
6803dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
6813dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
6823dfb8e84SJes Sorensen 
6833dfb8e84SJes Sorensen 	mdelay(10);
6843dfb8e84SJes Sorensen 
6853dfb8e84SJes Sorensen 	/* Check failed */
6863dfb8e84SJes Sorensen 	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
6873dfb8e84SJes Sorensen 	reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
6883dfb8e84SJes Sorensen 	reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
6893dfb8e84SJes Sorensen 
6903dfb8e84SJes Sorensen 	if (!(reg_eac & BIT(28)) &&
6913dfb8e84SJes Sorensen 	    ((reg_e94 & 0x03ff0000) != 0x01420000) &&
6923dfb8e84SJes Sorensen 	    ((reg_e9c & 0x03ff0000) != 0x00420000))
6933dfb8e84SJes Sorensen 		result |= 0x01;
6943dfb8e84SJes Sorensen 	else
6953dfb8e84SJes Sorensen 		goto out;
6963dfb8e84SJes Sorensen 
6973dfb8e84SJes Sorensen 	val32 = 0x80007c00 |
6983dfb8e84SJes Sorensen 		(reg_e94 & 0x03ff0000) | ((reg_e9c >> 16) & 0x03ff);
6993dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK, val32);
7003dfb8e84SJes Sorensen 
7013dfb8e84SJes Sorensen 	/* Modify RX IQK mode table */
7023dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
7033dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0, 0xffffff00);
7043dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
7053dfb8e84SJes Sorensen 
7063dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
7073dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
7083dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
7093dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ffa);
7103dfb8e84SJes Sorensen 
7113dfb8e84SJes Sorensen 	/* Enter IQK mode */
7123dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
7133dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0x808000, 0xffffff00);
7143dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
7153dfb8e84SJes Sorensen 
7163dfb8e84SJes Sorensen 	/* IQK setting */
7173dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
7183dfb8e84SJes Sorensen 
7193dfb8e84SJes Sorensen 	/* Path A IQK setting */
7203dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x30008c1c);
7213dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1c);
7223dfb8e84SJes Sorensen 
7233dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c05);
7243dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c05);
7253dfb8e84SJes Sorensen 
7263dfb8e84SJes Sorensen 	/* LO calibration setting */
7273dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
7283dfb8e84SJes Sorensen 
7293dfb8e84SJes Sorensen 	/* One shot, path A LOK & IQK */
7303dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
7313dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
7323dfb8e84SJes Sorensen 
7333dfb8e84SJes Sorensen 	mdelay(10);
7343dfb8e84SJes Sorensen 
7353dfb8e84SJes Sorensen 	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
7363dfb8e84SJes Sorensen 	reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2);
7373dfb8e84SJes Sorensen 
7383dfb8e84SJes Sorensen 	if (!(reg_eac & BIT(27)) &&
7393dfb8e84SJes Sorensen 	    ((reg_ea4 & 0x03ff0000) != 0x01320000) &&
7403dfb8e84SJes Sorensen 	    ((reg_eac & 0x03ff0000) != 0x00360000))
7413dfb8e84SJes Sorensen 		result |= 0x02;
7423dfb8e84SJes Sorensen 	else
7433dfb8e84SJes Sorensen 		dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n",
7443dfb8e84SJes Sorensen 			 __func__);
7453dfb8e84SJes Sorensen 
7463dfb8e84SJes Sorensen out:
7473dfb8e84SJes Sorensen 	return result;
7483dfb8e84SJes Sorensen }
7493dfb8e84SJes Sorensen 
rtl8188eu_phy_iqcalibrate(struct rtl8xxxu_priv * priv,int result[][8],int t)7503dfb8e84SJes Sorensen static void rtl8188eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
7513dfb8e84SJes Sorensen 				      int result[][8], int t)
7523dfb8e84SJes Sorensen {
7533dfb8e84SJes Sorensen 	struct device *dev = &priv->udev->dev;
7543dfb8e84SJes Sorensen 	u32 i, val32;
7553dfb8e84SJes Sorensen 	int path_a_ok;
7563dfb8e84SJes Sorensen 	int retry = 2;
7573dfb8e84SJes Sorensen 	static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
7583dfb8e84SJes Sorensen 		REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
7593dfb8e84SJes Sorensen 		REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
7603dfb8e84SJes Sorensen 		REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
7613dfb8e84SJes Sorensen 		REG_TX_OFDM_BBON, REG_TX_TO_RX,
7623dfb8e84SJes Sorensen 		REG_TX_TO_TX, REG_RX_CCK,
7633dfb8e84SJes Sorensen 		REG_RX_OFDM, REG_RX_WAIT_RIFS,
7643dfb8e84SJes Sorensen 		REG_RX_TO_RX, REG_STANDBY,
7653dfb8e84SJes Sorensen 		REG_SLEEP, REG_PMPD_ANAEN
7663dfb8e84SJes Sorensen 	};
7673dfb8e84SJes Sorensen 	static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
7683dfb8e84SJes Sorensen 		REG_TXPAUSE, REG_BEACON_CTRL,
7693dfb8e84SJes Sorensen 		REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
7703dfb8e84SJes Sorensen 	};
7713dfb8e84SJes Sorensen 	static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
7723dfb8e84SJes Sorensen 		REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
7733dfb8e84SJes Sorensen 		REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
7743dfb8e84SJes Sorensen 		REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
7753dfb8e84SJes Sorensen 		REG_FPGA0_XB_RF_INT_OE, REG_CCK0_AFE_SETTING
7763dfb8e84SJes Sorensen 	};
7773dfb8e84SJes Sorensen 
7783dfb8e84SJes Sorensen 	/*
7793dfb8e84SJes Sorensen 	 * Note: IQ calibration must be performed after loading
7803dfb8e84SJes Sorensen 	 *       PHY_REG.txt , and radio_a, radio_b.txt
7813dfb8e84SJes Sorensen 	 */
7823dfb8e84SJes Sorensen 
7833dfb8e84SJes Sorensen 	if (t == 0) {
7843dfb8e84SJes Sorensen 		/* Save ADDA parameters, turn Path A ADDA on */
7853dfb8e84SJes Sorensen 		rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
7863dfb8e84SJes Sorensen 				   RTL8XXXU_ADDA_REGS);
7873dfb8e84SJes Sorensen 		rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
7883dfb8e84SJes Sorensen 		rtl8xxxu_save_regs(priv, iqk_bb_regs,
7893dfb8e84SJes Sorensen 				   priv->bb_backup, RTL8XXXU_BB_REGS);
7903dfb8e84SJes Sorensen 	}
7913dfb8e84SJes Sorensen 
7923dfb8e84SJes Sorensen 	rtl8xxxu_path_adda_on(priv, adda_regs, true);
7933dfb8e84SJes Sorensen 
7943dfb8e84SJes Sorensen 	if (t == 0) {
7953dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
7963dfb8e84SJes Sorensen 		priv->pi_enabled = u32_get_bits(val32, FPGA0_HSSI_PARM1_PI);
7973dfb8e84SJes Sorensen 	}
7983dfb8e84SJes Sorensen 
7993dfb8e84SJes Sorensen 	if (!priv->pi_enabled) {
8003dfb8e84SJes Sorensen 		/* Switch BB to PI mode to do IQ Calibration. */
8013dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
8023dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
8033dfb8e84SJes Sorensen 	}
8043dfb8e84SJes Sorensen 
8053dfb8e84SJes Sorensen 	/* MAC settings */
8063dfb8e84SJes Sorensen 	rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
8073dfb8e84SJes Sorensen 
8083dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
8093dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0xf, 0x0f000000);
8103dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
8113dfb8e84SJes Sorensen 
8123dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
8133dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
8143dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
8153dfb8e84SJes Sorensen 
8163dfb8e84SJes Sorensen 	if (!priv->no_pape) {
8173dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
8183dfb8e84SJes Sorensen 		val32 |= (FPGA0_RF_PAPE |
8193dfb8e84SJes Sorensen 			  (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
8203dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
8213dfb8e84SJes Sorensen 	}
8223dfb8e84SJes Sorensen 
8233dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
8243dfb8e84SJes Sorensen 	val32 &= ~BIT(10);
8253dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
8263dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
8273dfb8e84SJes Sorensen 	val32 &= ~BIT(10);
8283dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
8293dfb8e84SJes Sorensen 
8303dfb8e84SJes Sorensen 	/* Page B init */
8313dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x0f600000);
8323dfb8e84SJes Sorensen 
8333dfb8e84SJes Sorensen 	/* IQ calibration setting */
8343dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
8353dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0x808000, 0xffffff00);
8363dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
8373dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
8383dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK, 0x81004800);
8393dfb8e84SJes Sorensen 
8403dfb8e84SJes Sorensen 	for (i = 0; i < retry; i++) {
8413dfb8e84SJes Sorensen 		path_a_ok = rtl8188eu_iqk_path_a(priv);
8423dfb8e84SJes Sorensen 		if (path_a_ok == 0x01) {
8433dfb8e84SJes Sorensen 			val32 = rtl8xxxu_read32(priv,
8443dfb8e84SJes Sorensen 						REG_TX_POWER_BEFORE_IQK_A);
8453dfb8e84SJes Sorensen 			result[t][0] = (val32 >> 16) & 0x3ff;
8463dfb8e84SJes Sorensen 			val32 = rtl8xxxu_read32(priv,
8473dfb8e84SJes Sorensen 						REG_TX_POWER_AFTER_IQK_A);
8483dfb8e84SJes Sorensen 			result[t][1] = (val32 >> 16) & 0x3ff;
8493dfb8e84SJes Sorensen 			break;
8503dfb8e84SJes Sorensen 		}
8513dfb8e84SJes Sorensen 	}
8523dfb8e84SJes Sorensen 
8533dfb8e84SJes Sorensen 	if (!path_a_ok)
8543dfb8e84SJes Sorensen 		dev_dbg(dev, "%s: Path A TX IQK failed!\n", __func__);
8553dfb8e84SJes Sorensen 
8563dfb8e84SJes Sorensen 	for (i = 0; i < retry; i++) {
8573dfb8e84SJes Sorensen 		path_a_ok = rtl8188eu_rx_iqk_path_a(priv);
8583dfb8e84SJes Sorensen 		if (path_a_ok == 0x03) {
8593dfb8e84SJes Sorensen 			val32 = rtl8xxxu_read32(priv,
8603dfb8e84SJes Sorensen 						REG_RX_POWER_BEFORE_IQK_A_2);
8613dfb8e84SJes Sorensen 			result[t][2] = (val32 >> 16) & 0x3ff;
8623dfb8e84SJes Sorensen 			val32 = rtl8xxxu_read32(priv,
8633dfb8e84SJes Sorensen 						REG_RX_POWER_AFTER_IQK_A_2);
8643dfb8e84SJes Sorensen 			result[t][3] = (val32 >> 16) & 0x3ff;
8653dfb8e84SJes Sorensen 
8663dfb8e84SJes Sorensen 			break;
8673dfb8e84SJes Sorensen 		}
8683dfb8e84SJes Sorensen 	}
8693dfb8e84SJes Sorensen 
8703dfb8e84SJes Sorensen 	if (!path_a_ok)
8713dfb8e84SJes Sorensen 		dev_dbg(dev, "%s: Path A RX IQK failed!\n", __func__);
8723dfb8e84SJes Sorensen 
8733dfb8e84SJes Sorensen 	/* Back to BB mode, load original value */
8743dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
8753dfb8e84SJes Sorensen 	u32p_replace_bits(&val32, 0, 0xffffff00);
8763dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
8773dfb8e84SJes Sorensen 
8783dfb8e84SJes Sorensen 	if (t == 0)
8793dfb8e84SJes Sorensen 		return;
8803dfb8e84SJes Sorensen 
8813dfb8e84SJes Sorensen 	if (!priv->pi_enabled) {
8823dfb8e84SJes Sorensen 		/* Switch back BB to SI mode after finishing IQ Calibration */
8833dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000);
8843dfb8e84SJes Sorensen 		rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000000);
8853dfb8e84SJes Sorensen 	}
8863dfb8e84SJes Sorensen 
8873dfb8e84SJes Sorensen 	/* Reload ADDA power saving parameters */
8883dfb8e84SJes Sorensen 	rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup,
8893dfb8e84SJes Sorensen 			      RTL8XXXU_ADDA_REGS);
8903dfb8e84SJes Sorensen 
8913dfb8e84SJes Sorensen 	/* Reload MAC parameters */
8923dfb8e84SJes Sorensen 	rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
8933dfb8e84SJes Sorensen 
8943dfb8e84SJes Sorensen 	/* Reload BB parameters */
8953dfb8e84SJes Sorensen 	rtl8xxxu_restore_regs(priv, iqk_bb_regs,
8963dfb8e84SJes Sorensen 			      priv->bb_backup, RTL8XXXU_BB_REGS);
8973dfb8e84SJes Sorensen 
8983dfb8e84SJes Sorensen 	/* Restore RX initial gain */
8993dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3);
9003dfb8e84SJes Sorensen 
9013dfb8e84SJes Sorensen 	/* Load 0xe30 IQC default value */
9023dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00);
9033dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00);
9043dfb8e84SJes Sorensen }
9053dfb8e84SJes Sorensen 
rtl8188eu_phy_iq_calibrate(struct rtl8xxxu_priv * priv)9063dfb8e84SJes Sorensen static void rtl8188eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
9073dfb8e84SJes Sorensen {
9083dfb8e84SJes Sorensen 	struct device *dev = &priv->udev->dev;
9093dfb8e84SJes Sorensen 	int result[4][8];	/* last is final result */
9103dfb8e84SJes Sorensen 	int i, candidate;
9113dfb8e84SJes Sorensen 	bool path_a_ok;
9123dfb8e84SJes Sorensen 	u32 reg_e94, reg_e9c, reg_ea4, reg_eac;
9133dfb8e84SJes Sorensen 	u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc;
9143dfb8e84SJes Sorensen 	bool simu;
9153dfb8e84SJes Sorensen 
9163dfb8e84SJes Sorensen 	memset(result, 0, sizeof(result));
9173dfb8e84SJes Sorensen 	result[3][0] = 0x100;
9183dfb8e84SJes Sorensen 	result[3][2] = 0x100;
9193dfb8e84SJes Sorensen 	result[3][4] = 0x100;
9203dfb8e84SJes Sorensen 	result[3][6] = 0x100;
9213dfb8e84SJes Sorensen 
9223dfb8e84SJes Sorensen 	candidate = -1;
9233dfb8e84SJes Sorensen 
9243dfb8e84SJes Sorensen 	path_a_ok = false;
9253dfb8e84SJes Sorensen 
9263dfb8e84SJes Sorensen 	for (i = 0; i < 3; i++) {
9273dfb8e84SJes Sorensen 		rtl8188eu_phy_iqcalibrate(priv, result, i);
9283dfb8e84SJes Sorensen 
9293dfb8e84SJes Sorensen 		if (i == 1) {
9303dfb8e84SJes Sorensen 			simu = rtl8xxxu_simularity_compare(priv,
9313dfb8e84SJes Sorensen 							   result, 0, 1);
9323dfb8e84SJes Sorensen 			if (simu) {
9333dfb8e84SJes Sorensen 				candidate = 0;
9343dfb8e84SJes Sorensen 				break;
9353dfb8e84SJes Sorensen 			}
9363dfb8e84SJes Sorensen 		}
9373dfb8e84SJes Sorensen 
9383dfb8e84SJes Sorensen 		if (i == 2) {
9393dfb8e84SJes Sorensen 			simu = rtl8xxxu_simularity_compare(priv,
9403dfb8e84SJes Sorensen 							   result, 0, 2);
9413dfb8e84SJes Sorensen 			if (simu) {
9423dfb8e84SJes Sorensen 				candidate = 0;
9433dfb8e84SJes Sorensen 				break;
9443dfb8e84SJes Sorensen 			}
9453dfb8e84SJes Sorensen 
9463dfb8e84SJes Sorensen 			simu = rtl8xxxu_simularity_compare(priv,
9473dfb8e84SJes Sorensen 							   result, 1, 2);
9483dfb8e84SJes Sorensen 			if (simu)
9493dfb8e84SJes Sorensen 				candidate = 1;
9503dfb8e84SJes Sorensen 			else
9513dfb8e84SJes Sorensen 				candidate = 3;
9523dfb8e84SJes Sorensen 		}
9533dfb8e84SJes Sorensen 	}
9543dfb8e84SJes Sorensen 
9553dfb8e84SJes Sorensen 	if (candidate >= 0) {
9563dfb8e84SJes Sorensen 		reg_e94 = result[candidate][0];
9573dfb8e84SJes Sorensen 		priv->rege94 =  reg_e94;
9583dfb8e84SJes Sorensen 		reg_e9c = result[candidate][1];
9593dfb8e84SJes Sorensen 		priv->rege9c = reg_e9c;
9603dfb8e84SJes Sorensen 		reg_ea4 = result[candidate][2];
9613dfb8e84SJes Sorensen 		reg_eac = result[candidate][3];
9623dfb8e84SJes Sorensen 		reg_eb4 = result[candidate][4];
9633dfb8e84SJes Sorensen 		priv->regeb4 = reg_eb4;
9643dfb8e84SJes Sorensen 		reg_ebc = result[candidate][5];
9653dfb8e84SJes Sorensen 		priv->regebc = reg_ebc;
9663dfb8e84SJes Sorensen 		reg_ec4 = result[candidate][6];
9673dfb8e84SJes Sorensen 		reg_ecc = result[candidate][7];
9683dfb8e84SJes Sorensen 		dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate);
9693dfb8e84SJes Sorensen 		dev_dbg(dev,
9703dfb8e84SJes Sorensen 			"%s: e94=%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%x\n",
9713dfb8e84SJes Sorensen 			__func__, reg_e94, reg_e9c, reg_ea4, reg_eac,
9723dfb8e84SJes Sorensen 			reg_eb4, reg_ebc, reg_ec4, reg_ecc);
9733dfb8e84SJes Sorensen 		path_a_ok = true;
9743dfb8e84SJes Sorensen 	} else {
9753dfb8e84SJes Sorensen 		reg_e94 = 0x100;
9763dfb8e84SJes Sorensen 		reg_eb4 = 0x100;
9773dfb8e84SJes Sorensen 		priv->rege94 = 0x100;
9783dfb8e84SJes Sorensen 		priv->regeb4 = 0x100;
9793dfb8e84SJes Sorensen 		reg_e9c = 0x0;
9803dfb8e84SJes Sorensen 		reg_ebc = 0x0;
9813dfb8e84SJes Sorensen 		priv->rege9c = 0x0;
9823dfb8e84SJes Sorensen 		priv->regebc = 0x0;
9833dfb8e84SJes Sorensen 	}
9843dfb8e84SJes Sorensen 
9853dfb8e84SJes Sorensen 	if (reg_e94 && candidate >= 0)
9863dfb8e84SJes Sorensen 		rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result,
9873dfb8e84SJes Sorensen 					   candidate, (reg_ea4 == 0));
9883dfb8e84SJes Sorensen 
9893dfb8e84SJes Sorensen 	rtl8xxxu_save_regs(priv, rtl8xxxu_iqk_phy_iq_bb_reg,
9903dfb8e84SJes Sorensen 			   priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
9913dfb8e84SJes Sorensen }
9923dfb8e84SJes Sorensen 
rtl8188e_disabled_to_emu(struct rtl8xxxu_priv * priv)9933dfb8e84SJes Sorensen static void rtl8188e_disabled_to_emu(struct rtl8xxxu_priv *priv)
9943dfb8e84SJes Sorensen {
9953dfb8e84SJes Sorensen 	u16 val16;
9963dfb8e84SJes Sorensen 
9973dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
9983dfb8e84SJes Sorensen 	val16 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE);
9993dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
10003dfb8e84SJes Sorensen }
10013dfb8e84SJes Sorensen 
rtl8188e_emu_to_active(struct rtl8xxxu_priv * priv)10023dfb8e84SJes Sorensen static int rtl8188e_emu_to_active(struct rtl8xxxu_priv *priv)
10033dfb8e84SJes Sorensen {
10043dfb8e84SJes Sorensen 	u8 val8;
10053dfb8e84SJes Sorensen 	u32 val32;
10063dfb8e84SJes Sorensen 	u16 val16;
10073dfb8e84SJes Sorensen 	int count, ret = 0;
10083dfb8e84SJes Sorensen 
10093dfb8e84SJes Sorensen 	/* wait till 0x04[17] = 1 power ready*/
10103dfb8e84SJes Sorensen 	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
10113dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
10123dfb8e84SJes Sorensen 		if (val32 & BIT(17))
10133dfb8e84SJes Sorensen 			break;
10143dfb8e84SJes Sorensen 
10153dfb8e84SJes Sorensen 		udelay(10);
10163dfb8e84SJes Sorensen 	}
10173dfb8e84SJes Sorensen 
10183dfb8e84SJes Sorensen 	if (!count) {
10193dfb8e84SJes Sorensen 		ret = -EBUSY;
10203dfb8e84SJes Sorensen 		goto exit;
10213dfb8e84SJes Sorensen 	}
10223dfb8e84SJes Sorensen 
10233dfb8e84SJes Sorensen 	/* reset baseband */
10243dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
10253dfb8e84SJes Sorensen 	val8 &= ~(SYS_FUNC_BBRSTB | SYS_FUNC_BB_GLB_RSTN);
10263dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
10273dfb8e84SJes Sorensen 
10283dfb8e84SJes Sorensen 	/*0x24[23] = 2b'01 schmit trigger */
10293dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
10303dfb8e84SJes Sorensen 	val32 |= BIT(23);
10313dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
10323dfb8e84SJes Sorensen 
10333dfb8e84SJes Sorensen 	/* 0x04[15] = 0 disable HWPDN (control by DRV)*/
10343dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
10353dfb8e84SJes Sorensen 	val16 &= ~APS_FSMCO_HW_POWERDOWN;
10363dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
10373dfb8e84SJes Sorensen 
10383dfb8e84SJes Sorensen 	/*0x04[12:11] = 2b'00 disable WL suspend*/
10393dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
10403dfb8e84SJes Sorensen 	val16 &= ~(APS_FSMCO_HW_SUSPEND | APS_FSMCO_PCIE);
10413dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
10423dfb8e84SJes Sorensen 
10433dfb8e84SJes Sorensen 	/* set, then poll until 0 */
10443dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
10453dfb8e84SJes Sorensen 	val32 |= APS_FSMCO_MAC_ENABLE;
10463dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
10473dfb8e84SJes Sorensen 
10483dfb8e84SJes Sorensen 	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
10493dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
10503dfb8e84SJes Sorensen 		if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
10513dfb8e84SJes Sorensen 			ret = 0;
10523dfb8e84SJes Sorensen 			break;
10533dfb8e84SJes Sorensen 		}
10543dfb8e84SJes Sorensen 		udelay(10);
10553dfb8e84SJes Sorensen 	}
10563dfb8e84SJes Sorensen 
10573dfb8e84SJes Sorensen 	if (!count) {
10583dfb8e84SJes Sorensen 		ret = -EBUSY;
10593dfb8e84SJes Sorensen 		goto exit;
10603dfb8e84SJes Sorensen 	}
10613dfb8e84SJes Sorensen 
10623dfb8e84SJes Sorensen 	/* LDO normal mode*/
10633dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_LPLDO_CTRL);
10643dfb8e84SJes Sorensen 	val8 &= ~BIT(4);
10653dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_LPLDO_CTRL, val8);
10663dfb8e84SJes Sorensen 
10673dfb8e84SJes Sorensen exit:
10683dfb8e84SJes Sorensen 	return ret;
10693dfb8e84SJes Sorensen }
10703dfb8e84SJes Sorensen 
rtl8188eu_active_to_emu(struct rtl8xxxu_priv * priv)10713dfb8e84SJes Sorensen static int rtl8188eu_active_to_emu(struct rtl8xxxu_priv *priv)
10723dfb8e84SJes Sorensen {
10733dfb8e84SJes Sorensen 	u8 val8;
10743dfb8e84SJes Sorensen 
10753dfb8e84SJes Sorensen 	/* Turn off RF */
10763dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_RF_CTRL);
10773dfb8e84SJes Sorensen 	val8 &= ~RF_ENABLE;
10783dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
10793dfb8e84SJes Sorensen 
10803dfb8e84SJes Sorensen 	/* LDO Sleep mode */
10813dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_LPLDO_CTRL);
10823dfb8e84SJes Sorensen 	val8 |= BIT(4);
10833dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_LPLDO_CTRL, val8);
10843dfb8e84SJes Sorensen 
10853dfb8e84SJes Sorensen 	return 0;
10863dfb8e84SJes Sorensen }
10873dfb8e84SJes Sorensen 
rtl8188eu_emu_to_disabled(struct rtl8xxxu_priv * priv)10883dfb8e84SJes Sorensen static int rtl8188eu_emu_to_disabled(struct rtl8xxxu_priv *priv)
10893dfb8e84SJes Sorensen {
10903dfb8e84SJes Sorensen 	u32 val32;
10913dfb8e84SJes Sorensen 	u16 val16;
10923dfb8e84SJes Sorensen 	u8 val8;
10933dfb8e84SJes Sorensen 
10943dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
10953dfb8e84SJes Sorensen 	val32 |= BIT(23);
10963dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
10973dfb8e84SJes Sorensen 
10983dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
10993dfb8e84SJes Sorensen 	val16 &= ~APS_FSMCO_PCIE;
11003dfb8e84SJes Sorensen 	val16 |= APS_FSMCO_HW_SUSPEND;
11013dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
11023dfb8e84SJes Sorensen 
11033dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x00);
11043dfb8e84SJes Sorensen 
11053dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG + 1);
11063dfb8e84SJes Sorensen 	val8 &= ~BIT(4);
11073dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_GPIO_MUXCFG + 1, val8);
11083dfb8e84SJes Sorensen 
11093dfb8e84SJes Sorensen 	/* Set USB suspend enable local register 0xfe10[4]=1 */
11103dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, 0xfe10);
11113dfb8e84SJes Sorensen 	val8 |= BIT(4);
11123dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, 0xfe10, val8);
11133dfb8e84SJes Sorensen 
11143dfb8e84SJes Sorensen 	return 0;
11153dfb8e84SJes Sorensen }
11163dfb8e84SJes Sorensen 
rtl8188eu_active_to_lps(struct rtl8xxxu_priv * priv)11173dfb8e84SJes Sorensen static int rtl8188eu_active_to_lps(struct rtl8xxxu_priv *priv)
11183dfb8e84SJes Sorensen {
11193dfb8e84SJes Sorensen 	struct device *dev = &priv->udev->dev;
11203dfb8e84SJes Sorensen 	u8 val8;
11213dfb8e84SJes Sorensen 	u16 val16;
11223dfb8e84SJes Sorensen 	u32 val32;
11233dfb8e84SJes Sorensen 	int retry, retval;
11243dfb8e84SJes Sorensen 
11253dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_TXPAUSE, 0x7f);
11263dfb8e84SJes Sorensen 
11273dfb8e84SJes Sorensen 	retry = 100;
11283dfb8e84SJes Sorensen 	retval = -EBUSY;
11293dfb8e84SJes Sorensen 	/* Poll 32 bit wide REG_SCH_TX_CMD for 0 to ensure no TX is pending. */
11303dfb8e84SJes Sorensen 	do {
11313dfb8e84SJes Sorensen 		val32 = rtl8xxxu_read32(priv, REG_SCH_TX_CMD);
11323dfb8e84SJes Sorensen 		if (!val32) {
11333dfb8e84SJes Sorensen 			retval = 0;
11343dfb8e84SJes Sorensen 			break;
11353dfb8e84SJes Sorensen 		}
11363dfb8e84SJes Sorensen 	} while (retry--);
11373dfb8e84SJes Sorensen 
11383dfb8e84SJes Sorensen 	if (!retry) {
11393dfb8e84SJes Sorensen 		dev_warn(dev, "Failed to flush TX queue\n");
11403dfb8e84SJes Sorensen 		retval = -EBUSY;
11413dfb8e84SJes Sorensen 		goto out;
11423dfb8e84SJes Sorensen 	}
11433dfb8e84SJes Sorensen 
11443dfb8e84SJes Sorensen 	/* Disable CCK and OFDM, clock gated */
11453dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
11463dfb8e84SJes Sorensen 	val8 &= ~SYS_FUNC_BBRSTB;
11473dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
11483dfb8e84SJes Sorensen 
11493dfb8e84SJes Sorensen 	udelay(2);
11503dfb8e84SJes Sorensen 
11513dfb8e84SJes Sorensen 	/* Reset MAC TRX */
11523dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_CR);
11533dfb8e84SJes Sorensen 	val16 |= 0xff;
11543dfb8e84SJes Sorensen 	val16 &= ~(CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE | CR_SECURITY_ENABLE);
11553dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_CR, val16);
11563dfb8e84SJes Sorensen 
11573dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST);
11583dfb8e84SJes Sorensen 	val8 |= DUAL_TSF_TX_OK;
11593dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8);
11603dfb8e84SJes Sorensen 
11613dfb8e84SJes Sorensen out:
11623dfb8e84SJes Sorensen 	return retval;
11633dfb8e84SJes Sorensen }
11643dfb8e84SJes Sorensen 
rtl8188eu_power_on(struct rtl8xxxu_priv * priv)11653dfb8e84SJes Sorensen static int rtl8188eu_power_on(struct rtl8xxxu_priv *priv)
11663dfb8e84SJes Sorensen {
11673dfb8e84SJes Sorensen 	u16 val16;
11683dfb8e84SJes Sorensen 	int ret;
11693dfb8e84SJes Sorensen 
11703dfb8e84SJes Sorensen 	rtl8188e_disabled_to_emu(priv);
11713dfb8e84SJes Sorensen 
11723dfb8e84SJes Sorensen 	ret = rtl8188e_emu_to_active(priv);
11733dfb8e84SJes Sorensen 	if (ret)
11743dfb8e84SJes Sorensen 		goto exit;
11753dfb8e84SJes Sorensen 
11763dfb8e84SJes Sorensen 	/*
11773dfb8e84SJes Sorensen 	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
11783dfb8e84SJes Sorensen 	 * Set CR bit10 to enable 32k calibration.
11793dfb8e84SJes Sorensen 	 * We do not set CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE here
11803dfb8e84SJes Sorensen 	 * due to a hardware bug in the 88E, requiring those to be
11813dfb8e84SJes Sorensen 	 * set after REG_TRXFF_BNDY is set. If not the RXFF bundary
11823dfb8e84SJes Sorensen 	 * will get set to a larger buffer size than the real buffer
11833dfb8e84SJes Sorensen 	 * size.
11843dfb8e84SJes Sorensen 	 */
11853dfb8e84SJes Sorensen 	val16 = (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
11863dfb8e84SJes Sorensen 		 CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
11873dfb8e84SJes Sorensen 		 CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
11883dfb8e84SJes Sorensen 		 CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
11893dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_CR, val16);
11903dfb8e84SJes Sorensen 
11913dfb8e84SJes Sorensen exit:
11923dfb8e84SJes Sorensen 	return ret;
11933dfb8e84SJes Sorensen }
11943dfb8e84SJes Sorensen 
rtl8188eu_power_off(struct rtl8xxxu_priv * priv)11953dfb8e84SJes Sorensen static void rtl8188eu_power_off(struct rtl8xxxu_priv *priv)
11963dfb8e84SJes Sorensen {
11973dfb8e84SJes Sorensen 	u8 val8;
11983dfb8e84SJes Sorensen 	u16 val16;
11993dfb8e84SJes Sorensen 
12003dfb8e84SJes Sorensen 	rtl8xxxu_flush_fifo(priv);
12013dfb8e84SJes Sorensen 
12023dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL);
12033dfb8e84SJes Sorensen 	val8 &= ~TX_REPORT_CTRL_TIMER_ENABLE;
12043dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8);
12053dfb8e84SJes Sorensen 
12063dfb8e84SJes Sorensen 	/* Turn off RF */
12073dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00);
12083dfb8e84SJes Sorensen 
12093dfb8e84SJes Sorensen 	rtl8188eu_active_to_lps(priv);
12103dfb8e84SJes Sorensen 
12113dfb8e84SJes Sorensen 	/* Reset Firmware if running in RAM */
12123dfb8e84SJes Sorensen 	if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL)
12133dfb8e84SJes Sorensen 		rtl8xxxu_firmware_self_reset(priv);
12143dfb8e84SJes Sorensen 
12153dfb8e84SJes Sorensen 	/* Reset MCU */
12163dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
12173dfb8e84SJes Sorensen 	val16 &= ~SYS_FUNC_CPU_ENABLE;
12183dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
12193dfb8e84SJes Sorensen 
12203dfb8e84SJes Sorensen 	/* Reset MCU ready status */
12213dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
12223dfb8e84SJes Sorensen 
12233dfb8e84SJes Sorensen 	/* 32K_CTRL looks to be very 8188e specific */
12243dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_32K_CTRL);
12253dfb8e84SJes Sorensen 	val8 &= ~BIT(0);
12263dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_32K_CTRL, val8);
12273dfb8e84SJes Sorensen 
12283dfb8e84SJes Sorensen 	rtl8188eu_active_to_emu(priv);
12293dfb8e84SJes Sorensen 	rtl8188eu_emu_to_disabled(priv);
12303dfb8e84SJes Sorensen 
12313dfb8e84SJes Sorensen 	/* Reset MCU IO Wrapper */
12323dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
12333dfb8e84SJes Sorensen 	val8 &= ~BIT(3);
12343dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
12353dfb8e84SJes Sorensen 
12363dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
12373dfb8e84SJes Sorensen 	val8 |= BIT(3);
12383dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
12393dfb8e84SJes Sorensen 
12403dfb8e84SJes Sorensen 	/* Vendor driver refers to GPIO_IN */
12413dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_GPIO_PIN_CTRL);
12423dfb8e84SJes Sorensen 	/* Vendor driver refers to GPIO_OUT */
12433dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_GPIO_PIN_CTRL + 1, val8);
12443dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_GPIO_PIN_CTRL + 2, 0xff);
12453dfb8e84SJes Sorensen 
12463dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL);
12473dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_GPIO_IO_SEL, val8 << 4);
12483dfb8e84SJes Sorensen 	val8 = rtl8xxxu_read8(priv, REG_GPIO_IO_SEL + 1);
12493dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_GPIO_IO_SEL + 1, val8 | 0x0f);
12503dfb8e84SJes Sorensen 
12513dfb8e84SJes Sorensen 	/*
12523dfb8e84SJes Sorensen 	 * Set LNA, TRSW, EX_PA Pin to output mode
12533dfb8e84SJes Sorensen 	 * Referred to as REG_BB_PAD_CTRL in 8188eu vendor driver
12543dfb8e84SJes Sorensen 	 */
12553dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_PAD_CTRL1, 0x00080808);
12563dfb8e84SJes Sorensen 
12573dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x00);
12583dfb8e84SJes Sorensen 
12593dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_GPIO_MUXCFG, 0x00000000);
12603dfb8e84SJes Sorensen }
12613dfb8e84SJes Sorensen 
rtl8188e_enable_rf(struct rtl8xxxu_priv * priv)12623dfb8e84SJes Sorensen static void rtl8188e_enable_rf(struct rtl8xxxu_priv *priv)
12633dfb8e84SJes Sorensen {
12643dfb8e84SJes Sorensen 	u32 val32;
12653dfb8e84SJes Sorensen 
12663dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_RF_CTRL, RF_ENABLE | RF_RSTB | RF_SDMRSTB);
12673dfb8e84SJes Sorensen 
12683dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
12693dfb8e84SJes Sorensen 	val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK);
12703dfb8e84SJes Sorensen 	val32 |= OFDM_RF_PATH_RX_A | OFDM_RF_PATH_TX_A;
12713dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
12723dfb8e84SJes Sorensen 
12733dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
12743dfb8e84SJes Sorensen }
12753dfb8e84SJes Sorensen 
rtl8188e_disable_rf(struct rtl8xxxu_priv * priv)12763dfb8e84SJes Sorensen static void rtl8188e_disable_rf(struct rtl8xxxu_priv *priv)
12773dfb8e84SJes Sorensen {
12783dfb8e84SJes Sorensen 	u32 val32;
12793dfb8e84SJes Sorensen 
12803dfb8e84SJes Sorensen 	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
12813dfb8e84SJes Sorensen 	val32 &= ~OFDM_RF_PATH_TX_MASK;
12823dfb8e84SJes Sorensen 	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
12833dfb8e84SJes Sorensen 
12843dfb8e84SJes Sorensen 	/* Power down RF module */
12853dfb8e84SJes Sorensen 	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0);
12863dfb8e84SJes Sorensen 
12873dfb8e84SJes Sorensen 	rtl8188eu_active_to_emu(priv);
12883dfb8e84SJes Sorensen }
12893dfb8e84SJes Sorensen 
rtl8188e_usb_quirks(struct rtl8xxxu_priv * priv)12903dfb8e84SJes Sorensen static void rtl8188e_usb_quirks(struct rtl8xxxu_priv *priv)
12913dfb8e84SJes Sorensen {
12923dfb8e84SJes Sorensen 	u16 val16;
12933dfb8e84SJes Sorensen 
12943dfb8e84SJes Sorensen 	/*
12953dfb8e84SJes Sorensen 	 * Technically this is not a USB quirk, but a chip quirk.
12963dfb8e84SJes Sorensen 	 * This has to be done after REG_TRXFF_BNDY is set, see
12973dfb8e84SJes Sorensen 	 * rtl8188eu_power_on() for details.
12983dfb8e84SJes Sorensen 	 */
12993dfb8e84SJes Sorensen 	val16 = rtl8xxxu_read16(priv, REG_CR);
13003dfb8e84SJes Sorensen 	val16 |= (CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE);
13013dfb8e84SJes Sorensen 	rtl8xxxu_write16(priv, REG_CR, val16);
13023dfb8e84SJes Sorensen 
13033dfb8e84SJes Sorensen 	rtl8xxxu_gen2_usb_quirks(priv);
13043dfb8e84SJes Sorensen 
13053dfb8e84SJes Sorensen 	/* Pre-TX enable WEP/TKIP security */
13063dfb8e84SJes Sorensen 	rtl8xxxu_write8(priv, REG_EARLY_MODE_CONTROL_8188E + 3, 0x01);
13073dfb8e84SJes Sorensen }
13083dfb8e84SJes Sorensen 
rtl8188e_cck_rssi(struct rtl8xxxu_priv * priv,struct rtl8723au_phy_stats * phy_stats)130970664495SBitterblue Smith static s8 rtl8188e_cck_rssi(struct rtl8xxxu_priv *priv, struct rtl8723au_phy_stats *phy_stats)
13103dfb8e84SJes Sorensen {
13113dfb8e84SJes Sorensen 	/* only use lna 0/1/2/3/7 */
13123dfb8e84SJes Sorensen 	static const s8 lna_gain_table_0[8] = {17, -1, -13, -29, -32, -35, -38, -41};
13133dfb8e84SJes Sorensen 	/* only use lna 3/7 */
13143dfb8e84SJes Sorensen 	static const s8 lna_gain_table_1[8] = {29, 20, 12, 3, -6, -15, -24, -33};
13153dfb8e84SJes Sorensen 
131670664495SBitterblue Smith 	u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
13173dfb8e84SJes Sorensen 	s8 rx_pwr_all = 0x00;
13183dfb8e84SJes Sorensen 	u8 vga_idx, lna_idx;
13193dfb8e84SJes Sorensen 	s8 lna_gain = 0;
13203dfb8e84SJes Sorensen 
13213dfb8e84SJes Sorensen 	lna_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_LNA_IDX_MASK);
13223dfb8e84SJes Sorensen 	vga_idx = u8_get_bits(cck_agc_rpt, CCK_AGC_RPT_VGA_IDX_MASK);
13233dfb8e84SJes Sorensen 
13243dfb8e84SJes Sorensen 	if (priv->chip_cut >= 8) /* cut I */ /* SMIC */
13253dfb8e84SJes Sorensen 		lna_gain = lna_gain_table_0[lna_idx];
13263dfb8e84SJes Sorensen 	else /* TSMC */
13273dfb8e84SJes Sorensen 		lna_gain = lna_gain_table_1[lna_idx];
13283dfb8e84SJes Sorensen 
13293dfb8e84SJes Sorensen 	rx_pwr_all = lna_gain - (2 * vga_idx);
13303dfb8e84SJes Sorensen 
13313dfb8e84SJes Sorensen 	return rx_pwr_all;
13323dfb8e84SJes Sorensen }
13333dfb8e84SJes Sorensen 
rtl8188eu_led_brightness_set(struct led_classdev * led_cdev,enum led_brightness brightness)1334873b3811SBitterblue Smith static int rtl8188eu_led_brightness_set(struct led_classdev *led_cdev,
1335873b3811SBitterblue Smith 					enum led_brightness brightness)
1336873b3811SBitterblue Smith {
1337873b3811SBitterblue Smith 	struct rtl8xxxu_priv *priv = container_of(led_cdev,
1338873b3811SBitterblue Smith 						  struct rtl8xxxu_priv,
1339873b3811SBitterblue Smith 						  led_cdev);
1340873b3811SBitterblue Smith 	u8 ledcfg = rtl8xxxu_read8(priv, REG_LEDCFG2);
1341873b3811SBitterblue Smith 
1342873b3811SBitterblue Smith 	if (brightness == LED_OFF) {
1343873b3811SBitterblue Smith 		ledcfg &= ~LEDCFG2_HW_LED_CONTROL;
1344873b3811SBitterblue Smith 		ledcfg |= LEDCFG2_SW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE;
1345873b3811SBitterblue Smith 	} else if (brightness == LED_ON) {
1346873b3811SBitterblue Smith 		ledcfg &= ~(LEDCFG2_HW_LED_CONTROL | LEDCFG2_SW_LED_DISABLE);
1347873b3811SBitterblue Smith 		ledcfg |= LEDCFG2_SW_LED_CONTROL;
1348873b3811SBitterblue Smith 	} else if (brightness == RTL8XXXU_HW_LED_CONTROL) {
1349873b3811SBitterblue Smith 		ledcfg &= ~LEDCFG2_SW_LED_DISABLE;
1350873b3811SBitterblue Smith 		ledcfg |= LEDCFG2_HW_LED_CONTROL | LEDCFG2_HW_LED_ENABLE;
1351873b3811SBitterblue Smith 	}
1352873b3811SBitterblue Smith 
1353873b3811SBitterblue Smith 	rtl8xxxu_write8(priv, REG_LEDCFG2, ledcfg);
1354873b3811SBitterblue Smith 
1355873b3811SBitterblue Smith 	return 0;
1356873b3811SBitterblue Smith }
1357873b3811SBitterblue Smith 
rtl8188e_set_tx_rpt_timing(struct rtl8xxxu_ra_info * ra,u8 timing)13588b9754b2SBitterblue Smith static void rtl8188e_set_tx_rpt_timing(struct rtl8xxxu_ra_info *ra, u8 timing)
13598b9754b2SBitterblue Smith {
13608b9754b2SBitterblue Smith 	u8 idx;
13618b9754b2SBitterblue Smith 
13628b9754b2SBitterblue Smith 	for (idx = 0; idx < 5; idx++)
13638b9754b2SBitterblue Smith 		if (dynamic_tx_rpt_timing[idx] == ra->rpt_time)
13648b9754b2SBitterblue Smith 			break;
13658b9754b2SBitterblue Smith 
13668b9754b2SBitterblue Smith 	if (timing == DEFAULT_TIMING) {
13678b9754b2SBitterblue Smith 		idx = 0; /* 200ms */
13688b9754b2SBitterblue Smith 	} else if (timing == INCREASE_TIMING) {
13698b9754b2SBitterblue Smith 		if (idx < 5)
13708b9754b2SBitterblue Smith 			idx++;
13718b9754b2SBitterblue Smith 	} else if (timing == DECREASE_TIMING) {
13728b9754b2SBitterblue Smith 		if (idx > 0)
13738b9754b2SBitterblue Smith 			idx--;
13748b9754b2SBitterblue Smith 	}
13758b9754b2SBitterblue Smith 
13768b9754b2SBitterblue Smith 	ra->rpt_time = dynamic_tx_rpt_timing[idx];
13778b9754b2SBitterblue Smith }
13788b9754b2SBitterblue Smith 
rtl8188e_rate_down(struct rtl8xxxu_ra_info * ra)13798b9754b2SBitterblue Smith static void rtl8188e_rate_down(struct rtl8xxxu_ra_info *ra)
13808b9754b2SBitterblue Smith {
13818b9754b2SBitterblue Smith 	u8 rate_id = ra->pre_rate;
13828b9754b2SBitterblue Smith 	u8 lowest_rate = ra->lowest_rate;
13838b9754b2SBitterblue Smith 	u8 highest_rate = ra->highest_rate;
13848b9754b2SBitterblue Smith 	s8 i;
13858b9754b2SBitterblue Smith 
13868b9754b2SBitterblue Smith 	if (rate_id > highest_rate) {
13878b9754b2SBitterblue Smith 		rate_id = highest_rate;
13888b9754b2SBitterblue Smith 	} else if (ra->rate_sgi) {
13898b9754b2SBitterblue Smith 		ra->rate_sgi = 0;
13908b9754b2SBitterblue Smith 	} else if (rate_id > lowest_rate) {
13918b9754b2SBitterblue Smith 		if (rate_id > 0) {
13928b9754b2SBitterblue Smith 			for (i = rate_id - 1; i >= lowest_rate; i--) {
13938b9754b2SBitterblue Smith 				if (ra->ra_use_rate & BIT(i)) {
13948b9754b2SBitterblue Smith 					rate_id = i;
13958b9754b2SBitterblue Smith 					goto rate_down_finish;
13968b9754b2SBitterblue Smith 				}
13978b9754b2SBitterblue Smith 			}
13988b9754b2SBitterblue Smith 		}
13998b9754b2SBitterblue Smith 	} else if (rate_id <= lowest_rate) {
14008b9754b2SBitterblue Smith 		rate_id = lowest_rate;
14018b9754b2SBitterblue Smith 	}
14028b9754b2SBitterblue Smith 
14038b9754b2SBitterblue Smith rate_down_finish:
14048b9754b2SBitterblue Smith 	if (ra->ra_waiting_counter == 1) {
14058b9754b2SBitterblue Smith 		ra->ra_waiting_counter++;
14068b9754b2SBitterblue Smith 		ra->ra_pending_counter++;
14078b9754b2SBitterblue Smith 	} else if (ra->ra_waiting_counter > 1) {
14088b9754b2SBitterblue Smith 		ra->ra_waiting_counter = 0;
14098b9754b2SBitterblue Smith 		ra->ra_pending_counter = 0;
14108b9754b2SBitterblue Smith 	}
14118b9754b2SBitterblue Smith 
14128b9754b2SBitterblue Smith 	if (ra->ra_pending_counter >= 4)
14138b9754b2SBitterblue Smith 		ra->ra_pending_counter = 4;
14148b9754b2SBitterblue Smith 
14158b9754b2SBitterblue Smith 	ra->ra_drop_after_down = 1;
14168b9754b2SBitterblue Smith 
14178b9754b2SBitterblue Smith 	ra->decision_rate = rate_id;
14188b9754b2SBitterblue Smith 
14198b9754b2SBitterblue Smith 	rtl8188e_set_tx_rpt_timing(ra, DECREASE_TIMING);
14208b9754b2SBitterblue Smith }
14218b9754b2SBitterblue Smith 
rtl8188e_rate_up(struct rtl8xxxu_ra_info * ra)14228b9754b2SBitterblue Smith static void rtl8188e_rate_up(struct rtl8xxxu_ra_info *ra)
14238b9754b2SBitterblue Smith {
14248b9754b2SBitterblue Smith 	u8 rate_id = ra->pre_rate;
14258b9754b2SBitterblue Smith 	u8 highest_rate = ra->highest_rate;
14268b9754b2SBitterblue Smith 	u8 i;
14278b9754b2SBitterblue Smith 
14288b9754b2SBitterblue Smith 	if (ra->ra_waiting_counter == 1) {
14298b9754b2SBitterblue Smith 		ra->ra_waiting_counter = 0;
14308b9754b2SBitterblue Smith 		ra->ra_pending_counter = 0;
14318b9754b2SBitterblue Smith 	} else if (ra->ra_waiting_counter > 1) {
14328b9754b2SBitterblue Smith 		ra->pre_rssi_sta_ra = ra->rssi_sta_ra;
14338b9754b2SBitterblue Smith 		goto rate_up_finish;
14348b9754b2SBitterblue Smith 	}
14358b9754b2SBitterblue Smith 
14368b9754b2SBitterblue Smith 	rtl8188e_set_tx_rpt_timing(ra, DEFAULT_TIMING);
14378b9754b2SBitterblue Smith 
14388b9754b2SBitterblue Smith 	if (rate_id < highest_rate) {
14398b9754b2SBitterblue Smith 		for (i = rate_id + 1; i <= highest_rate; i++) {
14408b9754b2SBitterblue Smith 			if (ra->ra_use_rate & BIT(i)) {
14418b9754b2SBitterblue Smith 				rate_id = i;
14428b9754b2SBitterblue Smith 				goto rate_up_finish;
14438b9754b2SBitterblue Smith 			}
14448b9754b2SBitterblue Smith 		}
14458b9754b2SBitterblue Smith 	} else if (rate_id == highest_rate) {
14468b9754b2SBitterblue Smith 		if (ra->sgi_enable && !ra->rate_sgi)
14478b9754b2SBitterblue Smith 			ra->rate_sgi = 1;
14488b9754b2SBitterblue Smith 		else if (!ra->sgi_enable)
14498b9754b2SBitterblue Smith 			ra->rate_sgi = 0;
14508b9754b2SBitterblue Smith 	} else { /* rate_id > ra->highest_rate */
14518b9754b2SBitterblue Smith 		rate_id = highest_rate;
14528b9754b2SBitterblue Smith 	}
14538b9754b2SBitterblue Smith 
14548b9754b2SBitterblue Smith rate_up_finish:
14558b9754b2SBitterblue Smith 	if (ra->ra_waiting_counter == (4 + pending_for_rate_up_fail[ra->ra_pending_counter]))
14568b9754b2SBitterblue Smith 		ra->ra_waiting_counter = 0;
14578b9754b2SBitterblue Smith 	else
14588b9754b2SBitterblue Smith 		ra->ra_waiting_counter++;
14598b9754b2SBitterblue Smith 
14608b9754b2SBitterblue Smith 	ra->decision_rate = rate_id;
14618b9754b2SBitterblue Smith }
14628b9754b2SBitterblue Smith 
rtl8188e_reset_ra_counter(struct rtl8xxxu_ra_info * ra)14638b9754b2SBitterblue Smith static void rtl8188e_reset_ra_counter(struct rtl8xxxu_ra_info *ra)
14648b9754b2SBitterblue Smith {
14658b9754b2SBitterblue Smith 	u8 rate_id = ra->decision_rate;
14668b9754b2SBitterblue Smith 
14678b9754b2SBitterblue Smith 	ra->nsc_up = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1;
14688b9754b2SBitterblue Smith 	ra->nsc_down = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1;
14698b9754b2SBitterblue Smith }
14708b9754b2SBitterblue Smith 
rtl8188e_rate_decision(struct rtl8xxxu_ra_info * ra)14718b9754b2SBitterblue Smith static void rtl8188e_rate_decision(struct rtl8xxxu_ra_info *ra)
14728b9754b2SBitterblue Smith {
14738b9754b2SBitterblue Smith 	struct rtl8xxxu_priv *priv = container_of(ra, struct rtl8xxxu_priv, ra_info);
14748b9754b2SBitterblue Smith 	const u8 *retry_penalty_idx_0;
14758b9754b2SBitterblue Smith 	const u8 *retry_penalty_idx_1;
14768b9754b2SBitterblue Smith 	const u8 *retry_penalty_up_idx;
14778b9754b2SBitterblue Smith 	u8 rate_id, penalty_id1, penalty_id2;
14788b9754b2SBitterblue Smith 	int i;
14798b9754b2SBitterblue Smith 
14808b9754b2SBitterblue Smith 	if (ra->total == 0)
14818b9754b2SBitterblue Smith 		return;
14828b9754b2SBitterblue Smith 
14838b9754b2SBitterblue Smith 	if (ra->ra_drop_after_down) {
14848b9754b2SBitterblue Smith 		ra->ra_drop_after_down--;
14858b9754b2SBitterblue Smith 
14868b9754b2SBitterblue Smith 		rtl8188e_reset_ra_counter(ra);
14878b9754b2SBitterblue Smith 
14888b9754b2SBitterblue Smith 		return;
14898b9754b2SBitterblue Smith 	}
14908b9754b2SBitterblue Smith 
14918b9754b2SBitterblue Smith 	if (priv->chip_cut == 8) { /* cut I */
14928b9754b2SBitterblue Smith 		retry_penalty_idx_0 = retry_penalty_idx_cut_i[0];
14938b9754b2SBitterblue Smith 		retry_penalty_idx_1 = retry_penalty_idx_cut_i[1];
14948b9754b2SBitterblue Smith 		retry_penalty_up_idx = retry_penalty_up_idx_cut_i;
14958b9754b2SBitterblue Smith 	} else {
14968b9754b2SBitterblue Smith 		retry_penalty_idx_0 = retry_penalty_idx_normal[0];
14978b9754b2SBitterblue Smith 		retry_penalty_idx_1 = retry_penalty_idx_normal[1];
14988b9754b2SBitterblue Smith 		retry_penalty_up_idx = retry_penalty_up_idx_normal;
14998b9754b2SBitterblue Smith 	}
15008b9754b2SBitterblue Smith 
15018b9754b2SBitterblue Smith 	if (ra->rssi_sta_ra < (ra->pre_rssi_sta_ra - 3) ||
15028b9754b2SBitterblue Smith 	    ra->rssi_sta_ra > (ra->pre_rssi_sta_ra + 3)) {
15038b9754b2SBitterblue Smith 		ra->pre_rssi_sta_ra = ra->rssi_sta_ra;
15048b9754b2SBitterblue Smith 		ra->ra_waiting_counter = 0;
15058b9754b2SBitterblue Smith 		ra->ra_pending_counter = 0;
15068b9754b2SBitterblue Smith 	}
15078b9754b2SBitterblue Smith 
15088b9754b2SBitterblue Smith 	/* Start RA decision */
15098b9754b2SBitterblue Smith 	if (ra->pre_rate > ra->highest_rate)
15108b9754b2SBitterblue Smith 		rate_id = ra->highest_rate;
15118b9754b2SBitterblue Smith 	else
15128b9754b2SBitterblue Smith 		rate_id = ra->pre_rate;
15138b9754b2SBitterblue Smith 
15148b9754b2SBitterblue Smith 	/* rate down */
15158b9754b2SBitterblue Smith 	if (ra->rssi_sta_ra > rssi_threshold[rate_id])
15168b9754b2SBitterblue Smith 		penalty_id1 = retry_penalty_idx_0[rate_id];
15178b9754b2SBitterblue Smith 	else
15188b9754b2SBitterblue Smith 		penalty_id1 = retry_penalty_idx_1[rate_id];
15198b9754b2SBitterblue Smith 
15208b9754b2SBitterblue Smith 	for (i = 0; i < 5; i++)
15218b9754b2SBitterblue Smith 		ra->nsc_down += ra->retry[i] * retry_penalty[penalty_id1][i];
15228b9754b2SBitterblue Smith 
15238b9754b2SBitterblue Smith 	if (ra->nsc_down > (ra->total * retry_penalty[penalty_id1][5]))
15248b9754b2SBitterblue Smith 		ra->nsc_down -= ra->total * retry_penalty[penalty_id1][5];
15258b9754b2SBitterblue Smith 	else
15268b9754b2SBitterblue Smith 		ra->nsc_down = 0;
15278b9754b2SBitterblue Smith 
15288b9754b2SBitterblue Smith 	/* rate up */
15298b9754b2SBitterblue Smith 	penalty_id2 = retry_penalty_up_idx[rate_id];
15308b9754b2SBitterblue Smith 
15318b9754b2SBitterblue Smith 	for (i = 0; i < 5; i++)
15328b9754b2SBitterblue Smith 		ra->nsc_up += ra->retry[i] * retry_penalty[penalty_id2][i];
15338b9754b2SBitterblue Smith 
15348b9754b2SBitterblue Smith 	if (ra->nsc_up > (ra->total * retry_penalty[penalty_id2][5]))
15358b9754b2SBitterblue Smith 		ra->nsc_up -= ra->total * retry_penalty[penalty_id2][5];
15368b9754b2SBitterblue Smith 	else
15378b9754b2SBitterblue Smith 		ra->nsc_up = 0;
15388b9754b2SBitterblue Smith 
15398b9754b2SBitterblue Smith 	if (ra->nsc_down < n_threshold_low[rate_id] ||
15408b9754b2SBitterblue Smith 	    ra->drop > dropping_necessary[rate_id]) {
15418b9754b2SBitterblue Smith 		rtl8188e_rate_down(ra);
15428b9754b2SBitterblue Smith 
15438b9754b2SBitterblue Smith 		rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate,
15448b9754b2SBitterblue Smith 					  ra->rate_sgi, priv->ra_report.txrate.bw);
15458b9754b2SBitterblue Smith 	} else if (ra->nsc_up > n_threshold_high[rate_id]) {
15468b9754b2SBitterblue Smith 		rtl8188e_rate_up(ra);
15478b9754b2SBitterblue Smith 
15488b9754b2SBitterblue Smith 		rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate,
15498b9754b2SBitterblue Smith 					  ra->rate_sgi, priv->ra_report.txrate.bw);
15508b9754b2SBitterblue Smith 	}
15518b9754b2SBitterblue Smith 
15528b9754b2SBitterblue Smith 	if (ra->decision_rate == ra->pre_rate)
15538b9754b2SBitterblue Smith 		ra->dynamic_tx_rpt_timing_counter++;
15548b9754b2SBitterblue Smith 	else
15558b9754b2SBitterblue Smith 		ra->dynamic_tx_rpt_timing_counter = 0;
15568b9754b2SBitterblue Smith 
15578b9754b2SBitterblue Smith 	if (ra->dynamic_tx_rpt_timing_counter >= 4) {
15588b9754b2SBitterblue Smith 		/* Rate didn't change 4 times, extend RPT timing */
15598b9754b2SBitterblue Smith 		rtl8188e_set_tx_rpt_timing(ra, INCREASE_TIMING);
15608b9754b2SBitterblue Smith 		ra->dynamic_tx_rpt_timing_counter = 0;
15618b9754b2SBitterblue Smith 	}
15628b9754b2SBitterblue Smith 
15638b9754b2SBitterblue Smith 	ra->pre_rate = ra->decision_rate;
15648b9754b2SBitterblue Smith 
15658b9754b2SBitterblue Smith 	rtl8188e_reset_ra_counter(ra);
15668b9754b2SBitterblue Smith }
15678b9754b2SBitterblue Smith 
rtl8188e_power_training_try_state(struct rtl8xxxu_ra_info * ra)15688b9754b2SBitterblue Smith static void rtl8188e_power_training_try_state(struct rtl8xxxu_ra_info *ra)
15698b9754b2SBitterblue Smith {
15708b9754b2SBitterblue Smith 	ra->pt_try_state = 0;
15718b9754b2SBitterblue Smith 	switch (ra->pt_mode_ss) {
15728b9754b2SBitterblue Smith 	case 3:
15738b9754b2SBitterblue Smith 		if (ra->decision_rate >= DESC_RATE_MCS13)
15748b9754b2SBitterblue Smith 			ra->pt_try_state = 1;
15758b9754b2SBitterblue Smith 		break;
15768b9754b2SBitterblue Smith 	case 2:
15778b9754b2SBitterblue Smith 		if (ra->decision_rate >= DESC_RATE_MCS5)
15788b9754b2SBitterblue Smith 			ra->pt_try_state = 1;
15798b9754b2SBitterblue Smith 		break;
15808b9754b2SBitterblue Smith 	case 1:
15818b9754b2SBitterblue Smith 		if (ra->decision_rate >= DESC_RATE_48M)
15828b9754b2SBitterblue Smith 			ra->pt_try_state = 1;
15838b9754b2SBitterblue Smith 		break;
15848b9754b2SBitterblue Smith 	case 0:
15858b9754b2SBitterblue Smith 		if (ra->decision_rate >= DESC_RATE_11M)
15868b9754b2SBitterblue Smith 			ra->pt_try_state = 1;
15878b9754b2SBitterblue Smith 		break;
15888b9754b2SBitterblue Smith 	default:
15898b9754b2SBitterblue Smith 		break;
15908b9754b2SBitterblue Smith 	}
15918b9754b2SBitterblue Smith 
15928b9754b2SBitterblue Smith 	if (ra->rssi_sta_ra < 48) {
15938b9754b2SBitterblue Smith 		ra->pt_stage = 0;
15948b9754b2SBitterblue Smith 	} else if (ra->pt_try_state == 1) {
15958b9754b2SBitterblue Smith 		if ((ra->pt_stop_count >= 10) ||
15968b9754b2SBitterblue Smith 		    (ra->pt_pre_rssi > ra->rssi_sta_ra + 5) ||
15978b9754b2SBitterblue Smith 		    (ra->pt_pre_rssi < ra->rssi_sta_ra - 5) ||
15988b9754b2SBitterblue Smith 		    (ra->decision_rate != ra->pt_pre_rate)) {
15998b9754b2SBitterblue Smith 			if (ra->pt_stage == 0)
16008b9754b2SBitterblue Smith 				ra->pt_stage = 1;
16018b9754b2SBitterblue Smith 			else if (ra->pt_stage == 1)
16028b9754b2SBitterblue Smith 				ra->pt_stage = 3;
16038b9754b2SBitterblue Smith 			else
16048b9754b2SBitterblue Smith 				ra->pt_stage = 5;
16058b9754b2SBitterblue Smith 
16068b9754b2SBitterblue Smith 			ra->pt_pre_rssi = ra->rssi_sta_ra;
16078b9754b2SBitterblue Smith 			ra->pt_stop_count = 0;
16088b9754b2SBitterblue Smith 		} else {
16098b9754b2SBitterblue Smith 			ra->ra_stage = 0;
16108b9754b2SBitterblue Smith 			ra->pt_stop_count++;
16118b9754b2SBitterblue Smith 		}
16128b9754b2SBitterblue Smith 	} else {
16138b9754b2SBitterblue Smith 		ra->pt_stage = 0;
16148b9754b2SBitterblue Smith 		ra->ra_stage = 0;
16158b9754b2SBitterblue Smith 	}
16168b9754b2SBitterblue Smith 
16178b9754b2SBitterblue Smith 	ra->pt_pre_rate = ra->decision_rate;
16188b9754b2SBitterblue Smith 
16198b9754b2SBitterblue Smith 	/* TODO: implement the "false alarm" statistics for this */
16208b9754b2SBitterblue Smith 	/* Disable power training when noisy environment */
16218b9754b2SBitterblue Smith 	/* if (p_dm_odm->is_disable_power_training) { */
16228b9754b2SBitterblue Smith 	if (1) {
16238b9754b2SBitterblue Smith 		ra->pt_stage = 0;
16248b9754b2SBitterblue Smith 		ra->ra_stage = 0;
16258b9754b2SBitterblue Smith 		ra->pt_stop_count = 0;
16268b9754b2SBitterblue Smith 	}
16278b9754b2SBitterblue Smith }
16288b9754b2SBitterblue Smith 
rtl8188e_power_training_decision(struct rtl8xxxu_ra_info * ra)16298b9754b2SBitterblue Smith static void rtl8188e_power_training_decision(struct rtl8xxxu_ra_info *ra)
16308b9754b2SBitterblue Smith {
16318b9754b2SBitterblue Smith 	u8 temp_stage;
16328b9754b2SBitterblue Smith 	u32 numsc;
16338b9754b2SBitterblue Smith 	u32 num_total;
16348b9754b2SBitterblue Smith 	u8 stage_id;
16358b9754b2SBitterblue Smith 	u8 j;
16368b9754b2SBitterblue Smith 
16378b9754b2SBitterblue Smith 	numsc = 0;
16388b9754b2SBitterblue Smith 	num_total = ra->total * pt_penalty[5];
16398b9754b2SBitterblue Smith 	for (j = 0; j <= 4; j++) {
16408b9754b2SBitterblue Smith 		numsc += ra->retry[j] * pt_penalty[j];
16418b9754b2SBitterblue Smith 
16428b9754b2SBitterblue Smith 		if (numsc > num_total)
16438b9754b2SBitterblue Smith 			break;
16448b9754b2SBitterblue Smith 	}
16458b9754b2SBitterblue Smith 
16468b9754b2SBitterblue Smith 	j >>= 1;
16478b9754b2SBitterblue Smith 	temp_stage = (ra->pt_stage + 1) >> 1;
16488b9754b2SBitterblue Smith 	if (temp_stage > j)
16498b9754b2SBitterblue Smith 		stage_id = temp_stage - j;
16508b9754b2SBitterblue Smith 	else
16518b9754b2SBitterblue Smith 		stage_id = 0;
16528b9754b2SBitterblue Smith 
16538b9754b2SBitterblue Smith 	ra->pt_smooth_factor = (ra->pt_smooth_factor >> 1) +
16548b9754b2SBitterblue Smith 			       (ra->pt_smooth_factor >> 2) +
16558b9754b2SBitterblue Smith 			       stage_id * 16 + 2;
16568b9754b2SBitterblue Smith 	if (ra->pt_smooth_factor > 192)
16578b9754b2SBitterblue Smith 		ra->pt_smooth_factor = 192;
16588b9754b2SBitterblue Smith 	stage_id = ra->pt_smooth_factor >> 6;
16598b9754b2SBitterblue Smith 	temp_stage = stage_id * 2;
16608b9754b2SBitterblue Smith 	if (temp_stage != 0)
16618b9754b2SBitterblue Smith 		temp_stage--;
16628b9754b2SBitterblue Smith 	if (ra->drop > 3)
16638b9754b2SBitterblue Smith 		temp_stage = 0;
16648b9754b2SBitterblue Smith 	ra->pt_stage = temp_stage;
16658b9754b2SBitterblue Smith }
16668b9754b2SBitterblue Smith 
rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv * priv,struct sk_buff * skb)16678b9754b2SBitterblue Smith void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
16688b9754b2SBitterblue Smith {
16698b9754b2SBitterblue Smith 	u32 *_rx_desc = (u32 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16));
16708b9754b2SBitterblue Smith 	struct rtl8xxxu_rxdesc16 *rx_desc = (struct rtl8xxxu_rxdesc16 *)_rx_desc;
16718b9754b2SBitterblue Smith 	struct device *dev = &priv->udev->dev;
16728b9754b2SBitterblue Smith 	struct rtl8xxxu_ra_info *ra = &priv->ra_info;
16738b9754b2SBitterblue Smith 	u32 tx_rpt_len = rx_desc->pktlen & 0x3ff;
16748b9754b2SBitterblue Smith 	u32 items = tx_rpt_len / TX_RPT2_ITEM_SIZE;
16758b9754b2SBitterblue Smith 	u64 macid_valid = ((u64)_rx_desc[5] << 32) | _rx_desc[4];
16768b9754b2SBitterblue Smith 	u32 macid;
16778b9754b2SBitterblue Smith 	u8 *rpt = skb->data;
16788b9754b2SBitterblue Smith 	bool valid;
16798b9754b2SBitterblue Smith 	u16 min_rpt_time = 0x927c;
16808b9754b2SBitterblue Smith 
16818b9754b2SBitterblue Smith 	dev_dbg(dev, "%s: len: %d items: %d\n", __func__, tx_rpt_len, items);
16828b9754b2SBitterblue Smith 
1683398eb194SPing-Ke Shih 	/* We only use macid 0, so only the first item is relevant.
1684398eb194SPing-Ke Shih 	 * AP mode will use more of them if it's ever implemented.
1685398eb194SPing-Ke Shih 	 */
1686a047e46aSMartin Kaistra 	if (!priv->vifs[0] || priv->vifs[0]->type == NL80211_IFTYPE_STATION)
1687398eb194SPing-Ke Shih 		items = 1;
1688398eb194SPing-Ke Shih 
16898b9754b2SBitterblue Smith 	for (macid = 0; macid < items; macid++) {
16908b9754b2SBitterblue Smith 		valid = false;
16918b9754b2SBitterblue Smith 
16928b9754b2SBitterblue Smith 		if (macid < 64)
16938b9754b2SBitterblue Smith 			valid = macid_valid & BIT(macid);
16948b9754b2SBitterblue Smith 
16958b9754b2SBitterblue Smith 		if (valid) {
16968b9754b2SBitterblue Smith 			ra->retry[0] = le16_to_cpu(*(__le16 *)rpt);
16978b9754b2SBitterblue Smith 			ra->retry[1] = rpt[2];
16988b9754b2SBitterblue Smith 			ra->retry[2] = rpt[3];
16998b9754b2SBitterblue Smith 			ra->retry[3] = rpt[4];
17008b9754b2SBitterblue Smith 			ra->retry[4] = rpt[5];
17018b9754b2SBitterblue Smith 			ra->drop = rpt[6];
17028b9754b2SBitterblue Smith 			ra->total = ra->retry[0] + ra->retry[1] + ra->retry[2] +
17038b9754b2SBitterblue Smith 				    ra->retry[3] + ra->retry[4] + ra->drop;
17048b9754b2SBitterblue Smith 
17058b9754b2SBitterblue Smith 			if (ra->total > 0) {
17068b9754b2SBitterblue Smith 				if (ra->ra_stage < 5)
17078b9754b2SBitterblue Smith 					rtl8188e_rate_decision(ra);
17088b9754b2SBitterblue Smith 				else if (ra->ra_stage == 5)
17098b9754b2SBitterblue Smith 					rtl8188e_power_training_try_state(ra);
17108b9754b2SBitterblue Smith 				else /* ra->ra_stage == 6 */
17118b9754b2SBitterblue Smith 					rtl8188e_power_training_decision(ra);
17128b9754b2SBitterblue Smith 
17138b9754b2SBitterblue Smith 				if (ra->ra_stage <= 5)
17148b9754b2SBitterblue Smith 					ra->ra_stage++;
17158b9754b2SBitterblue Smith 				else
17168b9754b2SBitterblue Smith 					ra->ra_stage = 0;
17178b9754b2SBitterblue Smith 			}
17188b9754b2SBitterblue Smith 		} else if (macid == 0) {
17198b9754b2SBitterblue Smith 			dev_warn(dev, "%s: TX report item 0 not valid\n", __func__);
17208b9754b2SBitterblue Smith 		}
17218b9754b2SBitterblue Smith 
17228b9754b2SBitterblue Smith 		dev_dbg(dev, "%s:  valid: %d retry: %d %d %d %d %d drop: %d\n",
17238b9754b2SBitterblue Smith 			__func__, valid,
17248b9754b2SBitterblue Smith 			ra->retry[0], ra->retry[1], ra->retry[2],
17258b9754b2SBitterblue Smith 			ra->retry[3], ra->retry[4], ra->drop);
17268b9754b2SBitterblue Smith 
17278b9754b2SBitterblue Smith 		if (min_rpt_time > ra->rpt_time)
17288b9754b2SBitterblue Smith 			min_rpt_time = ra->rpt_time;
17298b9754b2SBitterblue Smith 
17308b9754b2SBitterblue Smith 		rpt += TX_RPT2_ITEM_SIZE;
17318b9754b2SBitterblue Smith 	}
17328b9754b2SBitterblue Smith 
17338b9754b2SBitterblue Smith 	if (min_rpt_time != ra->pre_min_rpt_time) {
17348b9754b2SBitterblue Smith 		rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, min_rpt_time);
17358b9754b2SBitterblue Smith 		ra->pre_min_rpt_time = min_rpt_time;
17368b9754b2SBitterblue Smith 	}
17378b9754b2SBitterblue Smith }
17388b9754b2SBitterblue Smith 
rtl8188e_arfb_refresh(struct rtl8xxxu_ra_info * ra)17398b9754b2SBitterblue Smith static void rtl8188e_arfb_refresh(struct rtl8xxxu_ra_info *ra)
17408b9754b2SBitterblue Smith {
17418b9754b2SBitterblue Smith 	s8 i;
17428b9754b2SBitterblue Smith 
17438b9754b2SBitterblue Smith 	ra->ra_use_rate = ra->rate_mask;
17448b9754b2SBitterblue Smith 
17458b9754b2SBitterblue Smith 	/* Highest rate */
17468b9754b2SBitterblue Smith 	if (ra->ra_use_rate) {
17478b9754b2SBitterblue Smith 		for (i = RATESIZE; i >= 0; i--) {
17488b9754b2SBitterblue Smith 			if (ra->ra_use_rate & BIT(i)) {
17498b9754b2SBitterblue Smith 				ra->highest_rate = i;
17508b9754b2SBitterblue Smith 				break;
17518b9754b2SBitterblue Smith 			}
17528b9754b2SBitterblue Smith 		}
17538b9754b2SBitterblue Smith 	} else {
17548b9754b2SBitterblue Smith 		ra->highest_rate = 0;
17558b9754b2SBitterblue Smith 	}
17568b9754b2SBitterblue Smith 
17578b9754b2SBitterblue Smith 	/* Lowest rate */
17588b9754b2SBitterblue Smith 	if (ra->ra_use_rate) {
17598b9754b2SBitterblue Smith 		for (i = 0; i < RATESIZE; i++) {
17608b9754b2SBitterblue Smith 			if (ra->ra_use_rate & BIT(i)) {
17618b9754b2SBitterblue Smith 				ra->lowest_rate = i;
17628b9754b2SBitterblue Smith 				break;
17638b9754b2SBitterblue Smith 			}
17648b9754b2SBitterblue Smith 		}
17658b9754b2SBitterblue Smith 	} else {
17668b9754b2SBitterblue Smith 		ra->lowest_rate = 0;
17678b9754b2SBitterblue Smith 	}
17688b9754b2SBitterblue Smith 
17698b9754b2SBitterblue Smith 	if (ra->highest_rate > DESC_RATE_MCS7)
17708b9754b2SBitterblue Smith 		ra->pt_mode_ss = 3;
17718b9754b2SBitterblue Smith 	else if (ra->highest_rate > DESC_RATE_54M)
17728b9754b2SBitterblue Smith 		ra->pt_mode_ss = 2;
17738b9754b2SBitterblue Smith 	else if (ra->highest_rate > DESC_RATE_11M)
17748b9754b2SBitterblue Smith 		ra->pt_mode_ss = 1;
17758b9754b2SBitterblue Smith 	else
17768b9754b2SBitterblue Smith 		ra->pt_mode_ss = 0;
17778b9754b2SBitterblue Smith }
17788b9754b2SBitterblue Smith 
17798b9754b2SBitterblue Smith static void
rtl8188e_update_rate_mask(struct rtl8xxxu_priv * priv,u32 ramask,u8 rateid,int sgi,int txbw_40mhz,u8 macid)17808b9754b2SBitterblue Smith rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv,
1781769f3263SMartin Kaistra 			  u32 ramask, u8 rateid, int sgi, int txbw_40mhz,
1782769f3263SMartin Kaistra 			  u8 macid)
17838b9754b2SBitterblue Smith {
17848b9754b2SBitterblue Smith 	struct rtl8xxxu_ra_info *ra = &priv->ra_info;
17858b9754b2SBitterblue Smith 
17868b9754b2SBitterblue Smith 	ra->rate_id = rateid;
17878b9754b2SBitterblue Smith 	ra->rate_mask = ramask;
17888b9754b2SBitterblue Smith 	ra->sgi_enable = sgi;
17898b9754b2SBitterblue Smith 
17908b9754b2SBitterblue Smith 	rtl8188e_arfb_refresh(ra);
17918b9754b2SBitterblue Smith }
17928b9754b2SBitterblue Smith 
rtl8188e_ra_set_rssi(struct rtl8xxxu_priv * priv,u8 macid,u8 rssi)17933922dc9fSBitterblue Smith static void rtl8188e_ra_set_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi)
17943922dc9fSBitterblue Smith {
17953922dc9fSBitterblue Smith 	priv->ra_info.rssi_sta_ra = rssi;
17963922dc9fSBitterblue Smith }
17973922dc9fSBitterblue Smith 
rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info * ra)17988b9754b2SBitterblue Smith void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra)
17998b9754b2SBitterblue Smith {
18008b9754b2SBitterblue Smith 	ra->decision_rate = DESC_RATE_MCS7;
18018b9754b2SBitterblue Smith 	ra->pre_rate = DESC_RATE_MCS7;
18028b9754b2SBitterblue Smith 	ra->highest_rate = DESC_RATE_MCS7;
18038b9754b2SBitterblue Smith 	ra->lowest_rate = 0;
18048b9754b2SBitterblue Smith 	ra->rate_id = 0;
18058b9754b2SBitterblue Smith 	ra->rate_mask = 0xfffff;
18068b9754b2SBitterblue Smith 	ra->rssi_sta_ra = 0;
18078b9754b2SBitterblue Smith 	ra->pre_rssi_sta_ra = 0;
18088b9754b2SBitterblue Smith 	ra->sgi_enable = 0;
18098b9754b2SBitterblue Smith 	ra->ra_use_rate = 0xfffff;
18108b9754b2SBitterblue Smith 	ra->nsc_down = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2;
18118b9754b2SBitterblue Smith 	ra->nsc_up = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2;
18128b9754b2SBitterblue Smith 	ra->rate_sgi = 0;
18138b9754b2SBitterblue Smith 	ra->rpt_time = 0x927c;
18148b9754b2SBitterblue Smith 	ra->drop = 0;
18158b9754b2SBitterblue Smith 	ra->retry[0] = 0;
18168b9754b2SBitterblue Smith 	ra->retry[1] = 0;
18178b9754b2SBitterblue Smith 	ra->retry[2] = 0;
18188b9754b2SBitterblue Smith 	ra->retry[3] = 0;
18198b9754b2SBitterblue Smith 	ra->retry[4] = 0;
18208b9754b2SBitterblue Smith 	ra->total = 0;
18218b9754b2SBitterblue Smith 	ra->ra_waiting_counter = 0;
18228b9754b2SBitterblue Smith 	ra->ra_pending_counter = 0;
18238b9754b2SBitterblue Smith 	ra->ra_drop_after_down = 0;
18248b9754b2SBitterblue Smith 
18258b9754b2SBitterblue Smith 	ra->pt_try_state = 0;
18268b9754b2SBitterblue Smith 	ra->pt_stage = 5;
18278b9754b2SBitterblue Smith 	ra->pt_smooth_factor = 192;
18288b9754b2SBitterblue Smith 	ra->pt_stop_count = 0;
18298b9754b2SBitterblue Smith 	ra->pt_pre_rate = 0;
18308b9754b2SBitterblue Smith 	ra->pt_pre_rssi = 0;
18318b9754b2SBitterblue Smith 	ra->pt_mode_ss = 0;
18328b9754b2SBitterblue Smith 	ra->ra_stage = 0;
18338b9754b2SBitterblue Smith }
18348b9754b2SBitterblue Smith 
18353dfb8e84SJes Sorensen struct rtl8xxxu_fileops rtl8188eu_fops = {
18363dfb8e84SJes Sorensen 	.identify_chip = rtl8188eu_identify_chip,
18373dfb8e84SJes Sorensen 	.parse_efuse = rtl8188eu_parse_efuse,
18383dfb8e84SJes Sorensen 	.load_firmware = rtl8188eu_load_firmware,
18393dfb8e84SJes Sorensen 	.power_on = rtl8188eu_power_on,
18403dfb8e84SJes Sorensen 	.power_off = rtl8188eu_power_off,
184170664495SBitterblue Smith 	.read_efuse = rtl8xxxu_read_efuse,
18423dfb8e84SJes Sorensen 	.reset_8051 = rtl8188eu_reset_8051,
18433dfb8e84SJes Sorensen 	.llt_init = rtl8xxxu_init_llt_table,
18443dfb8e84SJes Sorensen 	.init_phy_bb = rtl8188eu_init_phy_bb,
18453dfb8e84SJes Sorensen 	.init_phy_rf = rtl8188eu_init_phy_rf,
18463dfb8e84SJes Sorensen 	.phy_lc_calibrate = rtl8723a_phy_lc_calibrate,
18473dfb8e84SJes Sorensen 	.phy_iq_calibrate = rtl8188eu_phy_iq_calibrate,
18483dfb8e84SJes Sorensen 	.config_channel = rtl8188eu_config_channel,
18493dfb8e84SJes Sorensen 	.parse_rx_desc = rtl8xxxu_parse_rxdesc16,
185070664495SBitterblue Smith 	.parse_phystats = rtl8723au_rx_parse_phystats,
18513dfb8e84SJes Sorensen 	.init_aggregation = rtl8188eu_init_aggregation,
18523dfb8e84SJes Sorensen 	.enable_rf = rtl8188e_enable_rf,
18533dfb8e84SJes Sorensen 	.disable_rf = rtl8188e_disable_rf,
18543dfb8e84SJes Sorensen 	.usb_quirks = rtl8188e_usb_quirks,
18553dfb8e84SJes Sorensen 	.set_tx_power = rtl8188f_set_tx_power,
18568b9754b2SBitterblue Smith 	.update_rate_mask = rtl8188e_update_rate_mask,
18573dfb8e84SJes Sorensen 	.report_connect = rtl8xxxu_gen2_report_connect,
18583922dc9fSBitterblue Smith 	.report_rssi = rtl8188e_ra_set_rssi,
18593dfb8e84SJes Sorensen 	.fill_txdesc = rtl8xxxu_fill_txdesc_v3,
18603dfb8e84SJes Sorensen 	.set_crystal_cap = rtl8188f_set_crystal_cap,
18613dfb8e84SJes Sorensen 	.cck_rssi = rtl8188e_cck_rssi,
1862873b3811SBitterblue Smith 	.led_classdev_brightness_set = rtl8188eu_led_brightness_set,
1863*93b3a456SBitterblue Smith 	.writeN_block_size = 196,
18643dfb8e84SJes Sorensen 	.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
18653dfb8e84SJes Sorensen 	.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
18663dfb8e84SJes Sorensen 	.has_tx_report = 1,
1867a5be45eaSBitterblue Smith 	.init_reg_pkt_life_time = 1,
18683dfb8e84SJes Sorensen 	.gen2_thermal_meter = 1,
1869563d5025SMartin Kaistra 	.max_sec_cam_num = 32,
18703dfb8e84SJes Sorensen 	.adda_1t_init = 0x0b1b25a0,
18713dfb8e84SJes Sorensen 	.adda_1t_path_on = 0x0bdb25a0,
18723dfb8e84SJes Sorensen 	/*
18733dfb8e84SJes Sorensen 	 * Use 9K for 8188e normal chip
18743dfb8e84SJes Sorensen 	 * Max RX buffer = 10K - max(TxReportSize(64*8), WOLPattern(16*24))
18753dfb8e84SJes Sorensen 	 */
18763dfb8e84SJes Sorensen 	.trxff_boundary = 0x25ff,
18773dfb8e84SJes Sorensen 	.pbp_rx = PBP_PAGE_SIZE_128,
18783dfb8e84SJes Sorensen 	.pbp_tx = PBP_PAGE_SIZE_128,
18793dfb8e84SJes Sorensen 	.mactable = rtl8188e_mac_init_table,
18803dfb8e84SJes Sorensen 	.total_page_num = TX_TOTAL_PAGE_NUM_8188E,
18813dfb8e84SJes Sorensen 	.page_num_hi = TX_PAGE_NUM_HI_PQ_8188E,
18823dfb8e84SJes Sorensen 	.page_num_lo = TX_PAGE_NUM_LO_PQ_8188E,
18833dfb8e84SJes Sorensen 	.page_num_norm = TX_PAGE_NUM_NORM_PQ_8188E,
18843dfb8e84SJes Sorensen 	.last_llt_entry = 175,
18853dfb8e84SJes Sorensen };
1886