From 2c38dc04d6f8bc84620bb3b67c8ccd9f910c4d03 Mon Sep 17 00:00:00 2001 From: Mir Saheb Ali Date: Tue, 20 Oct 2026 00:40:27 +0530 Subject: [PATCH] rtwn: add support for the RTL8188FTV USB chipset Add support for the RTL8188FTV chipset to rtwn(4)/rtwn_usb(4). Differential Revision: https://reviews.freebsd.org/D60875 --- share/man/man4/rtwn.4 | 5 +- share/man/man4/rtwn_usb.4 | 3 +- share/man/man4/rtwnfw.4 | 4 +- sys/conf/files | 11 + sys/contrib/dev/rtwn/rtwn-rtl8188fufw.fw.uu | 471 +++++++++++++ sys/dev/rtwn/if_rtwn.c | 4 +- sys/dev/rtwn/if_rtwnvar.h | 6 + sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c | 2 + sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c | 2 + sys/dev/rtwn/rtl8188f/r88f.h | 57 ++ sys/dev/rtwn/rtl8188f/r88f_calib.c | 728 ++++++++++++++++++++ sys/dev/rtwn/rtl8188f/r88f_chan.c | 358 ++++++++++ sys/dev/rtwn/rtl8188f/r88f_fw.c | 79 +++ sys/dev/rtwn/rtl8188f/r88f_init.c | 212 ++++++ sys/dev/rtwn/rtl8188f/r88f_priv.h | 214 ++++++ sys/dev/rtwn/rtl8188f/r88f_reg.h | 80 +++ sys/dev/rtwn/rtl8188f/r88f_rom.c | 121 ++++ sys/dev/rtwn/rtl8188f/r88f_rom_defs.h | 12 + sys/dev/rtwn/rtl8188f/r88f_rom_image.h | 56 ++ sys/dev/rtwn/rtl8188f/r88f_rx.c | 132 ++++ sys/dev/rtwn/rtl8188f/usb/r88fu.h | 24 + sys/dev/rtwn/rtl8188f/usb/r88fu_attach.c | 254 +++++++ sys/dev/rtwn/rtl8188f/usb/r88fu_init.c | 444 ++++++++++++ sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c | 2 + sys/dev/rtwn/rtl8192c/r92c.h | 1 + sys/dev/rtwn/rtl8192c/r92c_beacon.c | 6 + sys/dev/rtwn/rtl8192c/r92c_reg.h | 5 + sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c | 2 + sys/dev/rtwn/rtl8192e/r92e_reg.h | 11 + sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c | 2 + sys/dev/rtwn/rtl8723b/usb/r23bu_attach.c | 2 + sys/dev/rtwn/rtl8812a/usb/r12au_attach.c | 2 + sys/dev/rtwn/rtl8821a/usb/r21au_attach.c | 2 + sys/dev/rtwn/usb/rtwn_usb_attach.h | 10 + sys/dev/usb/usbdevs | 1 + sys/modules/rtwn/Makefile | 5 + sys/modules/rtwn_usb/Makefile | 4 + sys/modules/rtwnfw/Makefile | 3 +- sys/modules/rtwnfw/rtwnrtl8188fu/Makefile | 4 + 39 files changed, 3336 insertions(+), 5 deletions(-) create mode 100644 sys/contrib/dev/rtwn/rtwn-rtl8188fufw.fw.uu create mode 100644 sys/dev/rtwn/rtl8188f/r88f.h create mode 100644 sys/dev/rtwn/rtl8188f/r88f_calib.c create mode 100644 sys/dev/rtwn/rtl8188f/r88f_chan.c create mode 100644 sys/dev/rtwn/rtl8188f/r88f_fw.c create mode 100644 sys/dev/rtwn/rtl8188f/r88f_init.c create mode 100644 sys/dev/rtwn/rtl8188f/r88f_priv.h create mode 100644 sys/dev/rtwn/rtl8188f/r88f_reg.h create mode 100644 sys/dev/rtwn/rtl8188f/r88f_rom.c create mode 100644 sys/dev/rtwn/rtl8188f/r88f_rom_defs.h create mode 100644 sys/dev/rtwn/rtl8188f/r88f_rom_image.h create mode 100644 sys/dev/rtwn/rtl8188f/r88f_rx.c create mode 100644 sys/dev/rtwn/rtl8188f/usb/r88fu.h create mode 100644 sys/dev/rtwn/rtl8188f/usb/r88fu_attach.c create mode 100644 sys/dev/rtwn/rtl8188f/usb/r88fu_init.c create mode 100644 sys/modules/rtwnfw/rtwnrtl8188fu/Makefile diff --git a/share/man/man4/rtwn.4 b/share/man/man4/rtwn.4 index fd219f228f65..0b1aed6f52bf 100644 --- a/share/man/man4/rtwn.4 +++ b/share/man/man4/rtwn.4 @@ -19,7 +19,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd September 1, 2026 +.Dd October 22, 2026 .Dt RTWN 4 .Os .Sh NAME @@ -89,6 +89,8 @@ driver supports USB and PCI devices with the following chipsets: .It Realtek 802.11n wireless 8188e (RTL8188E) .It +Realtek 802.11n wireless 8188f (RTL8188F) +.It Realtek 802.11n wireless 8192c (RTL8192C) .It Realtek 802.11n wireless 8192e (RTL8192E) @@ -119,6 +121,7 @@ which are loaded when an interface is brought up: .Bl -tag -width Ds -offset indent -compact .It Pa /boot/kernel/rtwn-rtl8188eefw.ko .It Pa /boot/kernel/rtwn-rtl8188eufw.ko +.It Pa /boot/kernel/rtwn-rtl8188fufw.ko .It Pa /boot/kernel/rtwn-rtl8192cfwE_B.ko .It Pa /boot/kernel/rtwn-rtl8192cfwE.ko .It Pa /boot/kernel/rtwn-rtl8192cfwT.ko diff --git a/share/man/man4/rtwn_usb.4 b/share/man/man4/rtwn_usb.4 index 706696514920..285ef95430d2 100644 --- a/share/man/man4/rtwn_usb.4 +++ b/share/man/man4/rtwn_usb.4 @@ -29,7 +29,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" THE POSSIBILITY OF SUCH DAMAGES. .\" -.Dd September 11, 2026 +.Dd October 22, 2026 .Dt RTWN_USB 4 .Os .Sh NAME @@ -101,6 +101,7 @@ Realtek RTL 8188/8192/8723/8812 and 8821 chipsets, including: .It "Realtek RTL8723BU" Ta RTL8723BU Ta USB 2.0 .It "Realtek RTL8192CU" Ta RTL8192CU Ta USB 2.0 .It "Realtek RTL8188CUS" Ta RTL8188CUS Ta USB 2.0 +.It "Realtek RTL8188FTV" Ta RTL8188FTV Ta USB 2.0 .It "Sitecom WLA-7100" Ta RTL8812AU Ta USB 3.0 .It "TP-Link Archer T2U Nano" Ta RTL8821AU Ta USB 2.0 .It "TP-Link Archer T2U Plus" Ta RTL8821AU Ta USB 2.0 diff --git a/share/man/man4/rtwnfw.4 b/share/man/man4/rtwnfw.4 index 98e3ef0c13aa..c3eeae7f1bdf 100644 --- a/share/man/man4/rtwnfw.4 +++ b/share/man/man4/rtwnfw.4 @@ -41,6 +41,7 @@ of the following: .Bd -ragged -offset indent .Cd "device rtwn-rtl8188eefw" .Cd "device rtwn-rtl8188eufw" +.Cd "device rtwn-rtl8188fufw" .Cd "device rtwn-rtl8192cfwE_B" .Cd "device rtwn-rtl8192cfwE" .Cd "device rtwn-rtl8192cfwT" @@ -56,6 +57,7 @@ module at boot time, place the following line in .Bd -literal -offset indent rtwn-rtl8188eefw_load="YES" rtwn-rtl8188eufw_load="YES" +rtwn-rtl8188fufw_load="YES" rtwn-rtl8192cfwE_B_load="YES" rtwn-rtl8192cfwE_load="YES" rtwn-rtl8192cfwT_load="YES" @@ -70,7 +72,7 @@ to firmware sets for the Realtek RTL8188CE chip based PCIe adapters. rtwn-rtl8188ee module provides access to firmware sets for the Realtek RTL8188EE chip based PCIe adapters. Other modules provide access to firmware sets for the Realtek RTL8188CUS, -RTL8188CE-VAU, RTL8188EUS, RTL8188RU, RTL8192CU, RTL8192EU, RTL8812AU and +RTL8188CE-VAU, RTL8188EUS, RTL8188FTV, RTL8188RU, RTL8192CU, RTL8192EU, RTL8812AU and RTL8821AU chip based USB WiFi adapters. They may be statically linked into the kernel, or loaded as a modules. diff --git a/sys/conf/files b/sys/conf/files index c3b8e8288745..e83e27c54d4d 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2964,6 +2964,17 @@ dev/rtwn/rtl8188e/pci/r88ee_init.c optional rtwn_pci pci dev/rtwn/rtl8188e/pci/r88ee_rx.c optional rtwn_pci pci dev/rtwn/rtl8188e/usb/r88eu_attach.c optional rtwn_usb dev/rtwn/rtl8188e/usb/r88eu_init.c optional rtwn_usb + +# RTL8188F +dev/rtwn/rtl8188f/r88f_calib.c optional rtwn +dev/rtwn/rtl8188f/r88f_chan.c optional rtwn +dev/rtwn/rtl8188f/r88f_fw.c optional rtwn +dev/rtwn/rtl8188f/r88f_init.c optional rtwn +dev/rtwn/rtl8188f/r88f_rom.c optional rtwn +dev/rtwn/rtl8188f/r88f_rx.c optional rtwn +dev/rtwn/rtl8188f/usb/r88fu_attach.c optional rtwn_usb +dev/rtwn/rtl8188f/usb/r88fu_init.c optional rtwn_usb + # RTL8192C dev/rtwn/rtl8192c/r92c_attach.c optional rtwn dev/rtwn/rtl8192c/r92c_beacon.c optional rtwn diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8188fufw.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8188fufw.fw.uu new file mode 100644 index 000000000000..c73dba79f911 --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8188fufw.fw.uu @@ -0,0 +1,471 @@ +begin 644 rtwn-rtl8188fufw.fw.uu +M\8@0``0````((A +M%```,`("`P0$"`D)#`X0$@()"PX-#Q`2``0`!``(`!``(P`M`%``D0##`2`(P`R`#<`5X!:`&:`?6,THSL)(?XYKP"`G3_PY6!M$``0,YY`WB`%N8(<`O"K^8PX0-$&/;2 +MKPC9[>J+T"+E#/\C)('X#P@(OP,$?P!X@>8PY/(`Y0S#GU`@!0QTAB4,^.;] +MIH$(YJX,O@("=/_-^.AM8.`(YL#@@/;E#-.?0"?E#"2'^.:N#+X"`G3__1CF +MS?CE@6U@!M#@]AB`]>4,)(;(]A4,@-/E#",D@?A_!,*OYC#@`Q#B#'\`,.$' +M,.,$?PA4]%1\QM*O5(!"!R)XAJ:!=`)@!O\(=O_?^W\#Y'B`]@CV"-_Z>(%V +M,)"(#70!D\#@Y)/`X$.)`76*8'6,>=*,TJ\B`N_3E`)``W__(G2!+R_XYB#E +M],*OYD0P]M*OK@SNPY]0(0YTAB[XYOD(YAB^`@)T__WM:6`)"><9&?<)"8#S +M%A:`VN[3GT`$!8$%@>[3GT`B=(8N^`CF^>ZU#`*I@1@&!N;][6E@"1D9YPD) +M]QF`\QZ`V>\DAOCF!/CO+P20B`V3]@CO+Y/V?P`B[].4`D`#?_\B[R,D@?CF +M,.7TPJ_F5(SVTJ_E#+4'"G2&+_CF]8$"A$U0+G2'+_CFOP("=/_]&.;Y=(8O +M^/OF_.EL8`BH!>?V'1F`]*@#I@4?Y0RU!^-_`")TAR_XYOT8A@$/=(8O^*8! +M"(8$Y0RU!P*L@>UL8`@-":@%YO>`].4,M0?>B8%_`"+OTY0"0`-__R+O(R2! +M^,*OYC#E!3#@`M+DTN+&TJ]_`##B`0\"A$R/\.3__N4,(R2`^,*I,/<-?PCF +M8`LM]F`P4"Z`!S#Q!NWV8"5^`@@P\!#"K^80YR,.,.(,TJ]_!(`2PJ_F$.<3 +M5.Q.]M*O`H1-?P@([T2#],*O5L;2KU2`3_\B[RO_[CK^[3G][#C\(L/OF__N +MFO[MF?WLF/PBZ(_PI,R+\*0L_.F.\*0L_(KP[:0L_.J.\*3-J/"+\*0MS#@E +M\/WIC_"D+,TU\/SKCO"D_JGPZX_PI,_%\"[-.?[D//SJI"W.-?#]Y#S\(N]; +M_^Y:_NU9_>Q8_"+O2__N2O[M2?WL2/PBX/RCX/VCX/ZCX/\BX/BCX/FCX/JC +MX/LBX/NCX/JCX/DBZ_"CZO"CZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*( +M@^1S=`*3:&#OHZ.C@-\"A[L"A-WDDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5``OD&5$0!!E1(`0949``"[(,!FR`$27A!_!)"5%^_P?P(2AB>0 +MA,'@_Y"5%^#^[TZ0A,'P(I"3^^_P47Y_]'X`$F0WOP$(D)0:X)"4'/!1?G_U +M?@`29#>_`0B0E!K@D)0=\%%^?_9^`!)D-[\!")"4&N"0E![P47Y_]WX`$F0W +MOP$(D)0:X)"4'_!1?G_X?@`29#>_`0B0E!K@D)0@\%%^$K]LOP$(D)0:X)"4 +M(?!1?E&%<%*0E!K@D)0B\%0'8`B0E!K@5.!P/GL!>I1Y&W_Z48=P,I"4&N#\ +M5`=P$I"4(N#^D)0;X%0'_>Y-D)0B\.Q4X'`2D)0BX/^0E!O@5.#^[TZ0E"+P +M47Y__5&'<$>0E!K@_E3,D)0C\.Y4#/]@")"4&N!4P'`N[W`2D)0CX/^0E!K@ +M5`,2T_`0B0E!K@ +MD)0F\%%^?_-^`!)D-[\!")"4&N"0E"?P47Y__'X`$F0WOP$(D)0:X)"4*/"0 +MD_QT&?"0E`IT"/"0E!S@D)/^\)"4'>"0D__PD)0>X)"4`/"0E!_@D)0!\)"4 +M(."0E`+PD)0AX)"4`_"0E"+@D)0$\)"4(^"0E`7PD)0+=!KPD)09=`7PD)0D +MX)"4#?"0E"7@D)0.\)"4)N"0E`_PD)0GX)"4$/"0E"C@D)01\)"3^^"T`19[ +M`7J3>?P27A![`7J4>0L27A!_!`$8=1L!=1R3=1W\=1X*>P%Z`7F@$FHA=1L! +M=1R4=1T-=1X%>P%Z`7FJ`FHA>P%ZE'D:(G_[?@`29#?O9`$B$J`W$@+V__%S +M_E0#_>X3$U0'^\`#\5CQ\Q+0:M`#$JE9\5CQP%ZDWG&$EX0?P0!&)"3P!*'3I"3O^_P$H=7BS,`BSWP +MY*/P[Q1@`H&OD`8#X%3[\)"5%>#[Q#-4X/Z0!$+@5)]._O#D_1+-!9"5%N_P +MD`2#\)"4TQ($]P````&0E-<2!/<````!L8(2!/<````!D)37$@3W`````7\` +M?@FQAA($]P```!"0E16QI>]4`__D>`$2!,5X!/%D?P!^"K&&$@3W```,`)"5 +M%;&E[U0#_^1X"O%D?P!^#;&&$@3W#````)"5%K&E[U0#_^1X&O%D?QBQA!($ +M]P``#`"0E-<2!/<`````L1B0E,$2!/<```P`D)3%$@3W```$`(!;D`8#X$0$ +M\)"4TQ($]P````&0E-<2!/<`````L8(2!/<````!D)37$@3W`````'\`?@FQ +MAA($]P``#`"0E-<2!/<```P`L1B0E,$2!/<```P`D)3%$@3W```,`'T8?`#D +M_Q*ITM#0DJ\B?X1^"-,0KP'#P-"0E-'N\*/O\!)P89"4VQ($ZY"4TQ*'+1($ +MIY"4V_%>P`3`!<`&P`>0E-,2ARV0E-?Q7M`#T`+0`=``$H<@D)3?$@3KD)3? +M$H0E&_Q?.##GY"1;Q*OD?O]?U!^`1)A09"4 +M;^#_\:94!_YD`F`#[G`1[_%]X"3\_^20D6[PH^\2QB"0D@K@\:)4!_\48`\4 +M8`<48`DD`W`+$LQ>@`,2E^X2E!>0DK/@_Y"2MN#3GT`"X4FQC!*'(,`$P`7` +M!L`'D`5BL:5X$!($V-`#T`+0`=``$H<@P`3`!<`&P`>CL:5X&!($V-`#T`+0 +M`=``$H<@D)1P$@3KD`5EL:42KH"0!62QI1*'(,`$P`7`!L`'D`5FL:5X$!($ +MV-`#T`+0`=``$H<@P`3`!<`&P`>CL:5X&!($V-`#T`+0`=``$H<@D)1T$@3K +MD)1O\7RQI1*OII"4!($ZY"4!*OGU`1\4P2N3?D +M/?WD//R0E'02!.OQ3!*OM_%*$J_`\4H2K\GQ2I`%B._PD)1X$H!*'+1*OY._PD)1X$H`PX`L2KXKDD)(,\!+%\2+#$U0'=?`;I"0Z]8+D-)+U +M@^`B$@+V_Y"2O/"_`0E_`1$SY)"2O/`B$J^ND)(\\/%SD)(]\?*0DE?P$I$) +MD))8\!*7YY"2#_D(7!X%3]3_#L5`3_D)+)X%3[3_#M5`_$5/#_$K?<$H_QD(7$\!$Y +M,.!0PQ-4!__#E`20A=A0!._P@"=T`_`2CUCI)`82I^[_=`,D_?[OQ%0/_>]4 +M#__M+E0/_L14\$\2`SP2CU@1.<14#__#E`20AP%1KC$),S,S5/@2T?']=?`.I"06]8+D-)+U@^_P,0G$$U0'_^UU\`ZD)!?U +M@N0TDO6#[_#NQ%0/_Q1M<"&0D@OO\!$Y5`_$5/#_D)(*X%0/3_!4\?"0D@G@ +M1`$2T2,BCUZ-7ZX#=!_#E5Y`"E&FY/U1GB34@#%T/\.57D`*4:9](%&<)(B` +M('1?PY5>0`I1IGU`49PDT(`/='_#E5Y`(%&F?6!1G"2$_>0T!/SE7Q+1$_6# +M=?`#[A(%*.SPH^WP(L/OG?5@PY0(4!SD]6%QG\"#P(*0D\?@T(+0@W7P`Q(% +M*.5@\(`^Y6##E!!0"75A`>5@)/B`%^5@PY084`EU80+E8"3P@`=U80/E8"3H +M_W&?P(/`@I"3Q^#0@M"#=?`#$@4H[_"O82*O7E$UD)/#[_`BD)/'[O"K7R(Q +MU*M;JERI72+M=?`.I"0.]8+D-)+U@^`BCU[1YN5>\?WU@^#\Y5Y1N!+06J\$ +M$JE9Y5Y1N!*+ON5>$JKC_;&2L8*M7G\!@`#3$*\!P\#0D)3Y[_"C[?#DH_"0 +ME/O@_\.4`T`"89J0E/K@_A+1$_6#=?`#[Q+1>^"0E/SPD)3YX/RT`B"0E/S@ +M_>YQH,"#P(*0E/O@T(+0@Q*R>X`"PS/8_$V`(.RT`2`2T9UQH,"#P(*0E/O@ +MT(+0@Q*R>X`"PS/8_/1?D)3\\!+1G1+1$_6#P(/`@I"4^^#0@M"#=?`#$M%[ +M[_"0E/O@!/!A"-#0DJ\BZW7P#J0D$?6"Y#22]8,B$M"GM0<$[E3Q\!+%\>20 +MD@SPT>X2T+[Q_/6#X/I1M_Q4`_WL$Q-4!_ON$M!IKP(2J5F1#E&X$HN^D0[_ +M=?`.I"08]8+D-)+U@^`$\!*JXOVQDN3[_9$*_7\!0?9__[&'D)(*X,,35`0E'SP8`?@9`)@`J$ED)(,X'`N$M&P>TY] +M;Y$*\=G@_WX`>P1]`;&2OP$-\5K@1`'PD)(,=`'P(I"4?>#]>T^!_9"2#.!D +M`6`"H1:1#O\2CZ;^Q%0/,.`"H13O\6+@_S#@")"4?W0!\(`7[\,3(.`1D)1_ +M=`'P$M&P>U!];W__L8>0E'_@8&20DKO@_Y"2NN!O8$/@!/#@TY0!0`B0E(!T +M!/"`!>20E(#PD0[QV>#_?@"0E(#@^WT!L9*_`0X2T5?PY/O]?UA^`0)A09"4 +M?>#]>U'D_Z&'Y)"2NO'MD)(*X/_Q7N!4^_"``O'ND)(,X&0%<&/1-^]P7H!7 +MD)1\X/]D`V`%[V0!<$Z0D@S@9`5P1I"4?.!D`7`L$H]YX-.4'Y"2"N!`"O'6 +MX/]]`'Q\@!+#\=;@^Q*/>>!]`"7@)>#\KP,2F.Z1#OU_`A*J4M$W[W`%?P82 +MJOOP(M,0KP'#P-"0E/+N\*,2L0.0!!W@8">0!2+@ +MD)3X\'L4T>CO9`%P!1+0<8`$?P"`%9"4^.#]>Q7D_[&'@`,2T'$2G_A_`=#0 +MDJ\BD)()X##@4Y"2#.!P)7L6?6_1ZI$.$JKC?0&QDI$.$L4!X$0!\!+15Q+& +M()"2#'0!\"*0D@S@9`%P'I$.$L4`X##@%1*JXGT!L9(2T5?PY/O]?U1^`0)A +M07&N(M'N[W`"_R*1#I"2B/`2T*>U!P3N5/'PD0[U=^20D@SPY7=U\!ND)#OU +M@N0TDO6#X##@)_%.X"2+]8+D-)+U@^#_$JK2[_%-X`3Q3>#_D)**X/[OM08$ +M\4[D\!*JTN#\D)*(X!*JU.!L8`_E=Q+03*\$$JE9Y7<2B[#E=Q*/IE0'_V`# +MOP(.Y7?QV>#_?@![!.3]L9*M=W\!$JI2D)*)X,,35`/_OP(%Y/\2JO=_`2)[ +M%WW_?_^QA^20E07PH_"0!2+@D)4'\'U'?_\2F..0!?C@D2F.-_`2+3D)4&X)3HD)4%X)0#0!"0`<#@1"#P$M'I$ICC?P`B?S)^ +M`!)\GY"5!1*]_X"W\'2N)7?U@N0TDO6#(I"2"N##$U0'=?`;I"0^]8+D-)+U +M@R+DD)1O\)"2"N`PX%G#$U0'__%BX/XPX$WO\6+N5/[P[_%B$L2Y,.`1D)(* +MX/[Q7N]4^_"0E&]T`?"0!.#@,.$=\>[Q6N!$`O#DD)*Z\)$._7\"$JI2D)1O +MX&`*@1?Q6N!4_?"Q@B(35`=U\!ND)$#U@N0TDO6#(I``!`(##_"0D@QT!?`B +M\)``!0(##_UU\`ZD)`WU@N0TDB*+6XIY5[3E6!0*!'75`']KUX2;E^O7A)W.>^O7G`$$9^``O'@D)+$X&`$ +MKUX1GP5>@-'E7W`6_Q)W.>]P#Q*_BQ)Y81+&I52_\%1_\")]`=,0KP'#P-"0 +MD\/O\*/M\'U$?V]1@9"3Q."0D\.T`0G@4;S@1`3P@`?@4;S@5/OP$>#0T)*O +M(JM;JERI70("]N3]_Y`%(N_PD)(![?`BTQ"O`_PH^SPH^WPD`0= +MX&`.``C'4D`4BX%1O_WTX$>/Q +M^-#0DJ\BTQ"O`RI\`*T'D)3]X)`$)?"0 +ME/[@8`51K$2`\*\%="`O]8+D-/SU@^!4P/!1K%3`\)"5`.#_K@5T&"[U@N0T +M_/6#[_!1CO6#X"#A%U0!_Y"4_^`EX"7@^^]$`DO_48[U@^_PKP5T$2_U@N0T +M_/6#=/_P="DO]8+D-/SU@^!4]_"N!*\%T-"2KR*0E('@_Y"5`'0,\.3[?0$Q +M-I"4A.[PH^_PD)2"X/RCX/T"=]C3$*\!P\#0D)22[_"C[?"0A,/@!/"0!!W@ +M8#60!2+@D)26\'TF47_O9`%P%U&7^WT!$CK"$M#\(.`)D)()X"#@`E&AD)26 +MX/]])Q'C48:`'E&&49?[D)4`=`KP?0$Q-A+0_"#@"9"2">`@X`)1H?'XD(2_ +MH^`D?_6"Y#2"]8-T`?#_T-"2KR)__Q'C`I;ND)22X/\"7*-T$B[U@N0T_"*0 +MA,C@_Y"4D^`BD)24X/ZCX/\"4-=T(2_U@N0T_/6#X"+@_>5VQ%3P)`7U@N0T +M@?6#(HUV[S#F&G%(4;C@5`.0D0OPY/NO=A(G/7$[T5UT`8!)T60$\-%D9`)P +M'G2I)7;Q0>#]]&`"@`1Q2.#]4;H2T3MQ2-%==`*`(=%DTY0#0`VO=A)ME'$[ +MT5UT`X`-<4A1N!+1.W%(T5UT`O"K=N3]_P)2PW2\)7;U@N0TD/6#Y/#E=L14 +M\"0`]8+D-('U@R*0!(7@]6N0E*C@!/#D]6.0A;O@_^5CPY]``L%$Y6-Q2N#U +M;1+1A^!E;6`6D(IQY6WPY*/PJV/]_Q)2PQ+1A^5M\)`$H.!D`7!,H^!E8W!& +MH^#U9*/@D)1%\.5C<4K@961P`L%`Y6-Q2N5D\.5C4;S@5/S_D)1%X%0#3__E +M8U&\[_"0BG'E9/"C=/_PJV/D_?\24L/!0*]C$GP&0E$`2ATZ0``(2!!C_ +M$@/M+_\2T>'_$M&YD``($@08+_5L\=7@]6BCX/5I\##E`%`!=%%X!3PD)1`$H=%D``( +M$@08_Y"41.`O_Y"40^`U\/X2T;GN-?#^$M'A_>XU\/SE:,,3_N5I$__3[9_L +MGD`-Y6.4!5`%T45T`_"A_9"40!*'11(#[65L<`+E\'`JY6/#E`50"M%%X-.4 +M`$`"@`?E;,.4`U`(?0:O8_%OP4#D_:]CT7'Q:\$]$M'2P3W11>3PD)1*=`+P +MJVJM8Z]IKF@2RV^.9H]G$M%)PW0!DY5GY).59E`,T5'D\'T!KV/1<8!1$M'9 +MP^5GG^5FE`!0#=%1Y/!]`:]C$K18@#?Q:]%1X`3PY660@VV3_]%1X,.?0"+1 +M4>3P$M'9$M%)=`&3+__DDS0`PQ/^[Q/_Y6/Q7^[PH^_P$M'2!6-A9B)TN25C +M]8+D-)3U@R)TK"5C]8+D-(_U@R+@D(IQ\*,B=+PE=O6"Y#20]8/@(H]NC6_O +M<4K@_51_]7#M5(#U<77P$N\2M1?U_P@`<2 +MM0OE<_#]D)$+Y7+PJV^O;@(G/72I)6[U@N0TE/6#(N5P)>`D]?6"Y#2"]8/D +MD_YT`9/_Y6XEX"1[]8+D-(_U@R)]!Z]C[3#@(G7P$N^0B43QOI")1O&^D(E( +M\;Z0B4KQOI")3!(%*.3PH_#M,.$*=?`2[_':Y/"C\.TPX@AU\!+O\<_D\!+1 +M8.!4OT2`_A+18.[P(A(%*.3PH_!U\!+O(G7P$N5CD(E"`@4H=?`2Y6.0B4`" +M!2CD_0&A?1]_;Q'CD`4GX%2_\)"%OW0$\"*0!!]T(/`B$3>0!"3@]5OD_Q*/ +M6!$J=?`.I"09]8+D-)+U@^[P$2H2E]GN\`_OM`/@(H^"=8,`$@,/)5O^[R*0 +MD\,"ATX1-Q*/6!("]E1__1*/<_Y4'Y"3QU']D)/&$H_R_E0#_.Y4,,14#Y"3 +MR1*/\OY40,03$U0#D)/(4?W_$H_S^U0($Q,35!^0D\OP^NM4!!,35#^C\.]4 +M`<0S,S-4@#&*5']/\)"3R.!4`<0S,U3`,8I4OT_PZF`"(8F0D\?@5!]1Z53@ +M3_#L5`,QBE3\3_#L5`,EX"7@,8I4\T_PD)/&X%0!Q#-4X%'I5-]/\)"3R>!4 +M`\14\#&*5,]/\23@5/OQ),"#P(+@_Y"3S.`2T`D_&`/)`-@`D&I +MD)4(X/_1&T&ID)4(X"3<]8+D-(]1]O]1XG7P$C&/$Q-4`_L-Y/]1XG7P$C&/ +M<0'[#>3_4>)U\!(QC\14`_L-Y/]1XG7P$A*U%_OD_0]1XG7P$I")/1(%*%'? +M=?`24>[$$U0!^PU_`5'B=?`24>Y4'U'@\?51]@]1XG7P"*0D`?6"Y#2"4=UU +M\`BD)`+U@N0T@E'==?`(I"0#]8+D-()1W77P"*0D!/6"Y#2"4?8/4>)U\`BD +M)`7U@N0T@E'==?`(I"0&]8+D-()1W77P"*0D!_6"Y#2"]8/@^PU1M=$4,.`" +M\=+0T)*O(N]P!'3P@!;OM`$$=/2`#N^T`@1T^(`&[[0##'3\+?6"Y#0"]8/K +M\"+U@^#[#5&UD)4(X"+_=?`2[9")/A(%*.`B]8/@^^3](O#N5(#$$Q,35`$B +M?0%_!-,0KP'#P-"0E1OM\)"%P>#^Q!,35`,PX`*!9NYQ`3#@`H%FD(7(X/YO +M<`*!9N]P`F'1)/YP`H$.)/Y@323\<`*!323\8`*!7^ZT#@,2=).0A8"0A$LWQ[V0!<%82=_Z`49"%R."T#@B1 +M:[\!`Q)TDY"%R."T!@,2?.`$I"%R."T#`L2PTY4/S#@`Q)ZBI"%R!+1;O#0T)*O(M,0KP'# +MP-`2>BGO9`%@!74/`8`DD(7!X!,3$U0?,.`%=0\"@!.0A;P2:B$2F-?_PQ,@X`*A:Y"%O.`PX&S1:75>(=%Y,.`% +M$M$K@`WDD(6]\*/P?4#_$GQ!T7!4'S#@`T->$N_$5`\PX`-#7A20A;S@Q!-4 +M!S#@`T->@/'B(.`#0UY`T0V0A;_@<`5_`1+)7M&",.`$?P2`"]&-[V`$?P&` +M`G\"$LE>@'[1"I"%O^!D!&`"P07_$LE>P060A;S@,.!MT6E#7C'1>3#@!1+1 +M*X`'?4#D_Q)\0=%P5!\PX`-#7@+OQ%0/,.`#0UX$T0W1@C#@"O%L8##D_7\" +M@!X2RL*0A<#@M`(8$GJBT8V_`0F0AU'O(M,0KP'#P-"0E1/O\-$4,.8X?XT2>U'O +M9`%P+I"5%/"0E13@_9"5$^`2FTKE@BWQ-N#[Y/]1M9"5%.`$\.##E!!`W=$4 +M,.`"\=+0T)*O(GT#?P(">_V0A;S@_Q,3$R*0A;S@$Q-4/R*0A;S@_\03$U0# +M(I`%0^!_`##G`G\!(N3U=9"%Q>!@;Q+$9W!J$L?`=74!D(6\X##@$9"%P."T +M`@/D]771C>]P`O5UY75@2)"%R.`@X@)Q")"%R>!$$/"0A<[@8`1D`7`7Y)"1 +M;O"0A<[@\1*0D6\2QB"0A<[@@!'DD)%N\/$9\1*0D6\2QB#Q&?$2D(7>\"+_ +MD(7-X"\BD(7.X'7P`Z0D_B+P=,PM]8+D-(_U@R(2!2CE@BGU@N0U@_6#(JX' +MT8V_`0[QXB#@":\&?0%Q#'\!(G\`(M&",.`*\6Q@!GT!?P)Q#/%L8`+Q]P!?U_#'$,(I"%Q>!D`7`9$K?<8`SD +M_7\,<0P2F.`":YB0A0A;S@,.`0D(6\X##@!]&-OP$$ +M@*KQC"+@_WT!80SD_7^-`GL^$GHI[W`"\8PBD(6\X,03$U0#(B&7^>0Z^@(" +M]G7P"*0D`/6"Y#2"(O&N_U0/]5[OQ%0/9`]P.Y"2"N!4_O_PY5Y4!R7@_N]4 +M\4[P$I?GQ!-4!Y"2NR#@!70&\(`#=`'P\8JO7C$#OP$%Y/W_45)_`B$`Y5YU +M\!ND)#?Y=)(U\/I[`<`"P`'E720!^>0U7(5;&_4!P!Y"%O.`PX`1_!8!D$IC7Q%0/D)(+\!*0 +M.?Q4#\14\/Z0D@K@5`].\.Q48,14#_^0DHG@5/E/\)"2"N!4\?"0!5AT`O"0 +MDK'@D)*U,.`+X%3^\%3!1`+P@`?@1`'P5,'PD)*UX%2_\)"2"N!$`?!_`U'W +M(H]?D`4BX)"3P_`2EN;O9`%P->5?4=3@_.5?$M!,KP0Q6>5?$HNPY5\2CZ94 +M!_]@`[\""^5?$I?94?#]$I62K5]_`5%2?P$BD)/#X/U[2>3_$I6'?P`BTQ"O +M`_P[60!<"[KM`$'X"0"]0Z`")"5`>`D_O4.D)3!$@3W````_Z\. +M,<-12A($]P```/^O#H`@D)3!$@3W````_Y"5`1*-I3''44H2!/<```#_D)4! +MX/\QPW\!,=+0T)*O(N3\_?Z0E,42!.M]&'P`(M,0KP'#P-"0E+_L\*/M\)"4 +MON_PHZ/@_1)[X)"4R1($ZY"4P1*'+1($IY"4R1*/7L`$P`7`!L`'D)3!$HT`/0`M`!T``2AR"0E,T2!.N0E+^CX/W`!9"4S1*'+9"-G1($ZY"4 +MON#_T`42>-W0T)*O(N3_,=*0E,$BTQ"O`T8Q48!"D)2!X&0!<#$2E8.0 +ME(+@_W7P&Z0D//6"Y#22]8/@])`$U/#O=?`;I"0]]8+D-)+U@^#TD`35\(`' +MD`34Y/"C\'\!T-"2KR+E=W7P&Z0D-_6"Y#22]8,B[W7P#J0D&?6"Y#22]8/@ +M_WX`Y/LBTQ"O`@`D`/_J/I"4D/"C[_"0!6'@_I`% +M8.`D`/_J/O[MM`@*D`58X/PO_^H^_I"4@707\)"4CW0&\)"4@^WPD)(*X/W# +M$U0'4=3@D)2$\*/O\.ZC\)"4D.#^H^"0E(?P[J/P>P%ZE'F!$H@3T-"2KR*0 +MD@K@_R#@`L%-D)*UX/X@X`*!NY"2L^#]D)*VX-.=4`*!NY`%6."0E%WP[Q*/ +MHU0'_V0"8`/O<"/NQ!,35`,@X!J0DK7@1$#QD9"47>#_D)*RX"\D_9"1;Q+& +M(!*-C!*'(,`$P`7`!L`'D`5B$HVE>!`2!-C0`]`"T`'0`!*'(,`$P`7`!L`' +MHQ*-I7@8$@38T`/0`M`!T``2AR"0E%$2!.N0!642C:71@)`%9!*-I1*'(,`$ +MP`7`!L`'D`5F$HVE>!`2!-C0`]`"T`'0`!*'(,`$P`7`!L`'HQ*-I7@8$@38 +MT`/0`M`!T``2AR#1>I"2LN#[Y/KY^)"471*-I1*&J>3[>@02AL319Q*&J9"4 +M6=%>D)19\9]0!-%0T6W14/&WT4[QP-%.\]4P?_N%%0?_B7@3_#@ +MPQ-4'V`"P4V0!2+@1$#]>UA_0!*5AY`%4.!4]_"0!6D2C:71@)`%:!*-I1*' +M(,`$P`7`!L`'D`5J$HVE>!`2!-C0`]`"T`'0`!*'(,`$P`7`!L`'HQ*-I7@8 +M$@38T`/0`M`!T``2AR"0E%'17I"461($ZY`%;1*-I=&`D`5L$HVE$H<@P`3` +M!<`&P`>0!6X2C:5X$!($V-`#T`+0`=``$H<@P`3`!<`&P`>C$HVE>!@2!-C0 +M`]`"T`'0`!*'(-%ZT6?``,`!P`+``Y"2L>##$U1__^3\_?[QIM`#T`+0`=`` +M$H:ID)11$@3KT5C19\,2!+10!-%0T6W14'@8$@3%D`5GT4YX$!($Q9`%9M%. +M>`@2!,60!6713I`%9._PT6%X&!($Q9`%8^_PT6%X$!($Q9`%8N_PT6%X"!($ +MQ9`%8>_PT6&0!6#O\)`%4.!$"/"0!2+@5+_]>UE_0!*5AW\(4?>0DK7@5,%$ +M*/!$`?`B[_"0E%4"ARWO\)"460*'+1($ZY"440*'+9"440*'.>\D`?_D/O[D +M/?WD//R0E%4"!.MX"!($V*@$J06J!JL'(I"%O.`PX!"C=`'PD(6\X/_#$S#@ +M`M&N$J:9Y/_1R6%WTQ"O`#^$Q-4/S#@'Y"4XW0>\)"4\70!\)"4Y>_P>P%ZE'GC$EX0?P02MF+0 +MT)*O(A+%BO%Z?P'1R9"2!.`PX!3Q@9"2!^!@!13P`GJ*$K%8Y/_Q)2+3$*\! +MP\#0[V0!_WQ@8`(\6L2>[\2MR\2>HJ`%_%R8`?Q:Q)[_8`% +M\6L2>[_Q>O&8$GJYT-"2KR+PD`$_=!#P_7\#(I"2!N"0`3\B?0)_`@)\J9"2 +M!N"0!7/P(GT@Y/\">[_PY)"1;O`B?0%_`@)\J1*'.=,"!+3[>@3Y^`*&Q(M; +MBER)70("]G@8$@3%D`6+(G@0$@3%D`6*(G@($@3%D`6)(G@8$@3%D`6'(G@0 +M$@3%D`6&(G@($@3%D`6%(O&N_U0!_I"2L1*Q4%3^_^Y4`4_P$H]SD)*R$H_R +MD)*S\.2C\)"2L^#_M&0%=`'P@`KOM)8&D)*S=`/PD)*SX`20DK;P(A("]O^0 +MD@/POP$'$47DD)(#\")[`7J3><-_[WX`$F0WOP$&D)/#X*/P>P%ZDWG#?^Y^ +M`!)D-[\!")"3P^"0D\7P>P%ZDWG#?^U^`!)D-[\!")"3P^"0D\;P>P%ZDWG# +M?^Q^`!)D-[\!")"3P^"0D\?P>P%ZDWG#?^M^`!)D-[\!")"3P^"0D\CPD)/$ +MX/^CX/VCX/NCX)"3S/"0D\C@D)/-\)"3SG02\)"3W'0%\)"3T#$#D)/,X)"3 +MT_"0D\W@D)/4\'L!>I-YSA)>$'\$`H@8[_"C[?"CZ_`B$@+V5`'_D)+(X%3^ +M3_`B$@+VD(9Q\"(2`O;_5`'^D)($,5!4`O_N5/U/\!*/`4D)('\"*0`!1DH`%PS/.,\[8^?_O77`"04+DD).^\)"3ON#YPY0$4#918:3_Z?U\`"__ +M[#7P_G3046F0A,T2IS#O46"D+?_L-?#^=/!1:9"$T1*G,._PD).^X`3P@,"0 +MD[W@_Y"5$5&!@`+#,]C\]%^0D[WPD)41X/]T`:@'"(`"PS/8_)`!S/"0E1'@ +M!/#@5`/PD(4>48FT"@)_`>]P`B%LY)"%'O`A;)`!P.!$`O"0E1'@1("0`(I1 +M8)`!T!(%*."0`]@6>5U$Q,35!__Y754!_YT=2]Q$:\&49.`!<,SSC/.V/G_[UU@->5UQ%3P +M)`'U@N0T@?6#X"#G`H`3Y77$5/`D`O6"Y#2!]8/@_R#G"9`!P>!$(/"`!:UU +M$IK)!76`D"*`BO6"Y#2/]8/@_2*0A;7@_W`&H^!D"6`*[Q3_D(6VX+4'!'\! +M@`)_`.]@")`!P>!$`O`BP`&0A;;@=?`/I"0?^72%-?"H`?Q]`=`!?@!_#Q(" +MT'W,?_X2>SZ0A;91B;0*`G\![V`%Y)"%MO`BTQ"O`#^=?`(D(3-$@4HX/WN=?`(I"3.^72$-?#Z>P&O!1** +MV9"%'5&)M`H"?P'O8`7DD(4=\'UH?_X2>SX20+F0A,'@1`+PT-"2KR+D]7/O +M%/5R[?_E3_[\.5<5`S +MY6XPYPF%<&X9Z7`D@"60E$?@_>5PTYU`#ZL"D)1+Z?"O<''DCVZ`"Y"41^#U +M;H`##X#'KP*0D0OE;_#D^ZUN`B<]=,PE;O6"Y#20]8,BD(D\$@4HX"+U@N0T +MD/6#(L#@P/#`@\""P-!UT`#``,`!P`+``\`$P`7`!L`'D`'$="?P=+6C\!)Q +MD.5,,.$"L=_E3##D`M%=Y4PPY0,2S,GE3##F`Q+(V.5.,.`#$JZ.Y4XPX0+1 +M<>5.,.(#$L>>Y4XPXP+Q/>5.,.0#$L&-Y4XPY0+Q<>5.,.8"\5'E3S#A`Q*G +MKN5/,.0"\>/E3S#E`G$/="<$D`'$\'2UH_#0!]`&T`70!-`#T`+0`=``T-#0 +M@M"#T/#0X#+D_Y"44>_PD`1^X/^CX)"48?#@_F]@9I"44G0#\)"48'0(\.X$ +M5`__Y/[O=?`(I"0`]8+D-(#U@^6"+A*G-N#]=%0N]8+D-)3U@^WP#NZT"-E[ +M`7J4>5(27A"0E&'@!%0/__"_#P+D\)"48>"0!'_PD)11X'\$<`*`"1*(&"(2 +M0+E_`H\-?P(2AB>0A,'@10WP(I"%O.`PX`:0A;YT`?"0A<7@<`+A&I"%W.`$ +M\!*-C!*'(,`$P`7`!L`'D`5B$HVE>!`2!-C0`]`"T`'0`!*'(,`$P`7`!L`' +MHQ*-I7@8$@38T`/0`M`!T``2AR"0A?SN\*/O\)"2R>!4_O#@PQ,PX`T2QWT2 +M47V0DLG@5/WPD(7"X!,3$U0?,.`)D`$[X##D`O$OD)48X`3PX,.4@$`+D`&8 +MX%3^\.!$`?!_`=%BD)($X##@"9`!.^`PY`+Q+R)]`G\"$GQ!?0%_`@)\01+$ +M9W`.D(7%X&`($L2`\>L2QB`BY/\2=SF_`0^0A<7@8`GQ:50'<`,2P7LBD(7) +MX%3^\"+D_Q)W.;\!$I"%Q>!@#/'<9`)@`P)W81)Y02+D]760!JG@]754P'`( +M\6E4_?`"P7OE=3#F&)"%Q>!D`7`2\=5D`F`%$G=A@`<2>4&``O%IY760A!4_?`BD(7)X$0!\)"%P^!4#R+D_P(MO>!$`O#DD)%N\)"& +M;N"0D6\BY/SM+"0`$4KD\`SLM!CS=``M$4KO\.Y4/_]T`2WU@N0T^_6#[_!T +M`BWU@N0T^_6#X%3P\'0#+?6"Y#3[]8/@1(#P=`LM]8+D-/OU@^!$$/`B]8+D +M-/OU@R*0D_/O\*,2ATZ0E1+@_@3PD``![A(#3G0`+_GD-/OZ>P'``\`"P`&0 +MD_02AT6+&XHDD`OGD.HL;]1R)'9"3]!'$]1[0`=`"T`,":B$2AT60``X"`P_3$*\!P\#0 +MD)/W$H=.?Y9^`A)F@.]@3I`!%^#^D`$6X'P`)`#_[#[^,3>0D_KO\.[_D/T1 +M\)"3^N#]D`*4\*/O\)"3]Q'$)`+_Y#/^$EJED)/ZX"08_Y"3]Q*'11)6])`" +MEG0!\-#0DJ\B[R0!_^0^_B(2`O9D`6`"(="0D^+PD)/BX/_#E!!0)^\QT7J3 +M>>$29#>_`1*0D^'@_Z/@)./U@N0TD_6#[_"0D^+@!/"`SW4;`74 +M"'L!>I-YQ1)J(9"3PW0D\)"3T70(\'4;`74>P%ZDWG4$FHAD)/2 +M="7PD)/@=`CP>P%ZDWG#$EX0>P%ZDWG2$H@3(B3>_^0S_GL!(A*@-Q("]F0! +M8`)!;N\D.6`2%&`9)`)P'^20D\GPHW0&\(`4D)/)=`;PH_"`"I"3R70,\*-T +M!/!1@?!1;T`I-YQA)D-[\!!Y"3QN#T<#]1=_"`X%&!\%%O0#.0 +MD\?@_7P`)-[_[#/^[20!_>PS_)"3R>#[P^V;_>R4`/P2CUB-@HR#$@,/_5&1 +M47?P@,DBD)/(X-.4`"*0D\?@!/"CX!0BD)/)X)"3Q_"0D\K@D)/((HY;CUR- +M7>20D\OPD``WX$2`_7\W$GL^?6E_SQ)[/N5<_7\Q$GL^Y5M4`_^0`#+@5/Q/ +M_7\R$GL^K5U_,!)[/I``,^!$@/U_,Q)[/I``,^`PYPEQ"%`%X`3P@/#D_7_/ +M$GL^D``WX%1__7\W$GL^<0A_`%`"?P$BD)/+X,.49"+DD(3!\*/PH_"C\)"2 +M`?`BD`"`X$2`_7^`$GL^$L?H$LQU$GNSYU(/\2?,V0`:#@M/T%Y/\2B#.1 +MS9``@>!$!/U_@1)[/A+`*W&.Y/\"A9Y^`'\+?0![`7J2>;T2!MZ1%O%LOP$< +MD)/[X/Y4`9"2O?#N5`20DK_PD)/[X%0(D)*^\)$6$HJ%<#20D_O@5`=P%'L! +M>I-Y_'_Z_A)D-[\!#Y"3_(`#D)/[X%0'D)+!\)"3^^!4X,035`>0DL#PD19_ +M_7X`$F0WOP$.D)/[X%0,$Q-4/Y"2PO`B>P%ZDWG[(K'Y$GOO$CP#$LKI$LV1 +ML1Z1/GX`?[-]`'L!>I)Y"0(&WK'L`@;>D```X%3[_>3_\7M$!/U_`1)[/I`! +MF'2`\*-TB/"CY/"C=(#P(A)\3I"$Q>_PD9R0`61T`?"0!"/@1(#PD``7X%3\ +M1`3]?Q<2>SZ0`#C@1$#]?S@2>SX":.(2=;82=5CQY1+`#.3U0/5!]4)U0X"M +M0']0$GL^K4%_41)[/JU"?U(2>SZM0W]3`GL^Y)"3^_"C\!+,H.]D`6`[PY"3 +M_."4B)"3^^"4$T`/D`'!X$00\)`!QW3]\(`=D)/[L?_15].0D_S@E#*0D_O@ +ME`!`Q)`!QN`PX[V0`<=T_O`B?@!_K'T`>P%ZA7G!$@;>L>P2!MZ0A<1T`O"0 +MA3PHW0"L=P2SHGD_?\25X)]#'\"$E>"?0Q_`1)7@I"$ +MQ>#_M`$(D(70=-WP@`_OD(70M`,%=-3P@`-T0/!_+!)[4>]4#_^_!0B0A?MT +M`O"`!>20A?OPD(9M=`+PHW0/\*/@5`%$*/"C=`>QW.20A=?PH_!_`1)I,Y`% +M6'0"\)`&!.!4?_"0!@K@5/CPD`4BY/"0AG'P(O"0A?O@)`20A=WPHW0*\")^ +M`'\$?0![`7J2>00BY/W_`FY?Y'7P`0('"I"5"^_PY*/PH_"0`0G@?P`PYP)_ +M`9"5"^!O8#3#D)4-X)2(D)4,X)030`B0`<#@1!#P(I"5#+'_T5?3D)4-X)0R +MD)4,X)0`0,&0`<;@,."Z(G\4?@`"?)\2S7)_"!)[4>]4[_U_"!)[/N3_T09] +M-7\G$GL^D(7"X%3O\"+3$*\!P\#0T9+17M#0DJ\BD(7"X$00\)"%T.#]?Y,2 +M>SZ0A<;@8!*0`2_@,.<%=!#P@`:0`2]TD/!_"!)[4>]$$/U_"!)[/G\!T09] +M-'\G$GL^?Y#Q@W^0$GL^?Q1^``)\GY"%R.#_8`.T"`WQ';\!"-&"D`'EX`3P +M(I"%P>`PX!F0A;S@_S#@#\,3,.`($LVSOP$&@`*``-'D(I"2!.##$R#@-9`" +MA^!@`H`(D`$`X&0_8`5U8@&`(I`"EN!@!75B$(`7D`*&X"#A`H`'D`*&X##C +M!75B!(`"@!:0`;ET"/"0`;CE8O!_`")_^7X``F0WD`&XY/!_`2(2>SZ0`0'@ +M(A)[4>]$`?TBTQ"O` +M?P$BY)"4*?"C\*/PD)0IX&0!\)"2QN!P&)"2P^!P$J/@<`Z0E"G@)&:0`<3P +M=,"C\!)\9K\!`Q);)9"%Q>!@#I"%R.#_D(7'X&]@`C%[PJ\1-;\!`Q*^_-*O +M$<<2I^P2A$V`J-,0KP'#P-"0DL/@8"5_5'X)$G!A,6_O1/[_[D0#_NU$!/WL +M,6^0D682!.M_5'X)$G$8D)*^X'`DD`?,X##@'>3PD)0P="+PD)0^=`'PD)0R +M=`/P>P%ZE'DP$H@3D)+&X/]P"I"2P^!P!*/@8!60`!_@5/#PD`'%=.KPHW3O +M\*-T_?#O8`:0`<1T!_"0DL/@8`:0`<1T`?"0DL3@8`:0`<1T`O#0T)*O(I"4 +M+!($ZY"4+`*'+9"%O."0A<Y"2#."T`0,2E!R*0A<'@_Q*C`3#@'N]4 +M?U'+,.$&X$0"\(`(X%3]\%'4!/"0A<7@8`(Q>Y`$X.`PX061V1*7<"+`X,#P +MP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'0A\'3"H_`2=2CE5C#@`O&+ +MY58PX0)1WN56,.(",:?E5C#E`Q*/B^57,.`"L0_E6##A`K%"Y5@PX`,2R.7E +M6##D`M&MT(020`<3P +M=,*C\-`'T`;0!=`$T`/0`M`!T`#0T-""T(/0\-#@,O"0!.#@D(7"(I`!N70! +M\)`!N"*0A<7@8`)1[!*5W`*4%W%.$U0?,.`+[\03$U0#,.`"D7F0A<&1N3#@ +M">^1KE0'<#>`,Y'`0"^19W`M$K?<<`42<-N`)!)PVY"%S^`$\.#3E`)`"7%& +MY)"%S_"``Q)Y0>20A<[P(C%[(I"%PN!4^_`BD(7"X/\3$R*19V`"@4N0A<7@ +M<`*!2Y`%8^"0DL[PD`5BX)"2S_"0!6'@D)+0\)`%8."0DM'PD8#PD(7)X%3L +M\)%P)/U0`H`.D(6\X##@!-$K@`,2MXR1<&0!<#"0!JO@D(7,\)`&J>`PY06C +MX/^`!9"%R^#_D(7+[_"CX/]P")"%R^#^_X``D(7,[_`2SJ'DD(7.\-&M<4X3 +M5!\PX%WOQ!,35`,@X"217V]P3^]@3)"%PN!$0/"QZ1*O9Q)[_1*W-I%YD(7, +MX!3P@#"0A[\2KY@2KWJ15Y"%O.##$R#@`I%7(I"%PN!$!/`BD(7+X/^CX"+D_Q)W.>]D +M`2*0A!4_?`BX/\3$U0_(I"%SN`$\)"% +MR>!4[_"0AFW@_Y"%SN#3GR*0D@G@,.`?H^##$U0'L0#@_C#@$N^Q`>Y4_A*7 +M[1*4#OU_`A*2]B+_=?`.I"05]8+D-)+U@R(2S2V0E&_O\##@!7T!Y(`"Y/W_ +M$E>"D)1OX##F$9`!+^`PYP3D\(`&D`$O=(#P\7T"47V0A;S@_S#@/Y"%P.!^ +M`+0"`GX!D(6_X'T`M`0"?0'M3G`E[\,3,.`#`JZND8N0A<#@M`P&Y/U_"(`* +MD(7`X+0$!N3]_Q*C#"+DD)1O\)"%Q>!@4Y%G<$^QZ?#QP)"4;W0!\.20A]P!)"4;_"0E&_@8!R0A"0 +ME%'PX/U4P'`%$K=I@%KM,.9!D(7%X&0"<"B0A<'@_\,3(.`)D(7)X$0!\(`< +M$K?<9`%P(I"%R>!$!/!_`1)BCH`4$K?59`)@!1)W88`($GE!@`,2MVF0E%'@ +MD(7),.<'$K?HT2"`!N!4_?`B(I"%P>!$!/`BD(7!X%3W\"*0A=&CX)`%6/`B +MK`>0DLG@^3#@`N%KD(7!X##@%I"%^^`D!)"%VO"0A?O@)`.0A=GP@`V0A=IT +M`O"0A=D4\`L+D(79X/J0A=C@TYI0#I"%S>OPD(7:X,.=+(`1P^V:*Y"%S?"0 +MA=G@_Z/@PY^0A=WPD(7:X/\D"OWD,_R0A=WQ0S +M_)"%S?%SF$`$[R0C\)"%W>#_?@"0A='N\*/O\)`%6.!O<`'D8`+1K>E4_8`# +MZ40"D)+)\"+@TYWL9(#X=(`BD(77X/^CX/V0A=[@^R*0D@K@,.`+D)*TX&`% +M?P<2JO!P!.\PX`J0A#_<`2CX&#EPJ_O +M,.`/D(3!X%3^\.3_$BV]$IM7$4LPX094_?`28%T12S#B!E3[\!)J;=*O@,;2 +MK\*OD(3!X/\B,L#@P/#`@\""P-!UT`#``,`!P`+``\`$P`7`!L`'D`'$=%;P +M=,BC\!)LO'16!)`!Q/!TR*/PT`?0!M`%T`30`]`"T`'0`-#0T(+0@]#PT.`R +M,L#@P(/`@L#0==``P`7`!WVGD`'$[?!TR/^C\.T$D`'$\*/O\-`'T`70T-"" +MT(/0X#*0A;S@,.`%Y*/PH_`BD(6\X/\PX#^0A<#@?@"T`@)^`9"%O^!]`+0$ +M`GT![4YP)>_#$S#@`P*NKA*G5I"%P."T"`;D_7\,@`F0A<#@<`;]?P02HPPB +MTQ"O`P!Z`'D` +MD(D;$H=.>_]Z@GD`D(D>$H=.>H)Y/Y")(1*'3GJ">>&0B2<2ATYZ@GGUD(DJ +M$H=.>H-Y'9")+1*'3GJ#>3&0B3,2ATYZ@WE9D(DV$H=.>H-Y@9").1*'3N20 +ME*CPD)27\)"3^_"0D_O@_\.4!5`0=+DO$IY)Y/"0D_O@!/"`YB*0E$;N\*/O +M\*/M\.MU\`:D_Y")(1*'1>DO^>HU\/J0E$X2ATZ0E$C@$I]?X/^CX)"42\_P +MH^_PY*/PD)1.$H=%D)1-X/_U@G6#`!(##_U\`)"42.!U\!*0B402!2AU\`+O +M$@4HX/ZCX/^0E$K@^^^H`PB`!<[#$\X3V/F15NZ/\!('"I"43>`$\."T!:V0 +ME$X2AT42E_;]?`"0E$K@_Y"41N#^H^"H!PB`!<[#$\X3V/F15N#\H^#]TY_L +MGD`([9__[)[^@`1^`'\`D)1+[O"C[_"0E$O@_J/@_Y"42.`2GU_N\*/O\"+_ +M$@-PD)1+(A*76N`@X`C#$S#@"@*7[A*76N!$!/`BD`&4X$0!\)`!Q^3P(I`! +MFN!4P$0+\'\*?@`2?)^0`9C@5,!_`+1``G\!(I`!F.3PH_"C=!'PH^3P?PK^ +M$GR?D`&9X%0P_V008`3OM"`#?P$B?P`BD`'/X)"44?#@_S#@!Y`!S^!4_O#O +M,.4CD`'/X%3?\)`!-'0@\.3UJ/7H$G6VD``#X%3[_7\#$GL^@/XBTQ"O`^T`0WKM`(##8`&Z[0!`GT"KP;OQ%3P3?_0T)*O(N20E''PH_!_@Q)[ +M49"4<._P?X,2>U&N!Y"4<.#_M08!(L.0E'+@E&20E''@E`!`#9`!P.!$0/"0 +ME'#@_R*0E'$2O?^`PI`!Q'1R\'3-H_!_D!)[4>\@X/=T<@20`<3P=,VC\")^ +M`'\!?0![`7J%>;P2!MZ0A;S@5/WPY*/PH_"C\*-T#/`BD(6_X&0"?P%@`G\` +M(I"5#A*'3A)Q5)"%Q>#_$F#0D(7%X&`9D)4.$H=%$H]S5`__$H_S_1)JN!+' +M?1)1?2+3$*\!P\#0$GHI[V0!8`5U$`&`<9"%R>#_5`-@!740`H!CD(7'X/[D +MPYY0!740!(!4[S#B!740"(!+D(7)X##D!740$(`_D(7"X!,35#\@X`5U$""` +M+Y"&<>!@!740@(`DD`9BX##A!740$8`8D`9BX##@#.!4_/^_@`5U$!*`!1*_ +M"0DM(PX!`2T,B0A?O@ +M)`0O_Y"3`X`&$M#(D),$X/[#[YZ0E%+PD)12X/_#E"U0%G36+Q+01.`$\)"% +MV^`$\.#]?_X2>SZ0A=O@_].0DP;@GY"3!>"4`$`"X><2T9,2T:=0'A+0Y?^0 +ME%/@TY]`"I"44>"0E%3P@`B0E%'@!/"`W1+1DQ+1IU`N$M#E_\.0DP;@G_^0 +MDP7@E`#^D)13X-.?Y)Y`"I"44>"0E%7P@`B0E%'@!/"`S9"45."0A>#PD)15 +MX)"%X1+1PI0*0`KO)/:0A=CPY(`*Y)"%V!+1PG0*GY"%U_"0A>#@_Z/@PY^0 +MA=[PD(7!X##@!9"3`X`#D),$X/^0A=[@+P3PD(7>X,.4"E`#=`KPD(7>X"0" +M\!+'?1)1?>3_$FDS(A+$S4`OD(7?X`3PD),(X/^0A=_@TY]0')"%U^`$\!*G +M&1*G$I"%WO#[D(77X/^CX/T247TBY/YTUBX11.3P#NZT+?3DD(7<\)"%V_"0 +MA=_P[[0!!Z-T+?#DH_`B]8+D-)+U@R)U\!ND)#CU@N0TDO6#X/Y4`_WN$Q-4 +M!_N0D@K@_L14#Y"5!/`BD)3RH^#_D)4`=`/P>P9]`1*9-I"4]N[P_*/O\/V0 +ME/7@_W00+?6"Y#3\]8/O\)"4].#_`F5AD)(*X/_#$_[O5/'_[@14!R7@3_"C +MX/^0D@K@_L,35``H2!,60A=W@_L-T"IXO_R)TUB_U +M@N0TDO6#X/^0E%/@+_"0DP?@(I"4E.[P_*/O\/V0E)+@_Q)E89"2"N`B=?`. +MI"0/]8+D-)(BD`6$[_!](.3_`GO]D`$T=$#P_>3_$GRI0UX((N!4`Y"1"_![ +M`:]V`B<]Y64EX"3U]8+D-(+U@R+DD)%N\*-T`R+OQ%3P)`/U@N0T@?6#(N"0 +M`;KPD(7'X)`!NR(2!2C@_*/@]8*,@R)TO"5C]8+D-(_U@R+DD)13\)"44?`B +MD)3\X/^0E/K@(I"44>#_PY0M(I`%(N"0E'WP(I``!A($&"__(O"0A>#@_\,B +M)>`EX/[O3B)]`:]C`F7"Y660@QV3_R*0``02!!@O(I"5!^#_?4@B_Q("]OY4 +%#R(`:2H` +` +end diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c index c5889937fb08..aa17b9695f81 100644 --- a/sys/dev/rtwn/if_rtwn.c +++ b/sys/dev/rtwn/if_rtwn.c @@ -1520,6 +1520,8 @@ rtwn_dma_init(struct rtwn_softc *sc) if (error != 0) return (error); + rtwn_enable_mac_txrx(sc); + /* Set the number of pages for each queue. */ RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: pages per queue: high %d, normal %d, low %d, public %d\n", @@ -1903,7 +1905,7 @@ rtwn_init_beacon_reg(struct rtwn_softc *sc) rtwn_write_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_DIS_TSF_UDT0); rtwn_write_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_DIS_TSF_UDT0); rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); - rtwn_write_1(sc, R92C_DRVERLYINT, 0x05); + rtwn_init_beacon_timer(sc); rtwn_write_1(sc, R92C_BCNDMATIM, 0x02); rtwn_write_2(sc, R92C_BCNTCFG, 0x660f); } diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h index 54a74d898e00..a8793de853c9 100644 --- a/sys/dev/rtwn/if_rtwnvar.h +++ b/sys/dev/rtwn/if_rtwnvar.h @@ -308,6 +308,7 @@ struct rtwn_softc { void (*sc_fw_download_enable)(struct rtwn_softc *, int); #endif int (*sc_llt_init)(struct rtwn_softc *); + void (*sc_enable_mac_txrx)(struct rtwn_softc *); int (*sc_set_page_size)(struct rtwn_softc *); void (*sc_lc_calib)(struct rtwn_softc *); void (*sc_iq_calib)(struct rtwn_softc *); @@ -362,6 +363,7 @@ struct rtwn_softc { uint8_t (*sc_temp_read)(struct rtwn_softc *); void (*sc_init_tx_agg)(struct rtwn_softc *); void (*sc_init_rx_agg)(struct rtwn_softc *); + void (*sc_init_beacon_timer)(struct rtwn_softc *); void (*sc_init_intr)(struct rtwn_softc *); void (*sc_init_ampdu)(struct rtwn_softc *); void (*sc_init_edca)(struct rtwn_softc *); @@ -515,6 +517,8 @@ void rtwn_attach_vht_cap_info_mcs(struct rtwn_softc *); #endif #define rtwn_llt_init(_sc) \ (((_sc)->sc_llt_init)((_sc))) +#define rtwn_enable_mac_txrx(_sc) \ + (((_sc)->sc_enable_mac_txrx)((_sc))) #define rtwn_set_page_size(_sc) \ (((_sc)->sc_set_page_size)((_sc))) #define rtwn_lc_calib(_sc) \ @@ -587,6 +591,8 @@ void rtwn_attach_vht_cap_info_mcs(struct rtwn_softc *); (((_sc)->sc_init_tx_agg)((_sc))) #define rtwn_init_rx_agg(_sc) \ (((_sc)->sc_init_rx_agg)((_sc))) +#define rtwn_init_beacon_timer(_sc) \ + (((_sc)->sc_init_beacon_timer)((_sc))) #define rtwn_init_intr(_sc) \ (((_sc)->sc_init_intr)((_sc))) #define rtwn_init_ampdu(_sc) \ diff --git a/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c b/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c index 75f59b27d470..e92fdb664cd0 100644 --- a/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c +++ b/sys/dev/rtwn/rtl8188e/pci/r88ee_attach.c @@ -162,6 +162,7 @@ r88ee_attach(struct rtwn_pci_softc *pc) sc->sc_fw_download_enable = r88e_fw_download_enable; #endif sc->sc_llt_init = r92c_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = r92c_set_page_size; sc->sc_lc_calib = r92c_lc_calib; sc->sc_iq_calib = r88e_iq_calib; @@ -185,6 +186,7 @@ r88ee_attach(struct rtwn_pci_softc *pc) sc->sc_temp_read = r88e_temp_read; sc->sc_init_tx_agg = rtwn_nop_softc; sc->sc_init_rx_agg = rtwn_nop_softc; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = r92ce_init_ampdu; sc->sc_init_intr = r88ee_init_intr; sc->sc_init_edca = r92ce_init_edca; diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c index a0ead28037c2..266e20521772 100644 --- a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c +++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c @@ -155,6 +155,7 @@ r88eu_attach(struct rtwn_usb_softc *uc) sc->sc_fw_download_enable = r88e_fw_download_enable; #endif sc->sc_llt_init = r92c_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = r92c_set_page_size; sc->sc_lc_calib = r92c_lc_calib; sc->sc_iq_calib = r88e_iq_calib; @@ -178,6 +179,7 @@ r88eu_attach(struct rtwn_usb_softc *uc) sc->sc_temp_read = r88e_temp_read; sc->sc_init_tx_agg = r92cu_init_tx_agg; sc->sc_init_rx_agg = r88eu_init_rx_agg; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = rtwn_nop_softc; sc->sc_init_intr = r88eu_init_intr; sc->sc_init_edca = r92c_init_edca; diff --git a/sys/dev/rtwn/rtl8188f/r88f.h b/sys/dev/rtwn/rtl8188f/r88f.h new file mode 100644 index 000000000000..b3160c208aa2 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef RTL8188F_H +#define RTL8188F_H + +#include + +/* + * Global Definitions. + */ +#define R88F_HQ_NPAGES 12 +#define R88F_LQ_NPAGES 2 +#define R88F_NQ_NPAGES 2 +#define R88F_TXPKTBUF_COUNT 177 +#define R88F_TX_PAGE_COUNT 247 +#define R88F_RX_DMA_BUFFER_SIZE 0x3f80 +#define R88F_MAX_FW_SIZE 21020 +#define R88F_RTWN_POWER_COUNT 28 + +/* + * Function declarations. + */ + +/* r88f_rom.c */ +int r88f_efuse_preread(struct rtwn_softc *); +void r88f_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r88f_rx.c */ +int8_t r88f_get_rssi_cck(struct rtwn_softc *, void *); +int8_t r88f_get_rssi_ofdm(struct rtwn_softc *, void *); +void r88f_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, + const void *, const void *); + +/* r88f_init.c */ +int r88f_set_page_size(struct rtwn_softc *); +void r88f_init_ampdu(struct rtwn_softc *); +int r88f_llt_init(struct rtwn_softc *); +void r88f_init_rf(struct rtwn_softc *); + +/* r88f_calib.c */ +void r88f_lc_calib(struct rtwn_softc *); +void r88f_iq_calib(struct rtwn_softc *); + +/* r88f_chan.c */ +void r88f_set_chan(struct rtwn_softc *, struct ieee80211_channel *); +void r88f_get_txpower(struct rtwn_softc *, int, struct ieee80211_channel *, + uint8_t[RTWN_RIDX_COUNT]); + +/* r88f_fw.c */ +void r88f_fw_reset(struct rtwn_softc *, int); +void r88f_fw_download_enable(struct rtwn_softc *, int); + +#endif /* RTL8188F_H */ diff --git a/sys/dev/rtwn/rtl8188f/r88f_calib.c b/sys/dev/rtwn/rtl8188f/r88f_calib.c new file mode 100644 index 000000000000..75cf97763bdf --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_calib.c @@ -0,0 +1,728 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include + +#define OFDM_LSTF_MASK 0x70000000 + +void +r88f_lc_calib(struct rtwn_softc *sc) +{ + uint32_t reg; + uint32_t rf_amode, lstf; + int i; + + /* Check continuous TX and Packet TX */ + lstf = rtwn_bb_read(sc, R92C_OFDM1_LSTF); + + if (lstf & OFDM_LSTF_MASK) { + /* Disable all continuous TX */ + reg = lstf & ~OFDM_LSTF_MASK; + rtwn_bb_write(sc, R92C_OFDM1_LSTF, reg); + } else { + /* Deal with Packet TX case */ + /* block all queues */ + rtwn_write_1(sc, R92C_TXPAUSE, 0xff); + } + + /* Read original RF mode Path A */ + rf_amode = rtwn_rf_read(sc, 0, R92C_RF_CHNLBW); + + /* Start LC calibration */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, rf_amode | 0x08000); + + for (i = 0; i < 100; i++) { + if ((rtwn_rf_read(sc, 0, R92C_RF_CHNLBW) & 0x08000) == 0) + break; + rtwn_delay(sc, 10); + } + + if (i == 100) + device_printf(sc->sc_dev, "LC calibration timed out.\n"); + + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, rf_amode); + + /* Restore original parameters */ + if (lstf & OFDM_LSTF_MASK) + rtwn_bb_write(sc, R92C_OFDM1_LSTF, lstf); + else /* Deal with Packet TX case */ + rtwn_write_1(sc, R92C_TXPAUSE, 0x00); +} + +#define R88F_ADDA_REGS 16 +#define R88F_MAC_REGS 4 +#define R88F_BB_REGS 9 + +struct r88f_iqk_calib_regs { + uint32_t adda_regs[R88F_ADDA_REGS]; + uint32_t mac_regs[R88F_MAC_REGS]; + uint32_t bb_regs[R88F_BB_REGS]; + uint32_t hssi_param1; +}; + +struct r88f_iqk_result { + uint32_t before; + uint32_t after; +}; + +static const uint32_t iqk_adda_regs[R88F_ADDA_REGS] = { + R88F_FPGA0_XCD_SWITCH_CTRL, R88F_BLUETOOTH, + R88F_RX_WAIT_CCA, R88F_TX_CCK_RFON, + R88F_TX_CCK_BBON, R88F_TX_OFDM_RFON, + R88F_TX_OFDM_BBON, R88F_TX_TO_RX, + R88F_TX_TO_TX, R88F_RX_CCK, + R88F_RX_OFDM, R88F_RX_WAIT_RIFS, + R88F_RX_TO_RX, R88F_STANDBY, + R88F_SLEEP, R88F_PMPD_ANAEN +}; +static const uint32_t iqk_mac_regs[R88F_MAC_REGS] = { + R92C_TXPAUSE, R92C_BCN_CTRL(0), + R92C_BCN_CTRL(1), R92C_GPIO_MUXCFG +}; +static const uint32_t iqk_bb_regs[R88F_BB_REGS] = { + R92C_OFDM0_TRXPATHENA, R92C_OFDM0_TRMUXPAR, + R88F_FPGA0_XCD_RF_SW_CTRL, R92C_CONFIG_ANT(0), R92C_CONFIG_ANT(1), + R92C_FPGA0_RFIFACESW(0), R92C_FPGA0_RFIFACEOE(0), + R92C_FPGA0_RFIFACEOE(1), R92C_FPGA0_RFMOD +}; + +static void +r88f_iqk_save_regs(struct rtwn_softc *sc, struct r88f_iqk_calib_regs *backup) +{ + int i; + + for (i = 0; i < R88F_ADDA_REGS; i++) + backup->adda_regs[i] = rtwn_bb_read(sc, iqk_adda_regs[i]); + + for (i = 0; i < R88F_MAC_REGS - 1; i++) + backup->mac_regs[i] = rtwn_read_1(sc, iqk_mac_regs[i]); + + backup->mac_regs[i] = rtwn_bb_read(sc, iqk_mac_regs[i]); + + for (i = 0; i < R88F_BB_REGS; i++) + backup->bb_regs[i] = rtwn_bb_read(sc, iqk_bb_regs[i]); +} + +static void +r88f_iqk_restore_regs(struct rtwn_softc *sc, + const struct r88f_iqk_calib_regs *backup) +{ + int i; + + for (i = 0; i < R88F_ADDA_REGS; i++) + rtwn_bb_write(sc, iqk_adda_regs[i], backup->adda_regs[i]); + + for (i = 0; i < R88F_MAC_REGS - 1; i++) + rtwn_write_1(sc, iqk_mac_regs[i], backup->mac_regs[i]); + + rtwn_bb_write(sc, iqk_mac_regs[i], backup->mac_regs[i]); + + for (i = 0; i < R88F_BB_REGS; i++) + rtwn_bb_write(sc, iqk_bb_regs[i], backup->bb_regs[i]); +} + +static void +r88f_path_adda_on(struct rtwn_softc *sc) +{ + int i; + + rtwn_bb_write(sc, iqk_adda_regs[0], 0x03c00014); + + for (i = 1; i < R88F_ADDA_REGS; i++) + rtwn_bb_write(sc, iqk_adda_regs[i], 0x03c00014); +} + +static void +r88f_fill_iqk_matrix_a(struct rtwn_softc *sc, + const struct r88f_iqk_result *tx_result, + const struct r88f_iqk_result *rx_result, + bool tx_only) +{ + uint32_t oldval, x, tx0_a, result_reg; + int y, tx0_c; + uint32_t reg; + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(0)); + oldval = reg >> 22; + + x = tx_result->before; + if ((x & 0x00000200) != 0) + x = x | 0xfffffc00; + tx0_a = (x * oldval) >> 8; + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(0)); + reg &= ~0x3ff; + reg |= tx0_a; + rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(0), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD); + reg &= ~0x80000000; + if ((x * oldval >> 7) & 0x1) + reg |= 0x80000000; + rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg); + + y = tx_result->after; + if ((y & 0x00000200) != 0) + y |= 0xfffffc00; + tx0_c = (y * oldval) >> 8; + + rtwn_bb_setbits(sc, R92C_OFDM0_TXAFE(0), 0xf0000000, + ((tx0_c & 0x3c0) >> 6) << 28); + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(0)); + reg &= ~0x003f0000; + reg |= ((tx0_a & 0x3f) << 16); + rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(0), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD); + reg &= ~0x20000000; + if ((y * oldval >> 7) & 0x1) + reg |= 0x20000000; + rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg); + + if (tx_only) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: only TX\n", __func__); + return; + } + + result_reg = rx_result->before; + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(0), 0x3ff, + result_reg & 0x3ff); + + result_reg = rx_result->after & 0x3f; + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(0), 0xfc00, + (result_reg << 10) & 0xfc00); + + result_reg = (rx_result->after >> 6) & 0xf; + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000, + result_reg << 28); +} + +static bool +r88f_iq_calib_get_tx_result(struct rtwn_softc *sc, + struct r88f_iqk_result *tx_result) +{ + uint32_t reg_eac, reg_e94, reg_e9c; + + reg_eac = rtwn_bb_read(sc, R92C_RX_POWER_IQK_AFTER(0)); + + reg_e94 = rtwn_bb_read(sc, R92C_TX_POWER_IQK_BEFORE(0)); + tx_result->before = (reg_e94 >> 16) & 0x3ff; + + reg_e9c = rtwn_bb_read(sc, R92C_TX_POWER_IQK_AFTER(0)); + tx_result->after = (reg_e9c >> 16) & 0x3ff; + + return (!(reg_eac & 0x10000000) && + (tx_result->before != 0x142) && + (tx_result->after != 0x042)); +} + +static bool +r88f_iq_calib_get_rx_result(struct rtwn_softc *sc, uint32_t lok_result, + struct r88f_iqk_result *rx_result) +{ + + uint32_t reg_eac, reg_ea4; + + /* Reload LOK value from TX calibration */ + rtwn_rf_write(sc, 0, R92C_RF_TXM_IDAC, lok_result); + + reg_eac = rtwn_bb_read(sc, R92C_RX_POWER_IQK_AFTER(0)); + reg_ea4 = rtwn_bb_read(sc, R92C_RX_POWER_IQK_BEFORE(0)); + rx_result->before = (reg_ea4 >> 16) & 0x3ff; + rx_result->after = (reg_eac >> 16) & 0x3ff; + + return (!(reg_eac & 0x08000000) && + (rx_result->before != 0x132) && + (rx_result->after != 0x036)); +} + +static bool +r88f_iqk_path_a_tx(struct rtwn_softc *sc, uint32_t *lok_result, + struct r88f_iqk_result *tx_result) +{ + uint32_t reg; + + /* Leave IQK mode */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + /* Enable path A PA in TX IQK mode */ + rtwn_rf_setbits(sc, 0, R88E_RF_WE_LUT, 0, 0x80000); + rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x20000); + rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0000f); + rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0x07ff7); + + /* PA, PAD gain adjust */ + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, 0x980); + rtwn_rf_write(sc, 0, R88F_RF_PAD_TXG, 0x5102a); + + /* Enter IQK mode */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + reg |= 0x80800000; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + /* path-A IQK settings */ + rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x18008c1c); + rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x38008c1c); + + rtwn_bb_write(sc, R92C_TX_IQK_PI(0), 0x821403ff); + rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x28160000); + + /* LO calibration setting */ + rtwn_bb_write(sc, R92C_IQK_AGC_RSP, 0x00462911); + + /* One shot, path A LOK & IQK */ + rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf9000000); + rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf8000000); + + rtwn_delay(sc, 25); + + /* Leave IQK mode */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, 0x180); + + *lok_result = rtwn_rf_read(sc, 0, R92C_RF_TXM_IDAC); + + return (r88f_iq_calib_get_tx_result(sc, tx_result)); +} + +static bool +r88f_iqk_path_a_tx_rx(struct rtwn_softc *sc, uint32_t lok_result, + struct r88f_iqk_result *rx_result) +{ + uint32_t reg; + struct r88f_iqk_result tx_verify; + + /* + * Leave IQK mode + */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + /* + * Enable path A PA in TX IQK mode + */ + rtwn_rf_setbits(sc, 0, R88E_RF_WE_LUT, 0, 0x80000); + rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000); + rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0000f); + rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf1173); + + /* PA,PAD gain adjust */ + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, 0x980); + rtwn_rf_write(sc, 0, R88F_RF_PAD_TXG, 0x5102a); + + /* + * Enter IQK mode + */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + reg |= 0x80800000; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + /* + * TX IQK settings + */ + rtwn_bb_write(sc, R92C_TX_IQK, 0x01007c00); + rtwn_bb_write(sc, R92C_RX_IQK, 0x01004800); + + /* path-A IQK setting */ + rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x10008c1c); + rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x30008c1c); + + rtwn_bb_write(sc, R92C_TX_IQK_PI(0), 0x82160fff); + rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x28160000); + + /* LO calibration setting */ + rtwn_bb_write(sc, R92C_IQK_AGC_RSP, 0x00462911); + + /* One shot, path A LOK & IQK */ + rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf9000000); + rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf8000000); + + rtwn_delay(sc, 25); + + /* + * Leave IQK mode + */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, 0x180); + + if (!r88f_iq_calib_get_tx_result(sc, &tx_verify)) { + /* TX verification failed */ + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: TX verification failed in RX path\n", __func__); + return (false); + } + + rtwn_bb_write(sc, R92C_TX_IQK, 0x80007c00 | + (tx_verify.before << 16) | tx_verify.after); + + /* + * Modify RX IQK mode table + */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + rtwn_rf_setbits(sc, 0, R88E_RF_WE_LUT, 0, 0x80000); + rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000); + rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0000f); + rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf7ff2); + + /* + * PA, PAD setting + */ + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, 0x980); + rtwn_rf_write(sc, 0, R88F_RF_PAD_TXG, 0x51000); + /* + * Enter IQK mode + */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + reg |= 0x80800000; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + /* + * RX IQK setting + */ + rtwn_bb_write(sc, R92C_RX_IQK, 0x01004800); + + /* path-A IQK setting */ + rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x30008c1c); + rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x10008c1c); + + rtwn_bb_write(sc, R92C_TX_IQK_PI(0), 0x82160000); + rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x281613ff); + + /* LO calibration setting */ + rtwn_bb_write(sc, R92C_IQK_AGC_RSP, 0x0046a911); + + /* One shot, path A LOK & IQK */ + rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf9000000); + rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf8000000); + + rtwn_delay(sc, 25); + + /* + * Leave IQK Mode + */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0x000000ff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, 0x180); + + return (r88f_iq_calib_get_rx_result(sc, lok_result, rx_result)); + +} + +#define R88F_MAX_TOLERANCE 5 + +static bool +r88f_iq_calib_compare_results(struct r88f_iqk_result *tx_result1, + struct r88f_iqk_result *rx_result1, + struct r88f_iqk_result *tx_result2, + struct r88f_iqk_result *rx_result2, + struct r88f_iqk_result **tx_candidate, + struct r88f_iqk_result **rx_candidate) +{ + uint32_t diff; + bool tx_good = false; + int32_t tmp1, tmp2; + + diff = abs((int32_t)tx_result1->before - (int32_t)tx_result2->before); + + if (diff <= R88F_MAX_TOLERANCE) { + tmp1 = tx_result1->after & 0x00000200 ? + (tx_result1->after | 0xfffffc00) : tx_result1->after; + tmp2 = tx_result2->after & 0x00000200 ? + (tx_result2->after | 0xfffffc00) : tx_result2->after; + diff = abs(tmp1 - tmp2); + + if (diff <= R88F_MAX_TOLERANCE) { + *tx_candidate = tx_result1; + tx_good = true; + } + } + + diff = abs((int32_t)rx_result1->before - (int32_t)rx_result2->before); + + if (diff > R88F_MAX_TOLERANCE) { + if (tx_good && (rx_result1->before + rx_result1->after) == 0) + *tx_candidate = tx_result2; + + return (false); + } + + tmp1 = (rx_result1->after & 0x200) ? + (0xfffffc00 | rx_result1->after) : rx_result1->after; + tmp2 = (rx_result2->after & 0x200) ? + (0xfffffc00 | rx_result2->after) : rx_result2->after; + diff = abs(tmp1 - tmp2); + + if (diff > R88F_MAX_TOLERANCE) + return (false); + + *rx_candidate = rx_result1; + + return (tx_good); +} + +static void +r88f_iq_calib_run(struct rtwn_softc *sc, struct r88f_iqk_calib_regs *regs, + struct r88f_iqk_result *tx_result, struct r88f_iqk_result *rx_result, int t) +{ + uint32_t rx_initial_gain, lok_result; + uint32_t path_sel_rf, path_sel_bb; + uint32_t reg; + int retry = 2; + int i; + bool path_a_ok; + + /* + * Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt + */ + + rx_initial_gain = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); + + if (t == 0) { + r88f_iqk_save_regs(sc, regs); + } + + r88f_path_adda_on(sc); + + if (t == 0) { + /* Save ADDA parameters, turn Path A ADDA on */ + regs->hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0)); + } + + /* save RF path */ + path_sel_bb = rtwn_bb_read(sc, R23B_ANT_SEL); + path_sel_rf = rtwn_rf_read(sc, 0, R23B_RF_S0S1); + + /* BB setting */ + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4); + rtwn_bb_write(sc, R88F_FPGA0_XCD_RF_SW_CTRL, 0x25204000); + + rtwn_bb_setbits(sc, R92C_TX_PTCL_CTRL, 0, 0x00ff0000); + + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0xff; + reg |= 0x80800000; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + rtwn_bb_write(sc, R92C_TX_IQK, 0x01007c00); + rtwn_bb_write(sc, R92C_RX_IQK, 0x01004800); + + for (i = 0; i < retry; i++) { + path_a_ok = r88f_iqk_path_a_tx(sc, &lok_result, tx_result); + if (path_a_ok) { + rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x00); + break; + } + } + + for (i = 0; i < retry; i++) { + path_a_ok = r88f_iqk_path_a_tx_rx(sc, lok_result, rx_result); + if (path_a_ok) { + rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x00); + break; + } + } + + if (!path_a_ok) + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: Path A IQK failed!\n", __func__); + + /* Back to BB mode, load original value */ + reg = rtwn_bb_read(sc, R92C_FPGA0_IQK); + reg &= 0xff; + rtwn_bb_write(sc, R92C_FPGA0_IQK, reg); + + if (t == 0) + return; + + if (!(regs->hssi_param1 & R92C_HSSI_PARAM1_PI)) { + /* + * Switch back BB to SI mode after finishing + * IQ Calibration + */ + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), 0x01000000); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), 0x01000000); + } + + /* Reload ADDA power saving, MAC and BB paramters */ + r88f_iqk_restore_regs(sc, regs); + + /* Reload RF path */ + rtwn_bb_write(sc, R23B_ANT_SEL, path_sel_bb); + rtwn_rf_write(sc, 0, R23B_RF_S0S1, path_sel_rf); + + /* Restore RX initial gain */ + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); + reg &= 0xffffff00; + reg |= 0x50; + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); + reg &= 0xffffff00; + reg |= rx_initial_gain & 0xff; + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); + + /* Load 0xe30 IQC default value */ + rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x01008c00); + rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x01008c00); +} + +void +r88f_iq_calib(struct rtwn_softc *sc) +{ + struct r88f_iqk_calib_regs regs; + struct r88f_iqk_result tx_result[3] = { {0, 0} }; + struct r88f_iqk_result rx_result[3] = { {0, 0} }; + /* Final results */ + struct r88f_iqk_result *tx_candidate = NULL; + struct r88f_iqk_result *rx_candidate = NULL; + uint32_t path_sel_bb, path_sel_rf; + int i; + + /* Save RF path */ + path_sel_bb = rtwn_bb_read(sc, R23B_ANT_SEL); + path_sel_rf = rtwn_rf_read(sc, 0, R23B_RF_S0S1); + + for (i = 0; i < 3; i++) { + r88f_iq_calib_run(sc, ®s, &tx_result[i], &rx_result[i], i); + + if (i == 1) { + /* Compare 0 vs 1 */ + if (r88f_iq_calib_compare_results(&tx_result[0], + &rx_result[0], + &tx_result[1], &rx_result[1], + &tx_candidate, &rx_candidate)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: Run 0-1 passed\n", __func__); + goto write; + } + } + + if (i == 2) { + /* Compare 0 vs 2 */ + if (r88f_iq_calib_compare_results(&tx_result[0], + &rx_result[0], &tx_result[2], + &rx_result[2], &tx_candidate, + &rx_candidate)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: Run 0-2 passed\n", __func__); + goto write; + } + + /* Compare 1 vs 2 */ + if (r88f_iq_calib_compare_results(&tx_result[1], + &rx_result[1], &tx_result[2], + &rx_result[2], &tx_candidate, + &rx_candidate)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: Run 1-2 passed\n", __func__); + } else { + if (tx_candidate == NULL) + tx_candidate = &tx_result[0]; + if (rx_candidate == NULL) + rx_candidate = &rx_result[0]; + + /* check complete failure */ + if (tx_candidate->before == 0 && + tx_candidate->after == 0 && + rx_candidate->before == 0 && + rx_candidate->after == 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: IQK failed completely\n", __func__); + goto done; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: using fallback candidate\n", __func__); + } + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "IQK run %d: TX b=%#x a=%#x RX b=%#x a=%#x\n", i, + tx_result[i].before, tx_result[i].after, + rx_result[i].before, rx_result[i].after); + } + +write: + + r88f_fill_iqk_matrix_a(sc, tx_candidate, rx_candidate ? + rx_candidate : NULL, + (rx_candidate == NULL || rx_candidate->before == 0)); + + if (tx_candidate == NULL || (tx_candidate->before == 0 && + tx_candidate->after == 0)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: TX IQK failed completely\n", __func__); + goto done; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: IQK candidate - TX: before=%#x after=%#x RX: before=%#x after=%#x\n", + __func__, tx_candidate->before, tx_candidate->after, + rx_candidate ? rx_candidate->before : 0, + rx_candidate ? rx_candidate->after : 0); + +done: + r88f_iqk_save_regs(sc, ®s); + + /* Restore RF path */ + rtwn_bb_write(sc, R23B_ANT_SEL, path_sel_bb); + rtwn_rf_write(sc, 0, R23B_RF_S0S1, path_sel_rf); +} diff --git a/sys/dev/rtwn/rtl8188f/r88f_chan.c b/sys/dev/rtwn/rtl8188f/r88f_chan.c new file mode 100644 index 000000000000..52566a85f1e6 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_chan.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +static int +rtwn_chan2group(int chan) +{ + int group; + + if (chan <= 2) + group = 0; + else if (chan <= 5) + group = 1; + else if (chan <= 8) + group = 2; + else if (chan <= 11) + group = 3; + else + group = 4; + + return (group); +} + +void +r88f_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) +{ + struct r92c_softc *rs = sc->sc_priv; + const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; + uint32_t reg; + uint8_t cckpow, htpow, ofdmpow; + int8_t diff; + int ridx, chan, group; + + /* Determine channel group. */ + chan = rtwn_chan2centieee(c); /* XXX center freq! */ + group = rtwn_chan2group(chan); + + memset(power, 0, R88F_RTWN_POWER_COUNT * sizeof(power[0])); + + /* Compute per-CCK rate Tx power. */ + cckpow = rt->cck_tx_pwr[group]; + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) { + power[ridx] = cckpow; + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } + + reg = rtwn_read_4(sc, R92C_TXAGC_A_CCK1_MCS32); + reg &= 0xffff00ff; + reg |= (cckpow << 8); + rtwn_write_4(sc, R92C_TXAGC_A_CCK1_MCS32, reg); + + reg = rtwn_read_4(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg &= 0xff; + reg |= ((cckpow << 8) | (cckpow << 16) | (cckpow << 24)); + rtwn_write_4(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + + htpow = rt->ht40_tx_pwr[group]; + + /* Compute per-OFDM rate Tx power. */ + diff = rt->ofdm_tx_pwr_diff; + ofdmpow = htpow + diff; + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) { + power[ridx] = ofdmpow; + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } + + /* Compute per-MCS Tx power. */ + diff = rt->bw20_tx_pwr_diff; + htpow += diff; + for (ridx = RTWN_RIDX_HT_MCS(0); ridx < RTWN_RIDX_HT_MCS(8); ridx++) { + power[ridx] = htpow; + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } +} + +static void +r88f_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t power[RTWN_RIDX_COUNT]; + + memset(power, 0, sizeof(power)); + /* Compute per-rate Tx power values. */ + r88f_get_txpower(sc, 0, c, power); + /* Write per-rate Tx power values to hardware. */ + r92c_write_txpower(sc, 0, power); +} + +static void +r88f_spur_calibration(struct rtwn_softc *sc, struct ieee80211_channel *c, + int chan) +{ + static const uint32_t frequencies[14 + 1] = { + [5] = 0xFCCD, + [6] = 0xFC4D, + [7] = 0xFFCD, + [8] = 0xFF4D, + [11] = 0xFDCD, + [13] = 0xFCCD, + [14] = 0xFF9A + }; + + static const uint32_t reg_d40[14 + 1] = { + [5] = 0x06000000, + [6] = 0x00000600, + [13] = 0x06000000 + }; + + static const uint32_t reg_d44[14 + 1] = { + [11] = 0x04000000 + }; + + static const uint32_t reg_d4c[14 + 1] = { + [7] = 0x06000000, + [8] = 0x00000380, + [14] = 0x00180000 + }; + + const uint8_t threshold = 0x16; + bool do_notch, hw_ctrl, sw_ctrl, hw_ctrl_s1 = 0, sw_ctrl_s1 = 0; + uint32_t reg, initial_gain, reg948; + + rtwn_bb_setbits(sc, R88F_OFDM0_RX_D_SYNC_PATH, 0, 0x1f000000); + + /* enable notch filter */ + rtwn_bb_setbits(sc, R88F_OFDM0_RX_D_SYNC_PATH, 0, 0x00000200); + + if (chan <= 14 && frequencies[chan] > 0) { + reg948 = rtwn_read_4(sc, R23B_ANT_SEL); + hw_ctrl = reg948 & 0x00000040; + sw_ctrl = !hw_ctrl; + if (hw_ctrl) { + reg = rtwn_read_4(sc, R88F_FPGA0_XB_RF_INT_OE); + reg &= 0x00000038; + hw_ctrl_s1 = reg == 0x00000008; + } else if (sw_ctrl) { + sw_ctrl_s1 = !(reg948 & 0x00000200); + } + + if (hw_ctrl_s1 || sw_ctrl_s1) { + initial_gain = rtwn_read_4(sc, R92C_OFDM0_AGCCORE1(0)); + + /* Disable CCK block */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, + R92C_RFMOD_CCK_EN, 0); + + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), + R92C_OFDM0_AGCCORE1_GAIN_M, 0x30); + + /* disable 3-wire */ + rtwn_bb_write(sc, R88F_FPGA0_ANALOG4, 0xccf000c0); + + /* Setup PSD */ + rtwn_bb_write(sc, R88F_FPGA0_PSD_FUNC, + frequencies[chan]); + + /* Start PSD */ + rtwn_bb_write(sc, R88F_FPGA0_PSD_FUNC, + 0x400000 | frequencies[chan]); + + rtwn_delay(sc, 30); + + do_notch = rtwn_bb_read(sc, R88F_FPGA0_PSD_REPORT) >= + threshold; + + /* turn off PSD */ + rtwn_bb_write(sc, R88F_FPGA0_PSD_FUNC, + frequencies[chan]); + + /* enable 3-wire */ + rtwn_bb_write(sc, R88F_FPGA0_ANALOG4, 0xccc000c0); + + /* Enable CCK block */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, + R92C_RFMOD_CCK_EN); + + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), initial_gain); + + if (do_notch) { + rtwn_bb_write(sc, R88F_OFDM1_CSI_FIX_MASK1, + reg_d40[chan]); + rtwn_bb_write(sc, R88F_OFDM1_CSI_FIX_MASK2, + reg_d44[chan]); + + rtwn_bb_write(sc, 0xd48, 0x0); + rtwn_bb_write(sc, 0xd4c, reg_d4c[chan]); + + /* enable CSI mask */ + rtwn_bb_setbits(sc, R88F_OFDM1_CFO_TRACKING, 0, + 0x10000000); + + return; + } + } + } + + /* disable CSI mask function */ + rtwn_bb_setbits(sc, R88F_OFDM1_CFO_TRACKING, 0x10000000, 0); +} + +void +r88f_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t chan, subchannel; + bool sec_ch_above; + + chan = rtwn_chan2centieee(c); /* XXX center freq! */ + + /* Set Tx power for this new channel. */ + r88f_set_txpower(sc, c); + + /* Spur calibration */ + r88f_spur_calibration(sc, c, chan); + + /* Set bandwidth mode */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, + IEEE80211_IS_CHAN_HT40(c)); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, + IEEE80211_IS_CHAN_HT40(c)); + + /* RXADC CLK */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, 0x00000700); + + /* TXDAC CLK */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0x00002000, + 0x00004000 | 0x00001000); + + /* Small bandwidth */ + rtwn_bb_setbits(sc, R92C_OFDM0_TXPSEUDONOISEWGT, 0xc0000000, 0); + + /* ADC buffer clk */ + rtwn_bb_setbits(sc, R92C_OFDM0_TXPSEUDONOISEWGT, 0x20000000, + 0x10000000); + + /* ADC buffer clk */ + rtwn_bb_setbits(sc, R88F_OFDM0_XA_RX_AFE, 0x20000000, 0x10000000); + + /* OFDM Rx DFIR */ + rtwn_bb_setbits(sc, R88F_RX_DFIR, 0x00080000, 0); + + reg = rtwn_bb_read(sc, R88F_RX_DFIR); + reg &= ~0x00f00000; + reg |= 0x00200000; + if (IEEE80211_IS_CHAN_HT20(c) || IEEE80211_IS_CHAN_VHT20(c) || + (!IEEE80211_IS_CHAN_HT(c) && !IEEE80211_IS_CHAN_VHT(c))) + reg |= 0x00100000; + else if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) + reg |= 0x00400000; + rtwn_bb_write(sc, R88F_RX_DFIR, reg); + + if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) { + if (IEEE80211_IS_CHAN_HT40U(c) || + IEEE80211_IS_CHAN_VHT40U(c)) { + sec_ch_above = 1; + chan += 2; + } else { + sec_ch_above = 0; + chan -= 2; + } + + /* Set Control channel to upper or lower. */ + reg = rtwn_bb_read(sc, R92C_CCK0_SYSTEM); + reg &= ~R92C_CCK0_SYSTEM_CCK_SIDEBAND; + if (!sec_ch_above) + reg |= R92C_CCK0_SYSTEM_CCK_SIDEBAND; + rtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg); + + if (sec_ch_above) + subchannel = 2; + else + subchannel = 1; + rtwn_bb_setbits(sc, R12A_DATA_SEC, 0x0000000F, subchannel); + + rtwn_bb_setbits(sc, R92C_RRSR, R92C_RRSR_RSC_LOWSUBCHNL | + R92C_RRSR_RSC_UPSUBCHNL, 0); + } + + /* RF TRX_BW */ + + reg = chan; + if (IEEE80211_IS_CHAN_HT20(c) || IEEE80211_IS_CHAN_VHT20(c) || + (!IEEE80211_IS_CHAN_HT(c) && !IEEE80211_IS_CHAN_VHT(c))) + reg |= R88F_RF_CHNLBW_BW20; + else if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) + reg |= R88F_RF_CHNLBW_BW40; + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, reg); + + /* FILTER BW&RC Corner (ACPR) */ + if (IEEE80211_IS_CHAN_HT20(c) || IEEE80211_IS_CHAN_VHT20(c) || + (!IEEE80211_IS_CHAN_HT(c) && !IEEE80211_IS_CHAN_VHT(c))) + reg = 0x00065; + else if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) + reg = 0x00025; + rtwn_rf_write(sc, 0, R88F_RF_RXG_GAIN, reg); + + if (IEEE80211_IS_CHAN_HT20(c) || IEEE80211_IS_CHAN_VHT20(c) || + (!IEEE80211_IS_CHAN_HT(c) && !IEEE80211_IS_CHAN_VHT(c))) + reg = 0x0; + else if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) + reg = 0x01000; + rtwn_rf_write(sc, 0, R92C_RF_RX_BB2, reg); + + rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x1c6c); + rtwn_rf_write(sc, 0, R88F_RF_GAIN_CCA, + R88F_RF_PKTBUF_DBG_CTRL); + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan | R88E_RF_CHNLBW_BW20); +} diff --git a/sys/dev/rtwn/rtl8188f/r88f_fw.c b/sys/dev/rtwn/rtl8188f/r88f_fw.c new file mode 100644 index 000000000000..e96a0efbbe72 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_fw.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#define R88E_RSV_CTRL_MIO_EN 0x0100 +#define R88E_RSV_CTRL_MCU_RST 0x0800 + +#ifndef RTWN_WITHOUT_UCODE +void +r88f_fw_reset(struct rtwn_softc *sc, int reason) +{ + switch (reason) { + case RTWN_FW_RESET_CHECKSUM: + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_CHKSUM_RPT); + /* FALLTHROUGH */ + case RTWN_FW_RESET_DOWNLOAD: + case RTWN_FW_RESET_SHUTDOWN: + /* Reset MCU IO wrapper. */ + rtwn_setbits_2(sc, R92C_RSV_CTRL, R88E_RSV_CTRL_MIO_EN, 0); + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, 0); + + /* Enable MCU IO wrapper. */ + rtwn_setbits_2(sc, R92C_RSV_CTRL, 0, R88E_RSV_CTRL_MIO_EN); + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_CPUEN); + return; + } +} + +void +r88f_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* Enable FW download. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + rtwn_setbits_4(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, 0); + /* Wait 100ms */ + rtwn_delay(sc, 100); + } else { + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + } +} +#endif diff --git a/sys/dev/rtwn/rtl8188f/r88f_init.c b/sys/dev/rtwn/rtl8188f/r88f_init.c new file mode 100644 index 000000000000..6d7464b9d5e4 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_init.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +int +r88f_llt_init(struct rtwn_softc *sc) +{ + int ntries; + + rtwn_setbits_4(sc, R92E_AUTO_LLT, 0, R92E_AUTO_LLT_EN); + for (ntries = 0; ntries < 1000; ntries++) { + if (!(rtwn_read_4(sc, R92E_AUTO_LLT) & R92E_AUTO_LLT_EN)) + return (0); + rtwn_delay(sc, 2); + } + return (ETIMEDOUT); +} + +int +r88f_set_page_size(struct rtwn_softc *sc) +{ + return (rtwn_write_1(sc, R92C_PBP, + SM(R92C_PBP_PSRX, R92C_PBP_256) | + SM(R92C_PBP_PSTX, R92C_PBP_256))); +} + +void +r88f_init_ampdu(struct rtwn_softc *sc) +{ + /* Setup AMPDU aggregation. */ + rtwn_setbits_1(sc, R12A_HT_SINGLE_AMPDU, 0, + R12A_HT_SINGLE_AMPDU_PKT_ENA); + rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0c14); + rtwn_write_1(sc, R12A_AMPDU_MAX_TIME, 0x70); + rtwn_write_4(sc, R92C_AGGLEN_LMT, 0xffffffff); + + /* For VHT packet length 11K */ + rtwn_write_1(sc, R92C_RX_PKT_LIMIT, 0x18); + + rtwn_write_1(sc, R92C_PIFS, 0); + rtwn_write_1(sc, R92C_FWHW_TXQ_CTRL, 0x80); + rtwn_write_4(sc, R92C_FAST_EDCA_CTRL, 0x03086666); + rtwn_write_1(sc, R92C_USTIME_TSF, 0x28); + rtwn_write_1(sc, R92C_USTIME_EDCA, 0x28); + + /* To prevent bus resetting the mac. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0, + R92C_RSV_CTRL_R_DIS_PRST_0 | R92C_RSV_CTRL_R_DIS_PRST_1); +} + +static int +r88f_read_efuse_1(struct rtwn_softc *sc, uint16_t offset, uint8_t *data) +{ + int i; + uint8_t val8; + uint32_t reg; + + /* Write Address */ + rtwn_write_1(sc, R92C_EFUSE_CTRL + 1, offset & 0xff); + val8 = rtwn_read_1(sc, R92C_EFUSE_CTRL + 2); + val8 &= 0xfc; + val8 |= (offset >> 8) & 0x03; + rtwn_write_1(sc, R92C_EFUSE_CTRL + 2, val8); + + val8 = rtwn_read_1(sc, R92C_EFUSE_CTRL + 3); + rtwn_write_1(sc, R92C_EFUSE_CTRL + 3, val8 & 0x7f); + + /* Poll for data read */ + reg = rtwn_bb_read(sc, R92C_EFUSE_CTRL); + for (i = 0; i < 500; i++) { + reg = rtwn_bb_read(sc, R92C_EFUSE_CTRL); + if (reg & 0x80000000) + break; + } + + if (i == 500) + return (-EIO); + + rtwn_delay(sc, 50); + reg = rtwn_bb_read(sc, R92C_EFUSE_CTRL); + + *data = reg & 0xff; + return (0); +} + +#define PPG_BB_GAIN_2G_TXA_OFFSET_8188F 0xee +#define PPG_BB_GAIN_2G_TX_OFFSET_MASK 0x0f +#define OFDM_RF_PATH_RX_A 0x00000001 +#define OFDM_RF_PATH_TX_A 0x00000010 +#define OFDM_RF_PATH_TX_MASK 0xf0 +#define OFDM_RF_PATH_RX_MASK 0x0f + +static void +r88f_enable_rf(struct rtwn_softc *sc) +{ + uint8_t pg_pwrtrim = 0xff, val8; + int8_t bb_gain; + + /* Somehow this is not found in the efuse we read earlier. */ + r88f_read_efuse_1(sc, PPG_BB_GAIN_2G_TXA_OFFSET_8188F, &pg_pwrtrim); + + if (pg_pwrtrim != 0xff) { + bb_gain = pg_pwrtrim & PPG_BB_GAIN_2G_TX_OFFSET_MASK; + + if (bb_gain == PPG_BB_GAIN_2G_TX_OFFSET_MASK) + bb_gain = 0; + else if (bb_gain & 1) + bb_gain = bb_gain >> 1; + else + bb_gain = -(bb_gain >> 1); + + val8 = abs(bb_gain); + if (bb_gain > 0) + val8 |= 0x00000020; + + rtwn_rf_setbits(sc, 0, R88F_RF_UNKNOWN_55, + 0xfc000, val8 << 14); + } + + rtwn_write_1(sc, R92C_RF_CTRL, R92C_RF_CTRL_EN | + R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + rtwn_bb_setbits(sc, R92C_OFDM0_TRXPATHENA, OFDM_RF_PATH_RX_MASK | + OFDM_RF_PATH_TX_MASK, OFDM_RF_PATH_RX_A | OFDM_RF_PATH_TX_A); + + rtwn_write_1(sc, R92C_TXPAUSE, 0x00); +} + +void +r88f_init_rf(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg, type; + int i = 0; + + r88f_enable_rf(sc); + + /* Save RF_ENV control type. */ + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(0)); + type = reg & 0x10; + + /* Set RF_ENV enable. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(0), 0, 0x100000); + rtwn_delay(sc, 1); + + /* Set RF_ENV output high. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(0), 0, 0x10); + rtwn_delay(sc, 1); + + /* Set address and data lengths of RF registers. */ + rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(0), + R92C_HSSI_PARAM2_ADDR_LENGTH, 0); + rtwn_delay(sc, 1); + + rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(0), + R92C_HSSI_PARAM2_DATA_LENGTH, 0); + rtwn_delay(sc, 1); + + /* Write RF initialization values for this chain. */ + i += r92c_init_rf_chain(sc, &sc->rf_prog[0], 0); + + /* Restore RF_ENV control type. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACESW(0), 0x10, type); + + /* Cache RF register CHNLBW. */ + rs->rf_chnlbw[i] = rtwn_rf_read(sc, 0, R92C_RF_CHNLBW); + + /* Turn CCK and OFDM blocks on. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_CCK_EN); + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_OFDM_EN); +} diff --git a/sys/dev/rtwn/rtl8188f/r88f_priv.h b/sys/dev/rtwn/rtl8188f/r88f_priv.h new file mode 100644 index 000000000000..4892725a6830 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_priv.h @@ -0,0 +1,214 @@ +/* $OpenBSD: r92creg.h,v 1.30 2023/04/28 01:24:14 kevlo Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2023 Kevin Lo + * Copyright (c) 2026 Mir Saheb Ali + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef R88F_PRIV_H +#define R88F_PRIV_H + +#include + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8188ftv_mac[] = { + { 0x024, 0xdf }, { 0x025, 0x07 }, { 0x02b, 0x1c }, { 0x283, 0x20 }, + { 0x421, 0x0f }, { 0x428, 0x0a }, { 0x429, 0x10 }, { 0x430, 0x00 }, + { 0x431, 0x00 }, { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, + { 0x435, 0x05 }, { 0x436, 0x07 }, { 0x437, 0x08 }, { 0x43c, 0x04 }, + { 0x43d, 0x05 }, { 0x43e, 0x07 }, { 0x43f, 0x08 }, { 0x440, 0x5d }, + { 0x441, 0x01 }, { 0x442, 0x00 }, { 0x444, 0x10 }, { 0x445, 0x00 }, + { 0x446, 0x00 }, { 0x447, 0x00 }, { 0x448, 0x00 }, { 0x449, 0xf0 }, + { 0x44a, 0x0f }, { 0x44b, 0x3e }, { 0x44c, 0x10 }, { 0x44d, 0x00 }, + { 0x44e, 0x00 }, { 0x44f, 0x00 }, { 0x450, 0x00 }, { 0x451, 0xf0 }, + { 0x452, 0x0f }, { 0x453, 0x00 }, { 0x456, 0x5e }, { 0x460, 0x44 }, + { 0x461, 0x44 }, { 0x4bc, 0xc0 }, { 0x4c8, 0xff }, { 0x4c9, 0x08 }, + { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, + { 0x501, 0xa2 }, { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, + { 0x505, 0xa3 }, { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, + { 0x509, 0xa4 }, { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, + { 0x50d, 0xa4 }, { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, + { 0x514, 0x0a }, { 0x516, 0x0a }, { 0x525, 0x4f }, { 0x550, 0x10 }, + { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55c, 0x28 }, { 0x55d, 0xff }, + { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff }, + { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff }, + { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x28 }, + { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e }, + { 0x640, 0x40 }, { 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 }, + { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, + { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, + { 0x70b, 0x87 } +}; + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8188ftv_bb_regs[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x81c, 0x820, + 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, + 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, + 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, 0x888, 0x88c, + 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, 0x90c, 0x910, + 0x914, 0x948, 0x94c, 0x950, 0x954, 0x958, 0x95c, 0x96c, 0xa00, + 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, + 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xa88, + 0xa8c, 0xa90, 0xa94, 0xa98, 0xa9c, 0xaa0, 0xb2c, 0xc00, 0xc04, + 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, + 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, + 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, + 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, + 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, + 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, + 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, + 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, + 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, + 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, + 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, + 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe60, 0xe64, + 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, + 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8188ftv_bb_vals[] = { + 0x80045700, 0x00000001, 0x0000fc00, 0x0000000a, 0x10001331, + 0x020c3d10, 0x00200385, 0x00000000, 0x01000100, 0x00390204, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000, + 0x00030000, 0x00000000, 0x569a569a, 0x569a569a, 0x00000130, + 0x00000000, 0x00000000, 0x27272700, 0x00000000, 0x25004000, + 0x00000808, 0x004f0201, 0xb0000b1e, 0x00000007, 0x00000000, + 0xccc000c0, 0x00000800, 0xfffffffe, 0x40302010, 0x00706050, + 0x00000000, 0x00000023, 0x00000000, 0x81121111, 0x00000002, + 0x00000201, 0x99000000, 0x00000010, 0x20003000, 0x4a880000, + 0x4bc5d87a, 0x04eb9b79, 0x00000003, 0x00d047c8, 0x80ff800c, + 0x8c898300, 0x2e7f120f, 0x9500bb78, 0x1114d028, 0x00881117, + 0x89140f00, 0xd1d80000, 0x5a7da0bd, 0x0000223b, 0x00d30000, + 0x101fbf00, 0x00000007, 0x00000900, 0x225b0606, 0x218075b1, + 0x00120000, 0x040c0000, 0x12345678, 0xabcdef00, 0x001b1b89, + 0x05100000, 0x3f000000, 0x00000000, 0x00000000, 0x48071d40, + 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x18800000, 0x40000100, + 0x08800000, 0x40000100, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x69e9cc4a, 0x31000040, 0x21688080, 0x00001714, + 0x1f78403f, 0x00010036, 0xec020107, 0x007f037f, 0x69553420, + 0x43bc0094, 0x00013169, 0x00250492, 0x00000000, 0x7112848b, + 0x47c07bff, 0x00000036, 0x2c7f000d, 0x020600db, 0x0000001f, + 0x00b91612, 0x390000e4, 0x11f60000, 0x40000100, 0x20200000, + 0x00091521, 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, + 0x000300a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x28000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x64b22427, 0x00766932, + 0x00222222, 0x10000000, 0x37644302, 0x2f97d40c, 0x04030740, + 0x40020401, 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc53, + 0x7a8f5b6f, 0xcb979975, 0x00000000, 0x80608000, 0x98000000, + 0x40127353, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6437140a, 0x00000000, 0x00000282, 0x30032064, 0x4653de68, + 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, + 0x000e3c24, 0x2d2d2d2d, 0x2d2d2d2d, 0x0390272d, 0x2d2d2d2d, + 0x2d2d2d2d, 0x2d2d2d2d, 0x2d2d2d2d, 0x00000000, 0x1000dc1f, + 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, + 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, + 0x28160d05, 0x00000008, 0x021400a0, 0x281600a0, 0x01c00010, + 0x01c00010, 0x02000010, 0x02000010, 0x02000010, 0x02000010, + 0x01c00010, 0x02000010, 0x01c00010, 0x01c00010, 0x01c00010, + 0x01c00010, 0x00000010, 0x00000010, 0x03c00010, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8188ftv_bb[] = { + { + nitems(rtl8188ftv_bb_regs), + rtl8188ftv_bb_regs, + rtl8188ftv_bb_vals, + { 0 }, + NULL + } +}; + +static const uint32_t rtl8188ftv_agc_vals[] = { + 0xfc000001, 0xfb010001, 0xfa020001, 0xf9030001, 0xf8040001, + 0xf7050001, 0xf6060001, 0xf5070001, 0xf4080001, 0xf3090001, + 0xf20a0001, 0xf10b0001, 0xf00c0001, 0xef0d0001, 0xee0e0001, + 0xed0f0001, 0xec100001, 0xeb110001, 0xea120001, 0xe9130001, + 0xe8140001, 0xe7150001, 0xe6160001, 0xe5170001, 0xe4180001, + 0xe3190001, 0xe21a0001, 0xe11b0001, 0xe01c0001, 0xc21d0001, + 0xc11e0001, 0xc01f0001, 0xa5200001, 0xa4210001, 0xa3220001, + 0xa2230001, 0xa1240001, 0xa0250001, 0x65260001, 0x64270001, + 0x63280001, 0x62290001, 0x612a0001, 0x442b0001, 0x432c0001, + 0x422d0001, 0x412e0001, 0x402f0001, 0x21300001, 0x20310001, + 0x05320001, 0x04330001, 0x03340001, 0x02350001, 0x01360001, + 0x00370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001 +}; + +static const struct rtwn_agc_prog rtl8188ftv_agc[] = { + { + nitems(rtl8188ftv_agc_vals), + rtl8188ftv_agc_vals, + { 0 }, + NULL + } +}; + +/* + * RF initialization values. + */ +static const uint8_t rtl8188ftv_rf_regs[] = { + 0x00, 0x08, 0x18, 0x19, 0x1b, 0x1e, 0x1f, 0x2f, 0x3f, 0x42, + 0x57, 0x58, 0x67, 0x83, 0xb0, 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbf, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xdf, 0xef, 0x51, 0x52, 0x53, + 0x56, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x18, 0x5a, + 0x19, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x00, 0x84, 0x86, 0x87, 0x8e, 0x8f, 0xef, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0xef, 0x3b, 0x3b, 0xef, + 0xef, 0x30, 0x31, 0x32, 0xef, 0x00, 0x18, 0xfe, 0xfe, 0x1f, + 0xfe, 0xfe, 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8188ftv_rf_vals[] = { + 0x30000, 0x08400, 0x00407, 0x00012, 0x01c6c, 0x80009, 0x00880, + 0x1a060, 0x28000, 0x060c0, 0xd0000, 0xc0160, 0x01552, 0x00000, + 0xff9f0, 0x22218, 0x34c00, 0x4484b, 0x0112a, 0x0053e, 0x10408, + 0x10200, 0x80001, 0x40001, 0x00400, 0xc0000, 0x02400, 0x00009, + 0x40c91, 0x99999, 0x000a3, 0x8f820, 0x76c06, 0x00000, 0x80000, + 0x00180, 0x001a0, 0xe8231, 0xfac2c, 0x00141, 0x517f0, 0x00090, + 0x00190, 0x00290, 0x01064, 0x09064, 0x11064, 0x19064, 0x00c07, + 0x48000, 0x739d0, 0x0add2, 0x09dd0, 0x08cf3, 0x07cf0, 0x06ced, + 0x05cd2, 0x04ccf, 0x03ccc, 0x02cc9, 0x01c4c, 0x00c49, 0x30159, + 0x48000, 0x0002a, 0x00025, 0x65540, 0x88000, 0x020a0, 0xf0f00, + 0xe0b00, 0xd0900, 0xc0700, 0xb0600, 0xa0400, 0x90200, 0x80000, + 0x7bf00, 0x60b00, 0x5c900, 0x40700, 0x30600, 0x2d500, 0x10200, + 0x0e000, 0x000a0, 0x00010, 0x0c0a8, 0x10400, 0x00000, 0x80000, + 0x10000, 0x0000f, 0x07efe, 0x00000, 0x10159, 0x0fc07, 0x00000, + 0x00000, 0x80003, 0x00000, 0x00000, 0x00001, 0x80000, 0x33d95 +}; + +static const struct rtwn_rf_prog rtl8188ftv_rf[] = { + { + nitems(rtl8188ftv_rf_regs), + rtl8188ftv_rf_regs, + rtl8188ftv_rf_vals, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + +#endif /* R88F_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8188f/r88f_reg.h b/sys/dev/rtwn/rtl8188f/r88f_reg.h new file mode 100644 index 000000000000..0d7f0c7bdcf1 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_reg.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef R88F_REG_H +#define R88F_REG_H + +/* + * Baseband registers. + */ + +/* FPGA0. */ +#define R88F_FPGA0_PSD_FUNC 0x808 +#define R88F_FPGA0_XB_RF_INT_OE 0x864 +#define R88F_FPGA0_XCD_RF_SW_CTRL 0x874 +#define R88F_FPGA0_ANALOG4 0x88c +#define R88F_FPGA0_PSD_REPORT 0x8b4 + +/* Noise Histogram. */ +#define R88F_NHM_TH9_TH10_8723B 0x890 +#define R88F_NHM_TIMER_8723B 0x894 +#define R88F_NHM_TH3_TO_TH0_8723B 0x898 +#define R88F_NHM_TH7_TO_TH4_8723B 0x89c + +/* RX/CCK. */ +#define R88F_RX_DFIR 0x954 +#define R88F_CCK_PD_THRESH 0xa0a + +/* OFDM0. */ +#define R88F_OFDM0_FA_RSTC 0xc0c +#define R88F_OFDM0_XA_RX_AFE 0xc10 +#define R88F_OFDM0_RX_D_SYNC_PATH 0xc40 + +/* OFDM1. */ +#define R88F_OFDM1_CFO_TRACKING 0xd2c +#define R88F_OFDM1_CSI_FIX_MASK1 0xd40 +#define R88F_OFDM1_CSI_FIX_MASK2 0xd44 + +/* ADDA registers. */ +#define R88F_SLEEP 0xee0 +#define R88F_RX_OFDM 0xed0 +#define R88F_STANDBY 0xedc +#define R88F_RX_WAIT_RIFS 0xed4 +#define R88F_RX_TO_RX 0xed8 +#define R88F_PMPD_ANAEN 0xeec +#define R88F_RX_CCK 0xe8c +#define R88F_TX_OFDM_RFON 0xe7c +#define R88F_TX_TO_TX 0xe88 +#define R88F_FPGA0_XCD_SWITCH_CTRL 0x85c +#define R88F_BLUETOOTH 0xe6c +#define R88F_TX_OFDM_BBON 0xe80 +#define R88F_TX_CCK_RFON 0xe74 +#define R88F_TX_TO_RX 0xe84 +#define R88F_TX_CCK_BBON 0xe78 +#define R88F_RX_WAIT_CCA 0xe70 + +/* + * RF (6052) registers. + */ +#define R88F_RF_GAIN_CCA 0xdf +#define R88F_RF_UNKNOWN_55 0x55 +#define R88F_RF_PAD_TXG 0x56 +#define R88F_RF_RXG_GAIN 0x87 + +/* Bits for R92C_RF_CHNLBW. */ +#define R88F_RF_CHNLBW_BW20 0xc00 +#define R88F_RF_CHNLBW_BW40 0x400 + +/* Bits for R88F_RF_RXG_GAIN. */ +#define R88F_RF_TXA_PREPAD 0x65 + +/* Bits for R88F_RF_GAIN_CCA. */ +#define R88F_RF_PKTBUF_DBG_CTRL 0x140 + +/* Bits for R88F_CCK_PD_THRESH. */ +#define R88F_CCK_PD_TYPE1_LV1_TH 0x83 + +#endif /* R88F_REG_H */ diff --git a/sys/dev/rtwn/rtl8188f/r88f_rom.c b/sys/dev/rtwn/rtl8188f/r88f_rom.c new file mode 100644 index 000000000000..4b8959946cc0 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_rom.c @@ -0,0 +1,121 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * Copyright (c) 2026 Mir Saheb Ali + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define R88F_XTAL1_MASK 0x007e0000 /* bits 22:17 */ +#define R88F_XTAL0_MASK 0x0001f800 /* bits 16:11 */ + +int +r88f_efuse_preread(struct rtwn_softc *sc) +{ + int error; + uint32_t reg; + + /* Switch to the WIFI bank. */ + reg = rtwn_read_4(sc, R92C_EFUSE_TEST); + reg = RW(reg, R92C_EFUSE_TEST_SEL, 0); + error = rtwn_write_4(sc, R92C_EFUSE_TEST, reg); + + if (error != 0) + return (error); + + error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); + rtwn_delay(sc, 10); + + return (error); +} + +void +r88f_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; + struct r88f_rom *rom = (struct r88f_rom *)buf; + int i; + + rt->bw20_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, HIGH_PART)); + rt->ofdm_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, LOW_PART)); + + for (i = 0; i < nitems(rom->ht40_tx_pwr); i++) { + rt->ht40_tx_pwr[i] = rom->ht40_tx_pwr[i]; + if (rt->ht40_tx_pwr[i] > 0x3f) + rt->ht40_tx_pwr[i] = 0x27; + } + for (i = 0; i < nitems(rom->cck_tx_pwr); i++) { + rt->cck_tx_pwr[i] = rom->cck_tx_pwr[i]; + if (rt->cck_tx_pwr[i] > 0x3f) + rt->cck_tx_pwr[i] = 0x22; + } + + rs->crystalcap = rom->crystalcap & 0x3f; + + rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); + + rs->board_type = + MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE), + R92C_ROM_RF1_BOARD_TYPE); + + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type %d\n", + __func__, rs->regulatory); + + sc->thermal_meter = rom->thermal_meter; + + rtwn_r92c_set_rom_opts(sc, buf); +} diff --git a/sys/dev/rtwn/rtl8188f/r88f_rom_defs.h b/sys/dev/rtwn/rtl8188f/r88f_rom_defs.h new file mode 100644 index 000000000000..9e797afbe261 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_rom_defs.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef R88F_ROM_DEFS_H +#define R88F_ROM_DEFS_H + +#include + +#endif /* R88F_ROM_DEFS_H */ diff --git a/sys/dev/rtwn/rtl8188f/r88f_rom_image.h b/sys/dev/rtwn/rtl8188f/r88f_rom_image.h new file mode 100644 index 000000000000..77562047afb2 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_rom_image.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * Copyright (c) 2026 Mir Saheb Ali + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef R88F_ROM_IMAGE_H +#define R88F_ROM_IMAGE_H + +#include + +/* + * RTL8188FTV ROM image. + */ +struct r88f_rom { + uint8_t reserved1[16]; + uint8_t cck_tx_pwr[R88E_GROUP_2G]; + uint8_t ht40_tx_pwr[R88E_GROUP_2G - 1]; + uint8_t tx_pwr_diff; + uint8_t reserved2[156]; + uint8_t channel_plan; + uint8_t crystalcap; + uint8_t thermal_meter; + uint8_t iqk_lck; + uint8_t pa_type; + uint8_t lna_type_2g; + uint8_t reserved3[3]; + uint8_t rf_board_opt; + uint8_t rf_feature_opt; + uint8_t rf_bt_opt; + uint8_t version; + uint8_t customer_id; + uint8_t reserved4[10]; + uint16_t vid; + uint16_t pid; + uint8_t usb_opt; + uint8_t reserved5[2]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint8_t reserved6[291]; +} __packed; + +_Static_assert(sizeof(struct r88f_rom) == R88E_EFUSE_MAP_LEN, + "R88E_EFUSE_MAP_LEN must be equal to sizeof(struct r88f_rom)!"); + +#endif /* R88F_ROM_IMAGE_H */ diff --git a/sys/dev/rtwn/rtl8188f/r88f_rx.c b/sys/dev/rtwn/rtl8188f/r88f_rx.c new file mode 100644 index 000000000000..a7b115ee361d --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/r88f_rx.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +int8_t +r88f_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt; + int8_t lna_idx, vga_idx, rssi; + + lna_idx = (phy->agc_rpt & 0xe0) >> 5; + vga_idx = (phy->agc_rpt & 0x1f); + rssi = -(2 * vga_idx); + + switch (lna_idx) { + case 7: + if (vga_idx > 27) + rssi = -100; + else + rssi += -46; + break; + case 5: + rssi += -32; + break; + case 3: + rssi += -20; + break; + case 1: + rssi += -6; + break; + default: + rssi = 0; + break; + } + + return (rssi); +} + +int8_t +r88f_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) +{ + struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt; + int rssi; + + /* Get average RSSI. */ + rssi = ((le32toh(phy->sig_qual) >> 1) & 0x7f) - 110; + + return (rssi); +} + +void +r88f_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, + const void *desc, const void *physt_ptr) +{ + const struct r92c_rx_stat *stat = desc; + uint32_t rxdw1, rxdw3; + uint8_t rate; + + rxdw1 = le32toh(stat->rxdw1); + rxdw3 = le32toh(stat->rxdw3); + rate = MS(rxdw3, R92E_RXDW3_RATE); + + if (rxdw1 & R92C_RXDW1_AMPDU) + rxs->c_pktflags |= IEEE80211_RX_F_AMPDU; + else if (rxdw1 & R92C_RXDW1_AMPDU_MORE) + rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; + if ((rxdw3 & R92C_RXDW3_SPLCP) && RTWN_RATE_IS_HT(rate)) + rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; + + if (rxdw3 & R92C_RXDW3_HT40) + rxs->c_width = IEEE80211_RX_FW_40MHZ; + else + rxs->c_width = IEEE80211_RX_FW_20MHZ; + + if (RTWN_RATE_IS_CCK(rate)) + rxs->c_phytype = IEEE80211_RX_FP_11B; + else if (RTWN_RATE_IS_OFDM(rate)) + rxs->c_phytype = IEEE80211_RX_FP_11G; + else + rxs->c_phytype = IEEE80211_RX_FP_11NG; + + /* Map HW rate index to 802.11 rate. */ + if (RTWN_RATE_IS_CCK(rate) || RTWN_RATE_IS_OFDM(rate)) { + rxs->c_rate = ridx2rate[rate]; + if (RTWN_RATE_IS_CCK(rate)) + rxs->c_pktflags |= IEEE80211_RX_F_CCK; + else + rxs->c_pktflags |= IEEE80211_RX_F_OFDM; + } else { /* MCS0~15. */ + rxs->c_rate = + IEEE80211_RATE_MCS | (RTWN_RIDX_TO_MCS(rate)); + rxs->c_pktflags |= IEEE80211_RX_F_HT; + } +} diff --git a/sys/dev/rtwn/rtl8188f/usb/r88fu.h b/sys/dev/rtwn/rtl8188f/usb/r88fu.h new file mode 100644 index 000000000000..b79c64dedf48 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/usb/r88fu.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Mir Saheb Ali + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef RTL8188FU_H +#define RTL8188FU_H + +#include + +/* + * Function declarations + */ + +/* r88fu_init.c */ +int r88fu_power_on(struct rtwn_softc *); +void r88fu_power_off(struct rtwn_softc *); +void r88fu_init_rx_agg(struct rtwn_softc *); +void r88fu_init_tx_agg(struct rtwn_softc *); +void r88fu_init_bb(struct rtwn_softc *); +void r88fu_post_init(struct rtwn_softc *); + +#endif /* RTL8188FU_H */ diff --git a/sys/dev/rtwn/rtl8188f/usb/r88fu_attach.c b/sys/dev/rtwn/rtl8188f/usb/r88fu_attach.c new file mode 100644 index 000000000000..aba682dea5d7 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/usb/r88fu_attach.c @@ -0,0 +1,254 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * Copyright (c) 2026 Mir Saheb Ali + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include /* for 'macaddr' field */ +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static struct rtwn_r88e_txpwr r88e_txpwr; + +void r88fu_attach(struct rtwn_usb_softc *); + +static void +r88fu_set_macaddr(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r88f_rom *rom = (struct r88f_rom *)buf; + + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); +} + +static void +r88f_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r88fu_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r88e_txpwr; + rs->rs_txagc = NULL; + + rs->rs_set_bw20 = r88e_set_bw20; + rs->rs_get_txpower = r88f_get_txpower; + rs->rs_set_gain = r88e_set_gain; + rs->rs_tx_enable_ampdu = r88e_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r88e_tx_setup_hwseq; + rs->rs_tx_setup_macid = r88e_tx_setup_macid; + rs->rs_set_rom_opts = r88fu_set_macaddr; + + rs->rf_read_delay[0] = 10; + rs->rf_read_delay[1] = 100; + rs->rf_read_delay[2] = 10; + + sc->sc_priv = rs; +} + +static void +r88fu_enable_mac_txrx(struct rtwn_softc *sc) +{ + rtwn_setbits_2(sc, R92C_CR, 0, R92C_CR_MACTXEN | R92C_CR_MACRXEN); + rtwn_bb_setbits(sc, R92C_TXDMA_OFFSET_CHK, 0, R92C_RQPN); +} + +static void +r88fu_adj_devcaps(struct rtwn_softc *sc) +{ + /* XXX TODO? */ +} + +void +r88fu_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r12au_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r88f_set_chan; + sc->sc_fill_tx_desc = r12a_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r12a_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r12a_fill_tx_desc_null; + sc->sc_dump_tx_desc = r12au_dump_tx_desc; + sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rx_stats = r88f_get_rx_stats; + sc->sc_get_rssi_cck = r88f_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88f_get_rssi_ofdm; + sc->sc_classify_intr = r12au_classify_intr; + sc->sc_handle_tx_report = r12a_ratectl_tx_complete; + sc->sc_handle_tx_report2 = rtwn_nop_softc_uint8_int; + sc->sc_handle_c2h_report = r92e_handle_c2h_report; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r88e_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_efuse_preread = r88f_efuse_preread; + sc->sc_parse_rom = r88f_parse_rom; + sc->sc_set_led = r88e_set_led; + sc->sc_power_on = r88fu_power_on; + sc->sc_power_off = r88fu_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r88f_fw_reset; + sc->sc_fw_download_enable = r88f_fw_download_enable; +#endif + sc->sc_llt_init = r88f_llt_init; + sc->sc_enable_mac_txrx = r88fu_enable_mac_txrx; + sc->sc_set_page_size = r88f_set_page_size; + sc->sc_lc_calib = r88f_lc_calib; + sc->sc_iq_calib = r88f_iq_calib; + sc->sc_read_chipid_vendor = rtwn_nop_softc_uint32; + sc->sc_adj_devcaps = r88fu_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r88f_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r88e_set_media_status; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r88e_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO? */ +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r88e_beacon_enable; + sc->sc_sta_beacon_enable = r88e_sta_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r88fu_init_tx_agg; + sc->sc_init_rx_agg = r88fu_init_rx_agg; + sc->sc_init_beacon_timer = rtwn_nop_softc; + sc->sc_init_ampdu = r88f_init_ampdu; + sc->sc_init_intr = r88eu_init_intr; + sc->sc_init_edca = r92c_init_edca; + sc->sc_init_bb = r88fu_init_bb; + sc->sc_init_rf = r88f_init_rf; + sc->sc_init_antsel = r23b_init_antsel; + sc->sc_post_init = r88fu_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + sc->sc_set_tx_power = r92c_set_tx_power; + + sc->mac_prog = &rtl8188ftv_mac[0]; + sc->mac_size = nitems(rtl8188ftv_mac); + sc->bb_prog = &rtl8188ftv_bb[0]; + sc->bb_size = nitems(rtl8188ftv_bb); + sc->agc_prog = &rtl8188ftv_agc[0]; + sc->agc_size = nitems(rtl8188ftv_agc); + sc->rf_prog = &rtl8188ftv_rf[0]; + + sc->name = "RTL8188FTV"; + sc->fwname = "rtwn-rtl8188fufw"; + sc->fwsig = 0x88f; + + sc->ackto = 0x40; + sc->npubqpages = R88EU_PUBQ_NPAGES; + sc->nhqpages = R88F_HQ_NPAGES; + sc->nlqpages = R88F_LQ_NPAGES; + sc->nnqpages = R88F_NQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->page_count = R88F_TX_PAGE_COUNT; + sc->pktbuf_count = R88F_TXPKTBUF_COUNT; + + sc->txdesc_len = sizeof(struct r12au_tx_desc); + sc->efuse_maxlen = R88E_EFUSE_MAX_LEN; + sc->efuse_maplen = R88E_EFUSE_MAP_LEN; + sc->rx_dma_size = R88F_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R88E_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R88F_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + sc->ntxchains = 1; + sc->nrxchains = 1; + + r88fu_attach_private(sc); +} diff --git a/sys/dev/rtwn/rtl8188f/usb/r88fu_init.c b/sys/dev/rtwn/rtl8188f/usb/r88fu_init.c new file mode 100644 index 000000000000..66bbf79a9342 --- /dev/null +++ b/sys/dev/rtwn/rtl8188f/usb/r88fu_init.c @@ -0,0 +1,444 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * Copyright (c) 2026 Mir Saheb Ali + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +void +r88fu_init_tx_agg(struct rtwn_softc *sc) +{ + uint8_t agg_ctrl, rxdma_mode, usb_tx_agg_desc_num = 6; + uint32_t agg_rx; + + /* TX aggregation */ + rtwn_setbits_4(sc, R92C_TDECTRL, 0xf << 4, usb_tx_agg_desc_num << 4); + rtwn_write_1(sc, R92E_DWBCN1_CTRL, usb_tx_agg_desc_num << 1); + + /* RX aggegation */ + agg_ctrl = rtwn_read_1(sc, R92C_TRXDMA_CTRL); + agg_ctrl &= ~0x00000004; + + agg_rx = rtwn_read_1(sc, R92C_RXDMA_AGG_PG_TH); + agg_rx &= ~0x80000000; + agg_rx &= ~0xff0f; /* reset agg size and timeout */ + + rxdma_mode = rtwn_read_1(sc, R92E_RXDMA_PRO); + rxdma_mode &= ~0x00000002; + + rtwn_write_1(sc, R92C_TRXDMA_CTRL, agg_ctrl); + rtwn_write_4(sc, R92C_RXDMA_AGG_PG_TH, agg_rx); + rtwn_write_1(sc, R92E_RXDMA_PRO, rxdma_mode); +} + +int +r88fu_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while (0) + int ntries; + + /* Enable WL suspend. */ + RTWN_CHK(rtwn_setbits_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0)); + + /* Turn off USB APHY LDO under suspend mode. */ + RTWN_CHK(rtwn_setbits_1(sc, 0xc4, 0x10, 0)); + + RTWN_CHK(rtwn_setbits_2(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_APFM_RSM, 0)); + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Disable HWPDN. */ + RTWN_CHK(rtwn_setbits_2(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_APDM_HPDN, 0)); + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_2(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_AFSM_HSUS, 0)); + + /* Auto enable WLAN. */ + RTWN_CHK(rtwn_setbits_2(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_ONMAC)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Reduce RF noise. */ + rtwn_write_1(sc, R92C_AFE_LDO_CTRL, 0x35); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + R92C_CR_ENSEC | R92C_CR_CALTMR_EN)); + + return (0); +#undef RTWN_CHK +} + +#define R88F_RXPKT_NUM_RW_RELEASE_ENABLE 0x00040000 +#define R88F_RXPKT_NUM_RXDMA_IDLE 0x00020000 + +static int +r88fu_flush_fifo(struct rtwn_softc *sc) +{ + uint32_t reg; + int retry, retval; + + rtwn_write_1(sc, R92C_TXPAUSE, 0xff); + + rtwn_bb_setbits(sc, R92C_RXPKT_NUM, 0, R88F_RXPKT_NUM_RW_RELEASE_ENABLE); + + retry = 100; + + /* setting retval to (EBUSY = 16) */ + retval = -16; + + do { + reg = rtwn_bb_read(sc, R92C_RXPKT_NUM); + if (reg & R88F_RXPKT_NUM_RXDMA_IDLE) { + retval = 0; + break; + } + } while (retry--); + + rtwn_write_2(sc, R92C_RQPN_NPQ, 0); + rtwn_bb_write(sc, R92C_RQPN, 0x80000000); + rtwn_delay(sc, 2); + + if (!retry) + device_printf(sc->sc_dev, "%s: Failed to flush FIFO\n", __func__); + + return (retval); + +} + +void +r88fu_power_off(struct rtwn_softc *sc) +{ + uint8_t reg; + int error, ntries; + + r88fu_flush_fifo(sc); + + /* Disable any kind of TX reports. */ + error = rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, + R88E_TX_RPT1_ENA | R88E_TX_RPT2_ENA, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Stop Rx. */ + rtwn_write_1(sc, R92C_CR, 0); + + /* Move card to Low Power State. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset MAC TRX */ + rtwn_write_1(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN); + + /* check if removed later */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, 0x20); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) + r88f_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU ready status. */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Disable 32k. */ + rtwn_setbits_1(sc, R88E_32K_CTRL, 0x01, 0); + + /* Move card to Disabled state. */ + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + /* LDO Sleep mode. */ + rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_OFF, 1); + + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* schmit trigger */ + rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_PCIE, R92C_APS_FSMCO_AFSM_HSUS, 1); + + /* Enable bandgap mbias in suspend. */ + rtwn_write_1(sc, R92C_APS_FSMCO + 3, 0); + + /* Clear SIC_EN register. */ + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG + 1, 0x10, 0); + + /* Set USB suspend enable local register */ + rtwn_setbits_1(sc, R92C_USB_SUSPEND, 0, 0x10); + + /* Reset MCU IO Wrapper. */ + reg = rtwn_read_1(sc, R92C_RSV_CTRL + 1); + rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg & ~0x08); + rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg | 0x08); + + /* marked as 'For Power Consumption' code. */ + rtwn_write_1(sc, R92C_GPIO_OUT, rtwn_read_1(sc, R92C_GPIO_IN)); + rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff); + + rtwn_write_1(sc, R92C_GPIO_IO_SEL, + rtwn_read_1(sc, R92C_GPIO_IO_SEL) << 4); + rtwn_setbits_1(sc, R92C_GPIO_MOD, 0, 0x0f); + + /* Set LNA, TRSW, EX_PA Pin to output mode. */ + rtwn_write_4(sc, R88E_BB_PAD_CTRL, 0x00080808); +} + +void +r88fu_init_rx_agg(struct rtwn_softc *sc) +{ + rtwn_setbits_1(sc, R92E_RXDMA_PRO, 0x3c, 0x1c); + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, R92C_TRXDMA_CTRL_RXDMA_AGG_EN); + /* set 5 is the dmasize */ + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 5); + /* set 32 is the dmatiming */ + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 32); + rtwn_setbits_1(sc, R92E_RXDMA_PRO, 0, R92E_RXDMA_PRO_DMA_MODE); +} + +#define R88F_XTAL1_M 0x007E0000U +#define R88F_XTAL1_S 17 +#define R88F_XTAL0_M 0x0001F800U +#define R88F_XTAL0_S 11 + +static void +r88fu_set_crystal_cap(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t cap; + + cap = rs->crystalcap & 0x3f; + + reg = rtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); + + + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: Adjusting crystal cap from 0x%x (actually 0x%x 0x%x) to 0x%x\n", + __func__, + rs->crystalcap, + MS(reg, R88F_XTAL1), + MS(reg, R88F_XTAL0), + cap); + + reg &= ~(R88F_XTAL1_M | R88F_XTAL0_M); + reg |= SM(R88F_XTAL1, cap) | SM(R88F_XTAL0, cap); + rtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, reg); +} + +static void +r88f_init_bb_common(struct rtwn_softc *sc) +{ + r92c_init_bb_common(sc); + + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422); + rtwn_delay(sc, 1); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); + rtwn_delay(sc, 1); + + r88fu_set_crystal_cap(sc); +} + +void +r88fu_init_bb(struct rtwn_softc *sc) +{ + /* Enable BB and RF */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_DIO_RF); + + /* + * Per vendor driver, run power sequence before init of RF + */ + rtwn_write_1(sc, R92C_RF_CTRL, R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | + R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); + + rtwn_delay(sc, 10); + + rtwn_rf_write(sc, 0, R92C_RF_IQADJ_G(0), 0x780); + + r88f_init_bb_common(sc); + + /* CCK PD */ + rtwn_write_1(sc, R88F_CCK_PD_THRESH, R88F_CCK_PD_TYPE1_LV1_TH); +} + +static void +r88fu_init_stats(struct rtwn_softc *sc) +{ + uint32_t clr; + + rtwn_write_2(sc, R88F_NHM_TIMER_8723B + 2, 0xc350); + rtwn_write_2(sc, R88F_NHM_TH9_TH10_8723B + 2, 0xffff); + rtwn_write_4(sc, R88F_NHM_TH3_TO_TH0_8723B, 0xffffff50); + rtwn_write_4(sc, R88F_NHM_TH7_TO_TH4_8723B, 0xffffffff); + + rtwn_setbits_4(sc, R92C_FPGA0_IQK, 0, 0xff); + + clr = 0x00000100 | 0x00000200 | 0x00000400; + rtwn_setbits_4(sc, R88F_NHM_TH9_TH10_8723B, clr, 0x00000100); + + rtwn_setbits_4(sc, R88F_OFDM0_FA_RSTC, 0, 0x00000080); +} + +void +r88fu_post_init(struct rtwn_softc *sc) +{ + uint8_t reg8; + + /* + * This should enable thermal meter + */ + rtwn_rf_setbits(sc, 0, R88E_RF_T_METER, 0, 0x30000); + + rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, 0, R88E_TX_RPT2_ENA); + /* Set MAX RPT MACID */ + rtwn_write_1(sc, R88E_TX_RPT_CTRL + 1, R88E_TX_RPT2_ENA); + /* TX report Timer. Unit: 32us */ + rtwn_write_2(sc, R88E_TX_RPT_TIME, 0xcdf0); + /* tmp ps ? */ + reg8 = rtwn_read_1(sc, 0xa3); + reg8 &= 0xf8; + rtwn_write_1(sc, 0xa3, reg8); + + /* Perform LO and IQ calibrations. */ + r88f_iq_calib(sc); + /* Perform LC calibration. */ + r88f_lc_calib(sc); + + rtwn_write_1(sc, R92C_USB_HRPWM, 0); + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* No support (yet?) for f/w rate adaptation. */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + + r88fu_init_stats(sc); +} + diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c index b34a07714cf1..90bde4544cff 100644 --- a/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c @@ -192,6 +192,7 @@ r92ce_attach(struct rtwn_pci_softc *pc) sc->sc_fw_download_enable = r92c_fw_download_enable; #endif sc->sc_llt_init = r92c_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = r92c_set_page_size; sc->sc_lc_calib = r92c_lc_calib; sc->sc_iq_calib = r92ce_iq_calib; @@ -215,6 +216,7 @@ r92ce_attach(struct rtwn_pci_softc *pc) sc->sc_temp_read = r92c_temp_read; sc->sc_init_tx_agg = rtwn_nop_softc; sc->sc_init_rx_agg = rtwn_nop_softc; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = r92ce_init_ampdu; sc->sc_init_intr = r92ce_init_intr; sc->sc_init_edca = r92ce_init_edca; diff --git a/sys/dev/rtwn/rtl8192c/r92c.h b/sys/dev/rtwn/rtl8192c/r92c.h index cab7393caf39..f5756b331547 100644 --- a/sys/dev/rtwn/rtl8192c/r92c.h +++ b/sys/dev/rtwn/rtl8192c/r92c.h @@ -45,6 +45,7 @@ void r92c_read_chipid_vendor(struct rtwn_softc *, uint32_t); /* r92c_beacon.c */ void r92c_beacon_init(struct rtwn_softc *, void *, int); +void r92c_init_beacon_timer(struct rtwn_softc *); void r92c_beacon_enable(struct rtwn_softc *, int, int); void r92c_sta_beacon_enable(struct rtwn_softc *, int, bool); diff --git a/sys/dev/rtwn/rtl8192c/r92c_beacon.c b/sys/dev/rtwn/rtl8192c/r92c_beacon.c index 4646b9317c2f..55ea9639a6b0 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_beacon.c +++ b/sys/dev/rtwn/rtl8192c/r92c_beacon.c @@ -48,6 +48,12 @@ #include #include +void +r92c_init_beacon_timer(struct rtwn_softc *sc) +{ + rtwn_write_1(sc, R92C_DRVERLYINT, 0x05); +} + void r92c_beacon_init(struct rtwn_softc *sc, void *buf, int id) { diff --git a/sys/dev/rtwn/rtl8192c/r92c_reg.h b/sys/dev/rtwn/rtl8192c/r92c_reg.h index e6d232a88834..4a58d01351c1 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_reg.h +++ b/sys/dev/rtwn/rtl8192c/r92c_reg.h @@ -39,6 +39,7 @@ #define R92C_LDOHCI12_CTRL 0x022 #define R92C_LPLDO_CTRL 0x023 #define R92C_AFE_XTAL_CTRL 0x024 +#define R92C_AFE_LDO_CTRL 0x027 #define R92C_AFE_PLL_CTRL 0x028 #define R92C_APE_PLL_CTRL_EXT 0x02c #define R92C_MAC_PHY_CTRL R92C_APE_PLL_CTRL_EXT @@ -338,6 +339,10 @@ #define R92C_AFE_PLL_CTRL_WDOGB 0x0010 #define R92C_AFE_PLL_CTRL_LPFEN 0x0020 +/* Bits for R92C_EFUSE_TEST. */ +#define R92C_EFUSE_TEST_SEL_M 0x00000300 +#define R92C_EFUSE_TEST_SEL_S 8 + /* Bits for R92C_EFUSE_CTRL. */ #define R92C_EFUSE_CTRL_DATA_M 0x000000ff #define R92C_EFUSE_CTRL_DATA_S 0 diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c index aa8442b2ae87..85b1bda11b89 100644 --- a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c @@ -184,6 +184,7 @@ r92cu_attach(struct rtwn_usb_softc *uc) sc->sc_fw_download_enable = r92c_fw_download_enable; #endif sc->sc_llt_init = r92c_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = r92c_set_page_size; sc->sc_lc_calib = r92c_lc_calib; sc->sc_iq_calib = r92c_iq_calib; @@ -207,6 +208,7 @@ r92cu_attach(struct rtwn_usb_softc *uc) sc->sc_temp_read = r92c_temp_read; sc->sc_init_tx_agg = r92cu_init_tx_agg; sc->sc_init_rx_agg = r92cu_init_rx_agg; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = r92c_init_ampdu; sc->sc_init_intr = r92cu_init_intr; sc->sc_init_edca = r92c_init_edca; diff --git a/sys/dev/rtwn/rtl8192e/r92e_reg.h b/sys/dev/rtwn/rtl8192e/r92e_reg.h index 5106bcf9d5f0..782470d4645b 100644 --- a/sys/dev/rtwn/rtl8192e/r92e_reg.h +++ b/sys/dev/rtwn/rtl8192e/r92e_reg.h @@ -37,9 +37,20 @@ #define R92E_LDOV12_CTRL 0x014 #define R92E_AFE_XTAL_CTRL 0x02c #define R92E_APE_PLL_CTRL_EXT 0x078 +#define R92E_AUTO_LLT 0x224 +#define R92E_DWBCN1_CTRL 0x228 +#define R92E_RXDMA_PRO 0x290 +#define R92E_RXDW3_RATE_M 0x0000007f +#define R92E_RXDW3_RATE_S 0 /* Bits for R92E_AFE_XTAL_CTRL. */ #define R92E_AFE_XTAL_CTRL_ADDR_M 0x00fff000 #define R92E_AFE_XTAL_CTRL_ADDR_S 12 +/* Bits for R92E_AUTO_LLT. */ +#define R92E_AUTO_LLT_EN 0x00010000 + +/* Bits for R92E_RXDMA_PRO. */ +#define R92E_RXDMA_PRO_DMA_MODE 0x02 + #endif /* R92E_REG_H */ diff --git a/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c b/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c index 103994d69593..68c6b69549e9 100644 --- a/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c +++ b/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c @@ -133,6 +133,7 @@ r92eu_attach(struct rtwn_usb_softc *uc) sc->sc_fw_download_enable = r12a_fw_download_enable; #endif sc->sc_llt_init = r92e_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = rtwn_nop_int_softc; sc->sc_lc_calib = r92c_lc_calib; sc->sc_iq_calib = rtwn_nop_softc; /* XXX TODO */ @@ -158,6 +159,7 @@ r92eu_attach(struct rtwn_usb_softc *uc) sc->sc_temp_read = r88e_temp_read; sc->sc_init_tx_agg = r21au_init_tx_agg; sc->sc_init_rx_agg = r92eu_init_rx_agg; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = rtwn_nop_softc; sc->sc_init_intr = r12a_init_intr; sc->sc_init_edca = r92c_init_edca; diff --git a/sys/dev/rtwn/rtl8723b/usb/r23bu_attach.c b/sys/dev/rtwn/rtl8723b/usb/r23bu_attach.c index 507594f2251b..664bb8b02160 100644 --- a/sys/dev/rtwn/rtl8723b/usb/r23bu_attach.c +++ b/sys/dev/rtwn/rtl8723b/usb/r23bu_attach.c @@ -118,6 +118,7 @@ r23bu_attach(struct rtwn_usb_softc *uc) sc->sc_fw_download_enable = r23b_fw_download_enable; #endif sc->sc_llt_init = r92e_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = r23b_set_page_size; sc->sc_lc_calib = r23b_lc_calib; sc->sc_iq_calib = r23b_iq_calib; @@ -143,6 +144,7 @@ r23bu_attach(struct rtwn_usb_softc *uc) sc->sc_temp_read = r88e_temp_read; sc->sc_init_tx_agg = r21au_init_tx_agg; sc->sc_init_rx_agg = r23bu_init_rx_agg; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = r23bu_init_ampdu; sc->sc_init_intr = r92cu_init_intr; sc->sc_init_edca = r92c_init_edca; diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c b/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c index 562c23001a8d..069fb28d5be7 100644 --- a/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c @@ -234,6 +234,7 @@ r12au_attach(struct rtwn_usb_softc *uc) sc->sc_fw_download_enable = r12a_fw_download_enable; #endif sc->sc_llt_init = r92c_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = r12a_set_page_size; sc->sc_lc_calib = r12a_lc_calib; sc->sc_iq_calib = r12a_iq_calib; @@ -259,6 +260,7 @@ r12au_attach(struct rtwn_usb_softc *uc) sc->sc_temp_read = r88e_temp_read; sc->sc_init_tx_agg = r92cu_init_tx_agg; sc->sc_init_rx_agg = r12au_init_rx_agg; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = r12au_init_ampdu; sc->sc_init_intr = r12a_init_intr; sc->sc_init_edca = r12a_init_edca; diff --git a/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c b/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c index 64dac8ab68bf..1330193ff782 100644 --- a/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c +++ b/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c @@ -218,6 +218,7 @@ r21au_attach(struct rtwn_usb_softc *uc) sc->sc_fw_download_enable = r12a_fw_download_enable; #endif sc->sc_llt_init = r92c_llt_init; + sc->sc_enable_mac_txrx = rtwn_nop_softc; sc->sc_set_page_size = rtwn_nop_int_softc; sc->sc_lc_calib = rtwn_nop_softc; /* XXX not used */ sc->sc_iq_calib = r12a_iq_calib; @@ -243,6 +244,7 @@ r21au_attach(struct rtwn_usb_softc *uc) sc->sc_temp_read = r88e_temp_read; sc->sc_init_tx_agg = r21au_init_tx_agg; sc->sc_init_rx_agg = r12au_init_rx_agg; + sc->sc_init_beacon_timer = r92c_init_beacon_timer; sc->sc_init_ampdu = r12au_init_ampdu; sc->sc_init_intr = r12a_init_intr; sc->sc_init_edca = r12a_init_edca; diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.h b/sys/dev/rtwn/usb/rtwn_usb_attach.h index 8a44ba8f52ce..89445c54dc36 100644 --- a/sys/dev/rtwn/usb/rtwn_usb_attach.h +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.h @@ -21,6 +21,7 @@ void r92cu_attach(struct rtwn_usb_softc *); void r92eu_attach(struct rtwn_usb_softc *); void r88eu_attach(struct rtwn_usb_softc *); +void r88fu_attach(struct rtwn_usb_softc *); void r23bu_attach(struct rtwn_usb_softc *); void r12au_attach(struct rtwn_usb_softc *); void r21au_attach(struct rtwn_usb_softc *); @@ -29,6 +30,7 @@ enum { RTWN_CHIP_RTL8192CU, RTWN_CHIP_RTL8192EU, RTWN_CHIP_RTL8188EU, + RTWN_CHIP_RTL8188FU, RTWN_CHIP_RTL8723BU, RTWN_CHIP_RTL8812AU, RTWN_CHIP_RTL8821AU, @@ -134,6 +136,13 @@ static const STRUCT_USB_HOST_ID rtwn_devs[] = { RTWN_RTL8188EU_DEV(MERCUSYS, MW150US), #undef RTWN_RTL8188EU_DEV + /* RTL8188FU */ +#define RTWN_RTL8188FU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \ + RTWN_USB_DEVINFO(RTWN_CHIP_RTL8188FU, 0)) } + RTWN_RTL8188FU_DEV(REALTEK, RTL8188FTV), +#undef RTWN_RTL8188FU_DEV + /* RTL8723BU */ #define RTWN_RTL8723BU_DEV(v, p, i) \ { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p), \ @@ -196,6 +205,7 @@ static const chip_usb_attach rtwn_chip_usb_attach[RTWN_CHIP_MAX_USB] = { [RTWN_CHIP_RTL8192CU] = r92cu_attach, [RTWN_CHIP_RTL8192EU] = r92eu_attach, [RTWN_CHIP_RTL8188EU] = r88eu_attach, + [RTWN_CHIP_RTL8188FU] = r88fu_attach, [RTWN_CHIP_RTL8723BU] = r23bu_attach, [RTWN_CHIP_RTL8812AU] = r12au_attach, [RTWN_CHIP_RTL8821AU] = r21au_attach diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 4f7b4761ea7c..0f190a899571 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -4134,6 +4134,7 @@ product RATOC REXUSB60F 0xb020 USB serial adapter REX-USB60F /* Green House and CompUSA OEM this part */ product REALTEK USB20CRW 0x0158 USB20CRW Card Reader product REALTEK RTL8188ETV 0x0179 RTL8188ETV +product REALTEK RTL8188FTV 0xf179 RTL8188FTV product REALTEK RTL8188CTV 0x018a RTL8188CTV product REALTEK RTL8821AU_2 0x0811 RTL8821AU product REALTEK RTW8821CU_CD 0x1a2b RTW8821CU_CD diff --git a/sys/modules/rtwn/Makefile b/sys/modules/rtwn/Makefile index 2239f1b3d8da..c9a0cbc72f39 100644 --- a/sys/modules/rtwn/Makefile +++ b/sys/modules/rtwn/Makefile @@ -22,6 +22,11 @@ SRCS += r88e_beacon.c r88e_calib.c r88e_chan.c r88e_fw.c r88e_init.c \ r88e_priv.h r88e_reg.h r88e_rom_defs.h r88e_rom_image.h \ r88e_fw_cmd.h r88e_rx_desc.h r88e_tx_desc.h +.PATH: ${SRCTOP}/sys/dev/rtwn/rtl8188f +SRCS += r88f.h r88f_calib.c r88f_chan.c r88f_fw.c r88f_init.c \ + r88f_priv.h r88f_reg.h r88f_rx.c r88f_rom.c r88f_rom_defs.h \ + r88f_rom_image.h + .PATH: ${SRCTOP}/sys/dev/rtwn/rtl8192e SRCS += r92e_chan.c r92e_fw.c r92e_init.c r92e_led.c r92e_rf.c \ r92e_rom.c r92e_rx.c r92e.h r92e_priv.h r92e_reg.h \ diff --git a/sys/modules/rtwn_usb/Makefile b/sys/modules/rtwn_usb/Makefile index 7c7b67106a1c..b27acf68cd5f 100644 --- a/sys/modules/rtwn_usb/Makefile +++ b/sys/modules/rtwn_usb/Makefile @@ -12,6 +12,10 @@ SRCS = rtwn_usb_attach.c rtwn_usb_ep.c rtwn_usb_reg.c rtwn_usb_rx.c \ SRCS += r88eu_attach.c r88eu_init.c \ r88eu.h r88eu_reg.h +.PATH: ${SRCTOP}/sys/dev/rtwn/rtl8188f/usb +SRCS += r88fu_attach.c r88fu_init.c \ + r88fu.h + .PATH: ${SRCTOP}/sys/dev/rtwn/rtl8192c/usb SRCS += r92cu_attach.c r92cu_init.c r92cu_led.c r92cu_rx.c r92cu_tx.c \ r92cu.h r92cu_priv.h r92cu_reg.h r92cu_tx_desc.h diff --git a/sys/modules/rtwnfw/Makefile b/sys/modules/rtwnfw/Makefile index 1b9222b3672c..3292582ac510 100644 --- a/sys/modules/rtwnfw/Makefile +++ b/sys/modules/rtwnfw/Makefile @@ -1,4 +1,5 @@ SUBDIR= rtwnrtl8188eu rtwnrtl8192cT rtwnrtl8192cU rtwnrtl8192eu rtwnrtl8812au \ - rtwnrtl8821au rtwnrtl8192cE rtwnrtl8192cEB rtwnrtl8188ee rtwnrtl8723bu + rtwnrtl8821au rtwnrtl8192cE rtwnrtl8192cEB rtwnrtl8188ee rtwnrtl8723bu \ + rtwnrtl8188fu .include diff --git a/sys/modules/rtwnfw/rtwnrtl8188fu/Makefile b/sys/modules/rtwnfw/rtwnrtl8188fu/Makefile new file mode 100644 index 000000000000..2a16baa021b9 --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8188fu/Makefile @@ -0,0 +1,4 @@ +KMOD= rtwn-rtl8188fufw +IMG= rtwn-rtl8188fufw + +.include