bcm43xx_radio.c 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766
  1. /*
  2. Broadcom BCM43xx wireless driver
  3. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  4. Stefano Brivio <st3@riseup.net>
  5. Michael Buesch <mbuesch@freenet.de>
  6. Danny van Dyk <kugelfang@gentoo.org>
  7. Andreas Jaggi <andreas.jaggi@waterwave.ch>
  8. Some parts of the code in this file are derived from the ipw2200
  9. driver Copyright(c) 2003 - 2004 Intel Corporation.
  10. This program is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2 of the License, or
  13. (at your option) any later version.
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program; see the file COPYING. If not, write to
  20. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  21. Boston, MA 02110-1301, USA.
  22. */
  23. #include <linux/delay.h>
  24. #include "bcm43xx.h"
  25. #include "bcm43xx_main.h"
  26. #include "bcm43xx_phy.h"
  27. #include "bcm43xx_radio.h"
  28. #include "bcm43xx_ilt.h"
  29. /* Table for bcm43xx_radio_calibrationvalue() */
  30. static const u16 rcc_table[16] = {
  31. 0x0002, 0x0003, 0x0001, 0x000F,
  32. 0x0006, 0x0007, 0x0005, 0x000F,
  33. 0x000A, 0x000B, 0x0009, 0x000F,
  34. 0x000E, 0x000F, 0x000D, 0x000F,
  35. };
  36. /* Reverse the bits of a 4bit value.
  37. * Example: 1101 is flipped 1011
  38. */
  39. static u16 flip_4bit(u16 value)
  40. {
  41. u16 flipped = 0x0000;
  42. assert((value & ~0x000F) == 0x0000);
  43. flipped |= (value & 0x0001) << 3;
  44. flipped |= (value & 0x0002) << 1;
  45. flipped |= (value & 0x0004) >> 1;
  46. flipped |= (value & 0x0008) >> 3;
  47. return flipped;
  48. }
  49. /* Get the freq, as it has to be written to the device. */
  50. static inline
  51. u16 channel2freq_bg(u8 channel)
  52. {
  53. /* Frequencies are given as frequencies_bg[index] + 2.4GHz
  54. * Starting with channel 1
  55. */
  56. static const u16 frequencies_bg[14] = {
  57. 12, 17, 22, 27,
  58. 32, 37, 42, 47,
  59. 52, 57, 62, 67,
  60. 72, 84,
  61. };
  62. assert(channel >= 1 && channel <= 14);
  63. return frequencies_bg[channel - 1];
  64. }
  65. /* Get the freq, as it has to be written to the device. */
  66. static inline
  67. u16 channel2freq_a(u8 channel)
  68. {
  69. assert(channel <= 200);
  70. return (5000 + 5 * channel);
  71. }
  72. void bcm43xx_radio_lock(struct bcm43xx_private *bcm)
  73. {
  74. u32 status;
  75. status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
  76. status |= BCM43xx_SBF_RADIOREG_LOCK;
  77. bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
  78. udelay(10);
  79. }
  80. void bcm43xx_radio_unlock(struct bcm43xx_private *bcm)
  81. {
  82. u32 status;
  83. bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */
  84. status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
  85. status &= ~BCM43xx_SBF_RADIOREG_LOCK;
  86. bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
  87. }
  88. u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset)
  89. {
  90. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  91. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  92. switch (phy->type) {
  93. case BCM43xx_PHYTYPE_A:
  94. offset |= 0x0040;
  95. break;
  96. case BCM43xx_PHYTYPE_B:
  97. if (radio->version == 0x2053) {
  98. if (offset < 0x70)
  99. offset += 0x80;
  100. else if (offset < 0x80)
  101. offset += 0x70;
  102. } else if (radio->version == 0x2050) {
  103. offset |= 0x80;
  104. } else
  105. assert(0);
  106. break;
  107. case BCM43xx_PHYTYPE_G:
  108. offset |= 0x80;
  109. break;
  110. }
  111. bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
  112. return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);
  113. }
  114. void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val)
  115. {
  116. bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset);
  117. bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val);
  118. }
  119. static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm,
  120. s16 first, s16 second, s16 third)
  121. {
  122. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  123. u16 i;
  124. u16 start = 0x08, end = 0x18;
  125. u16 offset = 0x0400;
  126. u16 tmp;
  127. if (phy->rev <= 1) {
  128. offset = 0x5000;
  129. start = 0x10;
  130. end = 0x20;
  131. }
  132. for (i = 0; i < 4; i++)
  133. bcm43xx_ilt_write16(bcm, offset + i, first);
  134. for (i = start; i < end; i++)
  135. bcm43xx_ilt_write16(bcm, offset + i, second);
  136. if (third != -1) {
  137. tmp = ((u16)third << 14) | ((u16)third << 6);
  138. bcm43xx_phy_write(bcm, 0x04A0,
  139. (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp);
  140. bcm43xx_phy_write(bcm, 0x04A1,
  141. (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp);
  142. bcm43xx_phy_write(bcm, 0x04A2,
  143. (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp);
  144. }
  145. bcm43xx_dummy_transmission(bcm);
  146. }
  147. static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm)
  148. {
  149. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  150. u16 i, tmp;
  151. u16 offset = 0x0400;
  152. u16 start = 0x0008, end = 0x0018;
  153. if (phy->rev <= 1) {
  154. offset = 0x5000;
  155. start = 0x0010;
  156. end = 0x0020;
  157. }
  158. for (i = 0; i < 4; i++) {
  159. tmp = (i & 0xFFFC);
  160. tmp |= (i & 0x0001) << 1;
  161. tmp |= (i & 0x0002) >> 1;
  162. bcm43xx_ilt_write16(bcm, offset + i, tmp);
  163. }
  164. for (i = start; i < end; i++)
  165. bcm43xx_ilt_write16(bcm, offset + i, i - start);
  166. bcm43xx_phy_write(bcm, 0x04A0,
  167. (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040);
  168. bcm43xx_phy_write(bcm, 0x04A1,
  169. (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040);
  170. bcm43xx_phy_write(bcm, 0x04A2,
  171. (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000);
  172. bcm43xx_dummy_transmission(bcm);
  173. }
  174. /* Synthetic PU workaround */
  175. static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel)
  176. {
  177. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  178. if (radio->version != 0x2050 || radio->revision >= 6) {
  179. /* We do not need the workaround. */
  180. return;
  181. }
  182. if (channel <= 10) {
  183. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
  184. channel2freq_bg(channel + 4));
  185. } else {
  186. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
  187. channel2freq_bg(1));
  188. }
  189. udelay(100);
  190. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
  191. channel2freq_bg(channel));
  192. }
  193. u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel)
  194. {
  195. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  196. u8 ret = 0;
  197. u16 saved, rssi, temp;
  198. int i, j = 0;
  199. saved = bcm43xx_phy_read(bcm, 0x0403);
  200. bcm43xx_radio_selectchannel(bcm, channel, 0);
  201. bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5);
  202. if (radio->aci_hw_rssi)
  203. rssi = bcm43xx_phy_read(bcm, 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 = (bcm43xx_phy_read(bcm, 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. bcm43xx_phy_write(bcm, 0x0403, saved);
  219. return ret;
  220. }
  221. u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm)
  222. {
  223. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  224. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  225. u8 ret[13];
  226. unsigned int channel = radio->channel;
  227. unsigned int i, j, start, end;
  228. unsigned long phylock_flags;
  229. if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0)))
  230. return 0;
  231. bcm43xx_phy_lock(bcm, phylock_flags);
  232. bcm43xx_radio_lock(bcm);
  233. bcm43xx_phy_write(bcm, 0x0802,
  234. bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
  235. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  236. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
  237. bcm43xx_set_all_gains(bcm, 3, 8, 1);
  238. start = (channel - 5 > 0) ? channel - 5 : 1;
  239. end = (channel + 5 < 14) ? channel + 5 : 13;
  240. for (i = start; i <= end; i++) {
  241. if (abs(channel - i) > 2)
  242. ret[i-1] = bcm43xx_radio_aci_detect(bcm, i);
  243. }
  244. bcm43xx_radio_selectchannel(bcm, channel, 0);
  245. bcm43xx_phy_write(bcm, 0x0802,
  246. (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003);
  247. bcm43xx_phy_write(bcm, 0x0403,
  248. bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8);
  249. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  250. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
  251. bcm43xx_set_original_gains(bcm);
  252. for (i = 0; i < 13; i++) {
  253. if (!ret[i])
  254. continue;
  255. end = (i + 5 < 13) ? i + 5 : 13;
  256. for (j = i; j < end; j++)
  257. ret[j] = 1;
  258. }
  259. bcm43xx_radio_unlock(bcm);
  260. bcm43xx_phy_unlock(bcm, phylock_flags);
  261. return ret[channel - 1];
  262. }
  263. /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
  264. void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val)
  265. {
  266. bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
  267. bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val);
  268. }
  269. /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
  270. s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset)
  271. {
  272. u16 val;
  273. bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset);
  274. val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA);
  275. return (s16)val;
  276. }
  277. /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
  278. void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val)
  279. {
  280. u16 i;
  281. s16 tmp;
  282. for (i = 0; i < 64; i++) {
  283. tmp = bcm43xx_nrssi_hw_read(bcm, i);
  284. tmp -= val;
  285. tmp = limit_value(tmp, -32, 31);
  286. bcm43xx_nrssi_hw_write(bcm, i, tmp);
  287. }
  288. }
  289. /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
  290. void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm)
  291. {
  292. s16 i, delta;
  293. s32 tmp;
  294. delta = 0x1F - bcm->current_core->radio->nrssi[0];
  295. for (i = 0; i < 64; i++) {
  296. tmp = (i - delta) * bcm->current_core->radio->nrssislope;
  297. tmp /= 0x10000;
  298. tmp += 0x3A;
  299. tmp = limit_value(tmp, 0, 0x3F);
  300. bcm->current_core->radio->nrssi_lt[i] = tmp;
  301. }
  302. }
  303. static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
  304. {
  305. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  306. u16 backup[20] = { 0 };
  307. s16 v47F;
  308. u16 i;
  309. u16 saved = 0xFFFF;
  310. backup[0] = bcm43xx_phy_read(bcm, 0x0001);
  311. backup[1] = bcm43xx_phy_read(bcm, 0x0811);
  312. backup[2] = bcm43xx_phy_read(bcm, 0x0812);
  313. backup[3] = bcm43xx_phy_read(bcm, 0x0814);
  314. backup[4] = bcm43xx_phy_read(bcm, 0x0815);
  315. backup[5] = bcm43xx_phy_read(bcm, 0x005A);
  316. backup[6] = bcm43xx_phy_read(bcm, 0x0059);
  317. backup[7] = bcm43xx_phy_read(bcm, 0x0058);
  318. backup[8] = bcm43xx_phy_read(bcm, 0x000A);
  319. backup[9] = bcm43xx_phy_read(bcm, 0x0003);
  320. backup[10] = bcm43xx_radio_read16(bcm, 0x007A);
  321. backup[11] = bcm43xx_radio_read16(bcm, 0x0043);
  322. bcm43xx_phy_write(bcm, 0x0429,
  323. bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF);
  324. bcm43xx_phy_write(bcm, 0x0001,
  325. (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000);
  326. bcm43xx_phy_write(bcm, 0x0811,
  327. bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
  328. bcm43xx_phy_write(bcm, 0x0812,
  329. (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004);
  330. bcm43xx_phy_write(bcm, 0x0802,
  331. bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2));
  332. if (phy->rev >= 6) {
  333. backup[12] = bcm43xx_phy_read(bcm, 0x002E);
  334. backup[13] = bcm43xx_phy_read(bcm, 0x002F);
  335. backup[14] = bcm43xx_phy_read(bcm, 0x080F);
  336. backup[15] = bcm43xx_phy_read(bcm, 0x0810);
  337. backup[16] = bcm43xx_phy_read(bcm, 0x0801);
  338. backup[17] = bcm43xx_phy_read(bcm, 0x0060);
  339. backup[18] = bcm43xx_phy_read(bcm, 0x0014);
  340. backup[19] = bcm43xx_phy_read(bcm, 0x0478);
  341. bcm43xx_phy_write(bcm, 0x002E, 0);
  342. bcm43xx_phy_write(bcm, 0x002F, 0);
  343. bcm43xx_phy_write(bcm, 0x080F, 0);
  344. bcm43xx_phy_write(bcm, 0x0810, 0);
  345. bcm43xx_phy_write(bcm, 0x0478,
  346. bcm43xx_phy_read(bcm, 0x0478) | 0x0100);
  347. bcm43xx_phy_write(bcm, 0x0801,
  348. bcm43xx_phy_read(bcm, 0x0801) | 0x0040);
  349. bcm43xx_phy_write(bcm, 0x0060,
  350. bcm43xx_phy_read(bcm, 0x0060) | 0x0040);
  351. bcm43xx_phy_write(bcm, 0x0014,
  352. bcm43xx_phy_read(bcm, 0x0014) | 0x0200);
  353. }
  354. bcm43xx_radio_write16(bcm, 0x007A,
  355. bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
  356. bcm43xx_radio_write16(bcm, 0x007A,
  357. bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
  358. udelay(30);
  359. v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
  360. if (v47F >= 0x20)
  361. v47F -= 0x40;
  362. if (v47F == 31) {
  363. for (i = 7; i >= 4; i--) {
  364. bcm43xx_radio_write16(bcm, 0x007B, i);
  365. udelay(20);
  366. v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
  367. if (v47F >= 0x20)
  368. v47F -= 0x40;
  369. if (v47F < 31 && saved == 0xFFFF)
  370. saved = i;
  371. }
  372. if (saved == 0xFFFF)
  373. saved = 4;
  374. } else {
  375. bcm43xx_radio_write16(bcm, 0x007A,
  376. bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
  377. bcm43xx_phy_write(bcm, 0x0814,
  378. bcm43xx_phy_read(bcm, 0x0814) | 0x0001);
  379. bcm43xx_phy_write(bcm, 0x0815,
  380. bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE);
  381. bcm43xx_phy_write(bcm, 0x0811,
  382. bcm43xx_phy_read(bcm, 0x0811) | 0x000C);
  383. bcm43xx_phy_write(bcm, 0x0812,
  384. bcm43xx_phy_read(bcm, 0x0812) | 0x000C);
  385. bcm43xx_phy_write(bcm, 0x0811,
  386. bcm43xx_phy_read(bcm, 0x0811) | 0x0030);
  387. bcm43xx_phy_write(bcm, 0x0812,
  388. bcm43xx_phy_read(bcm, 0x0812) | 0x0030);
  389. bcm43xx_phy_write(bcm, 0x005A, 0x0480);
  390. bcm43xx_phy_write(bcm, 0x0059, 0x0810);
  391. bcm43xx_phy_write(bcm, 0x0058, 0x000D);
  392. if (phy->rev == 0) {
  393. bcm43xx_phy_write(bcm, 0x0003, 0x0122);
  394. } else {
  395. bcm43xx_phy_write(bcm, 0x000A,
  396. bcm43xx_phy_read(bcm, 0x000A)
  397. | 0x2000);
  398. }
  399. bcm43xx_phy_write(bcm, 0x0814,
  400. bcm43xx_phy_read(bcm, 0x0814) | 0x0004);
  401. bcm43xx_phy_write(bcm, 0x0815,
  402. bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB);
  403. bcm43xx_phy_write(bcm, 0x0003,
  404. (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F)
  405. | 0x0040);
  406. bcm43xx_radio_write16(bcm, 0x007A,
  407. bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
  408. bcm43xx_set_all_gains(bcm, 3, 0, 1);
  409. bcm43xx_radio_write16(bcm, 0x0043,
  410. (bcm43xx_radio_read16(bcm, 0x0043)
  411. & 0x00F0) | 0x000F);
  412. udelay(30);
  413. v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
  414. if (v47F >= 0x20)
  415. v47F -= 0x40;
  416. if (v47F == -32) {
  417. for (i = 0; i < 4; i++) {
  418. bcm43xx_radio_write16(bcm, 0x007B, i);
  419. udelay(20);
  420. v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
  421. if (v47F >= 0x20)
  422. v47F -= 0x40;
  423. if (v47F > -31 && saved == 0xFFFF)
  424. saved = i;
  425. }
  426. if (saved == 0xFFFF)
  427. saved = 3;
  428. } else
  429. saved = 0;
  430. }
  431. bcm43xx_radio_write16(bcm, 0x007B, saved);
  432. if (phy->rev >= 6) {
  433. bcm43xx_phy_write(bcm, 0x002E, backup[12]);
  434. bcm43xx_phy_write(bcm, 0x002F, backup[13]);
  435. bcm43xx_phy_write(bcm, 0x080F, backup[14]);
  436. bcm43xx_phy_write(bcm, 0x0810, backup[15]);
  437. }
  438. bcm43xx_phy_write(bcm, 0x0814, backup[3]);
  439. bcm43xx_phy_write(bcm, 0x0815, backup[4]);
  440. bcm43xx_phy_write(bcm, 0x005A, backup[5]);
  441. bcm43xx_phy_write(bcm, 0x0059, backup[6]);
  442. bcm43xx_phy_write(bcm, 0x0058, backup[7]);
  443. bcm43xx_phy_write(bcm, 0x000A, backup[8]);
  444. bcm43xx_phy_write(bcm, 0x0003, backup[9]);
  445. bcm43xx_radio_write16(bcm, 0x0043, backup[11]);
  446. bcm43xx_radio_write16(bcm, 0x007A, backup[10]);
  447. bcm43xx_phy_write(bcm, 0x0802,
  448. bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2);
  449. bcm43xx_phy_write(bcm, 0x0429,
  450. bcm43xx_phy_read(bcm, 0x0429) | 0x8000);
  451. bcm43xx_set_original_gains(bcm);
  452. if (phy->rev >= 6) {
  453. bcm43xx_phy_write(bcm, 0x0801, backup[16]);
  454. bcm43xx_phy_write(bcm, 0x0060, backup[17]);
  455. bcm43xx_phy_write(bcm, 0x0014, backup[18]);
  456. bcm43xx_phy_write(bcm, 0x0478, backup[19]);
  457. }
  458. bcm43xx_phy_write(bcm, 0x0001, backup[0]);
  459. bcm43xx_phy_write(bcm, 0x0812, backup[2]);
  460. bcm43xx_phy_write(bcm, 0x0811, backup[1]);
  461. }
  462. void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
  463. {
  464. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  465. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  466. u16 backup[18] = { 0 };
  467. u16 tmp;
  468. s16 nrssi0, nrssi1;
  469. switch (phy->type) {
  470. case BCM43xx_PHYTYPE_B:
  471. backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
  472. backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
  473. backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
  474. backup[3] = bcm43xx_phy_read(bcm, 0x0030);
  475. backup[4] = bcm43xx_phy_read(bcm, 0x0026);
  476. backup[5] = bcm43xx_phy_read(bcm, 0x0015);
  477. backup[6] = bcm43xx_phy_read(bcm, 0x002A);
  478. backup[7] = bcm43xx_phy_read(bcm, 0x0020);
  479. backup[8] = bcm43xx_phy_read(bcm, 0x005A);
  480. backup[9] = bcm43xx_phy_read(bcm, 0x0059);
  481. backup[10] = bcm43xx_phy_read(bcm, 0x0058);
  482. backup[11] = bcm43xx_read16(bcm, 0x03E2);
  483. backup[12] = bcm43xx_read16(bcm, 0x03E6);
  484. backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
  485. tmp = bcm43xx_radio_read16(bcm, 0x007A);
  486. tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
  487. bcm43xx_radio_write16(bcm, 0x007A, tmp);
  488. bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
  489. bcm43xx_write16(bcm, 0x03EC, 0x7F7F);
  490. bcm43xx_phy_write(bcm, 0x0026, 0x0000);
  491. bcm43xx_phy_write(bcm, 0x0015,
  492. bcm43xx_phy_read(bcm, 0x0015) | 0x0020);
  493. bcm43xx_phy_write(bcm, 0x002A, 0x08A3);
  494. bcm43xx_radio_write16(bcm, 0x007A,
  495. bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
  496. nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
  497. bcm43xx_radio_write16(bcm, 0x007A,
  498. bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
  499. if (phy->rev >= 2) {
  500. bcm43xx_write16(bcm, 0x03E6, 0x0040);
  501. } else if (phy->rev == 0) {
  502. bcm43xx_write16(bcm, 0x03E6, 0x0122);
  503. } else {
  504. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
  505. bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000);
  506. }
  507. bcm43xx_phy_write(bcm, 0x0020, 0x3F3F);
  508. bcm43xx_phy_write(bcm, 0x0015, 0xF330);
  509. bcm43xx_radio_write16(bcm, 0x005A, 0x0060);
  510. bcm43xx_radio_write16(bcm, 0x0043,
  511. bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0);
  512. bcm43xx_phy_write(bcm, 0x005A, 0x0480);
  513. bcm43xx_phy_write(bcm, 0x0059, 0x0810);
  514. bcm43xx_phy_write(bcm, 0x0058, 0x000D);
  515. udelay(20);
  516. nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027);
  517. bcm43xx_phy_write(bcm, 0x0030, backup[3]);
  518. bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
  519. bcm43xx_write16(bcm, 0x03E2, backup[11]);
  520. bcm43xx_phy_write(bcm, 0x0026, backup[4]);
  521. bcm43xx_phy_write(bcm, 0x0015, backup[5]);
  522. bcm43xx_phy_write(bcm, 0x002A, backup[6]);
  523. bcm43xx_synth_pu_workaround(bcm, radio->channel);
  524. if (phy->rev != 0)
  525. bcm43xx_write16(bcm, 0x03F4, backup[13]);
  526. bcm43xx_phy_write(bcm, 0x0020, backup[7]);
  527. bcm43xx_phy_write(bcm, 0x005A, backup[8]);
  528. bcm43xx_phy_write(bcm, 0x0059, backup[9]);
  529. bcm43xx_phy_write(bcm, 0x0058, backup[10]);
  530. bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
  531. bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
  532. if (nrssi0 == nrssi1)
  533. radio->nrssislope = 0x00010000;
  534. else
  535. radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
  536. if (nrssi0 <= -4) {
  537. radio->nrssi[0] = nrssi0;
  538. radio->nrssi[1] = nrssi1;
  539. }
  540. break;
  541. case BCM43xx_PHYTYPE_G:
  542. //FIXME: Something is broken here. This is called when enabling WLAN interfmode.
  543. // If this is done at runtime, I get an XMIT ERROR and transmission is
  544. // broken. I guess some important register is overwritten by accident.
  545. // The XMIT ERROR comes from the dummy_transmissions in set_gains.
  546. if (radio->revision >= 9)
  547. return;
  548. if (radio->revision == 8)
  549. bcm43xx_calc_nrssi_offset(bcm);
  550. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  551. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF);
  552. bcm43xx_phy_write(bcm, 0x0802,
  553. bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC);
  554. backup[7] = bcm43xx_read16(bcm, 0x03E2);
  555. bcm43xx_write16(bcm, 0x03E2,
  556. bcm43xx_read16(bcm, 0x03E2) | 0x8000);
  557. backup[0] = bcm43xx_radio_read16(bcm, 0x007A);
  558. backup[1] = bcm43xx_radio_read16(bcm, 0x0052);
  559. backup[2] = bcm43xx_radio_read16(bcm, 0x0043);
  560. backup[3] = bcm43xx_phy_read(bcm, 0x0015);
  561. backup[4] = bcm43xx_phy_read(bcm, 0x005A);
  562. backup[5] = bcm43xx_phy_read(bcm, 0x0059);
  563. backup[6] = bcm43xx_phy_read(bcm, 0x0058);
  564. backup[8] = bcm43xx_read16(bcm, 0x03E6);
  565. backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
  566. if (phy->rev >= 3) {
  567. backup[10] = bcm43xx_phy_read(bcm, 0x002E);
  568. backup[11] = bcm43xx_phy_read(bcm, 0x002F);
  569. backup[12] = bcm43xx_phy_read(bcm, 0x080F);
  570. backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL);
  571. backup[14] = bcm43xx_phy_read(bcm, 0x0801);
  572. backup[15] = bcm43xx_phy_read(bcm, 0x0060);
  573. backup[16] = bcm43xx_phy_read(bcm, 0x0014);
  574. backup[17] = bcm43xx_phy_read(bcm, 0x0478);
  575. bcm43xx_phy_write(bcm, 0x002E, 0);
  576. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0);
  577. switch (phy->rev) {
  578. case 4: case 6: case 7:
  579. bcm43xx_phy_write(bcm, 0x0478,
  580. bcm43xx_phy_read(bcm, 0x0478)
  581. | 0x0100);
  582. bcm43xx_phy_write(bcm, 0x0801,
  583. bcm43xx_phy_read(bcm, 0x0801)
  584. | 0x0040);
  585. break;
  586. case 3: case 5:
  587. bcm43xx_phy_write(bcm, 0x0801,
  588. bcm43xx_phy_read(bcm, 0x0801)
  589. & 0xFFBF);
  590. break;
  591. }
  592. bcm43xx_phy_write(bcm, 0x0060,
  593. bcm43xx_phy_read(bcm, 0x0060)
  594. | 0x0040);
  595. bcm43xx_phy_write(bcm, 0x0014,
  596. bcm43xx_phy_read(bcm, 0x0014)
  597. | 0x0200);
  598. }
  599. bcm43xx_radio_write16(bcm, 0x007A,
  600. bcm43xx_radio_read16(bcm, 0x007A) | 0x0070);
  601. bcm43xx_set_all_gains(bcm, 0, 8, 0);
  602. bcm43xx_radio_write16(bcm, 0x007A,
  603. bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7);
  604. if (phy->rev >= 2) {
  605. bcm43xx_phy_write(bcm, 0x0811,
  606. (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030);
  607. bcm43xx_phy_write(bcm, 0x0812,
  608. (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010);
  609. }
  610. bcm43xx_radio_write16(bcm, 0x007A,
  611. bcm43xx_radio_read16(bcm, 0x007A) | 0x0080);
  612. udelay(20);
  613. nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
  614. if (nrssi0 >= 0x0020)
  615. nrssi0 -= 0x0040;
  616. bcm43xx_radio_write16(bcm, 0x007A,
  617. bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
  618. if (phy->rev >= 2) {
  619. bcm43xx_phy_write(bcm, 0x0003,
  620. (bcm43xx_phy_read(bcm, 0x0003)
  621. & 0xFF9F) | 0x0040);
  622. }
  623. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
  624. bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
  625. | 0x2000);
  626. bcm43xx_radio_write16(bcm, 0x007A,
  627. bcm43xx_radio_read16(bcm, 0x007A) | 0x000F);
  628. bcm43xx_phy_write(bcm, 0x0015, 0xF330);
  629. if (phy->rev >= 2) {
  630. bcm43xx_phy_write(bcm, 0x0812,
  631. (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020);
  632. bcm43xx_phy_write(bcm, 0x0811,
  633. (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020);
  634. }
  635. bcm43xx_set_all_gains(bcm, 3, 0, 1);
  636. if (radio->revision == 8) {
  637. bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
  638. } else {
  639. tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F;
  640. bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060);
  641. tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0;
  642. bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009);
  643. }
  644. bcm43xx_phy_write(bcm, 0x005A, 0x0480);
  645. bcm43xx_phy_write(bcm, 0x0059, 0x0810);
  646. bcm43xx_phy_write(bcm, 0x0058, 0x000D);
  647. udelay(20);
  648. nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F);
  649. if (nrssi1 >= 0x0020)
  650. nrssi1 -= 0x0040;
  651. if (nrssi0 == nrssi1)
  652. radio->nrssislope = 0x00010000;
  653. else
  654. radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
  655. if (nrssi0 >= -4) {
  656. radio->nrssi[0] = nrssi1;
  657. radio->nrssi[1] = nrssi0;
  658. }
  659. if (phy->rev >= 3) {
  660. bcm43xx_phy_write(bcm, 0x002E, backup[10]);
  661. bcm43xx_phy_write(bcm, 0x002F, backup[11]);
  662. bcm43xx_phy_write(bcm, 0x080F, backup[12]);
  663. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]);
  664. }
  665. if (phy->rev >= 2) {
  666. bcm43xx_phy_write(bcm, 0x0812,
  667. bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF);
  668. bcm43xx_phy_write(bcm, 0x0811,
  669. bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF);
  670. }
  671. bcm43xx_radio_write16(bcm, 0x007A, backup[0]);
  672. bcm43xx_radio_write16(bcm, 0x0052, backup[1]);
  673. bcm43xx_radio_write16(bcm, 0x0043, backup[2]);
  674. bcm43xx_write16(bcm, 0x03E2, backup[7]);
  675. bcm43xx_write16(bcm, 0x03E6, backup[8]);
  676. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]);
  677. bcm43xx_phy_write(bcm, 0x0015, backup[3]);
  678. bcm43xx_phy_write(bcm, 0x005A, backup[4]);
  679. bcm43xx_phy_write(bcm, 0x0059, backup[5]);
  680. bcm43xx_phy_write(bcm, 0x0058, backup[6]);
  681. bcm43xx_synth_pu_workaround(bcm, radio->channel);
  682. bcm43xx_phy_write(bcm, 0x0802,
  683. bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002));
  684. bcm43xx_set_original_gains(bcm);
  685. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  686. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000);
  687. if (phy->rev >= 3) {
  688. bcm43xx_phy_write(bcm, 0x0801, backup[14]);
  689. bcm43xx_phy_write(bcm, 0x0060, backup[15]);
  690. bcm43xx_phy_write(bcm, 0x0014, backup[16]);
  691. bcm43xx_phy_write(bcm, 0x0478, backup[17]);
  692. }
  693. bcm43xx_nrssi_mem_update(bcm);
  694. bcm43xx_calc_nrssi_threshold(bcm);
  695. break;
  696. default:
  697. assert(0);
  698. }
  699. }
  700. void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm)
  701. {
  702. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  703. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  704. s16 threshold;
  705. s32 a, b;
  706. int tmp;
  707. s16 tmp16;
  708. u16 tmp_u16;
  709. switch (phy->type) {
  710. case BCM43xx_PHYTYPE_B: {
  711. int radiotype = 0;
  712. if (phy->rev < 2)
  713. return;
  714. if (radio->version != 0x2050)
  715. return;
  716. if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI))
  717. return;
  718. tmp = radio->revision;
  719. if ((radio->manufact == 0x175 && tmp == 5) ||
  720. (radio->manufact == 0x17F && (tmp == 3 || tmp == 4)))
  721. radiotype = 1;
  722. if (radiotype == 1) {
  723. threshold = bcm->current_core->radio->nrssi[1] - 5;
  724. } else {
  725. threshold = 40 * radio->nrssi[0];
  726. threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]);
  727. threshold += 20;
  728. threshold /= 10;
  729. }
  730. threshold = limit_value(threshold, 0, 0x3E);
  731. bcm43xx_phy_read(bcm, 0x0020); /* dummy read */
  732. bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C);
  733. if (radiotype == 1) {
  734. bcm43xx_phy_write(bcm, 0x0087, 0x0E0D);
  735. bcm43xx_phy_write(bcm, 0x0086, 0x0C0B);
  736. bcm43xx_phy_write(bcm, 0x0085, 0x0A09);
  737. bcm43xx_phy_write(bcm, 0x0084, 0x0808);
  738. bcm43xx_phy_write(bcm, 0x0083, 0x0808);
  739. bcm43xx_phy_write(bcm, 0x0082, 0x0604);
  740. bcm43xx_phy_write(bcm, 0x0081, 0x0302);
  741. bcm43xx_phy_write(bcm, 0x0080, 0x0100);
  742. }
  743. break;
  744. }
  745. case BCM43xx_PHYTYPE_G:
  746. if (!phy->connected ||
  747. !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) {
  748. tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20);
  749. if (tmp16 >= 0x20)
  750. tmp16 -= 0x40;
  751. if (tmp16 < 3) {
  752. bcm43xx_phy_write(bcm, 0x048A,
  753. (bcm43xx_phy_read(bcm, 0x048A)
  754. & 0xF000) | 0x09EB);
  755. } else {
  756. bcm43xx_phy_write(bcm, 0x048A,
  757. (bcm43xx_phy_read(bcm, 0x048A)
  758. & 0xF000) | 0x0AED);
  759. }
  760. } else {
  761. tmp = radio->interfmode;
  762. if (tmp == BCM43xx_RADIO_INTERFMODE_NONWLAN) {
  763. a = -13;
  764. b = -17;
  765. } else if (tmp == BCM43xx_RADIO_INTERFMODE_NONE &&
  766. !radio->aci_enable) {
  767. a = -13;
  768. b = -10;
  769. } else {
  770. a = -8;
  771. b = -9;
  772. }
  773. a += 0x1B;
  774. a *= radio->nrssi[1] - radio->nrssi[0];
  775. a += radio->nrssi[0] * 0x40;
  776. a /= 64;
  777. b += 0x1B;
  778. b *= radio->nrssi[1] - radio->nrssi[0];
  779. b += radio->nrssi[0] * 0x40;
  780. b /= 64;
  781. a = limit_value(a, -31, 31);
  782. b = limit_value(b, -31, 31);
  783. tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000;
  784. tmp_u16 |= ((u32)a & 0x003F);
  785. tmp_u16 |= (((u32)b & 0x003F) << 6);
  786. bcm43xx_phy_write(bcm, 0x048A, tmp_u16);
  787. }
  788. break;
  789. default:
  790. assert(0);
  791. }
  792. }
  793. /* Helper macros to save on and restore values from the radio->interfstack */
  794. #ifdef stack_save
  795. # undef stack_save
  796. #endif
  797. #ifdef stack_restore
  798. # undef stack_restore
  799. #endif
  800. #define stack_save(value) \
  801. do { \
  802. assert(i < ARRAY_SIZE(radio->interfstack)); \
  803. stack[i++] = (value); \
  804. } while (0)
  805. #define stack_restore() \
  806. ({ \
  807. assert(i < ARRAY_SIZE(radio->interfstack)); \
  808. stack[i++]; \
  809. })
  810. static void
  811. bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm,
  812. int mode)
  813. {
  814. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  815. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  816. int i = 0;
  817. u16 *stack = radio->interfstack;
  818. u16 tmp, flipped;
  819. switch (mode) {
  820. case BCM43xx_RADIO_INTERFMODE_NONWLAN:
  821. if (phy->rev != 1) {
  822. bcm43xx_phy_write(bcm, 0x042B,
  823. bcm43xx_phy_read(bcm, 0x042B) & 0x0800);
  824. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  825. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000);
  826. break;
  827. }
  828. tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
  829. flipped = flip_4bit(tmp);
  830. if ((flipped >> 1) >= 4)
  831. tmp = flipped - 3;
  832. tmp = flip_4bit(tmp);
  833. bcm43xx_radio_write16(bcm, 0x0078, tmp << 1);
  834. bcm43xx_calc_nrssi_threshold(bcm);
  835. if (bcm->current_core->rev < 5) {
  836. stack_save(bcm43xx_phy_read(bcm, 0x0406));
  837. bcm43xx_phy_write(bcm, 0x0406, 0x7E28);
  838. } else {
  839. stack_save(bcm43xx_phy_read(bcm, 0x04C0));
  840. stack_save(bcm43xx_phy_read(bcm, 0x04C1));
  841. bcm43xx_phy_write(bcm, 0x04C0, 0x3E04);
  842. bcm43xx_phy_write(bcm, 0x04C1, 0x0640);
  843. }
  844. bcm43xx_phy_write(bcm, 0x042B,
  845. bcm43xx_phy_read(bcm, 0x042B) | 0x0800);
  846. bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
  847. bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000);
  848. stack_save(bcm43xx_phy_read(bcm, 0x04A0));
  849. bcm43xx_phy_write(bcm, 0x04A0,
  850. (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008);
  851. stack_save(bcm43xx_phy_read(bcm, 0x04A1));
  852. bcm43xx_phy_write(bcm, 0x04A1,
  853. (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605);
  854. stack_save(bcm43xx_phy_read(bcm, 0x04A2));
  855. bcm43xx_phy_write(bcm, 0x04A2,
  856. (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204);
  857. stack_save(bcm43xx_phy_read(bcm, 0x04A8));
  858. bcm43xx_phy_write(bcm, 0x04A8,
  859. (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0403);
  860. stack_save(bcm43xx_phy_read(bcm, 0x04AB));
  861. bcm43xx_phy_write(bcm, 0x04AB,
  862. (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0504);
  863. stack_save(bcm43xx_phy_read(bcm, 0x04A7));
  864. bcm43xx_phy_write(bcm, 0x04A7, 0x0002);
  865. stack_save(bcm43xx_phy_read(bcm, 0x04A3));
  866. bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
  867. stack_save(bcm43xx_phy_read(bcm, 0x04A9));
  868. bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
  869. stack_save(bcm43xx_phy_read(bcm, 0x0493));
  870. bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
  871. stack_save(bcm43xx_phy_read(bcm, 0x04AA));
  872. bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
  873. stack_save(bcm43xx_phy_read(bcm, 0x04AC));
  874. bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
  875. break;
  876. case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
  877. if (bcm43xx_phy_read(bcm, 0x0033) == 0x0800)
  878. break;
  879. radio->aci_enable = 1;
  880. stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD));
  881. stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS));
  882. if (bcm->current_core->rev < 5) {
  883. stack_save(bcm43xx_phy_read(bcm, 0x0406));
  884. } else {
  885. stack_save(bcm43xx_phy_read(bcm, 0x04C0));
  886. stack_save(bcm43xx_phy_read(bcm, 0x04C1));
  887. }
  888. stack_save(bcm43xx_phy_read(bcm, 0x0033));
  889. stack_save(bcm43xx_phy_read(bcm, 0x04A7));
  890. stack_save(bcm43xx_phy_read(bcm, 0x04A3));
  891. stack_save(bcm43xx_phy_read(bcm, 0x04A9));
  892. stack_save(bcm43xx_phy_read(bcm, 0x04AA));
  893. stack_save(bcm43xx_phy_read(bcm, 0x04AC));
  894. stack_save(bcm43xx_phy_read(bcm, 0x0493));
  895. stack_save(bcm43xx_phy_read(bcm, 0x04A1));
  896. stack_save(bcm43xx_phy_read(bcm, 0x04A0));
  897. stack_save(bcm43xx_phy_read(bcm, 0x04A2));
  898. stack_save(bcm43xx_phy_read(bcm, 0x048A));
  899. stack_save(bcm43xx_phy_read(bcm, 0x04A8));
  900. stack_save(bcm43xx_phy_read(bcm, 0x04AB));
  901. bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
  902. bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & 0xEFFF);
  903. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  904. (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xEFFF) | 0x0002);
  905. bcm43xx_phy_write(bcm, 0x04A7, 0x0800);
  906. bcm43xx_phy_write(bcm, 0x04A3, 0x287A);
  907. bcm43xx_phy_write(bcm, 0x04A9, 0x2027);
  908. bcm43xx_phy_write(bcm, 0x0493, 0x32F5);
  909. bcm43xx_phy_write(bcm, 0x04AA, 0x2027);
  910. bcm43xx_phy_write(bcm, 0x04AC, 0x32F5);
  911. bcm43xx_phy_write(bcm, 0x04A0,
  912. (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFC0) | 0x001A);
  913. if (bcm->current_core->rev < 5) {
  914. bcm43xx_phy_write(bcm, 0x0406, 0x280D);
  915. } else {
  916. bcm43xx_phy_write(bcm, 0x04C0, 0x0640);
  917. bcm43xx_phy_write(bcm, 0x04C1, 0x00A9);
  918. }
  919. bcm43xx_phy_write(bcm, 0x04A1,
  920. (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0FF) | 0x1800);
  921. bcm43xx_phy_write(bcm, 0x04A1,
  922. (bcm43xx_phy_read(bcm, 0x04A1) & 0xFFC0) | 0x0016);
  923. bcm43xx_phy_write(bcm, 0x04A2,
  924. (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0900);
  925. bcm43xx_phy_write(bcm, 0x04A0,
  926. (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0700);
  927. bcm43xx_phy_write(bcm, 0x04A2,
  928. (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x000D);
  929. bcm43xx_phy_write(bcm, 0x04A8,
  930. (bcm43xx_phy_read(bcm, 0x04A8) & 0xCFFF) | 0x1000);
  931. bcm43xx_phy_write(bcm, 0x04A8,
  932. (bcm43xx_phy_read(bcm, 0x04A8) & 0xF0FF) | 0x0A00);
  933. bcm43xx_phy_write(bcm, 0x04AB,
  934. (bcm43xx_phy_read(bcm, 0x04AB) & 0xCFFF) | 0x1000);
  935. bcm43xx_phy_write(bcm, 0x04AB,
  936. (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0800);
  937. bcm43xx_phy_write(bcm, 0x04AB,
  938. (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFCF) | 0x0010);
  939. bcm43xx_phy_write(bcm, 0x04AB,
  940. (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFF0) | 0x0006);
  941. bcm43xx_calc_nrssi_slope(bcm);
  942. break;
  943. default:
  944. assert(0);
  945. }
  946. }
  947. static void
  948. bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm,
  949. int mode)
  950. {
  951. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  952. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  953. int i = 0;
  954. u16 *stack = radio->interfstack;
  955. u16 tmp, flipped;
  956. switch (mode) {
  957. case BCM43xx_RADIO_INTERFMODE_NONWLAN:
  958. if (phy->rev != 1) {
  959. bcm43xx_phy_write(bcm, 0x042B,
  960. bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
  961. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  962. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000);
  963. break;
  964. }
  965. tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E);
  966. flipped = flip_4bit(tmp);
  967. if ((flipped >> 1) >= 0x000C)
  968. tmp = flipped + 3;
  969. tmp = flip_4bit(tmp);
  970. bcm43xx_radio_write16(bcm, 0x0078, tmp << 1);
  971. bcm43xx_calc_nrssi_threshold(bcm);
  972. if (bcm->current_core->rev < 5) {
  973. bcm43xx_phy_write(bcm, 0x0406, stack_restore());
  974. } else {
  975. bcm43xx_phy_write(bcm, 0x04C0, stack_restore());
  976. bcm43xx_phy_write(bcm, 0x04C1, stack_restore());
  977. }
  978. bcm43xx_phy_write(bcm, 0x042B,
  979. bcm43xx_phy_read(bcm, 0x042B) & ~0x0800);
  980. if (!bcm->bad_frames_preempt)
  981. bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD,
  982. bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & ~(1 << 11));
  983. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  984. bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000);
  985. bcm43xx_phy_write(bcm, 0x04A0, stack_restore());
  986. bcm43xx_phy_write(bcm, 0x04A1, stack_restore());
  987. bcm43xx_phy_write(bcm, 0x04A2, stack_restore());
  988. bcm43xx_phy_write(bcm, 0x04A8, stack_restore());
  989. bcm43xx_phy_write(bcm, 0x04AB, stack_restore());
  990. bcm43xx_phy_write(bcm, 0x04A7, stack_restore());
  991. bcm43xx_phy_write(bcm, 0x04A3, stack_restore());
  992. bcm43xx_phy_write(bcm, 0x04A9, stack_restore());
  993. bcm43xx_phy_write(bcm, 0x0493, stack_restore());
  994. bcm43xx_phy_write(bcm, 0x04AA, stack_restore());
  995. bcm43xx_phy_write(bcm, 0x04AC, stack_restore());
  996. break;
  997. case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
  998. if (bcm43xx_phy_read(bcm, 0x0033) != 0x0800)
  999. break;
  1000. radio->aci_enable = 0;
  1001. bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, stack_restore());
  1002. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, stack_restore());
  1003. if (bcm->current_core->rev < 5) {
  1004. bcm43xx_phy_write(bcm, 0x0406, stack_restore());
  1005. } else {
  1006. bcm43xx_phy_write(bcm, 0x04C0, stack_restore());
  1007. bcm43xx_phy_write(bcm, 0x04C1, stack_restore());
  1008. }
  1009. bcm43xx_phy_write(bcm, 0x0033, stack_restore());
  1010. bcm43xx_phy_write(bcm, 0x04A7, stack_restore());
  1011. bcm43xx_phy_write(bcm, 0x04A3, stack_restore());
  1012. bcm43xx_phy_write(bcm, 0x04A9, stack_restore());
  1013. bcm43xx_phy_write(bcm, 0x04AA, stack_restore());
  1014. bcm43xx_phy_write(bcm, 0x04AC, stack_restore());
  1015. bcm43xx_phy_write(bcm, 0x0493, stack_restore());
  1016. bcm43xx_phy_write(bcm, 0x04A1, stack_restore());
  1017. bcm43xx_phy_write(bcm, 0x04A0, stack_restore());
  1018. bcm43xx_phy_write(bcm, 0x04A2, stack_restore());
  1019. bcm43xx_phy_write(bcm, 0x04A8, stack_restore());
  1020. bcm43xx_phy_write(bcm, 0x04AB, stack_restore());
  1021. bcm43xx_calc_nrssi_slope(bcm);
  1022. break;
  1023. default:
  1024. assert(0);
  1025. }
  1026. }
  1027. #undef stack_save
  1028. #undef stack_restore
  1029. int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm,
  1030. int mode)
  1031. {
  1032. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  1033. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  1034. int currentmode;
  1035. if ((phy->type != BCM43xx_PHYTYPE_G) ||
  1036. (phy->rev == 0) ||
  1037. (!phy->connected))
  1038. return -ENODEV;
  1039. radio->aci_wlan_automatic = 0;
  1040. switch (mode) {
  1041. case BCM43xx_RADIO_INTERFMODE_AUTOWLAN:
  1042. radio->aci_wlan_automatic = 1;
  1043. if (radio->aci_enable)
  1044. mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
  1045. else
  1046. mode = BCM43xx_RADIO_INTERFMODE_NONE;
  1047. break;
  1048. case BCM43xx_RADIO_INTERFMODE_NONE:
  1049. case BCM43xx_RADIO_INTERFMODE_NONWLAN:
  1050. case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
  1051. break;
  1052. default:
  1053. return -EINVAL;
  1054. }
  1055. currentmode = radio->interfmode;
  1056. if (currentmode == mode)
  1057. return 0;
  1058. if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE)
  1059. bcm43xx_radio_interference_mitigation_disable(bcm, currentmode);
  1060. if (mode == BCM43xx_RADIO_INTERFMODE_NONE) {
  1061. radio->aci_enable = 0;
  1062. radio->aci_hw_rssi = 0;
  1063. } else
  1064. bcm43xx_radio_interference_mitigation_enable(bcm, mode);
  1065. radio->interfmode = mode;
  1066. return 0;
  1067. }
  1068. static u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
  1069. {
  1070. u16 reg, index, ret;
  1071. reg = bcm43xx_radio_read16(bcm, 0x0060);
  1072. index = (reg & 0x001E) >> 1;
  1073. ret = rcc_table[index] << 1;
  1074. ret |= (reg & 0x0001);
  1075. ret |= 0x0020;
  1076. return ret;
  1077. }
  1078. u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
  1079. {
  1080. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  1081. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  1082. u16 backup[19] = { 0 };
  1083. u16 ret;
  1084. u16 i, j;
  1085. u32 tmp1 = 0, tmp2 = 0;
  1086. backup[0] = bcm43xx_radio_read16(bcm, 0x0043);
  1087. backup[14] = bcm43xx_radio_read16(bcm, 0x0051);
  1088. backup[15] = bcm43xx_radio_read16(bcm, 0x0052);
  1089. backup[1] = bcm43xx_phy_read(bcm, 0x0015);
  1090. backup[16] = bcm43xx_phy_read(bcm, 0x005A);
  1091. backup[17] = bcm43xx_phy_read(bcm, 0x0059);
  1092. backup[18] = bcm43xx_phy_read(bcm, 0x0058);
  1093. if (phy->type == BCM43xx_PHYTYPE_B) {
  1094. backup[2] = bcm43xx_phy_read(bcm, 0x0030);
  1095. backup[3] = bcm43xx_read16(bcm, 0x03EC);
  1096. bcm43xx_phy_write(bcm, 0x0030, 0x00FF);
  1097. bcm43xx_write16(bcm, 0x03EC, 0x3F3F);
  1098. } else {
  1099. if (phy->connected) {
  1100. backup[4] = bcm43xx_phy_read(bcm, 0x0811);
  1101. backup[5] = bcm43xx_phy_read(bcm, 0x0812);
  1102. backup[6] = bcm43xx_phy_read(bcm, 0x0814);
  1103. backup[7] = bcm43xx_phy_read(bcm, 0x0815);
  1104. backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
  1105. backup[9] = bcm43xx_phy_read(bcm, 0x0802);
  1106. bcm43xx_phy_write(bcm, 0x0814,
  1107. (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
  1108. bcm43xx_phy_write(bcm, 0x0815,
  1109. (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));
  1110. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
  1111. (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
  1112. bcm43xx_phy_write(bcm, 0x0802,
  1113. (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
  1114. bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
  1115. bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
  1116. }
  1117. bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
  1118. (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
  1119. }
  1120. backup[10] = bcm43xx_phy_read(bcm, 0x0035);
  1121. bcm43xx_phy_write(bcm, 0x0035,
  1122. (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
  1123. backup[11] = bcm43xx_read16(bcm, 0x03E6);
  1124. backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
  1125. // Initialization
  1126. if (phy->version == 0) {
  1127. bcm43xx_write16(bcm, 0x03E6, 0x0122);
  1128. } else {
  1129. if (phy->version >= 2)
  1130. bcm43xx_write16(bcm, 0x03E6, 0x0040);
  1131. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
  1132. (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
  1133. }
  1134. ret = bcm43xx_radio_calibrationvalue(bcm);
  1135. if (phy->type == BCM43xx_PHYTYPE_B)
  1136. bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
  1137. bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
  1138. bcm43xx_phy_write(bcm, 0x002B, 0x1403);
  1139. if (phy->connected)
  1140. bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
  1141. bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
  1142. bcm43xx_radio_write16(bcm, 0x0051,
  1143. (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
  1144. bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
  1145. bcm43xx_radio_write16(bcm, 0x0043,
  1146. bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
  1147. bcm43xx_phy_write(bcm, 0x0058, 0x0000);
  1148. for (i = 0; i < 16; i++) {
  1149. bcm43xx_phy_write(bcm, 0x005A, 0x0480);
  1150. bcm43xx_phy_write(bcm, 0x0059, 0xC810);
  1151. bcm43xx_phy_write(bcm, 0x0058, 0x000D);
  1152. if (phy->connected)
  1153. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1154. bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
  1155. udelay(10);
  1156. if (phy->connected)
  1157. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1158. bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
  1159. udelay(10);
  1160. if (phy->connected)
  1161. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1162. bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
  1163. udelay(10);
  1164. tmp1 += bcm43xx_phy_read(bcm, 0x002D);
  1165. bcm43xx_phy_write(bcm, 0x0058, 0x0000);
  1166. if (phy->connected)
  1167. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1168. bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
  1169. }
  1170. tmp1++;
  1171. tmp1 >>= 9;
  1172. udelay(10);
  1173. bcm43xx_phy_write(bcm, 0x0058, 0x0000);
  1174. for (i = 0; i < 16; i++) {
  1175. bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020);
  1176. backup[13] = bcm43xx_radio_read16(bcm, 0x0078);
  1177. udelay(10);
  1178. for (j = 0; j < 16; j++) {
  1179. bcm43xx_phy_write(bcm, 0x005A, 0x0D80);
  1180. bcm43xx_phy_write(bcm, 0x0059, 0xC810);
  1181. bcm43xx_phy_write(bcm, 0x0058, 0x000D);
  1182. if (phy->connected)
  1183. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1184. bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
  1185. udelay(10);
  1186. if (phy->connected)
  1187. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1188. bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
  1189. udelay(10);
  1190. if (phy->connected)
  1191. bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
  1192. bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
  1193. udelay(10);
  1194. tmp2 += bcm43xx_phy_read(bcm, 0x002D);
  1195. bcm43xx_phy_write(bcm, 0x0058, 0x0000);
  1196. if (phy->connected)
  1197. bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
  1198. bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
  1199. }
  1200. tmp2++;
  1201. tmp2 >>= 8;
  1202. if (tmp1 < tmp2)
  1203. break;
  1204. }
  1205. /* Restore the registers */
  1206. bcm43xx_phy_write(bcm, 0x0015, backup[1]);
  1207. bcm43xx_radio_write16(bcm, 0x0051, backup[14]);
  1208. bcm43xx_radio_write16(bcm, 0x0052, backup[15]);
  1209. bcm43xx_radio_write16(bcm, 0x0043, backup[0]);
  1210. bcm43xx_phy_write(bcm, 0x005A, backup[16]);
  1211. bcm43xx_phy_write(bcm, 0x0059, backup[17]);
  1212. bcm43xx_phy_write(bcm, 0x0058, backup[18]);
  1213. bcm43xx_write16(bcm, 0x03E6, backup[11]);
  1214. if (phy->version != 0)
  1215. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
  1216. bcm43xx_phy_write(bcm, 0x0035, backup[10]);
  1217. bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
  1218. if (phy->type == BCM43xx_PHYTYPE_B) {
  1219. bcm43xx_phy_write(bcm, 0x0030, backup[2]);
  1220. bcm43xx_write16(bcm, 0x03EC, backup[3]);
  1221. } else {
  1222. bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
  1223. (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
  1224. if (phy->connected) {
  1225. bcm43xx_phy_write(bcm, 0x0811, backup[4]);
  1226. bcm43xx_phy_write(bcm, 0x0812, backup[5]);
  1227. bcm43xx_phy_write(bcm, 0x0814, backup[6]);
  1228. bcm43xx_phy_write(bcm, 0x0815, backup[7]);
  1229. bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
  1230. bcm43xx_phy_write(bcm, 0x0802, backup[9]);
  1231. }
  1232. }
  1233. if (i >= 15)
  1234. ret = backup[13];
  1235. return ret;
  1236. }
  1237. void bcm43xx_radio_init2060(struct bcm43xx_private *bcm)
  1238. {
  1239. int err;
  1240. bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
  1241. bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
  1242. bcm43xx_radio_write16(bcm, 0x0009, 0x0040);
  1243. bcm43xx_radio_write16(bcm, 0x0005, 0x00AA);
  1244. bcm43xx_radio_write16(bcm, 0x0032, 0x008F);
  1245. bcm43xx_radio_write16(bcm, 0x0006, 0x008F);
  1246. bcm43xx_radio_write16(bcm, 0x0034, 0x008F);
  1247. bcm43xx_radio_write16(bcm, 0x002C, 0x0007);
  1248. bcm43xx_radio_write16(bcm, 0x0082, 0x0080);
  1249. bcm43xx_radio_write16(bcm, 0x0080, 0x0000);
  1250. bcm43xx_radio_write16(bcm, 0x003F, 0x00DA);
  1251. bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
  1252. bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010);
  1253. bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
  1254. bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020);
  1255. udelay(400);
  1256. bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010);
  1257. udelay(400);
  1258. bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008);
  1259. bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010);
  1260. bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008);
  1261. bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040);
  1262. bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040);
  1263. bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008);
  1264. bcm43xx_phy_write(bcm, 0x0063, 0xDDC6);
  1265. bcm43xx_phy_write(bcm, 0x0069, 0x07BE);
  1266. bcm43xx_phy_write(bcm, 0x006A, 0x0000);
  1267. err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0);
  1268. assert(err == 0);
  1269. udelay(1000);
  1270. }
  1271. static inline
  1272. u16 freq_r3A_value(u16 frequency)
  1273. {
  1274. u16 value;
  1275. if (frequency < 5091)
  1276. value = 0x0040;
  1277. else if (frequency < 5321)
  1278. value = 0x0000;
  1279. else if (frequency < 5806)
  1280. value = 0x0080;
  1281. else
  1282. value = 0x0040;
  1283. return value;
  1284. }
  1285. void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
  1286. {
  1287. static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
  1288. static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
  1289. u16 tmp = bcm43xx_radio_read16(bcm, 0x001E);
  1290. int i, j;
  1291. for (i = 0; i < 5; i++) {
  1292. for (j = 0; j < 5; j++) {
  1293. if (tmp == (data_high[i] << 4 | data_low[j])) {
  1294. bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
  1295. return;
  1296. }
  1297. }
  1298. }
  1299. }
  1300. int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
  1301. u8 channel,
  1302. int synthetic_pu_workaround)
  1303. {
  1304. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  1305. u16 r8, tmp;
  1306. u16 freq;
  1307. if ((radio->manufact == 0x17F) &&
  1308. (radio->version == 0x2060) &&
  1309. (radio->revision == 1)) {
  1310. if (channel > 200)
  1311. return -EINVAL;
  1312. freq = channel2freq_a(channel);
  1313. r8 = bcm43xx_radio_read16(bcm, 0x0008);
  1314. bcm43xx_write16(bcm, 0x03F0, freq);
  1315. bcm43xx_radio_write16(bcm, 0x0008, r8);
  1316. TODO();//TODO: write max channel TX power? to Radio 0x2D
  1317. tmp = bcm43xx_radio_read16(bcm, 0x002E);
  1318. tmp &= 0x0080;
  1319. TODO();//TODO: OR tmp with the Power out estimation for this channel?
  1320. bcm43xx_radio_write16(bcm, 0x002E, tmp);
  1321. if (freq >= 4920 && freq <= 5500) {
  1322. /*
  1323. * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
  1324. * = (freq * 0.025862069
  1325. */
  1326. r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
  1327. }
  1328. bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8);
  1329. bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8);
  1330. bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8);
  1331. bcm43xx_radio_write16(bcm, 0x0022,
  1332. (bcm43xx_radio_read16(bcm, 0x0022)
  1333. & 0x000F) | (r8 << 4));
  1334. bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4));
  1335. bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4));
  1336. bcm43xx_radio_write16(bcm, 0x0008,
  1337. (bcm43xx_radio_read16(bcm, 0x0008)
  1338. & 0x00F0) | (r8 << 4));
  1339. bcm43xx_radio_write16(bcm, 0x0029,
  1340. (bcm43xx_radio_read16(bcm, 0x0029)
  1341. & 0xFF0F) | 0x00B0);
  1342. bcm43xx_radio_write16(bcm, 0x0035, 0x00AA);
  1343. bcm43xx_radio_write16(bcm, 0x0036, 0x0085);
  1344. bcm43xx_radio_write16(bcm, 0x003A,
  1345. (bcm43xx_radio_read16(bcm, 0x003A)
  1346. & 0xFF20) | freq_r3A_value(freq));
  1347. bcm43xx_radio_write16(bcm, 0x003D,
  1348. bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF);
  1349. bcm43xx_radio_write16(bcm, 0x0081,
  1350. (bcm43xx_radio_read16(bcm, 0x0081)
  1351. & 0xFF7F) | 0x0080);
  1352. bcm43xx_radio_write16(bcm, 0x0035,
  1353. bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF);
  1354. bcm43xx_radio_write16(bcm, 0x0035,
  1355. (bcm43xx_radio_read16(bcm, 0x0035)
  1356. & 0xFFEF) | 0x0010);
  1357. bcm43xx_radio_set_tx_iq(bcm);
  1358. TODO(); //TODO: TSSI2dbm workaround
  1359. bcm43xx_phy_xmitpower(bcm);//FIXME correct?
  1360. } else {
  1361. if ((channel < 1) || (channel > 14))
  1362. return -EINVAL;
  1363. if (synthetic_pu_workaround)
  1364. bcm43xx_synth_pu_workaround(bcm, channel);
  1365. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL,
  1366. channel2freq_bg(channel));
  1367. if (channel == 14) {
  1368. if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) {
  1369. bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
  1370. BCM43xx_UCODEFLAGS_OFFSET,
  1371. bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
  1372. BCM43xx_UCODEFLAGS_OFFSET)
  1373. & ~(1 << 7));
  1374. } else {
  1375. bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
  1376. BCM43xx_UCODEFLAGS_OFFSET,
  1377. bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
  1378. BCM43xx_UCODEFLAGS_OFFSET)
  1379. | (1 << 7));
  1380. }
  1381. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
  1382. bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
  1383. | (1 << 11));
  1384. } else {
  1385. bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
  1386. bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
  1387. & 0xF7BF);
  1388. }
  1389. }
  1390. radio->channel = channel;
  1391. //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
  1392. // that 2000 usecs might suffice.
  1393. udelay(8000);
  1394. return 0;
  1395. }
  1396. void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val)
  1397. {
  1398. u16 tmp;
  1399. val <<= 8;
  1400. tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF;
  1401. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val);
  1402. tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF;
  1403. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val);
  1404. tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF;
  1405. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val);
  1406. }
  1407. /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
  1408. static u16 bcm43xx_get_txgain_base_band(u16 txpower)
  1409. {
  1410. u16 ret;
  1411. assert(txpower <= 63);
  1412. if (txpower >= 54)
  1413. ret = 2;
  1414. else if (txpower >= 49)
  1415. ret = 4;
  1416. else if (txpower >= 44)
  1417. ret = 5;
  1418. else
  1419. ret = 6;
  1420. return ret;
  1421. }
  1422. /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
  1423. static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower)
  1424. {
  1425. u16 ret;
  1426. assert(txpower <= 63);
  1427. if (txpower >= 32)
  1428. ret = 0;
  1429. else if (txpower >= 25)
  1430. ret = 1;
  1431. else if (txpower >= 20)
  1432. ret = 2;
  1433. else if (txpower >= 12)
  1434. ret = 3;
  1435. else
  1436. ret = 4;
  1437. return ret;
  1438. }
  1439. /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
  1440. static u16 bcm43xx_get_txgain_dac(u16 txpower)
  1441. {
  1442. u16 ret;
  1443. assert(txpower <= 63);
  1444. if (txpower >= 54)
  1445. ret = txpower - 53;
  1446. else if (txpower >= 49)
  1447. ret = txpower - 42;
  1448. else if (txpower >= 44)
  1449. ret = txpower - 37;
  1450. else if (txpower >= 32)
  1451. ret = txpower - 32;
  1452. else if (txpower >= 25)
  1453. ret = txpower - 20;
  1454. else if (txpower >= 20)
  1455. ret = txpower - 13;
  1456. else if (txpower >= 12)
  1457. ret = txpower - 8;
  1458. else
  1459. ret = txpower;
  1460. return ret;
  1461. }
  1462. void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower)
  1463. {
  1464. u16 pamp, base, dac, ilt;
  1465. txpower = limit_value(txpower, 0, 63);
  1466. pamp = bcm43xx_get_txgain_freq_power_amp(txpower);
  1467. pamp <<= 5;
  1468. pamp &= 0x00E0;
  1469. bcm43xx_phy_write(bcm, 0x0019, pamp);
  1470. base = bcm43xx_get_txgain_base_band(txpower);
  1471. base &= 0x000F;
  1472. bcm43xx_phy_write(bcm, 0x0017, base | 0x0020);
  1473. ilt = bcm43xx_ilt_read16(bcm, 0x3001);
  1474. ilt &= 0x0007;
  1475. dac = bcm43xx_get_txgain_dac(txpower);
  1476. dac <<= 3;
  1477. dac |= ilt;
  1478. bcm43xx_ilt_write16(bcm, 0x3001, dac);
  1479. bcm->current_core->radio->txpower[0] = txpower;
  1480. TODO();
  1481. //TODO: FuncPlaceholder (Adjust BB loft cancel)
  1482. }
  1483. void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm,
  1484. u16 baseband_attenuation, u16 radio_attenuation,
  1485. u16 txpower)
  1486. {
  1487. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  1488. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  1489. if (baseband_attenuation == 0xFFFF)
  1490. baseband_attenuation = radio->txpower[0];
  1491. else
  1492. radio->txpower[0] = baseband_attenuation;
  1493. if (radio_attenuation == 0xFFFF)
  1494. radio_attenuation = radio->txpower[1];
  1495. else
  1496. radio->txpower[1] = radio_attenuation;
  1497. if (txpower == 0xFFFF)
  1498. txpower = radio->txpower[2];
  1499. else
  1500. radio->txpower[2] = txpower;
  1501. assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11);
  1502. if (radio->revision < 6)
  1503. assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9);
  1504. else
  1505. assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31);
  1506. assert(/*txpower >= 0 &&*/ txpower <= 7);
  1507. bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation);
  1508. bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation);
  1509. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation);
  1510. if (radio->version == 0x2050) {
  1511. bcm43xx_radio_write16(bcm, 0x0052,
  1512. (bcm43xx_radio_read16(bcm, 0x0052) & 0xFF8F)
  1513. | (txpower << 4));
  1514. }
  1515. if (phy->type == BCM43xx_PHYTYPE_G)
  1516. bcm43xx_phy_lo_adjust(bcm, 0);
  1517. }
  1518. void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
  1519. {
  1520. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  1521. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  1522. int err;
  1523. if (radio->enabled)
  1524. return;
  1525. switch (phy->type) {
  1526. case BCM43xx_PHYTYPE_A:
  1527. bcm43xx_radio_write16(bcm, 0x0004, 0x00C0);
  1528. bcm43xx_radio_write16(bcm, 0x0005, 0x0008);
  1529. bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7);
  1530. bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7);
  1531. bcm43xx_radio_init2060(bcm);
  1532. break;
  1533. case BCM43xx_PHYTYPE_B:
  1534. case BCM43xx_PHYTYPE_G:
  1535. bcm43xx_phy_write(bcm, 0x0015, 0x8000);
  1536. bcm43xx_phy_write(bcm, 0x0015, 0xCC00);
  1537. bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000));
  1538. err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1);
  1539. assert(err == 0);
  1540. break;
  1541. default:
  1542. assert(0);
  1543. }
  1544. radio->enabled = 1;
  1545. dprintk(KERN_INFO PFX "Radio turned on\n");
  1546. }
  1547. void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
  1548. {
  1549. struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
  1550. struct bcm43xx_radioinfo *radio = bcm->current_core->radio;
  1551. if (phy->type == BCM43xx_PHYTYPE_A) {
  1552. bcm43xx_radio_write16(bcm, 0x0004, 0x00FF);
  1553. bcm43xx_radio_write16(bcm, 0x0005, 0x00FB);
  1554. bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008);
  1555. bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008);
  1556. }
  1557. if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) {
  1558. bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C);
  1559. bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73);
  1560. } else
  1561. bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
  1562. radio->enabled = 0;
  1563. dprintk(KERN_INFO PFX "Radio turned off\n");
  1564. }
  1565. void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
  1566. {
  1567. switch (bcm->current_core->phy->type) {
  1568. case BCM43xx_PHYTYPE_A:
  1569. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F);
  1570. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F);
  1571. break;
  1572. case BCM43xx_PHYTYPE_B:
  1573. case BCM43xx_PHYTYPE_G:
  1574. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F);
  1575. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F);
  1576. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F);
  1577. bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F);
  1578. break;
  1579. }
  1580. }