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