hndpmu.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Misc utility routines for accessing PMU corerev specific features
  3. * of the SiliconBackplane-based Broadcom chips.
  4. *
  5. * Copyright (C) 1999-2014, Broadcom Corporation
  6. *
  7. * Unless you and Broadcom execute a separate written software license
  8. * agreement governing use of this software, this software is licensed to you
  9. * under the terms of the GNU General Public License version 2 (the "GPL"),
  10. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  11. * following added to such license:
  12. *
  13. * As a special exception, the copyright holders of this software give you
  14. * permission to link this software with independent modules, and to copy and
  15. * distribute the resulting executable under terms of your choice, provided that
  16. * you also meet, for each linked independent module, the terms and conditions of
  17. * the license of that module. An independent module is a module which is not
  18. * derived from this software. The special exception does not apply to any
  19. * modifications of the software.
  20. *
  21. * Notwithstanding the above, under no circumstances may you combine this
  22. * software in any way with any other Broadcom software provided under a license
  23. * other than the GPL, without Broadcom's express prior written consent.
  24. *
  25. * $Id: hndpmu.c 433378 2013-10-31 17:19:39Z $
  26. */
  27. /*
  28. * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs.
  29. * However, in the context of this file the baseband ('BB') PLL/FLL is referred to.
  30. *
  31. * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used.
  32. * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012)
  33. * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports
  34. * fractional frequency generation. pmu2_ does not support fractional frequency generation.
  35. */
  36. #include <bcm_cfg.h>
  37. #include <typedefs.h>
  38. #include <bcmdefs.h>
  39. #include <osl.h>
  40. #include <bcmutils.h>
  41. #include <siutils.h>
  42. #include <bcmdevs.h>
  43. #include <hndsoc.h>
  44. #include <sbchipc.h>
  45. #include <hndpmu.h>
  46. #define PMU_ERROR(args)
  47. #define PMU_MSG(args)
  48. /* To check in verbose debugging messages not intended
  49. * to be on except on private builds.
  50. */
  51. #define PMU_NONE(args)
  52. /** contains resource bit positions for a specific chip */
  53. struct rsc_per_chip_s {
  54. uint8 ht_avail;
  55. uint8 macphy_clkavail;
  56. uint8 ht_start;
  57. uint8 otp_pu;
  58. };
  59. typedef struct rsc_per_chip_s rsc_per_chip_t;
  60. /* SDIO Pad drive strength to select value mappings.
  61. * The last strength value in each table must be 0 (the tri-state value).
  62. */
  63. typedef struct {
  64. uint8 strength; /* Pad Drive Strength in mA */
  65. uint8 sel; /* Chip-specific select value */
  66. } sdiod_drive_str_t;
  67. /* SDIO Drive Strength to sel value table for PMU Rev 1 */
  68. static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
  69. {4, 0x2},
  70. {2, 0x3},
  71. {1, 0x0},
  72. {0, 0x0} };
  73. /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
  74. static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
  75. {12, 0x7},
  76. {10, 0x6},
  77. {8, 0x5},
  78. {6, 0x4},
  79. {4, 0x2},
  80. {2, 0x1},
  81. {0, 0x0} };
  82. /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
  83. static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = {
  84. {32, 0x7},
  85. {26, 0x6},
  86. {22, 0x5},
  87. {16, 0x4},
  88. {12, 0x3},
  89. {8, 0x2},
  90. {4, 0x1},
  91. {0, 0x0} };
  92. /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */
  93. static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = {
  94. {32, 0x6},
  95. {26, 0x7},
  96. {22, 0x4},
  97. {16, 0x5},
  98. {12, 0x2},
  99. {8, 0x3},
  100. {4, 0x0},
  101. {0, 0x1} };
  102. /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
  103. /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
  104. /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
  105. static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
  106. {6, 0x7},
  107. {5, 0x6},
  108. {4, 0x5},
  109. {3, 0x4},
  110. {2, 0x2},
  111. {1, 0x1},
  112. {0, 0x0} };
  113. /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
  114. /** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
  115. static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = {
  116. {3, 0x3},
  117. {2, 0x2},
  118. {1, 0x1},
  119. {0, 0x0} };
  120. /**
  121. * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel
  122. * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture
  123. * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has
  124. * been written '1'.
  125. */
  126. #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
  127. static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = {
  128. /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */
  129. {16, 0x7},
  130. {12, 0x5},
  131. {8, 0x3},
  132. {4, 0x1} }; /* note: 43143 does not support tristate */
  133. #else
  134. static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = {
  135. /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */
  136. {8, 0x7},
  137. {6, 0x5},
  138. {4, 0x3},
  139. {2, 0x1} }; /* note: 43143 does not support tristate */
  140. #endif /* BCM_SDIO_VDDIO */
  141. #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
  142. /**
  143. * Balance between stable SDIO operation and power consumption is achieved using this function.
  144. * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this
  145. * function should read the VDDIO itself to select the correct table. For now it has been solved
  146. * with the 'BCM_SDIO_VDDIO' preprocessor constant.
  147. *
  148. * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if
  149. * hardware supports this), if no hw support drive strength is not programmed.
  150. */
  151. void
  152. si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
  153. {
  154. chipcregs_t *cc;
  155. uint origidx, intr_val = 0;
  156. sdiod_drive_str_t *str_tab = NULL;
  157. uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */
  158. uint32 str_shift = 0;
  159. uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */
  160. uint32 str_ovr_pmuval = 0; /* position of bit within this register */
  161. if (!(sih->cccaps & CC_CAP_PMU)) {
  162. return;
  163. }
  164. /* Remember original core before switch to chipc */
  165. cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
  166. switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
  167. case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
  168. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
  169. str_mask = 0x30000000;
  170. str_shift = 28;
  171. break;
  172. case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
  173. case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
  174. case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
  175. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
  176. str_mask = 0x00003800;
  177. str_shift = 11;
  178. break;
  179. case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
  180. case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11):
  181. if (sih->pmurev == 8) {
  182. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3;
  183. }
  184. else if (sih->pmurev == 11) {
  185. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
  186. }
  187. str_mask = 0x00003800;
  188. str_shift = 11;
  189. break;
  190. case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
  191. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
  192. str_mask = 0x00003800;
  193. str_shift = 11;
  194. break;
  195. case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
  196. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8;
  197. str_mask = 0x00003800;
  198. str_shift = 11;
  199. break;
  200. case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
  201. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8;
  202. str_mask = 0x00001800;
  203. str_shift = 11;
  204. break;
  205. case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
  206. #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
  207. if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) {
  208. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3;
  209. }
  210. #else
  211. if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) {
  212. str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8;
  213. }
  214. #endif /* BCM_SDIO_VDDIO */
  215. str_mask = 0x00000007;
  216. str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR;
  217. break;
  218. default:
  219. PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
  220. bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev));
  221. break;
  222. }
  223. if (str_tab != NULL && cc != NULL) {
  224. uint32 cc_data_temp;
  225. int i;
  226. /* Pick the lowest available drive strength equal or greater than the
  227. * requested strength. Drive strength of 0 requests tri-state.
  228. */
  229. for (i = 0; drivestrength < str_tab[i].strength; i++)
  230. ;
  231. if (i > 0 && drivestrength > str_tab[i].strength)
  232. i--;
  233. W_REG(osh, &cc->chipcontrol_addr, PMU_CHIPCTL1);
  234. cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
  235. cc_data_temp &= ~str_mask;
  236. cc_data_temp |= str_tab[i].sel << str_shift;
  237. W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
  238. if (str_ovr_pmuval) { /* enables the selected drive strength */
  239. W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl);
  240. OR_REG(osh, &cc->chipcontrol_data, str_ovr_pmuval);
  241. }
  242. PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n",
  243. drivestrength, str_tab[i].strength));
  244. }
  245. /* Return to original core */
  246. si_restore_core(sih, origidx, intr_val);
  247. } /* si_sdiod_drive_strength_init */