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