Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 #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
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
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
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
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
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
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
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
429 static void hdmi_phy_8960_reset(struct hdmi_phy *phy)
430 {
431         struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
432         struct hdmi *hdmi = phy_8960->hdmi;
433         unsigned int val;
434
435         val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
436
437         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
438                 /* pull low */
439                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
440                                 val & ~HDMI_PHY_CTRL_SW_RESET);
441         } else {
442                 /* pull high */
443                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
444                                 val | HDMI_PHY_CTRL_SW_RESET);
445         }
446
447         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
448                 /* pull low */
449                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
450                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
451         } else {
452                 /* pull high */
453                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
454                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
455         }
456
457         msleep(100);
458
459         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
460                 /* pull high */
461                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
462                                 val | HDMI_PHY_CTRL_SW_RESET);
463         } else {
464                 /* pull low */
465                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
466                                 val & ~HDMI_PHY_CTRL_SW_RESET);
467         }
468
469         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
470                 /* pull high */
471                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
472                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
473         } else {
474                 /* pull low */
475                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
476                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
477         }
478 }
479
480 static void hdmi_phy_8960_powerup(struct hdmi_phy *phy,
481                 unsigned long int pixclock)
482 {
483         struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
484         struct hdmi *hdmi = phy_8960->hdmi;
485
486         DBG("pixclock: %lu", pixclock);
487
488         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x00);
489         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG0, 0x1b);
490         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG1, 0xf2);
491         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG4, 0x00);
492         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG5, 0x00);
493         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG6, 0x00);
494         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG7, 0x00);
495         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG8, 0x00);
496         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG9, 0x00);
497         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG10, 0x00);
498         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG11, 0x00);
499         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG3, 0x20);
500 }
501
502 static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy)
503 {
504         struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy);
505         struct hdmi *hdmi = phy_8960->hdmi;
506
507         DBG("");
508
509         hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x7f);
510 }
511
512 static const struct hdmi_phy_funcs hdmi_phy_8960_funcs = {
513                 .destroy = hdmi_phy_8960_destroy,
514                 .reset = hdmi_phy_8960_reset,
515                 .powerup = hdmi_phy_8960_powerup,
516                 .powerdown = hdmi_phy_8960_powerdown,
517 };
518
519 struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi)
520 {
521         struct hdmi_phy_8960 *phy_8960;
522         struct hdmi_phy *phy = NULL;
523         int ret;
524 #ifdef CONFIG_COMMON_CLK
525         int i;
526
527         /* sanity check: */
528         for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
529                 if (WARN_ON(freqtbl[i].rate < freqtbl[i+1].rate))
530                         return ERR_PTR(-EINVAL);
531 #endif
532
533         phy_8960 = kzalloc(sizeof(*phy_8960), GFP_KERNEL);
534         if (!phy_8960) {
535                 ret = -ENOMEM;
536                 goto fail;
537         }
538
539         phy = &phy_8960->base;
540
541         phy->funcs = &hdmi_phy_8960_funcs;
542
543         phy_8960->hdmi = hdmi;
544
545 #ifdef CONFIG_COMMON_CLK
546         phy_8960->pll_hw.init = &pll_init;
547         phy_8960->pll = devm_clk_register(&hdmi->pdev->dev, &phy_8960->pll_hw);
548         if (IS_ERR(phy_8960->pll)) {
549                 ret = PTR_ERR(phy_8960->pll);
550                 phy_8960->pll = NULL;
551                 goto fail;
552         }
553 #endif
554
555         return phy;
556
557 fail:
558         if (phy)
559                 hdmi_phy_8960_destroy(phy);
560         return ERR_PTR(ret);
561 }