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