Commit | Line | Data |
---|---|---|
c1577c1e AT |
1 | /* |
2 | * HDMI PLL | |
3 | * | |
4 | * Copyright (C) 2013 Texas Instruments Incorporated | |
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 | ||
ac9f2421 TV |
11 | #define DSS_SUBSYS_NAME "HDMIPLL" |
12 | ||
c1577c1e AT |
13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | |
c1577c1e AT |
15 | #include <linux/err.h> |
16 | #include <linux/io.h> | |
17 | #include <linux/platform_device.h> | |
c84c3a5b | 18 | #include <linux/clk.h> |
2d802453 | 19 | #include <linux/seq_file.h> |
c84c3a5b | 20 | |
c1577c1e AT |
21 | #include <video/omapdss.h> |
22 | ||
23 | #include "dss.h" | |
ef26958a | 24 | #include "hdmi.h" |
c1577c1e | 25 | |
c1577c1e AT |
26 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) |
27 | { | |
28 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ | |
29 | hdmi_read_reg(pll->base, r)) | |
30 | ||
31 | DUMPPLL(PLLCTRL_PLL_CONTROL); | |
32 | DUMPPLL(PLLCTRL_PLL_STATUS); | |
33 | DUMPPLL(PLLCTRL_PLL_GO); | |
34 | DUMPPLL(PLLCTRL_CFG1); | |
35 | DUMPPLL(PLLCTRL_CFG2); | |
36 | DUMPPLL(PLLCTRL_CFG3); | |
37 | DUMPPLL(PLLCTRL_SSC_CFG1); | |
38 | DUMPPLL(PLLCTRL_SSC_CFG2); | |
39 | DUMPPLL(PLLCTRL_CFG4); | |
40 | } | |
41 | ||
c84c3a5b TV |
42 | void hdmi_pll_compute(struct hdmi_pll_data *pll, |
43 | unsigned long target_tmds, struct dss_pll_clock_info *pi) | |
c1577c1e | 44 | { |
33f13120 TV |
45 | unsigned long fint, clkdco, clkout; |
46 | unsigned long target_bitclk, target_clkdco; | |
47 | unsigned long min_dco; | |
48 | unsigned n, m, mf, m2, sd; | |
c84c3a5b TV |
49 | unsigned long clkin; |
50 | const struct dss_pll_hw *hw = pll->pll.hw; | |
51 | ||
52 | clkin = clk_get_rate(pll->pll.clkin); | |
33f13120 TV |
53 | |
54 | DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds); | |
55 | ||
56 | target_bitclk = target_tmds * 10; | |
c1577c1e | 57 | |
33f13120 | 58 | /* Fint */ |
c84c3a5b | 59 | n = DIV_ROUND_UP(clkin, hw->fint_max); |
33f13120 | 60 | fint = clkin / n; |
c1577c1e | 61 | |
33f13120 | 62 | /* adjust m2 so that the clkdco will be high enough */ |
c84c3a5b | 63 | min_dco = roundup(hw->clkdco_min, fint); |
33f13120 TV |
64 | m2 = DIV_ROUND_UP(min_dco, target_bitclk); |
65 | if (m2 == 0) | |
66 | m2 = 1; | |
c1577c1e | 67 | |
33f13120 TV |
68 | target_clkdco = target_bitclk * m2; |
69 | m = target_clkdco / fint; | |
c1577c1e | 70 | |
33f13120 | 71 | clkdco = fint * m; |
c1577c1e | 72 | |
33f13120 TV |
73 | /* adjust clkdco with fractional mf */ |
74 | if (WARN_ON(target_clkdco - clkdco > fint)) | |
75 | mf = 0; | |
2d64b1b3 | 76 | else |
33f13120 TV |
77 | mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint); |
78 | ||
79 | if (mf > 0) | |
80 | clkdco += (u32)div_u64((u64)mf * fint, 262144); | |
c1577c1e | 81 | |
33f13120 TV |
82 | clkout = clkdco / m2; |
83 | ||
84 | /* sigma-delta */ | |
85 | sd = DIV_ROUND_UP(fint * m, 250000000); | |
86 | ||
87 | DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n", | |
88 | n, m, mf, m2, sd); | |
89 | DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout); | |
90 | ||
c84c3a5b TV |
91 | pi->n = n; |
92 | pi->m = m; | |
93 | pi->mf = mf; | |
94 | pi->mX[0] = m2; | |
95 | pi->sd = sd; | |
33f13120 | 96 | |
c84c3a5b | 97 | pi->fint = fint; |
33f13120 | 98 | pi->clkdco = clkdco; |
c84c3a5b | 99 | pi->clkout[0] = clkout; |
c1577c1e AT |
100 | } |
101 | ||
c84c3a5b | 102 | static int hdmi_pll_enable(struct dss_pll *dsspll) |
c1577c1e | 103 | { |
c84c3a5b | 104 | struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); |
03aafa2c | 105 | struct hdmi_wp_data *wp = pll->wp; |
c1577c1e AT |
106 | u16 r = 0; |
107 | ||
adb5ff83 TV |
108 | dss_ctrl_pll_enable(DSS_PLL_HDMI, true); |
109 | ||
c1577c1e AT |
110 | r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); |
111 | if (r) | |
112 | return r; | |
113 | ||
c1577c1e AT |
114 | return 0; |
115 | } | |
116 | ||
c84c3a5b | 117 | static void hdmi_pll_disable(struct dss_pll *dsspll) |
c1577c1e | 118 | { |
c84c3a5b | 119 | struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); |
03aafa2c TV |
120 | struct hdmi_wp_data *wp = pll->wp; |
121 | ||
c1577c1e | 122 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); |
adb5ff83 TV |
123 | |
124 | dss_ctrl_pll_enable(DSS_PLL_HDMI, false); | |
c1577c1e AT |
125 | } |
126 | ||
c84c3a5b TV |
127 | static const struct dss_pll_ops dsi_pll_ops = { |
128 | .enable = hdmi_pll_enable, | |
129 | .disable = hdmi_pll_disable, | |
130 | .set_config = dss_pll_write_config_type_b, | |
131 | }; | |
132 | ||
133 | static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { | |
134 | .n_max = 255, | |
135 | .m_min = 20, | |
136 | .m_max = 4095, | |
137 | .mX_max = 127, | |
138 | .fint_min = 500000, | |
139 | .fint_max = 2500000, | |
c84c3a5b TV |
140 | |
141 | .clkdco_min = 500000000, | |
142 | .clkdco_low = 1000000000, | |
143 | .clkdco_max = 2000000000, | |
144 | ||
145 | .n_msb = 8, | |
146 | .n_lsb = 1, | |
147 | .m_msb = 20, | |
148 | .m_lsb = 9, | |
149 | ||
150 | .mX_msb[0] = 24, | |
151 | .mX_lsb[0] = 18, | |
152 | ||
153 | .has_selfreqdco = true, | |
2d64b1b3 AT |
154 | }; |
155 | ||
c84c3a5b TV |
156 | static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { |
157 | .n_max = 255, | |
158 | .m_min = 20, | |
159 | .m_max = 2045, | |
160 | .mX_max = 127, | |
161 | .fint_min = 620000, | |
162 | .fint_max = 2500000, | |
c84c3a5b TV |
163 | |
164 | .clkdco_min = 750000000, | |
165 | .clkdco_low = 1500000000, | |
166 | .clkdco_max = 2500000000UL, | |
167 | ||
168 | .n_msb = 8, | |
169 | .n_lsb = 1, | |
170 | .m_msb = 20, | |
171 | .m_lsb = 9, | |
172 | ||
173 | .mX_msb[0] = 24, | |
174 | .mX_lsb[0] = 18, | |
175 | ||
176 | .has_selfreqdco = true, | |
177 | .has_refsel = true, | |
2d64b1b3 AT |
178 | }; |
179 | ||
c84c3a5b | 180 | static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll) |
2d64b1b3 | 181 | { |
c84c3a5b TV |
182 | struct dss_pll *pll = &hpll->pll; |
183 | struct clk *clk; | |
184 | int r; | |
2d64b1b3 | 185 | |
c84c3a5b TV |
186 | clk = devm_clk_get(&pdev->dev, "sys_clk"); |
187 | if (IS_ERR(clk)) { | |
188 | DSSERR("can't get sys_clk\n"); | |
189 | return PTR_ERR(clk); | |
2d64b1b3 AT |
190 | } |
191 | ||
c84c3a5b | 192 | pll->name = "hdmi"; |
64e22ffd | 193 | pll->id = DSS_PLL_HDMI; |
c84c3a5b TV |
194 | pll->base = hpll->base; |
195 | pll->clkin = clk; | |
196 | ||
2d64b1b3 AT |
197 | switch (omapdss_get_version()) { |
198 | case OMAPDSS_VER_OMAP4430_ES1: | |
199 | case OMAPDSS_VER_OMAP4430_ES2: | |
200 | case OMAPDSS_VER_OMAP4: | |
c84c3a5b | 201 | pll->hw = &dss_omap4_hdmi_pll_hw; |
2d64b1b3 AT |
202 | break; |
203 | ||
204 | case OMAPDSS_VER_OMAP5: | |
adb5ff83 | 205 | case OMAPDSS_VER_DRA7xx: |
c84c3a5b | 206 | pll->hw = &dss_omap5_hdmi_pll_hw; |
2d64b1b3 AT |
207 | break; |
208 | ||
209 | default: | |
210 | return -ENODEV; | |
211 | } | |
212 | ||
c84c3a5b TV |
213 | pll->ops = &dsi_pll_ops; |
214 | ||
215 | r = dss_pll_register(pll); | |
216 | if (r) | |
217 | return r; | |
2d64b1b3 AT |
218 | |
219 | return 0; | |
220 | } | |
221 | ||
03aafa2c TV |
222 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, |
223 | struct hdmi_wp_data *wp) | |
c1577c1e | 224 | { |
2d64b1b3 | 225 | int r; |
c1577c1e | 226 | struct resource *res; |
c1577c1e | 227 | |
03aafa2c TV |
228 | pll->wp = wp; |
229 | ||
77601507 | 230 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); |
c1577c1e | 231 | if (!res) { |
59b3d38a TV |
232 | DSSERR("can't get PLL mem resource\n"); |
233 | return -EINVAL; | |
c1577c1e AT |
234 | } |
235 | ||
59b3d38a | 236 | pll->base = devm_ioremap_resource(&pdev->dev, res); |
2b22df83 | 237 | if (IS_ERR(pll->base)) { |
c1577c1e | 238 | DSSERR("can't ioremap PLLCTRL\n"); |
2b22df83 | 239 | return PTR_ERR(pll->base); |
c1577c1e AT |
240 | } |
241 | ||
c84c3a5b TV |
242 | r = dsi_init_pll_data(pdev, pll); |
243 | if (r) { | |
244 | DSSERR("failed to init HDMI PLL\n"); | |
245 | return r; | |
246 | } | |
247 | ||
c1577c1e AT |
248 | return 0; |
249 | } | |
c84c3a5b TV |
250 | |
251 | void hdmi_pll_uninit(struct hdmi_pll_data *hpll) | |
252 | { | |
253 | struct dss_pll *pll = &hpll->pll; | |
254 | ||
255 | dss_pll_unregister(pll); | |
256 | } |