Commit | Line | Data |
---|---|---|
ea184891 AT |
1 | /* |
2 | * Copyright (c) 2016, The Linux Foundation. All rights reserved. | |
3 | * Copyright (C) 2013 Red Hat | |
4 | * Author: Rob Clark <robdclark@gmail.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License version 2 as published by | |
8 | * the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along with | |
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include <linux/clk-provider.h> | |
20 | #include "hdmi.h" | |
21 | ||
22 | struct hdmi_pll_8960 { | |
23 | struct platform_device *pdev; | |
24 | struct clk_hw clk_hw; | |
25 | void __iomem *mmio; | |
26 | ||
27 | unsigned long pixclk; | |
28 | }; | |
29 | ||
30 | #define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8960, clk_hw) | |
31 | ||
32 | /* | |
33 | * HDMI PLL: | |
34 | * | |
35 | * To get the parent clock setup properly, we need to plug in hdmi pll | |
36 | * configuration into common-clock-framework. | |
37 | */ | |
38 | ||
39 | struct pll_rate { | |
40 | unsigned long rate; | |
41 | int num_reg; | |
42 | struct { | |
43 | u32 val; | |
44 | u32 reg; | |
45 | } conf[32]; | |
46 | }; | |
47 | ||
48 | /* NOTE: keep sorted highest freq to lowest: */ | |
49 | static const struct pll_rate freqtbl[] = { | |
50 | { 154000000, 14, { | |
51 | { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
52 | { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
53 | { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
54 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
55 | { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
56 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
57 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
58 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
59 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
60 | { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
61 | { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
62 | { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
63 | { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
64 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
65 | } | |
66 | }, | |
67 | /* 1080p60/1080p50 case */ | |
68 | { 148500000, 27, { | |
69 | { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
70 | { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, | |
71 | { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
72 | { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
73 | { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, | |
74 | { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, | |
75 | { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, | |
76 | { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
77 | { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
78 | { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
79 | { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
80 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
81 | { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, | |
82 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, | |
83 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, | |
84 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, | |
85 | { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, | |
86 | { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, | |
87 | { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, | |
88 | { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
89 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
90 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
91 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
92 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
93 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
94 | { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, | |
95 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, | |
96 | } | |
97 | }, | |
98 | { 108000000, 13, { | |
99 | { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
100 | { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
101 | { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
102 | { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
103 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
104 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
105 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
106 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
107 | { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
108 | { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
109 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
110 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
111 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
112 | } | |
113 | }, | |
114 | /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */ | |
115 | { 74250000, 8, { | |
116 | { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, | |
117 | { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
118 | { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
119 | { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
120 | { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
121 | { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
122 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
123 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
124 | } | |
125 | }, | |
126 | { 74176000, 14, { | |
127 | { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
128 | { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
129 | { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
130 | { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
131 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
132 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
133 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
134 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
135 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
136 | { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
137 | { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
138 | { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
139 | { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
140 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
141 | } | |
142 | }, | |
143 | { 65000000, 14, { | |
144 | { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
145 | { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
146 | { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
147 | { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
148 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
149 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
150 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
151 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
152 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
153 | { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
154 | { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
155 | { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
156 | { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
157 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
158 | } | |
159 | }, | |
160 | /* 480p60/480i60 */ | |
161 | { 27030000, 18, { | |
162 | { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, | |
163 | { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
164 | { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, | |
165 | { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
166 | { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
167 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
168 | { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
169 | { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
170 | { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
171 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
172 | { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
173 | { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
174 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
175 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
176 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
177 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
178 | { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, | |
179 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, | |
180 | } | |
181 | }, | |
182 | /* 576p50/576i50 */ | |
183 | { 27000000, 27, { | |
184 | { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
185 | { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, | |
186 | { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
187 | { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
188 | { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, | |
189 | { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, | |
190 | { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, | |
191 | { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
192 | { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
193 | { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
194 | { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
195 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
196 | { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, | |
197 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, | |
198 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, | |
199 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, | |
200 | { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, | |
201 | { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, | |
202 | { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, | |
203 | { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
204 | { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
205 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
206 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
207 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
208 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
209 | { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, | |
210 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, | |
211 | } | |
212 | }, | |
213 | /* 640x480p60 */ | |
214 | { 25200000, 27, { | |
215 | { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, | |
216 | { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, | |
217 | { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, | |
218 | { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, | |
219 | { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, | |
220 | { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, | |
221 | { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, | |
222 | { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, | |
223 | { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, | |
224 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, | |
225 | { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, | |
226 | { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, | |
227 | { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, | |
228 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, | |
229 | { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, | |
230 | { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, | |
231 | { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, | |
232 | { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, | |
233 | { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, | |
234 | { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, | |
235 | { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, | |
236 | { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, | |
237 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, | |
238 | { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, | |
239 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, | |
240 | { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, | |
241 | { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, | |
242 | } | |
243 | }, | |
244 | }; | |
245 | ||
246 | static inline void pll_write(struct hdmi_pll_8960 *pll, u32 reg, u32 data) | |
247 | { | |
248 | msm_writel(data, pll->mmio + reg); | |
249 | } | |
250 | ||
251 | static inline u32 pll_read(struct hdmi_pll_8960 *pll, u32 reg) | |
252 | { | |
253 | return msm_readl(pll->mmio + reg); | |
254 | } | |
255 | ||
256 | static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8960 *pll) | |
257 | { | |
258 | return platform_get_drvdata(pll->pdev); | |
259 | } | |
260 | ||
261 | static int hdmi_pll_enable(struct clk_hw *hw) | |
262 | { | |
263 | struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw); | |
264 | struct hdmi_phy *phy = pll_get_phy(pll); | |
265 | int timeout_count, pll_lock_retry = 10; | |
266 | unsigned int val; | |
267 | ||
268 | DBG(""); | |
269 | ||
270 | /* Assert PLL S/W reset */ | |
271 | pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d); | |
272 | pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10); | |
273 | pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a); | |
274 | ||
275 | /* Wait for a short time before de-asserting | |
276 | * to allow the hardware to complete its job. | |
277 | * This much of delay should be fine for hardware | |
278 | * to assert and de-assert. | |
279 | */ | |
280 | udelay(10); | |
281 | ||
282 | /* De-assert PLL S/W reset */ | |
283 | pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d); | |
284 | ||
285 | val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12); | |
286 | val |= HDMI_8960_PHY_REG12_SW_RESET; | |
287 | /* Assert PHY S/W reset */ | |
288 | hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); | |
289 | val &= ~HDMI_8960_PHY_REG12_SW_RESET; | |
290 | /* | |
291 | * Wait for a short time before de-asserting to allow the hardware to | |
292 | * complete its job. This much of delay should be fine for hardware to | |
293 | * assert and de-assert. | |
294 | */ | |
295 | udelay(10); | |
296 | /* De-assert PHY S/W reset */ | |
297 | hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); | |
298 | hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x3f); | |
299 | ||
300 | val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12); | |
301 | val |= HDMI_8960_PHY_REG12_PWRDN_B; | |
302 | hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); | |
303 | /* Wait 10 us for enabling global power for PHY */ | |
304 | mb(); | |
305 | udelay(10); | |
306 | ||
307 | val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B); | |
308 | val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B; | |
309 | val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL; | |
310 | pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val); | |
311 | hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80); | |
312 | ||
313 | timeout_count = 1000; | |
314 | while (--pll_lock_retry > 0) { | |
315 | /* are we there yet? */ | |
316 | val = pll_read(pll, REG_HDMI_8960_PHY_PLL_STATUS0); | |
317 | if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK) | |
318 | break; | |
319 | ||
320 | udelay(1); | |
321 | ||
322 | if (--timeout_count > 0) | |
323 | continue; | |
324 | ||
325 | /* | |
326 | * PLL has still not locked. | |
327 | * Do a software reset and try again | |
328 | * Assert PLL S/W reset first | |
329 | */ | |
330 | pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d); | |
331 | udelay(10); | |
332 | pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d); | |
333 | ||
334 | /* | |
335 | * Wait for a short duration for the PLL calibration | |
336 | * before checking if the PLL gets locked | |
337 | */ | |
338 | udelay(350); | |
339 | ||
340 | timeout_count = 1000; | |
341 | } | |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
346 | static void hdmi_pll_disable(struct clk_hw *hw) | |
347 | { | |
348 | struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw); | |
349 | struct hdmi_phy *phy = pll_get_phy(pll); | |
350 | unsigned int val; | |
351 | ||
352 | DBG(""); | |
353 | ||
354 | val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12); | |
355 | val &= ~HDMI_8960_PHY_REG12_PWRDN_B; | |
356 | hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); | |
357 | ||
358 | val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B); | |
359 | val |= HDMI_8960_PHY_REG12_SW_RESET; | |
360 | val &= ~HDMI_8960_PHY_REG12_PWRDN_B; | |
361 | pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val); | |
362 | /* Make sure HDMI PHY/PLL are powered down */ | |
363 | mb(); | |
364 | } | |
365 | ||
366 | static const struct pll_rate *find_rate(unsigned long rate) | |
367 | { | |
368 | int i; | |
369 | ||
370 | for (i = 1; i < ARRAY_SIZE(freqtbl); i++) | |
371 | if (rate > freqtbl[i].rate) | |
372 | return &freqtbl[i - 1]; | |
373 | ||
374 | return &freqtbl[i - 1]; | |
375 | } | |
376 | ||
377 | static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw, | |
378 | unsigned long parent_rate) | |
379 | { | |
380 | struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw); | |
381 | ||
382 | return pll->pixclk; | |
383 | } | |
384 | ||
385 | static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, | |
386 | unsigned long *parent_rate) | |
387 | { | |
388 | const struct pll_rate *pll_rate = find_rate(rate); | |
389 | ||
390 | return pll_rate->rate; | |
391 | } | |
392 | ||
393 | static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |
394 | unsigned long parent_rate) | |
395 | { | |
396 | struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw); | |
397 | const struct pll_rate *pll_rate = find_rate(rate); | |
398 | int i; | |
399 | ||
400 | DBG("rate=%lu", rate); | |
401 | ||
402 | for (i = 0; i < pll_rate->num_reg; i++) | |
403 | pll_write(pll, pll_rate->conf[i].reg, pll_rate->conf[i].val); | |
404 | ||
405 | pll->pixclk = rate; | |
406 | ||
407 | return 0; | |
408 | } | |
409 | ||
410 | static const struct clk_ops hdmi_pll_ops = { | |
411 | .enable = hdmi_pll_enable, | |
412 | .disable = hdmi_pll_disable, | |
413 | .recalc_rate = hdmi_pll_recalc_rate, | |
414 | .round_rate = hdmi_pll_round_rate, | |
415 | .set_rate = hdmi_pll_set_rate, | |
416 | }; | |
417 | ||
418 | static const char * const hdmi_pll_parents[] = { | |
419 | "pxo", | |
420 | }; | |
421 | ||
422 | static struct clk_init_data pll_init = { | |
423 | .name = "hdmi_pll", | |
424 | .ops = &hdmi_pll_ops, | |
425 | .parent_names = hdmi_pll_parents, | |
426 | .num_parents = ARRAY_SIZE(hdmi_pll_parents), | |
427 | }; | |
428 | ||
fcda50c8 | 429 | int msm_hdmi_pll_8960_init(struct platform_device *pdev) |
ea184891 AT |
430 | { |
431 | struct device *dev = &pdev->dev; | |
432 | struct hdmi_pll_8960 *pll; | |
433 | struct clk *clk; | |
434 | int i; | |
435 | ||
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 -EINVAL; | |
440 | ||
441 | pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); | |
442 | if (!pll) | |
443 | return -ENOMEM; | |
444 | ||
445 | pll->mmio = msm_ioremap(pdev, "hdmi_pll", "HDMI_PLL"); | |
446 | if (IS_ERR(pll->mmio)) { | |
447 | dev_err(dev, "failed to map pll base\n"); | |
448 | return -ENOMEM; | |
449 | } | |
450 | ||
451 | pll->pdev = pdev; | |
452 | pll->clk_hw.init = &pll_init; | |
453 | ||
454 | clk = devm_clk_register(dev, &pll->clk_hw); | |
455 | if (IS_ERR(clk)) { | |
456 | dev_err(dev, "failed to register pll clock\n"); | |
457 | return -EINVAL; | |
458 | } | |
459 | ||
460 | return 0; | |
461 | } |