hdmi_phy_8960.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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. /* 1080p60/1080p50 case */
  50. { 148500000, {
  51. { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  52. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  53. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  54. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  55. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  56. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  57. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  58. { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  59. { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  60. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  61. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  62. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  63. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  64. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  65. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  66. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  67. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  68. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  69. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  70. { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  71. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  72. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  73. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  74. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  75. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  76. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  77. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  78. { 0, 0 } }
  79. },
  80. { 108000000, {
  81. { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  82. { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  83. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  84. { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  85. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  86. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  87. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  88. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  89. { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  90. { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  91. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  92. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  93. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  94. { 0, 0 } }
  95. },
  96. /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */
  97. { 74250000, {
  98. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  99. { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  100. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  101. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  102. { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  103. { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  104. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  105. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  106. { 0, 0 } }
  107. },
  108. { 65000000, {
  109. { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  110. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  111. { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  112. { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  113. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  114. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  115. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  116. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  117. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  118. { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  119. { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  120. { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  121. { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  122. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  123. { 0, 0 } }
  124. },
  125. /* 480p60/480i60 */
  126. { 27030000, {
  127. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  128. { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  129. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  130. { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  131. { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  132. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  133. { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  134. { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  135. { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  136. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  137. { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  138. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  139. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  140. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  141. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  142. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  143. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  144. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  145. { 0, 0 } }
  146. },
  147. /* 576p50/576i50 */
  148. { 27000000, {
  149. { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  150. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  151. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  152. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  153. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  154. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  155. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  156. { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  157. { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  158. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  159. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  160. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  161. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  162. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  163. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  164. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  165. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  166. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  167. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  168. { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  169. { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  170. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  171. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  172. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  173. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  174. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  175. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  176. { 0, 0 } }
  177. },
  178. /* 640x480p60 */
  179. { 25200000, {
  180. { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
  181. { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
  182. { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
  183. { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
  184. { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
  185. { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
  186. { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
  187. { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
  188. { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
  189. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
  190. { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
  191. { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
  192. { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
  193. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
  194. { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
  195. { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
  196. { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
  197. { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
  198. { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
  199. { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
  200. { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
  201. { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
  202. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
  203. { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
  204. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
  205. { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
  206. { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
  207. { 0, 0 } }
  208. },
  209. };
  210. static int hdmi_pll_enable(struct clk_hw *hw)
  211. {
  212. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  213. struct hdmi *hdmi = phy_8960->hdmi;
  214. int timeout_count, pll_lock_retry = 10;
  215. unsigned int val;
  216. DBG("");
  217. /* Assert PLL S/W reset */
  218. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
  219. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
  220. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a);
  221. /* Wait for a short time before de-asserting
  222. * to allow the hardware to complete its job.
  223. * This much of delay should be fine for hardware
  224. * to assert and de-assert.
  225. */
  226. udelay(10);
  227. /* De-assert PLL S/W reset */
  228. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
  229. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12);
  230. val |= HDMI_8960_PHY_REG12_SW_RESET;
  231. /* Assert PHY S/W reset */
  232. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  233. val &= ~HDMI_8960_PHY_REG12_SW_RESET;
  234. /* Wait for a short time before de-asserting
  235. to allow the hardware to complete its job.
  236. This much of delay should be fine for hardware
  237. to assert and de-assert. */
  238. udelay(10);
  239. /* De-assert PHY S/W reset */
  240. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  241. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x3f);
  242. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12);
  243. val |= HDMI_8960_PHY_REG12_PWRDN_B;
  244. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  245. /* Wait 10 us for enabling global power for PHY */
  246. mb();
  247. udelay(10);
  248. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B);
  249. val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
  250. val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
  251. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
  252. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x80);
  253. timeout_count = 1000;
  254. while (--pll_lock_retry > 0) {
  255. /* are we there yet? */
  256. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_STATUS0);
  257. if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK)
  258. break;
  259. udelay(1);
  260. if (--timeout_count > 0)
  261. continue;
  262. /*
  263. * PLL has still not locked.
  264. * Do a software reset and try again
  265. * Assert PLL S/W reset first
  266. */
  267. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
  268. udelay(10);
  269. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
  270. /*
  271. * Wait for a short duration for the PLL calibration
  272. * before checking if the PLL gets locked
  273. */
  274. udelay(350);
  275. timeout_count = 1000;
  276. }
  277. return 0;
  278. }
  279. static void hdmi_pll_disable(struct clk_hw *hw)
  280. {
  281. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  282. struct hdmi *hdmi = phy_8960->hdmi;
  283. unsigned int val;
  284. DBG("");
  285. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12);
  286. val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
  287. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val);
  288. val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B);
  289. val |= HDMI_8960_PHY_REG12_SW_RESET;
  290. val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
  291. hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
  292. /* Make sure HDMI PHY/PLL are powered down */
  293. mb();
  294. }
  295. static const struct pll_rate *find_rate(unsigned long rate)
  296. {
  297. int i;
  298. for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
  299. if (rate > freqtbl[i].rate)
  300. return &freqtbl[i-1];
  301. return &freqtbl[i-1];
  302. }
  303. static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
  304. unsigned long parent_rate)
  305. {
  306. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  307. return phy_8960->pixclk;
  308. }
  309. static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
  310. unsigned long *parent_rate)
  311. {
  312. const struct pll_rate *pll_rate = find_rate(rate);
  313. return pll_rate->rate;
  314. }
  315. static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
  316. unsigned long parent_rate)
  317. {
  318. struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw);
  319. struct hdmi *hdmi = phy_8960->hdmi;
  320. const struct pll_rate *pll_rate = find_rate(rate);
  321. int i;
  322. DBG("rate=%lu", rate);
  323. for (i = 0; pll_rate->conf[i].reg; i++)
  324. hdmi_write(hdmi, pll_rate->conf[i].reg, pll_rate->conf[i].val);
  325. phy_8960->pixclk = rate;
  326. return 0;
  327. }
  328. static const struct clk_ops hdmi_pll_ops = {
  329. .enable = hdmi_pll_enable,
  330. .disable = hdmi_pll_disable,
  331. .recalc_rate = hdmi_pll_recalc_rate,
  332. .round_rate = hdmi_pll_round_rate,
  333. .set_rate = hdmi_pll_set_rate,
  334. };
  335. static const char *hdmi_pll_parents[] = {
  336. "pxo",
  337. };
  338. static struct clk_init_data pll_init = {
  339. .name = "hdmi_pll",
  340. .ops = &hdmi_pll_ops,
  341. .parent_names = hdmi_pll_parents,
  342. .num_parents = ARRAY_SIZE(hdmi_pll_parents),
  343. };
  344. #endif
  345. /*
  346. * HDMI Phy:
  347. */
  348. static void hdmi_phy_8960_destroy(struct hdmi_phy *phy)
  349. {
  350. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  351. kfree(phy_8960);
  352. }
  353. static void hdmi_phy_8960_reset(struct hdmi_phy *phy)
  354. {
  355. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  356. struct hdmi *hdmi = phy_8960->hdmi;
  357. unsigned int val;
  358. val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
  359. if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
  360. /* pull low */
  361. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  362. val & ~HDMI_PHY_CTRL_SW_RESET);
  363. } else {
  364. /* pull high */
  365. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  366. val | HDMI_PHY_CTRL_SW_RESET);
  367. }
  368. if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
  369. /* pull low */
  370. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  371. val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
  372. } else {
  373. /* pull high */
  374. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  375. val | HDMI_PHY_CTRL_SW_RESET_PLL);
  376. }
  377. msleep(100);
  378. if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
  379. /* pull high */
  380. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  381. val | HDMI_PHY_CTRL_SW_RESET);
  382. } else {
  383. /* pull low */
  384. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  385. val & ~HDMI_PHY_CTRL_SW_RESET);
  386. }
  387. if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
  388. /* pull high */
  389. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  390. val | HDMI_PHY_CTRL_SW_RESET_PLL);
  391. } else {
  392. /* pull low */
  393. hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
  394. val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
  395. }
  396. }
  397. static void hdmi_phy_8960_powerup(struct hdmi_phy *phy,
  398. unsigned long int pixclock)
  399. {
  400. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  401. struct hdmi *hdmi = phy_8960->hdmi;
  402. DBG("pixclock: %lu", pixclock);
  403. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x00);
  404. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG0, 0x1b);
  405. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG1, 0xf2);
  406. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG4, 0x00);
  407. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG5, 0x00);
  408. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG6, 0x00);
  409. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG7, 0x00);
  410. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG8, 0x00);
  411. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG9, 0x00);
  412. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG10, 0x00);
  413. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG11, 0x00);
  414. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG3, 0x20);
  415. }
  416. static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy)
  417. {
  418. struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
  419. struct hdmi *hdmi = phy_8960->hdmi;
  420. DBG("");
  421. hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x7f);
  422. }
  423. static const struct hdmi_phy_funcs hdmi_phy_8960_funcs = {
  424. .destroy = hdmi_phy_8960_destroy,
  425. .reset = hdmi_phy_8960_reset,
  426. .powerup = hdmi_phy_8960_powerup,
  427. .powerdown = hdmi_phy_8960_powerdown,
  428. };
  429. struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi)
  430. {
  431. struct hdmi_phy_8960 *phy_8960;
  432. struct hdmi_phy *phy = NULL;
  433. int ret;
  434. #ifdef CONFIG_COMMON_CLK
  435. int i;
  436. /* sanity check: */
  437. for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
  438. if (WARN_ON(freqtbl[i].rate < freqtbl[i+1].rate))
  439. return ERR_PTR(-EINVAL);
  440. #endif
  441. phy_8960 = kzalloc(sizeof(*phy_8960), GFP_KERNEL);
  442. if (!phy_8960) {
  443. ret = -ENOMEM;
  444. goto fail;
  445. }
  446. phy = &phy_8960->base;
  447. phy->funcs = &hdmi_phy_8960_funcs;
  448. phy_8960->hdmi = hdmi;
  449. #ifdef CONFIG_COMMON_CLK
  450. phy_8960->pll_hw.init = &pll_init;
  451. phy_8960->pll = devm_clk_register(&hdmi->pdev->dev, &phy_8960->pll_hw);
  452. if (IS_ERR(phy_8960->pll)) {
  453. ret = PTR_ERR(phy_8960->pll);
  454. phy_8960->pll = NULL;
  455. goto fail;
  456. }
  457. #endif
  458. return phy;
  459. fail:
  460. if (phy)
  461. hdmi_phy_8960_destroy(phy);
  462. return ERR_PTR(ret);
  463. }