bcm43xx_power.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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_power.h"
  26. #include "bcm43xx_main.h"
  27. /* Get the Slow Clock Source */
  28. static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm)
  29. {
  30. u32 tmp;
  31. int err;
  32. assert(bcm->current_core == &bcm->core_chipcommon);
  33. if (bcm->current_core->rev < 6) {
  34. if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA ||
  35. bcm->bustype == BCM43xx_BUSTYPE_SB)
  36. return BCM43xx_PCTL_CLKSRC_XTALOS;
  37. if (bcm->bustype == BCM43xx_BUSTYPE_PCI) {
  38. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
  39. assert(!err);
  40. if (tmp & 0x10)
  41. return BCM43xx_PCTL_CLKSRC_PCI;
  42. return BCM43xx_PCTL_CLKSRC_XTALOS;
  43. }
  44. }
  45. if (bcm->current_core->rev < 10) {
  46. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  47. tmp &= 0x7;
  48. if (tmp == 0)
  49. return BCM43xx_PCTL_CLKSRC_LOPWROS;
  50. if (tmp == 1)
  51. return BCM43xx_PCTL_CLKSRC_XTALOS;
  52. if (tmp == 2)
  53. return BCM43xx_PCTL_CLKSRC_PCI;
  54. }
  55. return BCM43xx_PCTL_CLKSRC_XTALOS;
  56. }
  57. /* Get max/min slowclock frequency
  58. * as described in http://bcm-specs.sipsolutions.net/PowerControl
  59. */
  60. static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
  61. int get_max)
  62. {
  63. int limit;
  64. int clocksrc;
  65. int divisor;
  66. u32 tmp;
  67. assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
  68. assert(bcm->current_core == &bcm->core_chipcommon);
  69. clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
  70. if (bcm->current_core->rev < 6) {
  71. switch (clocksrc) {
  72. case BCM43xx_PCTL_CLKSRC_PCI:
  73. divisor = 64;
  74. break;
  75. case BCM43xx_PCTL_CLKSRC_XTALOS:
  76. divisor = 32;
  77. break;
  78. default:
  79. assert(0);
  80. divisor = 1;
  81. }
  82. } else if (bcm->current_core->rev < 10) {
  83. switch (clocksrc) {
  84. case BCM43xx_PCTL_CLKSRC_LOPWROS:
  85. divisor = 1;
  86. break;
  87. case BCM43xx_PCTL_CLKSRC_XTALOS:
  88. case BCM43xx_PCTL_CLKSRC_PCI:
  89. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  90. divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
  91. divisor *= 4;
  92. break;
  93. default:
  94. assert(0);
  95. divisor = 1;
  96. }
  97. } else {
  98. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
  99. divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
  100. divisor *= 4;
  101. }
  102. switch (clocksrc) {
  103. case BCM43xx_PCTL_CLKSRC_LOPWROS:
  104. if (get_max)
  105. limit = 43000;
  106. else
  107. limit = 25000;
  108. break;
  109. case BCM43xx_PCTL_CLKSRC_XTALOS:
  110. if (get_max)
  111. limit = 20200000;
  112. else
  113. limit = 19800000;
  114. break;
  115. case BCM43xx_PCTL_CLKSRC_PCI:
  116. if (get_max)
  117. limit = 34000000;
  118. else
  119. limit = 25000000;
  120. break;
  121. default:
  122. assert(0);
  123. limit = 0;
  124. }
  125. limit /= divisor;
  126. return limit;
  127. }
  128. /* init power control
  129. * as described in http://bcm-specs.sipsolutions.net/PowerControl
  130. */
  131. int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
  132. {
  133. int err, maxfreq;
  134. struct bcm43xx_coreinfo *old_core;
  135. old_core = bcm->current_core;
  136. err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  137. if (err == -ENODEV)
  138. return 0;
  139. if (err)
  140. goto out;
  141. if (bcm->chip_id == 0x4321) {
  142. if (bcm->chip_rev == 0)
  143. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x03A4);
  144. if (bcm->chip_rev == 1)
  145. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x00A4);
  146. }
  147. if (bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) {
  148. if (bcm->current_core->rev >= 10) {
  149. /* Set Idle Power clock rate to 1Mhz */
  150. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL,
  151. (bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL)
  152. & 0x0000FFFF) | 0x40000);
  153. } else {
  154. maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
  155. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
  156. (maxfreq * 150 + 999999) / 1000000);
  157. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
  158. (maxfreq * 15 + 999999) / 1000000);
  159. }
  160. }
  161. err = bcm43xx_switch_core(bcm, old_core);
  162. assert(err == 0);
  163. out:
  164. return err;
  165. }
  166. u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
  167. {
  168. u16 delay = 0;
  169. int err;
  170. u32 pll_on_delay;
  171. struct bcm43xx_coreinfo *old_core;
  172. int minfreq;
  173. if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
  174. goto out;
  175. if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
  176. goto out;
  177. old_core = bcm->current_core;
  178. err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  179. if (err == -ENODEV)
  180. goto out;
  181. minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
  182. pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
  183. delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
  184. err = bcm43xx_switch_core(bcm, old_core);
  185. assert(err == 0);
  186. out:
  187. return delay;
  188. }
  189. /* set the powercontrol clock
  190. * as described in http://bcm-specs.sipsolutions.net/PowerControl
  191. */
  192. int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
  193. {
  194. int err;
  195. struct bcm43xx_coreinfo *old_core;
  196. u32 tmp;
  197. old_core = bcm->current_core;
  198. err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  199. if (err == -ENODEV)
  200. return 0;
  201. if (err)
  202. goto out;
  203. if (bcm->core_chipcommon.rev < 6) {
  204. if (mode == BCM43xx_PCTL_CLK_FAST) {
  205. err = bcm43xx_pctl_set_crystal(bcm, 1);
  206. if (err)
  207. goto out;
  208. }
  209. } else {
  210. if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
  211. (bcm->core_chipcommon.rev < 10)) {
  212. switch (mode) {
  213. case BCM43xx_PCTL_CLK_FAST:
  214. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  215. tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
  216. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
  217. break;
  218. case BCM43xx_PCTL_CLK_SLOW:
  219. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  220. tmp |= BCM43xx_PCTL_FORCE_SLOW;
  221. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
  222. break;
  223. case BCM43xx_PCTL_CLK_DYNAMIC:
  224. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  225. tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
  226. tmp |= BCM43xx_PCTL_FORCE_PLL;
  227. tmp &= ~BCM43xx_PCTL_DYN_XTAL;
  228. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
  229. }
  230. }
  231. }
  232. err = bcm43xx_switch_core(bcm, old_core);
  233. assert(err == 0);
  234. out:
  235. return err;
  236. }
  237. int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
  238. {
  239. int err;
  240. u32 in, out, outenable;
  241. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
  242. if (err)
  243. goto err_pci;
  244. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
  245. if (err)
  246. goto err_pci;
  247. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
  248. if (err)
  249. goto err_pci;
  250. outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
  251. if (on) {
  252. if (in & 0x40)
  253. return 0;
  254. out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
  255. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
  256. if (err)
  257. goto err_pci;
  258. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
  259. if (err)
  260. goto err_pci;
  261. udelay(1000);
  262. out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
  263. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
  264. if (err)
  265. goto err_pci;
  266. udelay(5000);
  267. } else {
  268. if (bcm->current_core->rev < 5)
  269. return 0;
  270. if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
  271. return 0;
  272. /* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
  273. * err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
  274. * if (err)
  275. * return err;
  276. * if (((bcm->current_core->rev >= 3) &&
  277. * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
  278. * ((bcm->current_core->rev < 3) &&
  279. * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
  280. * return 0;
  281. * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  282. * if (err)
  283. * return err;
  284. */
  285. err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
  286. if (err)
  287. goto out;
  288. out &= ~BCM43xx_PCTL_XTAL_POWERUP;
  289. out |= BCM43xx_PCTL_PLL_POWERDOWN;
  290. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
  291. if (err)
  292. goto err_pci;
  293. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
  294. if (err)
  295. goto err_pci;
  296. }
  297. out:
  298. return err;
  299. err_pci:
  300. printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
  301. err = -EBUSY;
  302. goto out;
  303. }
  304. /* Set the PowerSavingControlBits.
  305. * Bitvalues:
  306. * 0 => unset the bit
  307. * 1 => set the bit
  308. * -1 => calculate the bit
  309. */
  310. void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
  311. int bit25, int bit26)
  312. {
  313. int i;
  314. u32 status;
  315. //FIXME: Force 25 to off and 26 to on for now:
  316. bit25 = 0;
  317. bit26 = 1;
  318. if (bit25 == -1) {
  319. //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
  320. // and thus is not an AP and we are associated, set bit 25
  321. }
  322. if (bit26 == -1) {
  323. //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
  324. // or we are associated, or FIXME, or the latest PS-Poll packet sent was
  325. // successful, set bit26
  326. }
  327. status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
  328. if (bit25)
  329. status |= BCM43xx_SBF_PS1;
  330. else
  331. status &= ~BCM43xx_SBF_PS1;
  332. if (bit26)
  333. status |= BCM43xx_SBF_PS2;
  334. else
  335. status &= ~BCM43xx_SBF_PS2;
  336. bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
  337. if (bit26 && bcm->current_core->rev >= 5) {
  338. for (i = 0; i < 100; i++) {
  339. if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
  340. break;
  341. udelay(10);
  342. }
  343. }
  344. }