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.c107
1 files changed, 83 insertions, 24 deletions
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index 5fc71215c303..54df12a8d744 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -23,6 +23,18 @@
23#define HDMI_DEFAULT_REGN 16 23#define HDMI_DEFAULT_REGN 16
24#define HDMI_DEFAULT_REGM2 1 24#define HDMI_DEFAULT_REGM2 1
25 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
26void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) 38void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
27{ 39{
28#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ 40#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
@@ -57,7 +69,11 @@ void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
57 69
58 refclk = clkin / pi->regn; 70 refclk = clkin / pi->regn;
59 71
60 pi->regm2 = HDMI_DEFAULT_REGM2; 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;
61 77
62 /* 78 /*
63 * multiplier is pixel_clk/ref_clk 79 * multiplier is pixel_clk/ref_clk
@@ -154,7 +170,7 @@ static int hdmi_pll_config(struct hdmi_pll_data *pll)
154static int hdmi_pll_reset(struct hdmi_pll_data *pll) 170static int hdmi_pll_reset(struct hdmi_pll_data *pll)
155{ 171{
156 /* SYSRESET controlled by power FSM */ 172 /* SYSRESET controlled by power FSM */
157 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3); 173 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
158 174
159 /* READ 0x0 reset is in progress */ 175 /* READ 0x0 reset is in progress */
160 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1) 176 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
@@ -194,38 +210,81 @@ void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
194 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); 210 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
195} 211}
196 212
197#define PLL_OFFSET 0x200 213static const struct hdmi_pll_features omap44xx_pll_feats = {
198#define PLL_SIZE 0x100 214 .sys_reset = false,
215 .bound_dcofreq = false,
216 .fint_min = 500000,
217 .fint_max = 2500000,
218 .regm_max = 4095,
219 .dcofreq_low_min = 500000000,
220 .dcofreq_low_max = 1000000000,
221 .dcofreq_high_min = 1000000000,
222 .dcofreq_high_max = 2000000000,
223};
224
225static const struct hdmi_pll_features omap54xx_pll_feats = {
226 .sys_reset = true,
227 .bound_dcofreq = true,
228 .fint_min = 620000,
229 .fint_max = 2500000,
230 .regm_max = 2046,
231 .dcofreq_low_min = 750000000,
232 .dcofreq_low_max = 1500000000,
233 .dcofreq_high_min = 1250000000,
234 .dcofreq_high_max = 2500000000UL,
235};
236
237static int hdmi_pll_init_features(struct platform_device *pdev)
238{
239 struct hdmi_pll_features *dst;
240 const struct hdmi_pll_features *src;
241
242 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
243 if (!dst) {
244 dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
245 return -ENOMEM;
246 }
247
248 switch (omapdss_get_version()) {
249 case OMAPDSS_VER_OMAP4430_ES1:
250 case OMAPDSS_VER_OMAP4430_ES2:
251 case OMAPDSS_VER_OMAP4:
252 src = &omap44xx_pll_feats;
253 break;
254
255 case OMAPDSS_VER_OMAP5:
256 src = &omap54xx_pll_feats;
257 break;
258
259 default:
260 return -ENODEV;
261 }
262
263 memcpy(dst, src, sizeof(*dst));
264 pll_feat = dst;
265
266 return 0;
267}
199 268
200int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) 269int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
201{ 270{
271 int r;
202 struct resource *res; 272 struct resource *res;
203 struct resource temp_res; 273
274 r = hdmi_pll_init_features(pdev);
275 if (r)
276 return r;
204 277
205 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); 278 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
206 if (!res) { 279 if (!res) {
207 DSSDBG("can't get PLL mem resource by name\n"); 280 DSSERR("can't get PLL mem resource\n");
208 /* 281 return -EINVAL;
209 * if hwmod/DT doesn't have the memory resource information
210 * split into HDMI sub blocks by name, we try again by getting
211 * the platform's first resource. this code will be removed when
212 * the driver can get the mem resources by name
213 */
214 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
215 if (!res) {
216 DSSERR("can't get PLL mem resource\n");
217 return -EINVAL;
218 }
219
220 temp_res.start = res->start + PLL_OFFSET;
221 temp_res.end = temp_res.start + PLL_SIZE - 1;
222 res = &temp_res;
223 } 282 }
224 283
225 pll->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 284 pll->base = devm_ioremap_resource(&pdev->dev, res);
226 if (!pll->base) { 285 if (IS_ERR(pll->base)) {
227 DSSERR("can't ioremap PLLCTRL\n"); 286 DSSERR("can't ioremap PLLCTRL\n");
228 return -ENOMEM; 287 return PTR_ERR(pll->base);
229 } 288 }
230 289
231 return 0; 290 return 0;