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> | |
18 | #include <video/omapdss.h> | |
19 | ||
20 | #include "dss.h" | |
ef26958a | 21 | #include "hdmi.h" |
c1577c1e AT |
22 | |
23 | #define HDMI_DEFAULT_REGN 16 | |
24 | #define HDMI_DEFAULT_REGM2 1 | |
25 | ||
2d64b1b3 AT |
26 | struct 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 | ||
36 | static const struct hdmi_pll_features *pll_feat; | |
37 | ||
c1577c1e AT |
38 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) |
39 | { | |
40 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ | |
41 | hdmi_read_reg(pll->base, r)) | |
42 | ||
43 | DUMPPLL(PLLCTRL_PLL_CONTROL); | |
44 | DUMPPLL(PLLCTRL_PLL_STATUS); | |
45 | DUMPPLL(PLLCTRL_PLL_GO); | |
46 | DUMPPLL(PLLCTRL_CFG1); | |
47 | DUMPPLL(PLLCTRL_CFG2); | |
48 | DUMPPLL(PLLCTRL_CFG3); | |
49 | DUMPPLL(PLLCTRL_SSC_CFG1); | |
50 | DUMPPLL(PLLCTRL_SSC_CFG2); | |
51 | DUMPPLL(PLLCTRL_CFG4); | |
52 | } | |
53 | ||
54 | void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) | |
55 | { | |
56 | struct hdmi_pll_info *pi = &pll->info; | |
57 | unsigned long refclk; | |
58 | u32 mf; | |
59 | ||
60 | /* use our funky units */ | |
61 | clkin /= 10000; | |
62 | ||
63 | /* | |
64 | * Input clock is predivided by N + 1 | |
65 | * out put of which is reference clk | |
66 | */ | |
67 | ||
68 | pi->regn = HDMI_DEFAULT_REGN; | |
69 | ||
70 | refclk = clkin / pi->regn; | |
71 | ||
2d64b1b3 AT |
72 | /* temorary hack to make sure DCO freq isn't calculated too low */ |
73 | if (pll_feat->bound_dcofreq && phy <= 65000) | |
74 | pi->regm2 = 3; | |
75 | else | |
76 | pi->regm2 = HDMI_DEFAULT_REGM2; | |
c1577c1e AT |
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 | ||
106 | ||
107 | static int hdmi_pll_config(struct hdmi_pll_data *pll) | |
108 | { | |
109 | u32 r; | |
110 | struct hdmi_pll_info *fmt = &pll->info; | |
111 | ||
112 | /* PLL start always use manual mode */ | |
113 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); | |
114 | ||
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 | ||
0856eba7 | 127 | if (fmt->dcofreq) |
c1577c1e | 128 | r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ |
0856eba7 | 129 | else |
c1577c1e | 130 | r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ |
c1577c1e AT |
131 | |
132 | hdmi_write_reg(pll->base, PLLCTRL_CFG2, r); | |
133 | ||
0856eba7 TV |
134 | REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10); |
135 | ||
c1577c1e AT |
136 | r = hdmi_read_reg(pll->base, PLLCTRL_CFG4); |
137 | r = FLD_MOD(r, fmt->regm2, 24, 18); | |
138 | r = FLD_MOD(r, fmt->regmf, 17, 0); | |
139 | hdmi_write_reg(pll->base, PLLCTRL_CFG4, r); | |
140 | ||
141 | /* go now */ | |
142 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0); | |
143 | ||
144 | /* wait for bit change */ | |
145 | if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO, | |
88e3c76a TV |
146 | 0, 0, 0) != 0) { |
147 | DSSERR("PLL GO bit not clearing\n"); | |
c1577c1e AT |
148 | return -ETIMEDOUT; |
149 | } | |
150 | ||
151 | /* Wait till the lock bit is set in PLL status */ | |
152 | if (hdmi_wait_for_bit_change(pll->base, | |
153 | PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { | |
ac9f2421 TV |
154 | DSSERR("cannot lock PLL\n"); |
155 | DSSERR("CFG1 0x%x\n", | |
c1577c1e | 156 | hdmi_read_reg(pll->base, PLLCTRL_CFG1)); |
ac9f2421 | 157 | DSSERR("CFG2 0x%x\n", |
c1577c1e | 158 | hdmi_read_reg(pll->base, PLLCTRL_CFG2)); |
ac9f2421 | 159 | DSSERR("CFG4 0x%x\n", |
c1577c1e AT |
160 | hdmi_read_reg(pll->base, PLLCTRL_CFG4)); |
161 | return -ETIMEDOUT; | |
162 | } | |
163 | ||
ac9f2421 | 164 | DSSDBG("PLL locked!\n"); |
c1577c1e AT |
165 | |
166 | return 0; | |
167 | } | |
168 | ||
169 | static int hdmi_pll_reset(struct hdmi_pll_data *pll) | |
170 | { | |
171 | /* SYSRESET controlled by power FSM */ | |
2d64b1b3 | 172 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3); |
c1577c1e AT |
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) { | |
ac9f2421 | 177 | DSSERR("Failed to sysreset PLL\n"); |
c1577c1e AT |
178 | return -ETIMEDOUT; |
179 | } | |
180 | ||
181 | return 0; | |
182 | } | |
183 | ||
184 | int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) | |
185 | { | |
186 | u16 r = 0; | |
187 | ||
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); | |
193 | if (r) | |
194 | return r; | |
195 | ||
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; | |
205 | } | |
206 | ||
207 | void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) | |
208 | { | |
209 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); | |
210 | } | |
211 | ||
2d64b1b3 AT |
212 | static const struct hdmi_pll_features omap44xx_pll_feats = { |
213 | .sys_reset = false, | |
214 | .bound_dcofreq = false, | |
215 | .fint_min = 500000, | |
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 | }; | |
223 | ||
224 | static const struct hdmi_pll_features omap54xx_pll_feats = { | |
225 | .sys_reset = true, | |
226 | .bound_dcofreq = true, | |
227 | .fint_min = 620000, | |
228 | .fint_max = 2500000, | |
229 | .regm_max = 2046, | |
230 | .dcofreq_low_min = 750000000, | |
231 | .dcofreq_low_max = 1500000000, | |
232 | .dcofreq_high_min = 1250000000, | |
233 | .dcofreq_high_max = 2500000000UL, | |
234 | }; | |
235 | ||
236 | static int hdmi_pll_init_features(struct platform_device *pdev) | |
237 | { | |
238 | struct hdmi_pll_features *dst; | |
239 | const struct hdmi_pll_features *src; | |
240 | ||
241 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); | |
242 | if (!dst) { | |
243 | dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); | |
244 | return -ENOMEM; | |
245 | } | |
246 | ||
247 | switch (omapdss_get_version()) { | |
248 | case OMAPDSS_VER_OMAP4430_ES1: | |
249 | case OMAPDSS_VER_OMAP4430_ES2: | |
250 | case OMAPDSS_VER_OMAP4: | |
251 | src = &omap44xx_pll_feats; | |
252 | break; | |
253 | ||
254 | case OMAPDSS_VER_OMAP5: | |
255 | src = &omap54xx_pll_feats; | |
256 | break; | |
257 | ||
258 | default: | |
259 | return -ENODEV; | |
260 | } | |
261 | ||
262 | memcpy(dst, src, sizeof(*dst)); | |
263 | pll_feat = dst; | |
264 | ||
265 | return 0; | |
266 | } | |
267 | ||
c1577c1e AT |
268 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) |
269 | { | |
2d64b1b3 | 270 | int r; |
c1577c1e | 271 | struct resource *res; |
c1577c1e | 272 | |
2d64b1b3 AT |
273 | r = hdmi_pll_init_features(pdev); |
274 | if (r) | |
275 | return r; | |
276 | ||
77601507 | 277 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); |
c1577c1e | 278 | if (!res) { |
59b3d38a TV |
279 | DSSERR("can't get PLL mem resource\n"); |
280 | return -EINVAL; | |
c1577c1e AT |
281 | } |
282 | ||
59b3d38a | 283 | pll->base = devm_ioremap_resource(&pdev->dev, res); |
2b22df83 | 284 | if (IS_ERR(pll->base)) { |
c1577c1e | 285 | DSSERR("can't ioremap PLLCTRL\n"); |
2b22df83 | 286 | return PTR_ERR(pll->base); |
c1577c1e AT |
287 | } |
288 | ||
289 | return 0; | |
290 | } |