clk.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/mutex.h>
  10. #include <linux/err.h>
  11. #include <linux/clk.h>
  12. #include <linux/delay.h>
  13. #include <bcm63xx_cpu.h>
  14. #include <bcm63xx_io.h>
  15. #include <bcm63xx_regs.h>
  16. #include <bcm63xx_reset.h>
  17. #include <bcm63xx_clk.h>
  18. static DEFINE_MUTEX(clocks_mutex);
  19. static void clk_enable_unlocked(struct clk *clk)
  20. {
  21. if (clk->set && (clk->usage++) == 0)
  22. clk->set(clk, 1);
  23. }
  24. static void clk_disable_unlocked(struct clk *clk)
  25. {
  26. if (clk->set && (--clk->usage) == 0)
  27. clk->set(clk, 0);
  28. }
  29. static void bcm_hwclock_set(u32 mask, int enable)
  30. {
  31. u32 reg;
  32. reg = bcm_perf_readl(PERF_CKCTL_REG);
  33. if (enable)
  34. reg |= mask;
  35. else
  36. reg &= ~mask;
  37. bcm_perf_writel(reg, PERF_CKCTL_REG);
  38. }
  39. /*
  40. * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
  41. */
  42. static void enet_misc_set(struct clk *clk, int enable)
  43. {
  44. u32 mask;
  45. if (BCMCPU_IS_6338())
  46. mask = CKCTL_6338_ENET_EN;
  47. else if (BCMCPU_IS_6345())
  48. mask = CKCTL_6345_ENET_EN;
  49. else if (BCMCPU_IS_6348())
  50. mask = CKCTL_6348_ENET_EN;
  51. else
  52. /* BCMCPU_IS_6358 */
  53. mask = CKCTL_6358_EMUSB_EN;
  54. bcm_hwclock_set(mask, enable);
  55. }
  56. static struct clk clk_enet_misc = {
  57. .set = enet_misc_set,
  58. };
  59. /*
  60. * Ethernet MAC clocks: only revelant on 6358, silently enable misc
  61. * clocks
  62. */
  63. static void enetx_set(struct clk *clk, int enable)
  64. {
  65. if (enable)
  66. clk_enable_unlocked(&clk_enet_misc);
  67. else
  68. clk_disable_unlocked(&clk_enet_misc);
  69. if (BCMCPU_IS_6358()) {
  70. u32 mask;
  71. if (clk->id == 0)
  72. mask = CKCTL_6358_ENET0_EN;
  73. else
  74. mask = CKCTL_6358_ENET1_EN;
  75. bcm_hwclock_set(mask, enable);
  76. }
  77. }
  78. static struct clk clk_enet0 = {
  79. .id = 0,
  80. .set = enetx_set,
  81. };
  82. static struct clk clk_enet1 = {
  83. .id = 1,
  84. .set = enetx_set,
  85. };
  86. /*
  87. * Ethernet PHY clock
  88. */
  89. static void ephy_set(struct clk *clk, int enable)
  90. {
  91. if (!BCMCPU_IS_6358())
  92. return;
  93. bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
  94. }
  95. static struct clk clk_ephy = {
  96. .set = ephy_set,
  97. };
  98. /*
  99. * Ethernet switch clock
  100. */
  101. static void enetsw_set(struct clk *clk, int enable)
  102. {
  103. if (!BCMCPU_IS_6368())
  104. return;
  105. bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
  106. CKCTL_6368_SWPKT_USB_EN |
  107. CKCTL_6368_SWPKT_SAR_EN, enable);
  108. if (enable) {
  109. /* reset switch core afer clock change */
  110. bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
  111. msleep(10);
  112. bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
  113. msleep(10);
  114. }
  115. }
  116. static struct clk clk_enetsw = {
  117. .set = enetsw_set,
  118. };
  119. /*
  120. * PCM clock
  121. */
  122. static void pcm_set(struct clk *clk, int enable)
  123. {
  124. if (!BCMCPU_IS_6358())
  125. return;
  126. bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
  127. }
  128. static struct clk clk_pcm = {
  129. .set = pcm_set,
  130. };
  131. /*
  132. * USB host clock
  133. */
  134. static void usbh_set(struct clk *clk, int enable)
  135. {
  136. if (BCMCPU_IS_6328())
  137. bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
  138. else if (BCMCPU_IS_6348())
  139. bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
  140. else if (BCMCPU_IS_6368())
  141. bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
  142. }
  143. static struct clk clk_usbh = {
  144. .set = usbh_set,
  145. };
  146. /*
  147. * USB device clock
  148. */
  149. static void usbd_set(struct clk *clk, int enable)
  150. {
  151. if (BCMCPU_IS_6328())
  152. bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
  153. else if (BCMCPU_IS_6368())
  154. bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
  155. }
  156. static struct clk clk_usbd = {
  157. .set = usbd_set,
  158. };
  159. /*
  160. * SPI clock
  161. */
  162. static void spi_set(struct clk *clk, int enable)
  163. {
  164. u32 mask;
  165. if (BCMCPU_IS_6338())
  166. mask = CKCTL_6338_SPI_EN;
  167. else if (BCMCPU_IS_6348())
  168. mask = CKCTL_6348_SPI_EN;
  169. else if (BCMCPU_IS_6358())
  170. mask = CKCTL_6358_SPI_EN;
  171. else
  172. /* BCMCPU_IS_6368 */
  173. mask = CKCTL_6368_SPI_EN;
  174. bcm_hwclock_set(mask, enable);
  175. }
  176. static struct clk clk_spi = {
  177. .set = spi_set,
  178. };
  179. /*
  180. * XTM clock
  181. */
  182. static void xtm_set(struct clk *clk, int enable)
  183. {
  184. if (!BCMCPU_IS_6368())
  185. return;
  186. bcm_hwclock_set(CKCTL_6368_SAR_EN |
  187. CKCTL_6368_SWPKT_SAR_EN, enable);
  188. if (enable) {
  189. /* reset sar core afer clock change */
  190. bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
  191. mdelay(1);
  192. bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
  193. mdelay(1);
  194. }
  195. }
  196. static struct clk clk_xtm = {
  197. .set = xtm_set,
  198. };
  199. /*
  200. * IPsec clock
  201. */
  202. static void ipsec_set(struct clk *clk, int enable)
  203. {
  204. bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
  205. }
  206. static struct clk clk_ipsec = {
  207. .set = ipsec_set,
  208. };
  209. /*
  210. * PCIe clock
  211. */
  212. static void pcie_set(struct clk *clk, int enable)
  213. {
  214. bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
  215. }
  216. static struct clk clk_pcie = {
  217. .set = pcie_set,
  218. };
  219. /*
  220. * Internal peripheral clock
  221. */
  222. static struct clk clk_periph = {
  223. .rate = (50 * 1000 * 1000),
  224. };
  225. /*
  226. * Linux clock API implementation
  227. */
  228. int clk_enable(struct clk *clk)
  229. {
  230. mutex_lock(&clocks_mutex);
  231. clk_enable_unlocked(clk);
  232. mutex_unlock(&clocks_mutex);
  233. return 0;
  234. }
  235. EXPORT_SYMBOL(clk_enable);
  236. void clk_disable(struct clk *clk)
  237. {
  238. mutex_lock(&clocks_mutex);
  239. clk_disable_unlocked(clk);
  240. mutex_unlock(&clocks_mutex);
  241. }
  242. EXPORT_SYMBOL(clk_disable);
  243. unsigned long clk_get_rate(struct clk *clk)
  244. {
  245. return clk->rate;
  246. }
  247. EXPORT_SYMBOL(clk_get_rate);
  248. struct clk *clk_get(struct device *dev, const char *id)
  249. {
  250. if (!strcmp(id, "enet0"))
  251. return &clk_enet0;
  252. if (!strcmp(id, "enet1"))
  253. return &clk_enet1;
  254. if (!strcmp(id, "enetsw"))
  255. return &clk_enetsw;
  256. if (!strcmp(id, "ephy"))
  257. return &clk_ephy;
  258. if (!strcmp(id, "usbh"))
  259. return &clk_usbh;
  260. if (!strcmp(id, "usbd"))
  261. return &clk_usbd;
  262. if (!strcmp(id, "spi"))
  263. return &clk_spi;
  264. if (!strcmp(id, "xtm"))
  265. return &clk_xtm;
  266. if (!strcmp(id, "periph"))
  267. return &clk_periph;
  268. if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
  269. return &clk_pcm;
  270. if (BCMCPU_IS_6368() && !strcmp(id, "ipsec"))
  271. return &clk_ipsec;
  272. if (BCMCPU_IS_6328() && !strcmp(id, "pcie"))
  273. return &clk_pcie;
  274. return ERR_PTR(-ENOENT);
  275. }
  276. EXPORT_SYMBOL(clk_get);
  277. void clk_put(struct clk *clk)
  278. {
  279. }
  280. EXPORT_SYMBOL(clk_put);