radio.c 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. Broadcom B43legacy wireless driver
  4. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  5. Stefano Brivio <stefano.brivio@polimi.it>
  6. Michael Buesch <m@bues.ch>
  7. Danny van Dyk <kugelfang@gentoo.org>
  8. Andreas Jaggi <andreas.jaggi@waterwave.ch>
  9. Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
  10. Some parts of the code in this file are derived from the ipw2200
  11. driver Copyright(c) 2003 - 2004 Intel Corporation.
  12. */
  13. #include <linux/delay.h>
  14. #include "b43legacy.h"
  15. #include "main.h"
  16. #include "phy.h"
  17. #include "radio.h"
  18. #include "ilt.h"
  19. /* Table for b43legacy_radio_calibrationvalue() */
  20. static const u16 rcc_table[16] = {
  21. 0x0002, 0x0003, 0x0001, 0x000F,
  22. 0x0006, 0x0007, 0x0005, 0x000F,
  23. 0x000A, 0x000B, 0x0009, 0x000F,
  24. 0x000E, 0x000F, 0x000D, 0x000F,
  25. };
  26. /* Reverse the bits of a 4bit value.
  27. * Example: 1101 is flipped 1011
  28. */
  29. static u16 flip_4bit(u16 value)
  30. {
  31. u16 flipped = 0x0000;
  32. B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
  33. flipped |= (value & 0x0001) << 3;
  34. flipped |= (value & 0x0002) << 1;
  35. flipped |= (value & 0x0004) >> 1;
  36. flipped |= (value & 0x0008) >> 3;
  37. return flipped;
  38. }
  39. /* Get the freq, as it has to be written to the device. */
  40. static inline
  41. u16 channel2freq_bg(u8 channel)
  42. {
  43. /* Frequencies are given as frequencies_bg[index] + 2.4GHz
  44. * Starting with channel 1
  45. */
  46. static const u16 frequencies_bg[14] = {
  47. 12, 17, 22, 27,
  48. 32, 37, 42, 47,
  49. 52, 57, 62, 67,
  50. 72, 84,
  51. };
  52. if (unlikely(channel < 1 || channel > 14)) {
  53. printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
  54. channel);
  55. dump_stack();
  56. return 2412;
  57. }
  58. return frequencies_bg[channel - 1];
  59. }
  60. void b43legacy_radio_lock(struct b43legacy_wldev *dev)
  61. {
  62. u32 status;
  63. status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
  64. B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK);
  65. status |= B43legacy_MACCTL_RADIOLOCK;
  66. b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
  67. udelay(10);
  68. }
  69. void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
  70. {
  71. u32 status;
  72. b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
  73. status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
  74. B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));
  75. status &= ~B43legacy_MACCTL_RADIOLOCK;
  76. b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
  77. }
  78. u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
  79. {
  80. struct b43legacy_phy *phy = &dev->phy;
  81. switch (phy->type) {
  82. case B43legacy_PHYTYPE_B:
  83. if (phy->radio_ver == 0x2053) {
  84. if (offset < 0x70)
  85. offset += 0x80;
  86. else if (offset < 0x80)
  87. offset += 0x70;
  88. } else if (phy->radio_ver == 0x2050)
  89. offset |= 0x80;
  90. else
  91. B43legacy_WARN_ON(1);
  92. break;
  93. case B43legacy_PHYTYPE_G:
  94. offset |= 0x80;
  95. break;
  96. default:
  97. B43legacy_BUG_ON(1);
  98. }
  99. b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
  100. return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
  101. }
  102. void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
  103. {
  104. b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
  105. b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
  106. }
  107. static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
  108. s16 first, s16 second, s16 third)
  109. {
  110. struct b43legacy_phy *phy = &dev->phy;
  111. u16 i;
  112. u16 start = 0x08;
  113. u16 end = 0x18;
  114. u16 offset = 0x0400;
  115. u16 tmp;
  116. if (phy->rev <= 1) {
  117. offset = 0x5000;
  118. start = 0x10;
  119. end = 0x20;
  120. }
  121. for (i = 0; i < 4; i++)
  122. b43legacy_ilt_write(dev, offset + i, first);
  123. for (i = start; i < end; i++)
  124. b43legacy_ilt_write(dev, offset + i, second);
  125. if (third != -1) {
  126. tmp = ((u16)third << 14) | ((u16)third << 6);
  127. b43legacy_phy_write(dev, 0x04A0,
  128. (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
  129. | tmp);
  130. b43legacy_phy_write(dev, 0x04A1,
  131. (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
  132. | tmp);
  133. b43legacy_phy_write(dev, 0x04A2,
  134. (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
  135. | tmp);
  136. }
  137. b43legacy_dummy_transmission(dev);
  138. }
  139. static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
  140. {
  141. struct b43legacy_phy *phy = &dev->phy;
  142. u16 i;
  143. u16 tmp;
  144. u16 offset = 0x0400;
  145. u16 start = 0x0008;
  146. u16 end = 0x0018;
  147. if (phy->rev <= 1) {
  148. offset = 0x5000;
  149. start = 0x0010;
  150. end = 0x0020;
  151. }
  152. for (i = 0; i < 4; i++) {
  153. tmp = (i & 0xFFFC);
  154. tmp |= (i & 0x0001) << 1;
  155. tmp |= (i & 0x0002) >> 1;
  156. b43legacy_ilt_write(dev, offset + i, tmp);
  157. }
  158. for (i = start; i < end; i++)
  159. b43legacy_ilt_write(dev, offset + i, i - start);
  160. b43legacy_phy_write(dev, 0x04A0,
  161. (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
  162. | 0x4040);
  163. b43legacy_phy_write(dev, 0x04A1,
  164. (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
  165. | 0x4040);
  166. b43legacy_phy_write(dev, 0x04A2,
  167. (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
  168. | 0x4000);
  169. b43legacy_dummy_transmission(dev);
  170. }
  171. /* Synthetic PU workaround */
  172. static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
  173. u8 channel)
  174. {
  175. struct b43legacy_phy *phy = &dev->phy;
  176. might_sleep();
  177. if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
  178. /* We do not need the workaround. */
  179. return;
  180. if (channel <= 10)
  181. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
  182. channel2freq_bg(channel + 4));
  183. else
  184. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
  185. channel2freq_bg(channel));
  186. msleep(1);
  187. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
  188. channel2freq_bg(channel));
  189. }
  190. u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
  191. {
  192. struct b43legacy_phy *phy = &dev->phy;
  193. u8 ret = 0;
  194. u16 saved;
  195. u16 rssi;
  196. u16 temp;
  197. int i;
  198. int j = 0;
  199. saved = b43legacy_phy_read(dev, 0x0403);
  200. b43legacy_radio_selectchannel(dev, channel, 0);
  201. b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
  202. if (phy->aci_hw_rssi)
  203. rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
  204. else
  205. rssi = saved & 0x3F;
  206. /* clamp temp to signed 5bit */
  207. if (rssi > 32)
  208. rssi -= 64;
  209. for (i = 0; i < 100; i++) {
  210. temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
  211. if (temp > 32)
  212. temp -= 64;
  213. if (temp < rssi)
  214. j++;
  215. if (j >= 20)
  216. ret = 1;
  217. }
  218. b43legacy_phy_write(dev, 0x0403, saved);
  219. return ret;
  220. }
  221. u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
  222. {
  223. struct b43legacy_phy *phy = &dev->phy;
  224. u8 ret[13] = { 0 };
  225. unsigned int channel = phy->channel;
  226. unsigned int i;
  227. unsigned int j;
  228. unsigned int start;
  229. unsigned int end;
  230. if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
  231. return 0;
  232. b43legacy_phy_lock(dev);
  233. b43legacy_radio_lock(dev);
  234. b43legacy_phy_write(dev, 0x0802,
  235. b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
  236. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  237. b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
  238. & 0x7FFF);
  239. b43legacy_set_all_gains(dev, 3, 8, 1);
  240. start = (channel > 5) ? channel - 5 : 1;
  241. end = (channel + 5 < 14) ? channel + 5 : 13;
  242. for (i = start; i <= end; i++) {
  243. if (abs(channel - i) > 2)
  244. ret[i-1] = b43legacy_radio_aci_detect(dev, i);
  245. }
  246. b43legacy_radio_selectchannel(dev, channel, 0);
  247. b43legacy_phy_write(dev, 0x0802,
  248. (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
  249. | 0x0003);
  250. b43legacy_phy_write(dev, 0x0403,
  251. b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
  252. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  253. b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
  254. | 0x8000);
  255. b43legacy_set_original_gains(dev);
  256. for (i = 0; i < 13; i++) {
  257. if (!ret[i])
  258. continue;
  259. end = (i + 5 < 13) ? i + 5 : 13;
  260. for (j = i; j < end; j++)
  261. ret[j] = 1;
  262. }
  263. b43legacy_radio_unlock(dev);
  264. b43legacy_phy_unlock(dev);
  265. return ret[channel - 1];
  266. }
  267. /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
  268. void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
  269. {
  270. b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
  271. b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
  272. }
  273. /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
  274. s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
  275. {
  276. u16 val;
  277. b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
  278. val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
  279. return (s16)val;
  280. }
  281. /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
  282. void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
  283. {
  284. u16 i;
  285. s16 tmp;
  286. for (i = 0; i < 64; i++) {
  287. tmp = b43legacy_nrssi_hw_read(dev, i);
  288. tmp -= val;
  289. tmp = clamp_val(tmp, -32, 31);
  290. b43legacy_nrssi_hw_write(dev, i, tmp);
  291. }
  292. }
  293. /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
  294. void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
  295. {
  296. struct b43legacy_phy *phy = &dev->phy;
  297. s16 i;
  298. s16 delta;
  299. s32 tmp;
  300. delta = 0x1F - phy->nrssi[0];
  301. for (i = 0; i < 64; i++) {
  302. tmp = (i - delta) * phy->nrssislope;
  303. tmp /= 0x10000;
  304. tmp += 0x3A;
  305. tmp = clamp_val(tmp, 0, 0x3F);
  306. phy->nrssi_lt[i] = tmp;
  307. }
  308. }
  309. static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
  310. {
  311. struct b43legacy_phy *phy = &dev->phy;
  312. u16 backup[20] = { 0 };
  313. s16 v47F;
  314. u16 i;
  315. u16 saved = 0xFFFF;
  316. backup[0] = b43legacy_phy_read(dev, 0x0001);
  317. backup[1] = b43legacy_phy_read(dev, 0x0811);
  318. backup[2] = b43legacy_phy_read(dev, 0x0812);
  319. backup[3] = b43legacy_phy_read(dev, 0x0814);
  320. backup[4] = b43legacy_phy_read(dev, 0x0815);
  321. backup[5] = b43legacy_phy_read(dev, 0x005A);
  322. backup[6] = b43legacy_phy_read(dev, 0x0059);
  323. backup[7] = b43legacy_phy_read(dev, 0x0058);
  324. backup[8] = b43legacy_phy_read(dev, 0x000A);
  325. backup[9] = b43legacy_phy_read(dev, 0x0003);
  326. backup[10] = b43legacy_radio_read16(dev, 0x007A);
  327. backup[11] = b43legacy_radio_read16(dev, 0x0043);
  328. b43legacy_phy_write(dev, 0x0429,
  329. b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
  330. b43legacy_phy_write(dev, 0x0001,
  331. (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
  332. | 0x4000);
  333. b43legacy_phy_write(dev, 0x0811,
  334. b43legacy_phy_read(dev, 0x0811) | 0x000C);
  335. b43legacy_phy_write(dev, 0x0812,
  336. (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
  337. | 0x0004);
  338. b43legacy_phy_write(dev, 0x0802,
  339. b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
  340. if (phy->rev >= 6) {
  341. backup[12] = b43legacy_phy_read(dev, 0x002E);
  342. backup[13] = b43legacy_phy_read(dev, 0x002F);
  343. backup[14] = b43legacy_phy_read(dev, 0x080F);
  344. backup[15] = b43legacy_phy_read(dev, 0x0810);
  345. backup[16] = b43legacy_phy_read(dev, 0x0801);
  346. backup[17] = b43legacy_phy_read(dev, 0x0060);
  347. backup[18] = b43legacy_phy_read(dev, 0x0014);
  348. backup[19] = b43legacy_phy_read(dev, 0x0478);
  349. b43legacy_phy_write(dev, 0x002E, 0);
  350. b43legacy_phy_write(dev, 0x002F, 0);
  351. b43legacy_phy_write(dev, 0x080F, 0);
  352. b43legacy_phy_write(dev, 0x0810, 0);
  353. b43legacy_phy_write(dev, 0x0478,
  354. b43legacy_phy_read(dev, 0x0478) | 0x0100);
  355. b43legacy_phy_write(dev, 0x0801,
  356. b43legacy_phy_read(dev, 0x0801) | 0x0040);
  357. b43legacy_phy_write(dev, 0x0060,
  358. b43legacy_phy_read(dev, 0x0060) | 0x0040);
  359. b43legacy_phy_write(dev, 0x0014,
  360. b43legacy_phy_read(dev, 0x0014) | 0x0200);
  361. }
  362. b43legacy_radio_write16(dev, 0x007A,
  363. b43legacy_radio_read16(dev, 0x007A) | 0x0070);
  364. b43legacy_radio_write16(dev, 0x007A,
  365. b43legacy_radio_read16(dev, 0x007A) | 0x0080);
  366. udelay(30);
  367. v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
  368. if (v47F >= 0x20)
  369. v47F -= 0x40;
  370. if (v47F == 31) {
  371. for (i = 7; i >= 4; i--) {
  372. b43legacy_radio_write16(dev, 0x007B, i);
  373. udelay(20);
  374. v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
  375. & 0x003F);
  376. if (v47F >= 0x20)
  377. v47F -= 0x40;
  378. if (v47F < 31 && saved == 0xFFFF)
  379. saved = i;
  380. }
  381. if (saved == 0xFFFF)
  382. saved = 4;
  383. } else {
  384. b43legacy_radio_write16(dev, 0x007A,
  385. b43legacy_radio_read16(dev, 0x007A)
  386. & 0x007F);
  387. b43legacy_phy_write(dev, 0x0814,
  388. b43legacy_phy_read(dev, 0x0814) | 0x0001);
  389. b43legacy_phy_write(dev, 0x0815,
  390. b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
  391. b43legacy_phy_write(dev, 0x0811,
  392. b43legacy_phy_read(dev, 0x0811) | 0x000C);
  393. b43legacy_phy_write(dev, 0x0812,
  394. b43legacy_phy_read(dev, 0x0812) | 0x000C);
  395. b43legacy_phy_write(dev, 0x0811,
  396. b43legacy_phy_read(dev, 0x0811) | 0x0030);
  397. b43legacy_phy_write(dev, 0x0812,
  398. b43legacy_phy_read(dev, 0x0812) | 0x0030);
  399. b43legacy_phy_write(dev, 0x005A, 0x0480);
  400. b43legacy_phy_write(dev, 0x0059, 0x0810);
  401. b43legacy_phy_write(dev, 0x0058, 0x000D);
  402. if (phy->analog == 0)
  403. b43legacy_phy_write(dev, 0x0003, 0x0122);
  404. else
  405. b43legacy_phy_write(dev, 0x000A,
  406. b43legacy_phy_read(dev, 0x000A)
  407. | 0x2000);
  408. b43legacy_phy_write(dev, 0x0814,
  409. b43legacy_phy_read(dev, 0x0814) | 0x0004);
  410. b43legacy_phy_write(dev, 0x0815,
  411. b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
  412. b43legacy_phy_write(dev, 0x0003,
  413. (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
  414. | 0x0040);
  415. b43legacy_radio_write16(dev, 0x007A,
  416. b43legacy_radio_read16(dev, 0x007A)
  417. | 0x000F);
  418. b43legacy_set_all_gains(dev, 3, 0, 1);
  419. b43legacy_radio_write16(dev, 0x0043,
  420. (b43legacy_radio_read16(dev, 0x0043)
  421. & 0x00F0) | 0x000F);
  422. udelay(30);
  423. v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
  424. if (v47F >= 0x20)
  425. v47F -= 0x40;
  426. if (v47F == -32) {
  427. for (i = 0; i < 4; i++) {
  428. b43legacy_radio_write16(dev, 0x007B, i);
  429. udelay(20);
  430. v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
  431. 8) & 0x003F);
  432. if (v47F >= 0x20)
  433. v47F -= 0x40;
  434. if (v47F > -31 && saved == 0xFFFF)
  435. saved = i;
  436. }
  437. if (saved == 0xFFFF)
  438. saved = 3;
  439. } else
  440. saved = 0;
  441. }
  442. b43legacy_radio_write16(dev, 0x007B, saved);
  443. if (phy->rev >= 6) {
  444. b43legacy_phy_write(dev, 0x002E, backup[12]);
  445. b43legacy_phy_write(dev, 0x002F, backup[13]);
  446. b43legacy_phy_write(dev, 0x080F, backup[14]);
  447. b43legacy_phy_write(dev, 0x0810, backup[15]);
  448. }
  449. b43legacy_phy_write(dev, 0x0814, backup[3]);
  450. b43legacy_phy_write(dev, 0x0815, backup[4]);
  451. b43legacy_phy_write(dev, 0x005A, backup[5]);
  452. b43legacy_phy_write(dev, 0x0059, backup[6]);
  453. b43legacy_phy_write(dev, 0x0058, backup[7]);
  454. b43legacy_phy_write(dev, 0x000A, backup[8]);
  455. b43legacy_phy_write(dev, 0x0003, backup[9]);
  456. b43legacy_radio_write16(dev, 0x0043, backup[11]);
  457. b43legacy_radio_write16(dev, 0x007A, backup[10]);
  458. b43legacy_phy_write(dev, 0x0802,
  459. b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
  460. b43legacy_phy_write(dev, 0x0429,
  461. b43legacy_phy_read(dev, 0x0429) | 0x8000);
  462. b43legacy_set_original_gains(dev);
  463. if (phy->rev >= 6) {
  464. b43legacy_phy_write(dev, 0x0801, backup[16]);
  465. b43legacy_phy_write(dev, 0x0060, backup[17]);
  466. b43legacy_phy_write(dev, 0x0014, backup[18]);
  467. b43legacy_phy_write(dev, 0x0478, backup[19]);
  468. }
  469. b43legacy_phy_write(dev, 0x0001, backup[0]);
  470. b43legacy_phy_write(dev, 0x0812, backup[2]);
  471. b43legacy_phy_write(dev, 0x0811, backup[1]);
  472. }
  473. void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
  474. {
  475. struct b43legacy_phy *phy = &dev->phy;
  476. u16 backup[18] = { 0 };
  477. u16 tmp;
  478. s16 nrssi0;
  479. s16 nrssi1;
  480. switch (phy->type) {
  481. case B43legacy_PHYTYPE_B:
  482. backup[0] = b43legacy_radio_read16(dev, 0x007A);
  483. backup[1] = b43legacy_radio_read16(dev, 0x0052);
  484. backup[2] = b43legacy_radio_read16(dev, 0x0043);
  485. backup[3] = b43legacy_phy_read(dev, 0x0030);
  486. backup[4] = b43legacy_phy_read(dev, 0x0026);
  487. backup[5] = b43legacy_phy_read(dev, 0x0015);
  488. backup[6] = b43legacy_phy_read(dev, 0x002A);
  489. backup[7] = b43legacy_phy_read(dev, 0x0020);
  490. backup[8] = b43legacy_phy_read(dev, 0x005A);
  491. backup[9] = b43legacy_phy_read(dev, 0x0059);
  492. backup[10] = b43legacy_phy_read(dev, 0x0058);
  493. backup[11] = b43legacy_read16(dev, 0x03E2);
  494. backup[12] = b43legacy_read16(dev, 0x03E6);
  495. backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
  496. tmp = b43legacy_radio_read16(dev, 0x007A);
  497. tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
  498. b43legacy_radio_write16(dev, 0x007A, tmp);
  499. b43legacy_phy_write(dev, 0x0030, 0x00FF);
  500. b43legacy_write16(dev, 0x03EC, 0x7F7F);
  501. b43legacy_phy_write(dev, 0x0026, 0x0000);
  502. b43legacy_phy_write(dev, 0x0015,
  503. b43legacy_phy_read(dev, 0x0015) | 0x0020);
  504. b43legacy_phy_write(dev, 0x002A, 0x08A3);
  505. b43legacy_radio_write16(dev, 0x007A,
  506. b43legacy_radio_read16(dev, 0x007A)
  507. | 0x0080);
  508. nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
  509. b43legacy_radio_write16(dev, 0x007A,
  510. b43legacy_radio_read16(dev, 0x007A)
  511. & 0x007F);
  512. if (phy->analog >= 2)
  513. b43legacy_write16(dev, 0x03E6, 0x0040);
  514. else if (phy->analog == 0)
  515. b43legacy_write16(dev, 0x03E6, 0x0122);
  516. else
  517. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
  518. b43legacy_read16(dev,
  519. B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
  520. b43legacy_phy_write(dev, 0x0020, 0x3F3F);
  521. b43legacy_phy_write(dev, 0x0015, 0xF330);
  522. b43legacy_radio_write16(dev, 0x005A, 0x0060);
  523. b43legacy_radio_write16(dev, 0x0043,
  524. b43legacy_radio_read16(dev, 0x0043)
  525. & 0x00F0);
  526. b43legacy_phy_write(dev, 0x005A, 0x0480);
  527. b43legacy_phy_write(dev, 0x0059, 0x0810);
  528. b43legacy_phy_write(dev, 0x0058, 0x000D);
  529. udelay(20);
  530. nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
  531. b43legacy_phy_write(dev, 0x0030, backup[3]);
  532. b43legacy_radio_write16(dev, 0x007A, backup[0]);
  533. b43legacy_write16(dev, 0x03E2, backup[11]);
  534. b43legacy_phy_write(dev, 0x0026, backup[4]);
  535. b43legacy_phy_write(dev, 0x0015, backup[5]);
  536. b43legacy_phy_write(dev, 0x002A, backup[6]);
  537. b43legacy_synth_pu_workaround(dev, phy->channel);
  538. if (phy->analog != 0)
  539. b43legacy_write16(dev, 0x03F4, backup[13]);
  540. b43legacy_phy_write(dev, 0x0020, backup[7]);
  541. b43legacy_phy_write(dev, 0x005A, backup[8]);
  542. b43legacy_phy_write(dev, 0x0059, backup[9]);
  543. b43legacy_phy_write(dev, 0x0058, backup[10]);
  544. b43legacy_radio_write16(dev, 0x0052, backup[1]);
  545. b43legacy_radio_write16(dev, 0x0043, backup[2]);
  546. if (nrssi0 == nrssi1)
  547. phy->nrssislope = 0x00010000;
  548. else
  549. phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
  550. if (nrssi0 <= -4) {
  551. phy->nrssi[0] = nrssi0;
  552. phy->nrssi[1] = nrssi1;
  553. }
  554. break;
  555. case B43legacy_PHYTYPE_G:
  556. if (phy->radio_rev >= 9)
  557. return;
  558. if (phy->radio_rev == 8)
  559. b43legacy_calc_nrssi_offset(dev);
  560. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  561. b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
  562. & 0x7FFF);
  563. b43legacy_phy_write(dev, 0x0802,
  564. b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
  565. backup[7] = b43legacy_read16(dev, 0x03E2);
  566. b43legacy_write16(dev, 0x03E2,
  567. b43legacy_read16(dev, 0x03E2) | 0x8000);
  568. backup[0] = b43legacy_radio_read16(dev, 0x007A);
  569. backup[1] = b43legacy_radio_read16(dev, 0x0052);
  570. backup[2] = b43legacy_radio_read16(dev, 0x0043);
  571. backup[3] = b43legacy_phy_read(dev, 0x0015);
  572. backup[4] = b43legacy_phy_read(dev, 0x005A);
  573. backup[5] = b43legacy_phy_read(dev, 0x0059);
  574. backup[6] = b43legacy_phy_read(dev, 0x0058);
  575. backup[8] = b43legacy_read16(dev, 0x03E6);
  576. backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
  577. if (phy->rev >= 3) {
  578. backup[10] = b43legacy_phy_read(dev, 0x002E);
  579. backup[11] = b43legacy_phy_read(dev, 0x002F);
  580. backup[12] = b43legacy_phy_read(dev, 0x080F);
  581. backup[13] = b43legacy_phy_read(dev,
  582. B43legacy_PHY_G_LO_CONTROL);
  583. backup[14] = b43legacy_phy_read(dev, 0x0801);
  584. backup[15] = b43legacy_phy_read(dev, 0x0060);
  585. backup[16] = b43legacy_phy_read(dev, 0x0014);
  586. backup[17] = b43legacy_phy_read(dev, 0x0478);
  587. b43legacy_phy_write(dev, 0x002E, 0);
  588. b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
  589. switch (phy->rev) {
  590. case 4: case 6: case 7:
  591. b43legacy_phy_write(dev, 0x0478,
  592. b43legacy_phy_read(dev,
  593. 0x0478) | 0x0100);
  594. b43legacy_phy_write(dev, 0x0801,
  595. b43legacy_phy_read(dev,
  596. 0x0801) | 0x0040);
  597. break;
  598. case 3: case 5:
  599. b43legacy_phy_write(dev, 0x0801,
  600. b43legacy_phy_read(dev,
  601. 0x0801) & 0xFFBF);
  602. break;
  603. }
  604. b43legacy_phy_write(dev, 0x0060,
  605. b43legacy_phy_read(dev, 0x0060)
  606. | 0x0040);
  607. b43legacy_phy_write(dev, 0x0014,
  608. b43legacy_phy_read(dev, 0x0014)
  609. | 0x0200);
  610. }
  611. b43legacy_radio_write16(dev, 0x007A,
  612. b43legacy_radio_read16(dev, 0x007A)
  613. | 0x0070);
  614. b43legacy_set_all_gains(dev, 0, 8, 0);
  615. b43legacy_radio_write16(dev, 0x007A,
  616. b43legacy_radio_read16(dev, 0x007A)
  617. & 0x00F7);
  618. if (phy->rev >= 2) {
  619. b43legacy_phy_write(dev, 0x0811,
  620. (b43legacy_phy_read(dev, 0x0811)
  621. & 0xFFCF) | 0x0030);
  622. b43legacy_phy_write(dev, 0x0812,
  623. (b43legacy_phy_read(dev, 0x0812)
  624. & 0xFFCF) | 0x0010);
  625. }
  626. b43legacy_radio_write16(dev, 0x007A,
  627. b43legacy_radio_read16(dev, 0x007A)
  628. | 0x0080);
  629. udelay(20);
  630. nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
  631. if (nrssi0 >= 0x0020)
  632. nrssi0 -= 0x0040;
  633. b43legacy_radio_write16(dev, 0x007A,
  634. b43legacy_radio_read16(dev, 0x007A)
  635. & 0x007F);
  636. if (phy->analog >= 2)
  637. b43legacy_phy_write(dev, 0x0003,
  638. (b43legacy_phy_read(dev, 0x0003)
  639. & 0xFF9F) | 0x0040);
  640. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
  641. b43legacy_read16(dev,
  642. B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
  643. b43legacy_radio_write16(dev, 0x007A,
  644. b43legacy_radio_read16(dev, 0x007A)
  645. | 0x000F);
  646. b43legacy_phy_write(dev, 0x0015, 0xF330);
  647. if (phy->rev >= 2) {
  648. b43legacy_phy_write(dev, 0x0812,
  649. (b43legacy_phy_read(dev, 0x0812)
  650. & 0xFFCF) | 0x0020);
  651. b43legacy_phy_write(dev, 0x0811,
  652. (b43legacy_phy_read(dev, 0x0811)
  653. & 0xFFCF) | 0x0020);
  654. }
  655. b43legacy_set_all_gains(dev, 3, 0, 1);
  656. if (phy->radio_rev == 8)
  657. b43legacy_radio_write16(dev, 0x0043, 0x001F);
  658. else {
  659. tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
  660. b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
  661. tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
  662. b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
  663. }
  664. b43legacy_phy_write(dev, 0x005A, 0x0480);
  665. b43legacy_phy_write(dev, 0x0059, 0x0810);
  666. b43legacy_phy_write(dev, 0x0058, 0x000D);
  667. udelay(20);
  668. nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
  669. if (nrssi1 >= 0x0020)
  670. nrssi1 -= 0x0040;
  671. if (nrssi0 == nrssi1)
  672. phy->nrssislope = 0x00010000;
  673. else
  674. phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
  675. if (nrssi0 >= -4) {
  676. phy->nrssi[0] = nrssi1;
  677. phy->nrssi[1] = nrssi0;
  678. }
  679. if (phy->rev >= 3) {
  680. b43legacy_phy_write(dev, 0x002E, backup[10]);
  681. b43legacy_phy_write(dev, 0x002F, backup[11]);
  682. b43legacy_phy_write(dev, 0x080F, backup[12]);
  683. b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
  684. backup[13]);
  685. }
  686. if (phy->rev >= 2) {
  687. b43legacy_phy_write(dev, 0x0812,
  688. b43legacy_phy_read(dev, 0x0812)
  689. & 0xFFCF);
  690. b43legacy_phy_write(dev, 0x0811,
  691. b43legacy_phy_read(dev, 0x0811)
  692. & 0xFFCF);
  693. }
  694. b43legacy_radio_write16(dev, 0x007A, backup[0]);
  695. b43legacy_radio_write16(dev, 0x0052, backup[1]);
  696. b43legacy_radio_write16(dev, 0x0043, backup[2]);
  697. b43legacy_write16(dev, 0x03E2, backup[7]);
  698. b43legacy_write16(dev, 0x03E6, backup[8]);
  699. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
  700. b43legacy_phy_write(dev, 0x0015, backup[3]);
  701. b43legacy_phy_write(dev, 0x005A, backup[4]);
  702. b43legacy_phy_write(dev, 0x0059, backup[5]);
  703. b43legacy_phy_write(dev, 0x0058, backup[6]);
  704. b43legacy_synth_pu_workaround(dev, phy->channel);
  705. b43legacy_phy_write(dev, 0x0802,
  706. b43legacy_phy_read(dev, 0x0802) | 0x0003);
  707. b43legacy_set_original_gains(dev);
  708. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  709. b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
  710. | 0x8000);
  711. if (phy->rev >= 3) {
  712. b43legacy_phy_write(dev, 0x0801, backup[14]);
  713. b43legacy_phy_write(dev, 0x0060, backup[15]);
  714. b43legacy_phy_write(dev, 0x0014, backup[16]);
  715. b43legacy_phy_write(dev, 0x0478, backup[17]);
  716. }
  717. b43legacy_nrssi_mem_update(dev);
  718. b43legacy_calc_nrssi_threshold(dev);
  719. break;
  720. default:
  721. B43legacy_BUG_ON(1);
  722. }
  723. }
  724. void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
  725. {
  726. struct b43legacy_phy *phy = &dev->phy;
  727. s32 threshold;
  728. s32 a;
  729. s32 b;
  730. s16 tmp16;
  731. u16 tmp_u16;
  732. switch (phy->type) {
  733. case B43legacy_PHYTYPE_B: {
  734. if (phy->radio_ver != 0x2050)
  735. return;
  736. if (!(dev->dev->bus->sprom.boardflags_lo &
  737. B43legacy_BFL_RSSI))
  738. return;
  739. if (phy->radio_rev >= 6) {
  740. threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
  741. threshold += 20 * (phy->nrssi[0] + 1);
  742. threshold /= 40;
  743. } else
  744. threshold = phy->nrssi[1] - 5;
  745. threshold = clamp_val(threshold, 0, 0x3E);
  746. b43legacy_phy_read(dev, 0x0020); /* dummy read */
  747. b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
  748. | 0x001C);
  749. if (phy->radio_rev >= 6) {
  750. b43legacy_phy_write(dev, 0x0087, 0x0E0D);
  751. b43legacy_phy_write(dev, 0x0086, 0x0C0B);
  752. b43legacy_phy_write(dev, 0x0085, 0x0A09);
  753. b43legacy_phy_write(dev, 0x0084, 0x0808);
  754. b43legacy_phy_write(dev, 0x0083, 0x0808);
  755. b43legacy_phy_write(dev, 0x0082, 0x0604);
  756. b43legacy_phy_write(dev, 0x0081, 0x0302);
  757. b43legacy_phy_write(dev, 0x0080, 0x0100);
  758. }
  759. break;
  760. }
  761. case B43legacy_PHYTYPE_G:
  762. if (!phy->gmode ||
  763. !(dev->dev->bus->sprom.boardflags_lo &
  764. B43legacy_BFL_RSSI)) {
  765. tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
  766. if (tmp16 >= 0x20)
  767. tmp16 -= 0x40;
  768. if (tmp16 < 3)
  769. b43legacy_phy_write(dev, 0x048A,
  770. (b43legacy_phy_read(dev,
  771. 0x048A) & 0xF000) | 0x09EB);
  772. else
  773. b43legacy_phy_write(dev, 0x048A,
  774. (b43legacy_phy_read(dev,
  775. 0x048A) & 0xF000) | 0x0AED);
  776. } else {
  777. if (phy->interfmode ==
  778. B43legacy_RADIO_INTERFMODE_NONWLAN) {
  779. a = 0xE;
  780. b = 0xA;
  781. } else if (!phy->aci_wlan_automatic &&
  782. phy->aci_enable) {
  783. a = 0x13;
  784. b = 0x12;
  785. } else {
  786. a = 0xE;
  787. b = 0x11;
  788. }
  789. a = a * (phy->nrssi[1] - phy->nrssi[0]);
  790. a += (phy->nrssi[0] << 6);
  791. if (a < 32)
  792. a += 31;
  793. else
  794. a += 32;
  795. a = a >> 6;
  796. a = clamp_val(a, -31, 31);
  797. b = b * (phy->nrssi[1] - phy->nrssi[0]);
  798. b += (phy->nrssi[0] << 6);
  799. if (b < 32)
  800. b += 31;
  801. else
  802. b += 32;
  803. b = b >> 6;
  804. b = clamp_val(b, -31, 31);
  805. tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
  806. tmp_u16 |= ((u32)b & 0x0000003F);
  807. tmp_u16 |= (((u32)a & 0x0000003F) << 6);
  808. b43legacy_phy_write(dev, 0x048A, tmp_u16);
  809. }
  810. break;
  811. default:
  812. B43legacy_BUG_ON(1);
  813. }
  814. }
  815. /* Stack implementation to save/restore values from the
  816. * interference mitigation code.
  817. * It is save to restore values in random order.
  818. */
  819. static void _stack_save(u32 *_stackptr, size_t *stackidx,
  820. u8 id, u16 offset, u16 value)
  821. {
  822. u32 *stackptr = &(_stackptr[*stackidx]);
  823. B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
  824. B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
  825. *stackptr = offset;
  826. *stackptr |= ((u32)id) << 13;
  827. *stackptr |= ((u32)value) << 16;
  828. (*stackidx)++;
  829. B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
  830. }
  831. static u16 _stack_restore(u32 *stackptr,
  832. u8 id, u16 offset)
  833. {
  834. size_t i;
  835. B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
  836. B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
  837. for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
  838. if ((*stackptr & 0x00001FFF) != offset)
  839. continue;
  840. if (((*stackptr & 0x00007000) >> 13) != id)
  841. continue;
  842. return ((*stackptr & 0xFFFF0000) >> 16);
  843. }
  844. B43legacy_BUG_ON(1);
  845. return 0;
  846. }
  847. #define phy_stacksave(offset) \
  848. do { \
  849. _stack_save(stack, &stackidx, 0x1, (offset), \
  850. b43legacy_phy_read(dev, (offset))); \
  851. } while (0)
  852. #define phy_stackrestore(offset) \
  853. do { \
  854. b43legacy_phy_write(dev, (offset), \
  855. _stack_restore(stack, 0x1, \
  856. (offset))); \
  857. } while (0)
  858. #define radio_stacksave(offset) \
  859. do { \
  860. _stack_save(stack, &stackidx, 0x2, (offset), \
  861. b43legacy_radio_read16(dev, (offset))); \
  862. } while (0)
  863. #define radio_stackrestore(offset) \
  864. do { \
  865. b43legacy_radio_write16(dev, (offset), \
  866. _stack_restore(stack, 0x2, \
  867. (offset))); \
  868. } while (0)
  869. #define ilt_stacksave(offset) \
  870. do { \
  871. _stack_save(stack, &stackidx, 0x3, (offset), \
  872. b43legacy_ilt_read(dev, (offset))); \
  873. } while (0)
  874. #define ilt_stackrestore(offset) \
  875. do { \
  876. b43legacy_ilt_write(dev, (offset), \
  877. _stack_restore(stack, 0x3, \
  878. (offset))); \
  879. } while (0)
  880. static void
  881. b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
  882. int mode)
  883. {
  884. struct b43legacy_phy *phy = &dev->phy;
  885. u16 tmp;
  886. u16 flipped;
  887. u32 tmp32;
  888. size_t stackidx = 0;
  889. u32 *stack = phy->interfstack;
  890. switch (mode) {
  891. case B43legacy_RADIO_INTERFMODE_NONWLAN:
  892. if (phy->rev != 1) {
  893. b43legacy_phy_write(dev, 0x042B,
  894. b43legacy_phy_read(dev, 0x042B)
  895. | 0x0800);
  896. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  897. b43legacy_phy_read(dev,
  898. B43legacy_PHY_G_CRS) & ~0x4000);
  899. break;
  900. }
  901. radio_stacksave(0x0078);
  902. tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
  903. flipped = flip_4bit(tmp);
  904. if (flipped < 10 && flipped >= 8)
  905. flipped = 7;
  906. else if (flipped >= 10)
  907. flipped -= 3;
  908. flipped = flip_4bit(flipped);
  909. flipped = (flipped << 1) | 0x0020;
  910. b43legacy_radio_write16(dev, 0x0078, flipped);
  911. b43legacy_calc_nrssi_threshold(dev);
  912. phy_stacksave(0x0406);
  913. b43legacy_phy_write(dev, 0x0406, 0x7E28);
  914. b43legacy_phy_write(dev, 0x042B,
  915. b43legacy_phy_read(dev, 0x042B) | 0x0800);
  916. b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
  917. b43legacy_phy_read(dev,
  918. B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
  919. phy_stacksave(0x04A0);
  920. b43legacy_phy_write(dev, 0x04A0,
  921. (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
  922. | 0x0008);
  923. phy_stacksave(0x04A1);
  924. b43legacy_phy_write(dev, 0x04A1,
  925. (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
  926. | 0x0605);
  927. phy_stacksave(0x04A2);
  928. b43legacy_phy_write(dev, 0x04A2,
  929. (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
  930. | 0x0204);
  931. phy_stacksave(0x04A8);
  932. b43legacy_phy_write(dev, 0x04A8,
  933. (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
  934. | 0x0803);
  935. phy_stacksave(0x04AB);
  936. b43legacy_phy_write(dev, 0x04AB,
  937. (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
  938. | 0x0605);
  939. phy_stacksave(0x04A7);
  940. b43legacy_phy_write(dev, 0x04A7, 0x0002);
  941. phy_stacksave(0x04A3);
  942. b43legacy_phy_write(dev, 0x04A3, 0x287A);
  943. phy_stacksave(0x04A9);
  944. b43legacy_phy_write(dev, 0x04A9, 0x2027);
  945. phy_stacksave(0x0493);
  946. b43legacy_phy_write(dev, 0x0493, 0x32F5);
  947. phy_stacksave(0x04AA);
  948. b43legacy_phy_write(dev, 0x04AA, 0x2027);
  949. phy_stacksave(0x04AC);
  950. b43legacy_phy_write(dev, 0x04AC, 0x32F5);
  951. break;
  952. case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
  953. if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
  954. break;
  955. phy->aci_enable = true;
  956. phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
  957. phy_stacksave(B43legacy_PHY_G_CRS);
  958. if (phy->rev < 2)
  959. phy_stacksave(0x0406);
  960. else {
  961. phy_stacksave(0x04C0);
  962. phy_stacksave(0x04C1);
  963. }
  964. phy_stacksave(0x0033);
  965. phy_stacksave(0x04A7);
  966. phy_stacksave(0x04A3);
  967. phy_stacksave(0x04A9);
  968. phy_stacksave(0x04AA);
  969. phy_stacksave(0x04AC);
  970. phy_stacksave(0x0493);
  971. phy_stacksave(0x04A1);
  972. phy_stacksave(0x04A0);
  973. phy_stacksave(0x04A2);
  974. phy_stacksave(0x048A);
  975. phy_stacksave(0x04A8);
  976. phy_stacksave(0x04AB);
  977. if (phy->rev == 2) {
  978. phy_stacksave(0x04AD);
  979. phy_stacksave(0x04AE);
  980. } else if (phy->rev >= 3) {
  981. phy_stacksave(0x04AD);
  982. phy_stacksave(0x0415);
  983. phy_stacksave(0x0416);
  984. phy_stacksave(0x0417);
  985. ilt_stacksave(0x1A00 + 0x2);
  986. ilt_stacksave(0x1A00 + 0x3);
  987. }
  988. phy_stacksave(0x042B);
  989. phy_stacksave(0x048C);
  990. b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
  991. b43legacy_phy_read(dev,
  992. B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
  993. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  994. (b43legacy_phy_read(dev,
  995. B43legacy_PHY_G_CRS)
  996. & 0xFFFC) | 0x0002);
  997. b43legacy_phy_write(dev, 0x0033, 0x0800);
  998. b43legacy_phy_write(dev, 0x04A3, 0x2027);
  999. b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
  1000. b43legacy_phy_write(dev, 0x0493, 0x287A);
  1001. b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
  1002. b43legacy_phy_write(dev, 0x04AC, 0x287A);
  1003. b43legacy_phy_write(dev, 0x04A0,
  1004. (b43legacy_phy_read(dev, 0x04A0)
  1005. & 0xFFC0) | 0x001A);
  1006. b43legacy_phy_write(dev, 0x04A7, 0x000D);
  1007. if (phy->rev < 2)
  1008. b43legacy_phy_write(dev, 0x0406, 0xFF0D);
  1009. else if (phy->rev == 2) {
  1010. b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
  1011. b43legacy_phy_write(dev, 0x04C1, 0x00A9);
  1012. } else {
  1013. b43legacy_phy_write(dev, 0x04C0, 0x00C1);
  1014. b43legacy_phy_write(dev, 0x04C1, 0x0059);
  1015. }
  1016. b43legacy_phy_write(dev, 0x04A1,
  1017. (b43legacy_phy_read(dev, 0x04A1)
  1018. & 0xC0FF) | 0x1800);
  1019. b43legacy_phy_write(dev, 0x04A1,
  1020. (b43legacy_phy_read(dev, 0x04A1)
  1021. & 0xFFC0) | 0x0015);
  1022. b43legacy_phy_write(dev, 0x04A8,
  1023. (b43legacy_phy_read(dev, 0x04A8)
  1024. & 0xCFFF) | 0x1000);
  1025. b43legacy_phy_write(dev, 0x04A8,
  1026. (b43legacy_phy_read(dev, 0x04A8)
  1027. & 0xF0FF) | 0x0A00);
  1028. b43legacy_phy_write(dev, 0x04AB,
  1029. (b43legacy_phy_read(dev, 0x04AB)
  1030. & 0xCFFF) | 0x1000);
  1031. b43legacy_phy_write(dev, 0x04AB,
  1032. (b43legacy_phy_read(dev, 0x04AB)
  1033. & 0xF0FF) | 0x0800);
  1034. b43legacy_phy_write(dev, 0x04AB,
  1035. (b43legacy_phy_read(dev, 0x04AB)
  1036. & 0xFFCF) | 0x0010);
  1037. b43legacy_phy_write(dev, 0x04AB,
  1038. (b43legacy_phy_read(dev, 0x04AB)
  1039. & 0xFFF0) | 0x0005);
  1040. b43legacy_phy_write(dev, 0x04A8,
  1041. (b43legacy_phy_read(dev, 0x04A8)
  1042. & 0xFFCF) | 0x0010);
  1043. b43legacy_phy_write(dev, 0x04A8,
  1044. (b43legacy_phy_read(dev, 0x04A8)
  1045. & 0xFFF0) | 0x0006);
  1046. b43legacy_phy_write(dev, 0x04A2,
  1047. (b43legacy_phy_read(dev, 0x04A2)
  1048. & 0xF0FF) | 0x0800);
  1049. b43legacy_phy_write(dev, 0x04A0,
  1050. (b43legacy_phy_read(dev, 0x04A0)
  1051. & 0xF0FF) | 0x0500);
  1052. b43legacy_phy_write(dev, 0x04A2,
  1053. (b43legacy_phy_read(dev, 0x04A2)
  1054. & 0xFFF0) | 0x000B);
  1055. if (phy->rev >= 3) {
  1056. b43legacy_phy_write(dev, 0x048A,
  1057. b43legacy_phy_read(dev, 0x048A)
  1058. & ~0x8000);
  1059. b43legacy_phy_write(dev, 0x0415,
  1060. (b43legacy_phy_read(dev, 0x0415)
  1061. & 0x8000) | 0x36D8);
  1062. b43legacy_phy_write(dev, 0x0416,
  1063. (b43legacy_phy_read(dev, 0x0416)
  1064. & 0x8000) | 0x36D8);
  1065. b43legacy_phy_write(dev, 0x0417,
  1066. (b43legacy_phy_read(dev, 0x0417)
  1067. & 0xFE00) | 0x016D);
  1068. } else {
  1069. b43legacy_phy_write(dev, 0x048A,
  1070. b43legacy_phy_read(dev, 0x048A)
  1071. | 0x1000);
  1072. b43legacy_phy_write(dev, 0x048A,
  1073. (b43legacy_phy_read(dev, 0x048A)
  1074. & 0x9FFF) | 0x2000);
  1075. tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
  1076. B43legacy_UCODEFLAGS_OFFSET);
  1077. if (!(tmp32 & 0x800)) {
  1078. tmp32 |= 0x800;
  1079. b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
  1080. B43legacy_UCODEFLAGS_OFFSET,
  1081. tmp32);
  1082. }
  1083. }
  1084. if (phy->rev >= 2)
  1085. b43legacy_phy_write(dev, 0x042B,
  1086. b43legacy_phy_read(dev, 0x042B)
  1087. | 0x0800);
  1088. b43legacy_phy_write(dev, 0x048C,
  1089. (b43legacy_phy_read(dev, 0x048C)
  1090. & 0xF0FF) | 0x0200);
  1091. if (phy->rev == 2) {
  1092. b43legacy_phy_write(dev, 0x04AE,
  1093. (b43legacy_phy_read(dev, 0x04AE)
  1094. & 0xFF00) | 0x007F);
  1095. b43legacy_phy_write(dev, 0x04AD,
  1096. (b43legacy_phy_read(dev, 0x04AD)
  1097. & 0x00FF) | 0x1300);
  1098. } else if (phy->rev >= 6) {
  1099. b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
  1100. b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
  1101. b43legacy_phy_write(dev, 0x04AD,
  1102. b43legacy_phy_read(dev, 0x04AD)
  1103. & 0x00FF);
  1104. }
  1105. b43legacy_calc_nrssi_slope(dev);
  1106. break;
  1107. default:
  1108. B43legacy_BUG_ON(1);
  1109. }
  1110. }
  1111. static void
  1112. b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
  1113. int mode)
  1114. {
  1115. struct b43legacy_phy *phy = &dev->phy;
  1116. u32 tmp32;
  1117. u32 *stack = phy->interfstack;
  1118. switch (mode) {
  1119. case B43legacy_RADIO_INTERFMODE_NONWLAN:
  1120. if (phy->rev != 1) {
  1121. b43legacy_phy_write(dev, 0x042B,
  1122. b43legacy_phy_read(dev, 0x042B)
  1123. & ~0x0800);
  1124. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  1125. b43legacy_phy_read(dev,
  1126. B43legacy_PHY_G_CRS) | 0x4000);
  1127. break;
  1128. }
  1129. phy_stackrestore(0x0078);
  1130. b43legacy_calc_nrssi_threshold(dev);
  1131. phy_stackrestore(0x0406);
  1132. b43legacy_phy_write(dev, 0x042B,
  1133. b43legacy_phy_read(dev, 0x042B) & ~0x0800);
  1134. if (!dev->bad_frames_preempt)
  1135. b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
  1136. b43legacy_phy_read(dev,
  1137. B43legacy_PHY_RADIO_BITFIELD)
  1138. & ~(1 << 11));
  1139. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  1140. b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
  1141. | 0x4000);
  1142. phy_stackrestore(0x04A0);
  1143. phy_stackrestore(0x04A1);
  1144. phy_stackrestore(0x04A2);
  1145. phy_stackrestore(0x04A8);
  1146. phy_stackrestore(0x04AB);
  1147. phy_stackrestore(0x04A7);
  1148. phy_stackrestore(0x04A3);
  1149. phy_stackrestore(0x04A9);
  1150. phy_stackrestore(0x0493);
  1151. phy_stackrestore(0x04AA);
  1152. phy_stackrestore(0x04AC);
  1153. break;
  1154. case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
  1155. if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
  1156. break;
  1157. phy->aci_enable = false;
  1158. phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
  1159. phy_stackrestore(B43legacy_PHY_G_CRS);
  1160. phy_stackrestore(0x0033);
  1161. phy_stackrestore(0x04A3);
  1162. phy_stackrestore(0x04A9);
  1163. phy_stackrestore(0x0493);
  1164. phy_stackrestore(0x04AA);
  1165. phy_stackrestore(0x04AC);
  1166. phy_stackrestore(0x04A0);
  1167. phy_stackrestore(0x04A7);
  1168. if (phy->rev >= 2) {
  1169. phy_stackrestore(0x04C0);
  1170. phy_stackrestore(0x04C1);
  1171. } else
  1172. phy_stackrestore(0x0406);
  1173. phy_stackrestore(0x04A1);
  1174. phy_stackrestore(0x04AB);
  1175. phy_stackrestore(0x04A8);
  1176. if (phy->rev == 2) {
  1177. phy_stackrestore(0x04AD);
  1178. phy_stackrestore(0x04AE);
  1179. } else if (phy->rev >= 3) {
  1180. phy_stackrestore(0x04AD);
  1181. phy_stackrestore(0x0415);
  1182. phy_stackrestore(0x0416);
  1183. phy_stackrestore(0x0417);
  1184. ilt_stackrestore(0x1A00 + 0x2);
  1185. ilt_stackrestore(0x1A00 + 0x3);
  1186. }
  1187. phy_stackrestore(0x04A2);
  1188. phy_stackrestore(0x04A8);
  1189. phy_stackrestore(0x042B);
  1190. phy_stackrestore(0x048C);
  1191. tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
  1192. B43legacy_UCODEFLAGS_OFFSET);
  1193. if (tmp32 & 0x800) {
  1194. tmp32 &= ~0x800;
  1195. b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
  1196. B43legacy_UCODEFLAGS_OFFSET,
  1197. tmp32);
  1198. }
  1199. b43legacy_calc_nrssi_slope(dev);
  1200. break;
  1201. default:
  1202. B43legacy_BUG_ON(1);
  1203. }
  1204. }
  1205. #undef phy_stacksave
  1206. #undef phy_stackrestore
  1207. #undef radio_stacksave
  1208. #undef radio_stackrestore
  1209. #undef ilt_stacksave
  1210. #undef ilt_stackrestore
  1211. int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
  1212. int mode)
  1213. {
  1214. struct b43legacy_phy *phy = &dev->phy;
  1215. int currentmode;
  1216. if ((phy->type != B43legacy_PHYTYPE_G) ||
  1217. (phy->rev == 0) || (!phy->gmode))
  1218. return -ENODEV;
  1219. phy->aci_wlan_automatic = false;
  1220. switch (mode) {
  1221. case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
  1222. phy->aci_wlan_automatic = true;
  1223. if (phy->aci_enable)
  1224. mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
  1225. else
  1226. mode = B43legacy_RADIO_INTERFMODE_NONE;
  1227. break;
  1228. case B43legacy_RADIO_INTERFMODE_NONE:
  1229. case B43legacy_RADIO_INTERFMODE_NONWLAN:
  1230. case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
  1231. break;
  1232. default:
  1233. return -EINVAL;
  1234. }
  1235. currentmode = phy->interfmode;
  1236. if (currentmode == mode)
  1237. return 0;
  1238. if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
  1239. b43legacy_radio_interference_mitigation_disable(dev,
  1240. currentmode);
  1241. if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
  1242. phy->aci_enable = false;
  1243. phy->aci_hw_rssi = false;
  1244. } else
  1245. b43legacy_radio_interference_mitigation_enable(dev, mode);
  1246. phy->interfmode = mode;
  1247. return 0;
  1248. }
  1249. u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
  1250. {
  1251. u16 reg;
  1252. u16 index;
  1253. u16 ret;
  1254. reg = b43legacy_radio_read16(dev, 0x0060);
  1255. index = (reg & 0x001E) >> 1;
  1256. ret = rcc_table[index] << 1;
  1257. ret |= (reg & 0x0001);
  1258. ret |= 0x0020;
  1259. return ret;
  1260. }
  1261. #define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
  1262. static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
  1263. {
  1264. struct b43legacy_phy *phy = &dev->phy;
  1265. u16 loop_or = 0;
  1266. u16 adj_loopback_gain = phy->loopback_gain[0];
  1267. u8 loop;
  1268. u16 extern_lna_control;
  1269. if (!phy->gmode)
  1270. return 0;
  1271. if (!has_loopback_gain(phy)) {
  1272. if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo
  1273. & B43legacy_BFL_EXTLNA)) {
  1274. switch (lpd) {
  1275. case LPD(0, 1, 1):
  1276. return 0x0FB2;
  1277. case LPD(0, 0, 1):
  1278. return 0x00B2;
  1279. case LPD(1, 0, 1):
  1280. return 0x30B2;
  1281. case LPD(1, 0, 0):
  1282. return 0x30B3;
  1283. default:
  1284. B43legacy_BUG_ON(1);
  1285. }
  1286. } else {
  1287. switch (lpd) {
  1288. case LPD(0, 1, 1):
  1289. return 0x8FB2;
  1290. case LPD(0, 0, 1):
  1291. return 0x80B2;
  1292. case LPD(1, 0, 1):
  1293. return 0x20B2;
  1294. case LPD(1, 0, 0):
  1295. return 0x20B3;
  1296. default:
  1297. B43legacy_BUG_ON(1);
  1298. }
  1299. }
  1300. } else {
  1301. if (phy->radio_rev == 8)
  1302. adj_loopback_gain += 0x003E;
  1303. else
  1304. adj_loopback_gain += 0x0026;
  1305. if (adj_loopback_gain >= 0x46) {
  1306. adj_loopback_gain -= 0x46;
  1307. extern_lna_control = 0x3000;
  1308. } else if (adj_loopback_gain >= 0x3A) {
  1309. adj_loopback_gain -= 0x3A;
  1310. extern_lna_control = 0x2000;
  1311. } else if (adj_loopback_gain >= 0x2E) {
  1312. adj_loopback_gain -= 0x2E;
  1313. extern_lna_control = 0x1000;
  1314. } else {
  1315. adj_loopback_gain -= 0x10;
  1316. extern_lna_control = 0x0000;
  1317. }
  1318. for (loop = 0; loop < 16; loop++) {
  1319. u16 tmp = adj_loopback_gain - 6 * loop;
  1320. if (tmp < 6)
  1321. break;
  1322. }
  1323. loop_or = (loop << 8) | extern_lna_control;
  1324. if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo
  1325. & B43legacy_BFL_EXTLNA) {
  1326. if (extern_lna_control)
  1327. loop_or |= 0x8000;
  1328. switch (lpd) {
  1329. case LPD(0, 1, 1):
  1330. return 0x8F92;
  1331. case LPD(0, 0, 1):
  1332. return (0x8092 | loop_or);
  1333. case LPD(1, 0, 1):
  1334. return (0x2092 | loop_or);
  1335. case LPD(1, 0, 0):
  1336. return (0x2093 | loop_or);
  1337. default:
  1338. B43legacy_BUG_ON(1);
  1339. }
  1340. } else {
  1341. switch (lpd) {
  1342. case LPD(0, 1, 1):
  1343. return 0x0F92;
  1344. case LPD(0, 0, 1):
  1345. case LPD(1, 0, 1):
  1346. return (0x0092 | loop_or);
  1347. case LPD(1, 0, 0):
  1348. return (0x0093 | loop_or);
  1349. default:
  1350. B43legacy_BUG_ON(1);
  1351. }
  1352. }
  1353. }
  1354. return 0;
  1355. }
  1356. u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
  1357. {
  1358. struct b43legacy_phy *phy = &dev->phy;
  1359. u16 backup[21] = { 0 };
  1360. u16 ret;
  1361. u16 i;
  1362. u16 j;
  1363. u32 tmp1 = 0;
  1364. u32 tmp2 = 0;
  1365. backup[0] = b43legacy_radio_read16(dev, 0x0043);
  1366. backup[14] = b43legacy_radio_read16(dev, 0x0051);
  1367. backup[15] = b43legacy_radio_read16(dev, 0x0052);
  1368. backup[1] = b43legacy_phy_read(dev, 0x0015);
  1369. backup[16] = b43legacy_phy_read(dev, 0x005A);
  1370. backup[17] = b43legacy_phy_read(dev, 0x0059);
  1371. backup[18] = b43legacy_phy_read(dev, 0x0058);
  1372. if (phy->type == B43legacy_PHYTYPE_B) {
  1373. backup[2] = b43legacy_phy_read(dev, 0x0030);
  1374. backup[3] = b43legacy_read16(dev, 0x03EC);
  1375. b43legacy_phy_write(dev, 0x0030, 0x00FF);
  1376. b43legacy_write16(dev, 0x03EC, 0x3F3F);
  1377. } else {
  1378. if (phy->gmode) {
  1379. backup[4] = b43legacy_phy_read(dev, 0x0811);
  1380. backup[5] = b43legacy_phy_read(dev, 0x0812);
  1381. backup[6] = b43legacy_phy_read(dev, 0x0814);
  1382. backup[7] = b43legacy_phy_read(dev, 0x0815);
  1383. backup[8] = b43legacy_phy_read(dev,
  1384. B43legacy_PHY_G_CRS);
  1385. backup[9] = b43legacy_phy_read(dev, 0x0802);
  1386. b43legacy_phy_write(dev, 0x0814,
  1387. (b43legacy_phy_read(dev, 0x0814)
  1388. | 0x0003));
  1389. b43legacy_phy_write(dev, 0x0815,
  1390. (b43legacy_phy_read(dev, 0x0815)
  1391. & 0xFFFC));
  1392. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  1393. (b43legacy_phy_read(dev,
  1394. B43legacy_PHY_G_CRS) & 0x7FFF));
  1395. b43legacy_phy_write(dev, 0x0802,
  1396. (b43legacy_phy_read(dev, 0x0802)
  1397. & 0xFFFC));
  1398. if (phy->rev > 1) { /* loopback gain enabled */
  1399. backup[19] = b43legacy_phy_read(dev, 0x080F);
  1400. backup[20] = b43legacy_phy_read(dev, 0x0810);
  1401. if (phy->rev >= 3)
  1402. b43legacy_phy_write(dev, 0x080F,
  1403. 0xC020);
  1404. else
  1405. b43legacy_phy_write(dev, 0x080F,
  1406. 0x8020);
  1407. b43legacy_phy_write(dev, 0x0810, 0x0000);
  1408. }
  1409. b43legacy_phy_write(dev, 0x0812,
  1410. b43legacy_get_812_value(dev,
  1411. LPD(0, 1, 1)));
  1412. if (phy->rev < 7 ||
  1413. !(dev->dev->bus->sprom.boardflags_lo
  1414. & B43legacy_BFL_EXTLNA))
  1415. b43legacy_phy_write(dev, 0x0811, 0x01B3);
  1416. else
  1417. b43legacy_phy_write(dev, 0x0811, 0x09B3);
  1418. }
  1419. }
  1420. b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
  1421. (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
  1422. | 0x8000));
  1423. backup[10] = b43legacy_phy_read(dev, 0x0035);
  1424. b43legacy_phy_write(dev, 0x0035,
  1425. (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
  1426. backup[11] = b43legacy_read16(dev, 0x03E6);
  1427. backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
  1428. /* Initialization */
  1429. if (phy->analog == 0)
  1430. b43legacy_write16(dev, 0x03E6, 0x0122);
  1431. else {
  1432. if (phy->analog >= 2)
  1433. b43legacy_phy_write(dev, 0x0003,
  1434. (b43legacy_phy_read(dev, 0x0003)
  1435. & 0xFFBF) | 0x0040);
  1436. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
  1437. (b43legacy_read16(dev,
  1438. B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
  1439. }
  1440. ret = b43legacy_radio_calibrationvalue(dev);
  1441. if (phy->type == B43legacy_PHYTYPE_B)
  1442. b43legacy_radio_write16(dev, 0x0078, 0x0026);
  1443. if (phy->gmode)
  1444. b43legacy_phy_write(dev, 0x0812,
  1445. b43legacy_get_812_value(dev,
  1446. LPD(0, 1, 1)));
  1447. b43legacy_phy_write(dev, 0x0015, 0xBFAF);
  1448. b43legacy_phy_write(dev, 0x002B, 0x1403);
  1449. if (phy->gmode)
  1450. b43legacy_phy_write(dev, 0x0812,
  1451. b43legacy_get_812_value(dev,
  1452. LPD(0, 0, 1)));
  1453. b43legacy_phy_write(dev, 0x0015, 0xBFA0);
  1454. b43legacy_radio_write16(dev, 0x0051,
  1455. (b43legacy_radio_read16(dev, 0x0051)
  1456. | 0x0004));
  1457. if (phy->radio_rev == 8)
  1458. b43legacy_radio_write16(dev, 0x0043, 0x001F);
  1459. else {
  1460. b43legacy_radio_write16(dev, 0x0052, 0x0000);
  1461. b43legacy_radio_write16(dev, 0x0043,
  1462. (b43legacy_radio_read16(dev, 0x0043)
  1463. & 0xFFF0) | 0x0009);
  1464. }
  1465. b43legacy_phy_write(dev, 0x0058, 0x0000);
  1466. for (i = 0; i < 16; i++) {
  1467. b43legacy_phy_write(dev, 0x005A, 0x0480);
  1468. b43legacy_phy_write(dev, 0x0059, 0xC810);
  1469. b43legacy_phy_write(dev, 0x0058, 0x000D);
  1470. if (phy->gmode)
  1471. b43legacy_phy_write(dev, 0x0812,
  1472. b43legacy_get_812_value(dev,
  1473. LPD(1, 0, 1)));
  1474. b43legacy_phy_write(dev, 0x0015, 0xAFB0);
  1475. udelay(10);
  1476. if (phy->gmode)
  1477. b43legacy_phy_write(dev, 0x0812,
  1478. b43legacy_get_812_value(dev,
  1479. LPD(1, 0, 1)));
  1480. b43legacy_phy_write(dev, 0x0015, 0xEFB0);
  1481. udelay(10);
  1482. if (phy->gmode)
  1483. b43legacy_phy_write(dev, 0x0812,
  1484. b43legacy_get_812_value(dev,
  1485. LPD(1, 0, 0)));
  1486. b43legacy_phy_write(dev, 0x0015, 0xFFF0);
  1487. udelay(20);
  1488. tmp1 += b43legacy_phy_read(dev, 0x002D);
  1489. b43legacy_phy_write(dev, 0x0058, 0x0000);
  1490. if (phy->gmode)
  1491. b43legacy_phy_write(dev, 0x0812,
  1492. b43legacy_get_812_value(dev,
  1493. LPD(1, 0, 1)));
  1494. b43legacy_phy_write(dev, 0x0015, 0xAFB0);
  1495. }
  1496. tmp1++;
  1497. tmp1 >>= 9;
  1498. udelay(10);
  1499. b43legacy_phy_write(dev, 0x0058, 0x0000);
  1500. for (i = 0; i < 16; i++) {
  1501. b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
  1502. | 0x0020);
  1503. backup[13] = b43legacy_radio_read16(dev, 0x0078);
  1504. udelay(10);
  1505. for (j = 0; j < 16; j++) {
  1506. b43legacy_phy_write(dev, 0x005A, 0x0D80);
  1507. b43legacy_phy_write(dev, 0x0059, 0xC810);
  1508. b43legacy_phy_write(dev, 0x0058, 0x000D);
  1509. if (phy->gmode)
  1510. b43legacy_phy_write(dev, 0x0812,
  1511. b43legacy_get_812_value(dev,
  1512. LPD(1, 0, 1)));
  1513. b43legacy_phy_write(dev, 0x0015, 0xAFB0);
  1514. udelay(10);
  1515. if (phy->gmode)
  1516. b43legacy_phy_write(dev, 0x0812,
  1517. b43legacy_get_812_value(dev,
  1518. LPD(1, 0, 1)));
  1519. b43legacy_phy_write(dev, 0x0015, 0xEFB0);
  1520. udelay(10);
  1521. if (phy->gmode)
  1522. b43legacy_phy_write(dev, 0x0812,
  1523. b43legacy_get_812_value(dev,
  1524. LPD(1, 0, 0)));
  1525. b43legacy_phy_write(dev, 0x0015, 0xFFF0);
  1526. udelay(10);
  1527. tmp2 += b43legacy_phy_read(dev, 0x002D);
  1528. b43legacy_phy_write(dev, 0x0058, 0x0000);
  1529. if (phy->gmode)
  1530. b43legacy_phy_write(dev, 0x0812,
  1531. b43legacy_get_812_value(dev,
  1532. LPD(1, 0, 1)));
  1533. b43legacy_phy_write(dev, 0x0015, 0xAFB0);
  1534. }
  1535. tmp2++;
  1536. tmp2 >>= 8;
  1537. if (tmp1 < tmp2)
  1538. break;
  1539. }
  1540. /* Restore the registers */
  1541. b43legacy_phy_write(dev, 0x0015, backup[1]);
  1542. b43legacy_radio_write16(dev, 0x0051, backup[14]);
  1543. b43legacy_radio_write16(dev, 0x0052, backup[15]);
  1544. b43legacy_radio_write16(dev, 0x0043, backup[0]);
  1545. b43legacy_phy_write(dev, 0x005A, backup[16]);
  1546. b43legacy_phy_write(dev, 0x0059, backup[17]);
  1547. b43legacy_phy_write(dev, 0x0058, backup[18]);
  1548. b43legacy_write16(dev, 0x03E6, backup[11]);
  1549. if (phy->analog != 0)
  1550. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
  1551. b43legacy_phy_write(dev, 0x0035, backup[10]);
  1552. b43legacy_radio_selectchannel(dev, phy->channel, 1);
  1553. if (phy->type == B43legacy_PHYTYPE_B) {
  1554. b43legacy_phy_write(dev, 0x0030, backup[2]);
  1555. b43legacy_write16(dev, 0x03EC, backup[3]);
  1556. } else {
  1557. if (phy->gmode) {
  1558. b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
  1559. (b43legacy_read16(dev,
  1560. B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
  1561. b43legacy_phy_write(dev, 0x0811, backup[4]);
  1562. b43legacy_phy_write(dev, 0x0812, backup[5]);
  1563. b43legacy_phy_write(dev, 0x0814, backup[6]);
  1564. b43legacy_phy_write(dev, 0x0815, backup[7]);
  1565. b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
  1566. backup[8]);
  1567. b43legacy_phy_write(dev, 0x0802, backup[9]);
  1568. if (phy->rev > 1) {
  1569. b43legacy_phy_write(dev, 0x080F, backup[19]);
  1570. b43legacy_phy_write(dev, 0x0810, backup[20]);
  1571. }
  1572. }
  1573. }
  1574. if (i >= 15)
  1575. ret = backup[13];
  1576. return ret;
  1577. }
  1578. int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
  1579. u8 channel,
  1580. int synthetic_pu_workaround)
  1581. {
  1582. struct b43legacy_phy *phy = &dev->phy;
  1583. if (channel == 0xFF) {
  1584. switch (phy->type) {
  1585. case B43legacy_PHYTYPE_B:
  1586. case B43legacy_PHYTYPE_G:
  1587. channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
  1588. break;
  1589. default:
  1590. B43legacy_WARN_ON(1);
  1591. }
  1592. }
  1593. /* TODO: Check if channel is valid - return -EINVAL if not */
  1594. if (synthetic_pu_workaround)
  1595. b43legacy_synth_pu_workaround(dev, channel);
  1596. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
  1597. channel2freq_bg(channel));
  1598. if (channel == 14) {
  1599. if (dev->dev->bus->sprom.country_code == 5) /* JAPAN) */
  1600. b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
  1601. B43legacy_UCODEFLAGS_OFFSET,
  1602. b43legacy_shm_read32(dev,
  1603. B43legacy_SHM_SHARED,
  1604. B43legacy_UCODEFLAGS_OFFSET)
  1605. & ~(1 << 7));
  1606. else
  1607. b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
  1608. B43legacy_UCODEFLAGS_OFFSET,
  1609. b43legacy_shm_read32(dev,
  1610. B43legacy_SHM_SHARED,
  1611. B43legacy_UCODEFLAGS_OFFSET)
  1612. | (1 << 7));
  1613. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
  1614. b43legacy_read16(dev,
  1615. B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
  1616. } else
  1617. b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
  1618. b43legacy_read16(dev,
  1619. B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
  1620. phy->channel = channel;
  1621. /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
  1622. * that 2000 usecs might suffice. */
  1623. msleep(8);
  1624. return 0;
  1625. }
  1626. void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
  1627. {
  1628. u16 tmp;
  1629. val <<= 8;
  1630. tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
  1631. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
  1632. tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
  1633. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
  1634. tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
  1635. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
  1636. }
  1637. /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
  1638. static u16 b43legacy_get_txgain_base_band(u16 txpower)
  1639. {
  1640. u16 ret;
  1641. B43legacy_WARN_ON(txpower > 63);
  1642. if (txpower >= 54)
  1643. ret = 2;
  1644. else if (txpower >= 49)
  1645. ret = 4;
  1646. else if (txpower >= 44)
  1647. ret = 5;
  1648. else
  1649. ret = 6;
  1650. return ret;
  1651. }
  1652. /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
  1653. static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
  1654. {
  1655. u16 ret;
  1656. B43legacy_WARN_ON(txpower > 63);
  1657. if (txpower >= 32)
  1658. ret = 0;
  1659. else if (txpower >= 25)
  1660. ret = 1;
  1661. else if (txpower >= 20)
  1662. ret = 2;
  1663. else if (txpower >= 12)
  1664. ret = 3;
  1665. else
  1666. ret = 4;
  1667. return ret;
  1668. }
  1669. /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
  1670. static u16 b43legacy_get_txgain_dac(u16 txpower)
  1671. {
  1672. u16 ret;
  1673. B43legacy_WARN_ON(txpower > 63);
  1674. if (txpower >= 54)
  1675. ret = txpower - 53;
  1676. else if (txpower >= 49)
  1677. ret = txpower - 42;
  1678. else if (txpower >= 44)
  1679. ret = txpower - 37;
  1680. else if (txpower >= 32)
  1681. ret = txpower - 32;
  1682. else if (txpower >= 25)
  1683. ret = txpower - 20;
  1684. else if (txpower >= 20)
  1685. ret = txpower - 13;
  1686. else if (txpower >= 12)
  1687. ret = txpower - 8;
  1688. else
  1689. ret = txpower;
  1690. return ret;
  1691. }
  1692. void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
  1693. {
  1694. struct b43legacy_phy *phy = &dev->phy;
  1695. u16 pamp;
  1696. u16 base;
  1697. u16 dac;
  1698. u16 ilt;
  1699. txpower = clamp_val(txpower, 0, 63);
  1700. pamp = b43legacy_get_txgain_freq_power_amp(txpower);
  1701. pamp <<= 5;
  1702. pamp &= 0x00E0;
  1703. b43legacy_phy_write(dev, 0x0019, pamp);
  1704. base = b43legacy_get_txgain_base_band(txpower);
  1705. base &= 0x000F;
  1706. b43legacy_phy_write(dev, 0x0017, base | 0x0020);
  1707. ilt = b43legacy_ilt_read(dev, 0x3001);
  1708. ilt &= 0x0007;
  1709. dac = b43legacy_get_txgain_dac(txpower);
  1710. dac <<= 3;
  1711. dac |= ilt;
  1712. b43legacy_ilt_write(dev, 0x3001, dac);
  1713. phy->txpwr_offset = txpower;
  1714. /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
  1715. }
  1716. void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
  1717. u16 baseband_attenuation,
  1718. u16 radio_attenuation,
  1719. u16 txpower)
  1720. {
  1721. struct b43legacy_phy *phy = &dev->phy;
  1722. if (baseband_attenuation == 0xFFFF)
  1723. baseband_attenuation = phy->bbatt;
  1724. if (radio_attenuation == 0xFFFF)
  1725. radio_attenuation = phy->rfatt;
  1726. if (txpower == 0xFFFF)
  1727. txpower = phy->txctl1;
  1728. phy->bbatt = baseband_attenuation;
  1729. phy->rfatt = radio_attenuation;
  1730. phy->txctl1 = txpower;
  1731. B43legacy_WARN_ON(baseband_attenuation > 11);
  1732. if (phy->radio_rev < 6)
  1733. B43legacy_WARN_ON(radio_attenuation > 9);
  1734. else
  1735. B43legacy_WARN_ON(radio_attenuation > 31);
  1736. B43legacy_WARN_ON(txpower > 7);
  1737. b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
  1738. b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
  1739. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
  1740. radio_attenuation);
  1741. if (phy->radio_ver == 0x2050)
  1742. b43legacy_radio_write16(dev, 0x0052,
  1743. (b43legacy_radio_read16(dev, 0x0052)
  1744. & ~0x0070) | ((txpower << 4) & 0x0070));
  1745. /* FIXME: The spec is very weird and unclear here. */
  1746. if (phy->type == B43legacy_PHYTYPE_G)
  1747. b43legacy_phy_lo_adjust(dev, 0);
  1748. }
  1749. u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
  1750. {
  1751. struct b43legacy_phy *phy = &dev->phy;
  1752. if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
  1753. return 0;
  1754. return 2;
  1755. }
  1756. u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
  1757. {
  1758. struct b43legacy_phy *phy = &dev->phy;
  1759. u16 att = 0xFFFF;
  1760. switch (phy->radio_ver) {
  1761. case 0x2053:
  1762. switch (phy->radio_rev) {
  1763. case 1:
  1764. att = 6;
  1765. break;
  1766. }
  1767. break;
  1768. case 0x2050:
  1769. switch (phy->radio_rev) {
  1770. case 0:
  1771. att = 5;
  1772. break;
  1773. case 1:
  1774. if (phy->type == B43legacy_PHYTYPE_G) {
  1775. if (is_bcm_board_vendor(dev) &&
  1776. dev->dev->bus->boardinfo.type == 0x421 &&
  1777. dev->dev->bus->sprom.board_rev >= 30)
  1778. att = 3;
  1779. else if (is_bcm_board_vendor(dev) &&
  1780. dev->dev->bus->boardinfo.type == 0x416)
  1781. att = 3;
  1782. else
  1783. att = 1;
  1784. } else {
  1785. if (is_bcm_board_vendor(dev) &&
  1786. dev->dev->bus->boardinfo.type == 0x421 &&
  1787. dev->dev->bus->sprom.board_rev >= 30)
  1788. att = 7;
  1789. else
  1790. att = 6;
  1791. }
  1792. break;
  1793. case 2:
  1794. if (phy->type == B43legacy_PHYTYPE_G) {
  1795. if (is_bcm_board_vendor(dev) &&
  1796. dev->dev->bus->boardinfo.type == 0x421 &&
  1797. dev->dev->bus->sprom.board_rev >= 30)
  1798. att = 3;
  1799. else if (is_bcm_board_vendor(dev) &&
  1800. dev->dev->bus->boardinfo.type ==
  1801. 0x416)
  1802. att = 5;
  1803. else if (dev->dev->bus->chip_id == 0x4320)
  1804. att = 4;
  1805. else
  1806. att = 3;
  1807. } else
  1808. att = 6;
  1809. break;
  1810. case 3:
  1811. att = 5;
  1812. break;
  1813. case 4:
  1814. case 5:
  1815. att = 1;
  1816. break;
  1817. case 6:
  1818. case 7:
  1819. att = 5;
  1820. break;
  1821. case 8:
  1822. att = 0x1A;
  1823. break;
  1824. case 9:
  1825. default:
  1826. att = 5;
  1827. }
  1828. }
  1829. if (is_bcm_board_vendor(dev) &&
  1830. dev->dev->bus->boardinfo.type == 0x421) {
  1831. if (dev->dev->bus->sprom.board_rev < 0x43)
  1832. att = 2;
  1833. else if (dev->dev->bus->sprom.board_rev < 0x51)
  1834. att = 3;
  1835. }
  1836. if (att == 0xFFFF)
  1837. att = 5;
  1838. return att;
  1839. }
  1840. u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
  1841. {
  1842. struct b43legacy_phy *phy = &dev->phy;
  1843. if (phy->radio_ver != 0x2050)
  1844. return 0;
  1845. if (phy->radio_rev == 1)
  1846. return 3;
  1847. if (phy->radio_rev < 6)
  1848. return 2;
  1849. if (phy->radio_rev == 8)
  1850. return 1;
  1851. return 0;
  1852. }
  1853. void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
  1854. {
  1855. struct b43legacy_phy *phy = &dev->phy;
  1856. int err;
  1857. u8 channel;
  1858. might_sleep();
  1859. if (phy->radio_on)
  1860. return;
  1861. switch (phy->type) {
  1862. case B43legacy_PHYTYPE_B:
  1863. case B43legacy_PHYTYPE_G:
  1864. b43legacy_phy_write(dev, 0x0015, 0x8000);
  1865. b43legacy_phy_write(dev, 0x0015, 0xCC00);
  1866. b43legacy_phy_write(dev, 0x0015,
  1867. (phy->gmode ? 0x00C0 : 0x0000));
  1868. if (phy->radio_off_context.valid) {
  1869. /* Restore the RFover values. */
  1870. b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
  1871. phy->radio_off_context.rfover);
  1872. b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
  1873. phy->radio_off_context.rfoverval);
  1874. phy->radio_off_context.valid = false;
  1875. }
  1876. channel = phy->channel;
  1877. err = b43legacy_radio_selectchannel(dev,
  1878. B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
  1879. err |= b43legacy_radio_selectchannel(dev, channel, 0);
  1880. B43legacy_WARN_ON(err);
  1881. break;
  1882. default:
  1883. B43legacy_BUG_ON(1);
  1884. }
  1885. phy->radio_on = true;
  1886. }
  1887. void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
  1888. {
  1889. struct b43legacy_phy *phy = &dev->phy;
  1890. if (!phy->radio_on && !force)
  1891. return;
  1892. if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
  1893. u16 rfover, rfoverval;
  1894. rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
  1895. rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
  1896. if (!force) {
  1897. phy->radio_off_context.rfover = rfover;
  1898. phy->radio_off_context.rfoverval = rfoverval;
  1899. phy->radio_off_context.valid = true;
  1900. }
  1901. b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
  1902. b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
  1903. rfoverval & 0xFF73);
  1904. } else
  1905. b43legacy_phy_write(dev, 0x0015, 0xAA00);
  1906. phy->radio_on = false;
  1907. b43legacydbg(dev->wl, "Radio initialized\n");
  1908. }
  1909. void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
  1910. {
  1911. struct b43legacy_phy *phy = &dev->phy;
  1912. switch (phy->type) {
  1913. case B43legacy_PHYTYPE_B:
  1914. case B43legacy_PHYTYPE_G:
  1915. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
  1916. 0x7F7F);
  1917. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
  1918. 0x7F7F);
  1919. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
  1920. 0x7F7F);
  1921. b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
  1922. 0x7F7F);
  1923. break;
  1924. }
  1925. }