diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss/pll.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/pll.c | 129 |
1 files changed, 125 insertions, 4 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index f974ddcd3b6e..0a76c89cdc2e 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c | |||
@@ -22,8 +22,7 @@ | |||
22 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | 24 | ||
25 | #include <video/omapdss.h> | 25 | #include "omapdss.h" |
26 | |||
27 | #include "dss.h" | 26 | #include "dss.h" |
28 | 27 | ||
29 | #define PLL_CONTROL 0x0000 | 28 | #define PLL_CONTROL 0x0000 |
@@ -76,6 +75,59 @@ struct dss_pll *dss_pll_find(const char *name) | |||
76 | return NULL; | 75 | return NULL; |
77 | } | 76 | } |
78 | 77 | ||
78 | struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) | ||
79 | { | ||
80 | struct dss_pll *pll; | ||
81 | |||
82 | switch (src) { | ||
83 | default: | ||
84 | case DSS_CLK_SRC_FCK: | ||
85 | return NULL; | ||
86 | |||
87 | case DSS_CLK_SRC_HDMI_PLL: | ||
88 | return dss_pll_find("hdmi"); | ||
89 | |||
90 | case DSS_CLK_SRC_PLL1_1: | ||
91 | case DSS_CLK_SRC_PLL1_2: | ||
92 | case DSS_CLK_SRC_PLL1_3: | ||
93 | pll = dss_pll_find("dsi0"); | ||
94 | if (!pll) | ||
95 | pll = dss_pll_find("video0"); | ||
96 | return pll; | ||
97 | |||
98 | case DSS_CLK_SRC_PLL2_1: | ||
99 | case DSS_CLK_SRC_PLL2_2: | ||
100 | case DSS_CLK_SRC_PLL2_3: | ||
101 | pll = dss_pll_find("dsi1"); | ||
102 | if (!pll) | ||
103 | pll = dss_pll_find("video1"); | ||
104 | return pll; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src) | ||
109 | { | ||
110 | switch (src) { | ||
111 | case DSS_CLK_SRC_HDMI_PLL: | ||
112 | return 0; | ||
113 | |||
114 | case DSS_CLK_SRC_PLL1_1: | ||
115 | case DSS_CLK_SRC_PLL2_1: | ||
116 | return 0; | ||
117 | |||
118 | case DSS_CLK_SRC_PLL1_2: | ||
119 | case DSS_CLK_SRC_PLL2_2: | ||
120 | return 1; | ||
121 | |||
122 | case DSS_CLK_SRC_PLL1_3: | ||
123 | case DSS_CLK_SRC_PLL2_3: | ||
124 | return 2; | ||
125 | |||
126 | default: | ||
127 | return 0; | ||
128 | } | ||
129 | } | ||
130 | |||
79 | int dss_pll_enable(struct dss_pll *pll) | 131 | int dss_pll_enable(struct dss_pll *pll) |
80 | { | 132 | { |
81 | int r; | 133 | int r; |
@@ -129,7 +181,7 @@ int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cin | |||
129 | return 0; | 181 | return 0; |
130 | } | 182 | } |
131 | 183 | ||
132 | bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, | 184 | bool dss_pll_hsdiv_calc_a(const struct dss_pll *pll, unsigned long clkdco, |
133 | unsigned long out_min, unsigned long out_max, | 185 | unsigned long out_min, unsigned long out_max, |
134 | dss_hsdiv_calc_func func, void *data) | 186 | dss_hsdiv_calc_func func, void *data) |
135 | { | 187 | { |
@@ -154,7 +206,11 @@ bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, | |||
154 | return false; | 206 | return false; |
155 | } | 207 | } |
156 | 208 | ||
157 | bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, | 209 | /* |
210 | * clkdco = clkin / n * m * 2 | ||
211 | * clkoutX = clkdco / mX | ||
212 | */ | ||
213 | bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin, | ||
158 | unsigned long pll_min, unsigned long pll_max, | 214 | unsigned long pll_min, unsigned long pll_max, |
159 | dss_pll_calc_func func, void *data) | 215 | dss_pll_calc_func func, void *data) |
160 | { | 216 | { |
@@ -195,6 +251,71 @@ bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, | |||
195 | return false; | 251 | return false; |
196 | } | 252 | } |
197 | 253 | ||
254 | /* | ||
255 | * This calculates a PLL config that will provide the target_clkout rate | ||
256 | * for clkout. Additionally clkdco rate will be the same as clkout rate | ||
257 | * when clkout rate is >= min_clkdco. | ||
258 | * | ||
259 | * clkdco = clkin / n * m + clkin / n * mf / 262144 | ||
260 | * clkout = clkdco / m2 | ||
261 | */ | ||
262 | bool dss_pll_calc_b(const struct dss_pll *pll, unsigned long clkin, | ||
263 | unsigned long target_clkout, struct dss_pll_clock_info *cinfo) | ||
264 | { | ||
265 | unsigned long fint, clkdco, clkout; | ||
266 | unsigned long target_clkdco; | ||
267 | unsigned long min_dco; | ||
268 | unsigned n, m, mf, m2, sd; | ||
269 | const struct dss_pll_hw *hw = pll->hw; | ||
270 | |||
271 | DSSDBG("clkin %lu, target clkout %lu\n", clkin, target_clkout); | ||
272 | |||
273 | /* Fint */ | ||
274 | n = DIV_ROUND_UP(clkin, hw->fint_max); | ||
275 | fint = clkin / n; | ||
276 | |||
277 | /* adjust m2 so that the clkdco will be high enough */ | ||
278 | min_dco = roundup(hw->clkdco_min, fint); | ||
279 | m2 = DIV_ROUND_UP(min_dco, target_clkout); | ||
280 | if (m2 == 0) | ||
281 | m2 = 1; | ||
282 | |||
283 | target_clkdco = target_clkout * m2; | ||
284 | m = target_clkdco / fint; | ||
285 | |||
286 | clkdco = fint * m; | ||
287 | |||
288 | /* adjust clkdco with fractional mf */ | ||
289 | if (WARN_ON(target_clkdco - clkdco > fint)) | ||
290 | mf = 0; | ||
291 | else | ||
292 | mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint); | ||
293 | |||
294 | if (mf > 0) | ||
295 | clkdco += (u32)div_u64((u64)mf * fint, 262144); | ||
296 | |||
297 | clkout = clkdco / m2; | ||
298 | |||
299 | /* sigma-delta */ | ||
300 | sd = DIV_ROUND_UP(fint * m, 250000000); | ||
301 | |||
302 | DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n", | ||
303 | n, m, mf, m2, sd); | ||
304 | DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout); | ||
305 | |||
306 | cinfo->n = n; | ||
307 | cinfo->m = m; | ||
308 | cinfo->mf = mf; | ||
309 | cinfo->mX[0] = m2; | ||
310 | cinfo->sd = sd; | ||
311 | |||
312 | cinfo->fint = fint; | ||
313 | cinfo->clkdco = clkdco; | ||
314 | cinfo->clkout[0] = clkout; | ||
315 | |||
316 | return true; | ||
317 | } | ||
318 | |||
198 | static int wait_for_bit_change(void __iomem *reg, int bitnum, int value) | 319 | static int wait_for_bit_change(void __iomem *reg, int bitnum, int value) |
199 | { | 320 | { |
200 | unsigned long timeout; | 321 | unsigned long timeout; |