bcm43xx_power.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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. if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
  136. return 0;
  137. old_core = bcm->current_core;
  138. err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  139. if (err == -ENODEV)
  140. return 0;
  141. if (err)
  142. goto out;
  143. maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
  144. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
  145. (maxfreq * 150 + 999999) / 1000000);
  146. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
  147. (maxfreq * 15 + 999999) / 1000000);
  148. err = bcm43xx_switch_core(bcm, old_core);
  149. assert(err == 0);
  150. out:
  151. return err;
  152. }
  153. u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
  154. {
  155. u16 delay = 0;
  156. int err;
  157. u32 pll_on_delay;
  158. struct bcm43xx_coreinfo *old_core;
  159. int minfreq;
  160. if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
  161. goto out;
  162. if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
  163. goto out;
  164. old_core = bcm->current_core;
  165. err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  166. if (err == -ENODEV)
  167. goto out;
  168. minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
  169. pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
  170. delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
  171. err = bcm43xx_switch_core(bcm, old_core);
  172. assert(err == 0);
  173. out:
  174. return delay;
  175. }
  176. /* set the powercontrol clock
  177. * as described in http://bcm-specs.sipsolutions.net/PowerControl
  178. */
  179. int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
  180. {
  181. int err;
  182. struct bcm43xx_coreinfo *old_core;
  183. u32 tmp;
  184. old_core = bcm->current_core;
  185. err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  186. if (err == -ENODEV)
  187. return 0;
  188. if (err)
  189. goto out;
  190. if (bcm->core_chipcommon.rev < 6) {
  191. if (mode == BCM43xx_PCTL_CLK_FAST) {
  192. err = bcm43xx_pctl_set_crystal(bcm, 1);
  193. if (err)
  194. goto out;
  195. }
  196. } else {
  197. if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
  198. (bcm->core_chipcommon.rev < 10)) {
  199. switch (mode) {
  200. case BCM43xx_PCTL_CLK_FAST:
  201. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  202. tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
  203. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
  204. break;
  205. case BCM43xx_PCTL_CLK_SLOW:
  206. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  207. tmp |= BCM43xx_PCTL_FORCE_SLOW;
  208. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
  209. break;
  210. case BCM43xx_PCTL_CLK_DYNAMIC:
  211. tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
  212. tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
  213. tmp |= BCM43xx_PCTL_FORCE_PLL;
  214. tmp &= ~BCM43xx_PCTL_DYN_XTAL;
  215. bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
  216. }
  217. }
  218. }
  219. err = bcm43xx_switch_core(bcm, old_core);
  220. assert(err == 0);
  221. out:
  222. return err;
  223. }
  224. int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
  225. {
  226. int err;
  227. u32 in, out, outenable;
  228. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
  229. if (err)
  230. goto err_pci;
  231. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
  232. if (err)
  233. goto err_pci;
  234. err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
  235. if (err)
  236. goto err_pci;
  237. outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
  238. if (on) {
  239. if (in & 0x40)
  240. return 0;
  241. out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
  242. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
  243. if (err)
  244. goto err_pci;
  245. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
  246. if (err)
  247. goto err_pci;
  248. udelay(1000);
  249. out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
  250. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
  251. if (err)
  252. goto err_pci;
  253. udelay(5000);
  254. } else {
  255. if (bcm->current_core->rev < 5)
  256. return 0;
  257. if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
  258. return 0;
  259. /* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
  260. * err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
  261. * if (err)
  262. * return err;
  263. * if (((bcm->current_core->rev >= 3) &&
  264. * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
  265. * ((bcm->current_core->rev < 3) &&
  266. * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
  267. * return 0;
  268. * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
  269. * if (err)
  270. * return err;
  271. */
  272. err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
  273. if (err)
  274. goto out;
  275. out &= ~BCM43xx_PCTL_XTAL_POWERUP;
  276. out |= BCM43xx_PCTL_PLL_POWERDOWN;
  277. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
  278. if (err)
  279. goto err_pci;
  280. err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
  281. if (err)
  282. goto err_pci;
  283. }
  284. out:
  285. return err;
  286. err_pci:
  287. printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
  288. err = -EBUSY;
  289. goto out;
  290. }
  291. /* Set the PowerSavingControlBits.
  292. * Bitvalues:
  293. * 0 => unset the bit
  294. * 1 => set the bit
  295. * -1 => calculate the bit
  296. */
  297. void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
  298. int bit25, int bit26)
  299. {
  300. int i;
  301. u32 status;
  302. //FIXME: Force 25 to off and 26 to on for now:
  303. bit25 = 0;
  304. bit26 = 1;
  305. if (bit25 == -1) {
  306. //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
  307. // and thus is not an AP and we are associated, set bit 25
  308. }
  309. if (bit26 == -1) {
  310. //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
  311. // or we are associated, or FIXME, or the latest PS-Poll packet sent was
  312. // successful, set bit26
  313. }
  314. status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
  315. if (bit25)
  316. status |= BCM43xx_SBF_PS1;
  317. else
  318. status &= ~BCM43xx_SBF_PS1;
  319. if (bit26)
  320. status |= BCM43xx_SBF_PS2;
  321. else
  322. status &= ~BCM43xx_SBF_PS2;
  323. bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
  324. if (bit26 && bcm->current_core->rev >= 5) {
  325. for (i = 0; i < 100; i++) {
  326. if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
  327. break;
  328. udelay(10);
  329. }
  330. }
  331. }