hdmi_phy_8960.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * Copyright (C) 2013 Red Hat
  3. * Author: Rob Clark <robdclark@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 as published by
  7. * the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #ifdef CONFIG_COMMON_CLK
  18. #include <linux/clk.h>
  19. #include <linux/clk-provider.h>
  20. #endif
  21. #include "hdmi.h"
  22. struct hdmi_phy_8960 {
  23. struct hdmi_phy base;
  24. struct hdmi *hdmi;
  25. #ifdef CONFIG_COMMON_CLK
  26. struct clk_hw pll_hw;
  27. struct clk *pll;
  28. unsigned long pixclk;
  29. #endif
  30. };
  31. #define to_hdmi_phy_8960(x) container_of(x, struct hdmi_phy_8960, base)
  32. #ifdef CONFIG_COMMON_CLK
  33. #define clk_to_phy(x) container_of(x, struct hdmi_phy_8960, pll_hw)
  34. /*
  35. * HDMI PLL:
  36. *
  37. * To get the parent clock setup properly, we need to plug in hdmi pll
  38. * configuration into common-clock-framework.
  39. */
  40. struct pll_rate {
  41. unsigned long rate;
  42. struct {
  43. uint32_t val;
  44. uint32_t reg;
  45. } conf[32];
  46. };
  47. /* NOTE: keep sorted highest freq to lowest: */
  48. static const struct pll_rate freqtbl[] = {
  49. { 154000000, {
  50. { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  51. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  52. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  53. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  54. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  55. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  56. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  57. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  58. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  59. { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  60. { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  61. { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  62. { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  63. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  64. { 0, 0 } }
  65. },
  66. /* 1080p60/1080p50 case */
  67. { 148500000, {
  68. { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  69. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  70. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  71. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  72. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  73. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  74. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  75. { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  76. { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  77. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  78. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  79. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  80. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  81. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  82. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  83. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  84. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  85. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  86. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  87. { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  88. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  89. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  90. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  91. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  92. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  93. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  94. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  95. { 0, 0 } }
  96. },
  97. { 108000000, {
  98. { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  99. { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  100. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  101. { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  102. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  103. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  104. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  105. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  106. { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  107. { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  108. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  109. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  110. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  111. { 0, 0 } }
  112. },
  113. /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */
  114. { 74250000, {
  115. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  116. { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  117. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  118. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  119. { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  120. { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  121. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  122. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  123. { 0, 0 } }
  124. },
  125. { 74176000, {
  126. { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  127. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  128. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  129. { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  130. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  131. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  132. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  133. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  134. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  135. { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  136. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  137. { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  138. { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  139. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  140. { 0, 0 } }
  141. },
  142. { 65000000, {
  143. { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  144. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  145. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  146. { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  147. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  148. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  149. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  150. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  151. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  152. { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  153. { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  154. { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  155. { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  156. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  157. { 0, 0 } }
  158. },
  159. /* 480p60/480i60 */
  160. { 27030000, {
  161. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  162. { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  163. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  164. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  165. { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  166. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  167. { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  168. { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  169. { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  170. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  171. { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  172. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  173. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  174. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  175. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  176. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  177. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  178. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  179. { 0, 0 } }
  180. },
  181. /* 576p50/576i50 */
  182. { 27000000, {
  183. { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  184. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  185. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  186. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  187. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  188. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  189. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  190. { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  191. { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  192. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  193. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  194. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  195. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  196. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  197. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  198. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  199. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  200. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  201. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  202. { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  203. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  204. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  205. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  206. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  207. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  208. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  209. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  210. { 0, 0 } }
  211. },
  212. /* 640x480p60 */
  213. { 25200000, {
  214. { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  215. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  216. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  217. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  218. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  219. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  220. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  221. { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  222. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  223. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  224. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  225. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  226. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  227. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  228. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  229. { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  230. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  231. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  232. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  233. { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  234. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  235. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  236. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  237. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  238. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  239. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  240. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  241. { 0, 0 } }
  242. },
  243. };
  244. static int hdmi_pll_enable(struct clk_hw *hw)
  245. {
  246. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  247. struct hdmi *hdmi = phy_8960->hdmi;
  248. int timeout_count, pll_lock_retry = 10;
  249. unsigned int val;
  250. DBG("");
  251. /* Assert PLL S/W reset */
  252. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
  253. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
  254. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a);
  255. /* Wait for a short time before de-asserting
  256. * to allow the hardware to complete its job.
  257. * This much of delay should be fine for hardware
  258. * to assert and de-assert.
  259. */
  260. udelay(10);
  261. /* De-assert PLL S/W reset */
  262. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
  263. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12);
  264. val |= HDMI_8960_PHY_REG12_SW_RESET;
  265. /* Assert PHY S/W reset */
  266. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  267. val &= ~HDMI_8960_PHY_REG12_SW_RESET;
  268. /* Wait for a short time before de-asserting
  269. to allow the hardware to complete its job.
  270. This much of delay should be fine for hardware
  271. to assert and de-assert. */
  272. udelay(10);
  273. /* De-assert PHY S/W reset */
  274. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  275. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x3f);
  276. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12);
  277. val |= HDMI_8960_PHY_REG12_PWRDN_B;
  278. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  279. /* Wait 10 us for enabling global power for PHY */
  280. mb();
  281. udelay(10);
  282. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B);
  283. val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
  284. val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
  285. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
  286. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x80);
  287. timeout_count = 1000;
  288. while (--pll_lock_retry > 0) {
  289. /* are we there yet? */
  290. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_STATUS0);
  291. if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK)
  292. break;
  293. udelay(1);
  294. if (--timeout_count > 0)
  295. continue;
  296. /*
  297. * PLL has still not locked.
  298. * Do a software reset and try again
  299. * Assert PLL S/W reset first
  300. */
  301. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
  302. udelay(10);
  303. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
  304. /*
  305. * Wait for a short duration for the PLL calibration
  306. * before checking if the PLL gets locked
  307. */
  308. udelay(350);
  309. timeout_count = 1000;
  310. }
  311. return 0;
  312. }
  313. static void hdmi_pll_disable(struct clk_hw *hw)
  314. {
  315. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  316. struct hdmi *hdmi = phy_8960->hdmi;
  317. unsigned int val;
  318. DBG("");
  319. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12);
  320. val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
  321. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  322. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B);
  323. val |= HDMI_8960_PHY_REG12_SW_RESET;
  324. val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
  325. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
  326. /* Make sure HDMI PHY/PLL are powered down */
  327. mb();
  328. }
  329. static const struct pll_rate *find_rate(unsigned long rate)
  330. {
  331. int i;
  332. for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
  333. if (rate > freqtbl[i].rate)
  334. return &freqtbl[i-1];
  335. return &freqtbl[i-1];
  336. }
  337. static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
  338. unsigned long parent_rate)
  339. {
  340. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  341. return phy_8960->pixclk;
  342. }
  343. static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
  344. unsigned long *parent_rate)
  345. {
  346. const struct pll_rate *pll_rate = find_rate(rate);
  347. return pll_rate->rate;
  348. }
  349. static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
  350. unsigned long parent_rate)
  351. {
  352. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  353. struct hdmi *hdmi = phy_8960->hdmi;
  354. const struct pll_rate *pll_rate = find_rate(rate);
  355. int i;
  356. DBG("rate=%lu", rate);
  357. for (i = 0; pll_rate->conf[i].reg; i++)
  358. hdmi_write(hdmi, pll_rate->conf[i].reg, pll_rate->conf[i].val);
  359. phy_8960->pixclk = rate;
  360. return 0;
  361. }
  362. static const struct clk_ops hdmi_pll_ops = {
  363. .enable = hdmi_pll_enable,
  364. .disable = hdmi_pll_disable,
  365. .recalc_rate = hdmi_pll_recalc_rate,
  366. .round_rate = hdmi_pll_round_rate,
  367. .set_rate = hdmi_pll_set_rate,
  368. };
  369. static const char *hdmi_pll_parents[] = {
  370. "pxo",
  371. };
  372. static struct clk_init_data pll_init = {
  373. .name = "hdmi_pll",
  374. .ops = &hdmi_pll_ops,
  375. .parent_names = hdmi_pll_parents,
  376. .num_parents = ARRAY_SIZE(hdmi_pll_parents),
  377. };
  378. #endif
  379. /*
  380. * HDMI Phy:
  381. */
  382. static void hdmi_phy_8960_destroy(struct hdmi_phy *phy)
  383. {
  384. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  385. kfree(phy_8960);
  386. }
  387. static void hdmi_phy_8960_powerup(struct hdmi_phy *phy,
  388. unsigned long int pixclock)
  389. {
  390. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  391. struct hdmi *hdmi = phy_8960->hdmi;
  392. DBG("pixclock: %lu", pixclock);
  393. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x00);
  394. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG0, 0x1b);
  395. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG1, 0xf2);
  396. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG4, 0x00);
  397. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG5, 0x00);
  398. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG6, 0x00);
  399. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG7, 0x00);
  400. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG8, 0x00);
  401. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG9, 0x00);
  402. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG10, 0x00);
  403. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG11, 0x00);
  404. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG3, 0x20);
  405. }
  406. static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy)
  407. {
  408. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  409. struct hdmi *hdmi = phy_8960->hdmi;
  410. DBG("");
  411. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x7f);
  412. }
  413. static const struct hdmi_phy_funcs hdmi_phy_8960_funcs = {
  414. .destroy = hdmi_phy_8960_destroy,
  415. .powerup = hdmi_phy_8960_powerup,
  416. .powerdown = hdmi_phy_8960_powerdown,
  417. };
  418. struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi)
  419. {
  420. struct hdmi_phy_8960 *phy_8960;
  421. struct hdmi_phy *phy = NULL;
  422. int ret;
  423. #ifdef CONFIG_COMMON_CLK
  424. int i;
  425. /* sanity check: */
  426. for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
  427. if (WARN_ON(freqtbl[i].rate < freqtbl[i+1].rate))
  428. return ERR_PTR(-EINVAL);
  429. #endif
  430. phy_8960 = kzalloc(sizeof(*phy_8960), GFP_KERNEL);
  431. if (!phy_8960) {
  432. ret = -ENOMEM;
  433. goto fail;
  434. }
  435. phy = &phy_8960->base;
  436. phy->funcs = &hdmi_phy_8960_funcs;
  437. phy_8960->hdmi = hdmi;
  438. #ifdef CONFIG_COMMON_CLK
  439. phy_8960->pll_hw.init = &pll_init;
  440. phy_8960->pll = devm_clk_register(&hdmi->pdev->dev, &phy_8960->pll_hw);
  441. if (IS_ERR(phy_8960->pll)) {
  442. ret = PTR_ERR(phy_8960->pll);
  443. phy_8960->pll = NULL;
  444. goto fail;
  445. }
  446. #endif
  447. return phy;
  448. fail:
  449. if (phy)
  450. hdmi_phy_8960_destroy(phy);
  451. return ERR_PTR(ret);
  452. }