radio.c 58 KB

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