hdmi_pll_8960.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016, The Linux Foundation. All rights reserved.
  4. * Copyright (C) 2013 Red Hat
  5. * Author: Rob Clark <robdclark@gmail.com>
  6. */
  7. #include <linux/clk-provider.h>
  8. #include <linux/delay.h>
  9. #include "hdmi.h"
  10. struct hdmi_pll_8960 {
  11. struct platform_device *pdev;
  12. struct clk_hw clk_hw;
  13. void __iomem *mmio;
  14. unsigned long pixclk;
  15. };
  16. #define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8960, clk_hw)
  17. /*
  18. * HDMI PLL:
  19. *
  20. * To get the parent clock setup properly, we need to plug in hdmi pll
  21. * configuration into common-clock-framework.
  22. */
  23. struct pll_rate {
  24. unsigned long rate;
  25. int num_reg;
  26. struct {
  27. u32 val;
  28. u32 reg;
  29. } conf[32];
  30. };
  31. /* NOTE: keep sorted highest freq to lowest: */
  32. static const struct pll_rate freqtbl[] = {
  33. { 154000000, 14, {
  34. { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  35. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  36. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  37. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  38. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  39. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  40. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  41. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  42. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  43. { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  44. { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  45. { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  46. { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  47. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  48. }
  49. },
  50. /* 1080p60/1080p50 case */
  51. { 148500000, 27, {
  52. { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  53. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  54. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  55. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  56. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  57. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  58. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  59. { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  60. { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  61. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  62. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  63. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  64. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  65. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  66. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  67. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  68. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  69. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  70. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  71. { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  72. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  73. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  74. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  75. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  76. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  77. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  78. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  79. }
  80. },
  81. { 108000000, 13, {
  82. { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  83. { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  84. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  85. { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  86. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  87. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  88. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  89. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  90. { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  91. { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  92. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  93. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  94. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  95. }
  96. },
  97. /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */
  98. { 74250000, 8, {
  99. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  100. { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  101. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  102. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  103. { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  104. { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  105. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  106. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  107. }
  108. },
  109. { 74176000, 14, {
  110. { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  111. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  112. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  113. { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  114. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  115. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  116. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  117. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  118. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  119. { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  120. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  121. { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  122. { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  123. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  124. }
  125. },
  126. { 65000000, 14, {
  127. { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  128. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  129. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  130. { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  131. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  132. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  133. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  134. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  135. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  136. { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  137. { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  138. { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  139. { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  140. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  141. }
  142. },
  143. /* 480p60/480i60 */
  144. { 27030000, 18, {
  145. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  146. { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  147. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  148. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  149. { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  150. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  151. { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  152. { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  153. { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  154. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  155. { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  156. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  157. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  158. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  159. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  160. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  161. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  162. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  163. }
  164. },
  165. /* 576p50/576i50 */
  166. { 27000000, 27, {
  167. { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  168. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  169. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  170. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  171. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  172. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  173. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  174. { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  175. { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  176. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  177. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  178. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  179. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  180. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  181. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  182. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  183. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  184. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  185. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  186. { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  187. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  188. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  189. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  190. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  191. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  192. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  193. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  194. }
  195. },
  196. /* 640x480p60 */
  197. { 25200000, 27, {
  198. { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  199. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  200. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  201. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  202. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  203. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  204. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  205. { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  206. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  207. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  208. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  209. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  210. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  211. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  212. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  213. { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  214. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  215. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  216. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  217. { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  218. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  219. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  220. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  221. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  222. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  223. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  224. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  225. }
  226. },
  227. };
  228. static inline void pll_write(struct hdmi_pll_8960 *pll, u32 reg, u32 data)
  229. {
  230. writel(data, pll->mmio + reg);
  231. }
  232. static inline u32 pll_read(struct hdmi_pll_8960 *pll, u32 reg)
  233. {
  234. return readl(pll->mmio + reg);
  235. }
  236. static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8960 *pll)
  237. {
  238. return platform_get_drvdata(pll->pdev);
  239. }
  240. static int hdmi_pll_enable(struct clk_hw *hw)
  241. {
  242. struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
  243. struct hdmi_phy *phy = pll_get_phy(pll);
  244. int timeout_count, pll_lock_retry = 10;
  245. unsigned int val;
  246. DBG("");
  247. /* Assert PLL S/W reset */
  248. pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
  249. pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
  250. pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a);
  251. /* Wait for a short time before de-asserting
  252. * to allow the hardware to complete its job.
  253. * This much of delay should be fine for hardware
  254. * to assert and de-assert.
  255. */
  256. udelay(10);
  257. /* De-assert PLL S/W reset */
  258. pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
  259. val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
  260. val |= HDMI_8960_PHY_REG12_SW_RESET;
  261. /* Assert PHY S/W reset */
  262. hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
  263. val &= ~HDMI_8960_PHY_REG12_SW_RESET;
  264. /*
  265. * Wait for a short time before de-asserting to allow the hardware to
  266. * complete its job. This much of delay should be fine for hardware to
  267. * assert and de-assert.
  268. */
  269. udelay(10);
  270. /* De-assert PHY S/W reset */
  271. hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
  272. hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x3f);
  273. val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
  274. val |= HDMI_8960_PHY_REG12_PWRDN_B;
  275. hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
  276. /* Wait 10 us for enabling global power for PHY */
  277. mb();
  278. udelay(10);
  279. val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
  280. val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
  281. val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
  282. pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
  283. hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80);
  284. timeout_count = 1000;
  285. while (--pll_lock_retry > 0) {
  286. /* are we there yet? */
  287. val = pll_read(pll, REG_HDMI_8960_PHY_PLL_STATUS0);
  288. if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK)
  289. break;
  290. udelay(1);
  291. if (--timeout_count > 0)
  292. continue;
  293. /*
  294. * PLL has still not locked.
  295. * Do a software reset and try again
  296. * Assert PLL S/W reset first
  297. */
  298. pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
  299. udelay(10);
  300. pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
  301. /*
  302. * Wait for a short duration for the PLL calibration
  303. * before checking if the PLL gets locked
  304. */
  305. udelay(350);
  306. timeout_count = 1000;
  307. }
  308. return 0;
  309. }
  310. static void hdmi_pll_disable(struct clk_hw *hw)
  311. {
  312. struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
  313. struct hdmi_phy *phy = pll_get_phy(pll);
  314. unsigned int val;
  315. DBG("");
  316. val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
  317. val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
  318. hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
  319. val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
  320. val |= HDMI_8960_PHY_REG12_SW_RESET;
  321. val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
  322. pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
  323. /* Make sure HDMI PHY/PLL are powered down */
  324. mb();
  325. }
  326. static const struct pll_rate *find_rate(unsigned long rate)
  327. {
  328. int i;
  329. for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
  330. if (rate > freqtbl[i].rate)
  331. return &freqtbl[i - 1];
  332. return &freqtbl[i - 1];
  333. }
  334. static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
  335. unsigned long parent_rate)
  336. {
  337. struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
  338. return pll->pixclk;
  339. }
  340. static int hdmi_pll_determine_rate(struct clk_hw *hw,
  341. struct clk_rate_request *req)
  342. {
  343. const struct pll_rate *pll_rate = find_rate(req->rate);
  344. req->rate = pll_rate->rate;
  345. return 0;
  346. }
  347. static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
  348. unsigned long parent_rate)
  349. {
  350. struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
  351. const struct pll_rate *pll_rate = find_rate(rate);
  352. int i;
  353. DBG("rate=%lu", rate);
  354. for (i = 0; i < pll_rate->num_reg; i++)
  355. pll_write(pll, pll_rate->conf[i].reg, pll_rate->conf[i].val);
  356. pll->pixclk = rate;
  357. return 0;
  358. }
  359. static const struct clk_ops hdmi_pll_ops = {
  360. .enable = hdmi_pll_enable,
  361. .disable = hdmi_pll_disable,
  362. .recalc_rate = hdmi_pll_recalc_rate,
  363. .determine_rate = hdmi_pll_determine_rate,
  364. .set_rate = hdmi_pll_set_rate,
  365. };
  366. static const struct clk_parent_data hdmi_pll_parents[] = {
  367. { .fw_name = "pxo", .name = "pxo_board" },
  368. };
  369. static struct clk_init_data pll_init = {
  370. .name = "hdmi_pll",
  371. .ops = &hdmi_pll_ops,
  372. .parent_data = hdmi_pll_parents,
  373. .num_parents = ARRAY_SIZE(hdmi_pll_parents),
  374. .flags = CLK_IGNORE_UNUSED,
  375. };
  376. int msm_hdmi_pll_8960_init(struct platform_device *pdev)
  377. {
  378. struct device *dev = &pdev->dev;
  379. struct hdmi_pll_8960 *pll;
  380. int i, ret;
  381. /* sanity check: */
  382. for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
  383. if (WARN_ON(freqtbl[i].rate < freqtbl[i + 1].rate))
  384. return -EINVAL;
  385. pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
  386. if (!pll)
  387. return -ENOMEM;
  388. pll->mmio = msm_ioremap(pdev, "hdmi_pll");
  389. if (IS_ERR(pll->mmio)) {
  390. DRM_DEV_ERROR(dev, "failed to map pll base\n");
  391. return -ENOMEM;
  392. }
  393. pll->pdev = pdev;
  394. pll->clk_hw.init = &pll_init;
  395. ret = devm_clk_hw_register(dev, &pll->clk_hw);
  396. if (ret < 0) {
  397. DRM_DEV_ERROR(dev, "failed to register pll clock\n");
  398. return ret;
  399. }
  400. ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
  401. if (ret) {
  402. DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
  403. return ret;
  404. }
  405. return 0;
  406. }