aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev/omap2/dss/hdmi_pll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/omap2/dss/hdmi_pll.c')
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c313
1 files changed, 137 insertions, 176 deletions
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index 6d92bb32fe51..87accdb59c81 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -15,26 +15,13 @@
15#include <linux/err.h> 15#include <linux/err.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/clk.h>
19
18#include <video/omapdss.h> 20#include <video/omapdss.h>
19 21
20#include "dss.h" 22#include "dss.h"
21#include "hdmi.h" 23#include "hdmi.h"
22 24
23#define HDMI_DEFAULT_REGN 16
24#define HDMI_DEFAULT_REGM2 1
25
26struct hdmi_pll_features {
27 bool sys_reset;
28 /* this is a hack, need to replace it with a better computation of M2 */
29 bool bound_dcofreq;
30 unsigned long fint_min, fint_max;
31 u16 regm_max;
32 unsigned long dcofreq_low_min, dcofreq_low_max;
33 unsigned long dcofreq_high_min, dcofreq_high_max;
34};
35
36static const struct hdmi_pll_features *pll_feat;
37
38void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) 25void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
39{ 26{
40#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ 27#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
@@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
51 DUMPPLL(PLLCTRL_CFG4); 38 DUMPPLL(PLLCTRL_CFG4);
52} 39}
53 40
54void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) 41void hdmi_pll_compute(struct hdmi_pll_data *pll,
42 unsigned long target_tmds, struct dss_pll_clock_info *pi)
55{ 43{
56 struct hdmi_pll_info *pi = &pll->info; 44 unsigned long fint, clkdco, clkout;
57 unsigned long refclk; 45 unsigned long target_bitclk, target_clkdco;
58 u32 mf; 46 unsigned long min_dco;
47 unsigned n, m, mf, m2, sd;
48 unsigned long clkin;
49 const struct dss_pll_hw *hw = pll->pll.hw;
59 50
60 /* use our funky units */ 51 clkin = clk_get_rate(pll->pll.clkin);
61 clkin /= 10000;
62 52
63 /* 53 DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
64 * Input clock is predivided by N + 1
65 * out put of which is reference clk
66 */
67 54
68 pi->regn = HDMI_DEFAULT_REGN; 55 target_bitclk = target_tmds * 10;
69 56
70 refclk = clkin / pi->regn; 57 /* Fint */
58 n = DIV_ROUND_UP(clkin, hw->fint_max);
59 fint = clkin / n;
71 60
72 /* temorary hack to make sure DCO freq isn't calculated too low */ 61 /* adjust m2 so that the clkdco will be high enough */
73 if (pll_feat->bound_dcofreq && phy <= 65000) 62 min_dco = roundup(hw->clkdco_min, fint);
74 pi->regm2 = 3; 63 m2 = DIV_ROUND_UP(min_dco, target_bitclk);
75 else 64 if (m2 == 0)
76 pi->regm2 = HDMI_DEFAULT_REGM2; 65 m2 = 1;
77
78 /*
79 * multiplier is pixel_clk/ref_clk
80 * Multiplying by 100 to avoid fractional part removal
81 */
82 pi->regm = phy * pi->regm2 / refclk;
83
84 /*
85 * fractional multiplier is remainder of the difference between
86 * multiplier and actual phy(required pixel clock thus should be
87 * multiplied by 2^18(262144) divided by the reference clock
88 */
89 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
90 pi->regmf = pi->regm2 * mf / refclk;
91
92 /*
93 * Dcofreq should be set to 1 if required pixel clock
94 * is greater than 1000MHz
95 */
96 pi->dcofreq = phy > 1000 * 100;
97 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
98
99 /* Set the reference clock to sysclk reference */
100 pi->refsel = HDMI_REFSEL_SYSCLK;
101
102 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
103 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
104}
105 66
67 target_clkdco = target_bitclk * m2;
68 m = target_clkdco / fint;
106 69
107static int hdmi_pll_config(struct hdmi_pll_data *pll) 70 clkdco = fint * m;
108{
109 u32 r;
110 struct hdmi_pll_info *fmt = &pll->info;
111 71
112 /* PLL start always use manual mode */ 72 /* adjust clkdco with fractional mf */
113 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); 73 if (WARN_ON(target_clkdco - clkdco > fint))
114 74 mf = 0;
115 r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
116 r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
117 r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
118 hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
119
120 r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
121
122 r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
123 r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
124 r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
125 r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
126
127 if (fmt->dcofreq)
128 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
129 else 75 else
130 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ 76 mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
131
132 hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
133
134 REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
135 77
136 r = hdmi_read_reg(pll->base, PLLCTRL_CFG4); 78 if (mf > 0)
137 r = FLD_MOD(r, fmt->regm2, 24, 18); 79 clkdco += (u32)div_u64((u64)mf * fint, 262144);
138 r = FLD_MOD(r, fmt->regmf, 17, 0);
139 hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
140 80
141 /* go now */ 81 clkout = clkdco / m2;
142 REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
143 82
144 /* wait for bit change */ 83 /* sigma-delta */
145 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO, 84 sd = DIV_ROUND_UP(fint * m, 250000000);
146 0, 0, 0) != 0) {
147 DSSERR("PLL GO bit not clearing\n");
148 return -ETIMEDOUT;
149 }
150 85
151 /* Wait till the lock bit is set in PLL status */ 86 DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
152 if (hdmi_wait_for_bit_change(pll->base, 87 n, m, mf, m2, sd);
153 PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { 88 DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
154 DSSERR("cannot lock PLL\n");
155 DSSERR("CFG1 0x%x\n",
156 hdmi_read_reg(pll->base, PLLCTRL_CFG1));
157 DSSERR("CFG2 0x%x\n",
158 hdmi_read_reg(pll->base, PLLCTRL_CFG2));
159 DSSERR("CFG4 0x%x\n",
160 hdmi_read_reg(pll->base, PLLCTRL_CFG4));
161 return -ETIMEDOUT;
162 }
163 89
164 DSSDBG("PLL locked!\n"); 90 pi->n = n;
91 pi->m = m;
92 pi->mf = mf;
93 pi->mX[0] = m2;
94 pi->sd = sd;
165 95
166 return 0; 96 pi->fint = fint;
97 pi->clkdco = clkdco;
98 pi->clkout[0] = clkout;
167} 99}
168 100
169static int hdmi_pll_reset(struct hdmi_pll_data *pll) 101static int hdmi_pll_enable(struct dss_pll *dsspll)
170{
171 /* SYSRESET controlled by power FSM */
172 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
173
174 /* READ 0x0 reset is in progress */
175 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
176 != 1) {
177 DSSERR("Failed to sysreset PLL\n");
178 return -ETIMEDOUT;
179 }
180
181 return 0;
182}
183
184int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
185{ 102{
103 struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
104 struct hdmi_wp_data *wp = pll->wp;
186 u16 r = 0; 105 u16 r = 0;
187 106
188 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
189 if (r)
190 return r;
191
192 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); 107 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
193 if (r) 108 if (r)
194 return r; 109 return r;
195 110
196 r = hdmi_pll_reset(pll);
197 if (r)
198 return r;
199
200 r = hdmi_pll_config(pll);
201 if (r)
202 return r;
203
204 return 0; 111 return 0;
205} 112}
206 113
207void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) 114static void hdmi_pll_disable(struct dss_pll *dsspll)
208{ 115{
116 struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
117 struct hdmi_wp_data *wp = pll->wp;
118
209 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); 119 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
210} 120}
211 121
212static const struct hdmi_pll_features omap44xx_pll_feats = { 122static const struct dss_pll_ops dsi_pll_ops = {
213 .sys_reset = false, 123 .enable = hdmi_pll_enable,
214 .bound_dcofreq = false, 124 .disable = hdmi_pll_disable,
215 .fint_min = 500000, 125 .set_config = dss_pll_write_config_type_b,
216 .fint_max = 2500000,
217 .regm_max = 4095,
218 .dcofreq_low_min = 500000000,
219 .dcofreq_low_max = 1000000000,
220 .dcofreq_high_min = 1000000000,
221 .dcofreq_high_max = 2000000000,
222}; 126};
223 127
224static const struct hdmi_pll_features omap54xx_pll_feats = { 128static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
225 .sys_reset = true, 129 .n_max = 255,
226 .bound_dcofreq = true, 130 .m_min = 20,
227 .fint_min = 620000, 131 .m_max = 4095,
228 .fint_max = 2500000, 132 .mX_max = 127,
229 .regm_max = 2046, 133 .fint_min = 500000,
230 .dcofreq_low_min = 750000000, 134 .fint_max = 2500000,
231 .dcofreq_low_max = 1500000000, 135 .clkdco_max = 1800000000,
232 .dcofreq_high_min = 1250000000, 136
233 .dcofreq_high_max = 2500000000UL, 137 .clkdco_min = 500000000,
138 .clkdco_low = 1000000000,
139 .clkdco_max = 2000000000,
140
141 .n_msb = 8,
142 .n_lsb = 1,
143 .m_msb = 20,
144 .m_lsb = 9,
145
146 .mX_msb[0] = 24,
147 .mX_lsb[0] = 18,
148
149 .has_selfreqdco = true,
234}; 150};
235 151
236static int hdmi_pll_init_features(struct platform_device *pdev) 152static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
153 .n_max = 255,
154 .m_min = 20,
155 .m_max = 2045,
156 .mX_max = 127,
157 .fint_min = 620000,
158 .fint_max = 2500000,
159 .clkdco_max = 1800000000,
160
161 .clkdco_min = 750000000,
162 .clkdco_low = 1500000000,
163 .clkdco_max = 2500000000UL,
164
165 .n_msb = 8,
166 .n_lsb = 1,
167 .m_msb = 20,
168 .m_lsb = 9,
169
170 .mX_msb[0] = 24,
171 .mX_lsb[0] = 18,
172
173 .has_selfreqdco = true,
174 .has_refsel = true,
175};
176
177static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
237{ 178{
238 struct hdmi_pll_features *dst; 179 struct dss_pll *pll = &hpll->pll;
239 const struct hdmi_pll_features *src; 180 struct clk *clk;
181 int r;
240 182
241 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); 183 clk = devm_clk_get(&pdev->dev, "sys_clk");
242 if (!dst) { 184 if (IS_ERR(clk)) {
243 dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); 185 DSSERR("can't get sys_clk\n");
244 return -ENOMEM; 186 return PTR_ERR(clk);
245 } 187 }
246 188
189 pll->name = "hdmi";
190 pll->base = hpll->base;
191 pll->clkin = clk;
192
247 switch (omapdss_get_version()) { 193 switch (omapdss_get_version()) {
248 case OMAPDSS_VER_OMAP4430_ES1: 194 case OMAPDSS_VER_OMAP4430_ES1:
249 case OMAPDSS_VER_OMAP4430_ES2: 195 case OMAPDSS_VER_OMAP4430_ES2:
250 case OMAPDSS_VER_OMAP4: 196 case OMAPDSS_VER_OMAP4:
251 src = &omap44xx_pll_feats; 197 pll->hw = &dss_omap4_hdmi_pll_hw;
252 break; 198 break;
253 199
254 case OMAPDSS_VER_OMAP5: 200 case OMAPDSS_VER_OMAP5:
255 src = &omap54xx_pll_feats; 201 pll->hw = &dss_omap5_hdmi_pll_hw;
256 break; 202 break;
257 203
258 default: 204 default:
259 return -ENODEV; 205 return -ENODEV;
260 } 206 }
261 207
262 memcpy(dst, src, sizeof(*dst)); 208 pll->ops = &dsi_pll_ops;
263 pll_feat = dst; 209
210 r = dss_pll_register(pll);
211 if (r)
212 return r;
264 213
265 return 0; 214 return 0;
266} 215}
267 216
268int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) 217int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
218 struct hdmi_wp_data *wp)
269{ 219{
270 int r; 220 int r;
271 struct resource *res; 221 struct resource *res;
272 222
273 r = hdmi_pll_init_features(pdev); 223 pll->wp = wp;
274 if (r)
275 return r;
276 224
277 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); 225 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
278 if (!res) { 226 if (!res) {
@@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
286 return PTR_ERR(pll->base); 234 return PTR_ERR(pll->base);
287 } 235 }
288 236
237 r = dsi_init_pll_data(pdev, pll);
238 if (r) {
239 DSSERR("failed to init HDMI PLL\n");
240 return r;
241 }
242
289 return 0; 243 return 0;
290} 244}
245
246void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
247{
248 struct dss_pll *pll = &hpll->pll;
249
250 dss_pll_unregister(pll);
251}