aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorArchit Taneja <archit@ti.com>2013-10-08 03:25:26 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2013-10-09 05:42:07 -0400
commitc1577c1ea01732fea5bc18f05a9e005c0dce6261 (patch)
treebb7ed2719a32b448a7a1b70bc03794013d0494fd /drivers/video
parentf382d9eb82cac42b5d162cb498cd41245dfafb42 (diff)
omapdss: HDMI: create a PLL library
HDMI PLL is a block common to DSS in OMAP4, OMAP5 and DRA7x. Move the existing PLL functions from ti_hdmi_4xxx_ip.c and hdmi.c to a separate file. These funcs are called directly from the hdmi driver rather than hdmi_ip_ops function pointer calls. Add the PLL library function declarations to ti_hdmi.h. These will be shared amongst the omap4/5 hdmi platform drivers. Remove the PLL function pointer ops from the ti_hdmi_ip_ops struct. These will be shared amongst the omap4/5 hdmi platform drivers and other libraries. The DT/hwmod information for hdmi doesn't split the address space according to the required sub blocks. Keep the address offset and size information in the driver for now. This will be removed when the driver gets the information correctly from DT/hwmod. Signed-off-by: Archit Taneja <archit@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/dss/Makefile2
-rw-r--r--drivers/video/omap2/dss/dss_features.c3
-rw-r--r--drivers/video/omap2/dss/hdmi.c65
-rw-r--r--drivers/video/omap2/dss/hdmi_pll.c261
-rw-r--r--drivers/video/omap2/dss/ti_hdmi.h25
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c132
6 files changed, 285 insertions, 203 deletions
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 56ce6bd36905..5ea65d327cfb 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -10,5 +10,5 @@ omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
10omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o 10omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
11omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o 11omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
12omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o 12omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
13omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o hdmi_wp.o ti_hdmi_4xxx_ip.o 13omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o hdmi_wp.o hdmi_pll.o ti_hdmi_4xxx_ip.o
14ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG 14ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index db359e8df503..9ee92e90caff 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -797,10 +797,7 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
797 .phy_enable = ti_hdmi_4xxx_phy_enable, 797 .phy_enable = ti_hdmi_4xxx_phy_enable,
798 .phy_disable = ti_hdmi_4xxx_phy_disable, 798 .phy_disable = ti_hdmi_4xxx_phy_disable,
799 .read_edid = ti_hdmi_4xxx_read_edid, 799 .read_edid = ti_hdmi_4xxx_read_edid,
800 .pll_enable = ti_hdmi_4xxx_pll_enable,
801 .pll_disable = ti_hdmi_4xxx_pll_disable,
802 .dump_core = ti_hdmi_4xxx_core_dump, 800 .dump_core = ti_hdmi_4xxx_core_dump,
803 .dump_pll = ti_hdmi_4xxx_pll_dump,
804 .dump_phy = ti_hdmi_4xxx_phy_dump, 801 .dump_phy = ti_hdmi_4xxx_phy_dump,
805#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) 802#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
806 .audio_start = ti_hdmi_4xxx_audio_start, 803 .audio_start = ti_hdmi_4xxx_audio_start,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index f2475fc1b632..f6a2eba244e7 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -42,7 +42,6 @@
42 42
43#define HDMI_CORE_SYS 0x400 43#define HDMI_CORE_SYS 0x400
44#define HDMI_CORE_AV 0x900 44#define HDMI_CORE_AV 0x900
45#define HDMI_PLLCTRL 0x200
46#define HDMI_PHY 0x300 45#define HDMI_PHY 0x300
47 46
48/* HDMI EDID Length move this */ 47/* HDMI EDID Length move this */
@@ -53,9 +52,6 @@
53#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 52#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4
54#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 53#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4
55 54
56#define HDMI_DEFAULT_REGN 16
57#define HDMI_DEFAULT_REGM2 1
58
59static struct { 55static struct {
60 struct mutex lock; 56 struct mutex lock;
61 struct platform_device *pdev; 57 struct platform_device *pdev;
@@ -428,52 +424,6 @@ end: return cm;
428 424
429} 425}
430 426
431static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
432 struct hdmi_pll_info *pi)
433{
434 unsigned long clkin, refclk;
435 u32 mf;
436
437 clkin = clk_get_rate(hdmi.sys_clk) / 10000;
438 /*
439 * Input clock is predivided by N + 1
440 * out put of which is reference clk
441 */
442
443 pi->regn = HDMI_DEFAULT_REGN;
444
445 refclk = clkin / pi->regn;
446
447 pi->regm2 = HDMI_DEFAULT_REGM2;
448
449 /*
450 * multiplier is pixel_clk/ref_clk
451 * Multiplying by 100 to avoid fractional part removal
452 */
453 pi->regm = phy * pi->regm2 / refclk;
454
455 /*
456 * fractional multiplier is remainder of the difference between
457 * multiplier and actual phy(required pixel clock thus should be
458 * multiplied by 2^18(262144) divided by the reference clock
459 */
460 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
461 pi->regmf = pi->regm2 * mf / refclk;
462
463 /*
464 * Dcofreq should be set to 1 if required pixel clock
465 * is greater than 1000MHz
466 */
467 pi->dcofreq = phy > 1000 * 100;
468 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
469
470 /* Set the reference clock to sysclk reference */
471 pi->refsel = HDMI_REFSEL_SYSCLK;
472
473 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
474 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
475}
476
477static int hdmi_power_on_core(struct omap_dss_device *dssdev) 427static int hdmi_power_on_core(struct omap_dss_device *dssdev)
478{ 428{
479 int r; 429 int r;
@@ -526,12 +476,12 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
526 476
527 phy = p->pixel_clock; 477 phy = p->pixel_clock;
528 478
529 hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); 479 hdmi_pll_compute(&hdmi.ip_data.pll, clk_get_rate(hdmi.sys_clk), phy);
530 480
531 hdmi_wp_video_stop(&hdmi.ip_data.wp); 481 hdmi_wp_video_stop(&hdmi.ip_data.wp);
532 482
533 /* config the PLL and PHY hdmi_set_pll_pwrfirst */ 483 /* config the PLL and PHY hdmi_set_pll_pwrfirst */
534 r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); 484 r = hdmi_pll_enable(&hdmi.ip_data.pll, &hdmi.ip_data.wp);
535 if (r) { 485 if (r) {
536 DSSDBG("Failed to lock PLL\n"); 486 DSSDBG("Failed to lock PLL\n");
537 goto err_pll_enable; 487 goto err_pll_enable;
@@ -566,7 +516,7 @@ err_mgr_enable:
566err_vid_enable: 516err_vid_enable:
567 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); 517 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
568err_phy_enable: 518err_phy_enable:
569 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); 519 hdmi_pll_disable(&hdmi.ip_data.pll, &hdmi.ip_data.wp);
570err_pll_enable: 520err_pll_enable:
571 hdmi_power_off_core(dssdev); 521 hdmi_power_off_core(dssdev);
572 return -EIO; 522 return -EIO;
@@ -580,7 +530,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
580 530
581 hdmi_wp_video_stop(&hdmi.ip_data.wp); 531 hdmi_wp_video_stop(&hdmi.ip_data.wp);
582 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); 532 hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
583 hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); 533 hdmi_pll_disable(&hdmi.ip_data.pll, &hdmi.ip_data.wp);
584 534
585 hdmi_power_off_core(dssdev); 535 hdmi_power_off_core(dssdev);
586} 536}
@@ -642,7 +592,7 @@ static void hdmi_dump_regs(struct seq_file *s)
642 } 592 }
643 593
644 hdmi_wp_dump(&hdmi.ip_data.wp, s); 594 hdmi_wp_dump(&hdmi.ip_data.wp, s);
645 hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); 595 hdmi_pll_dump(&hdmi.ip_data.pll, s);
646 hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s); 596 hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s);
647 hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s); 597 hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s);
648 598
@@ -1095,6 +1045,10 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
1095 if (r) 1045 if (r)
1096 return r; 1046 return r;
1097 1047
1048 r = hdmi_pll_init(pdev, &hdmi.ip_data.pll);
1049 if (r)
1050 return r;
1051
1098 hdmi.ip_data.irq = platform_get_irq(pdev, 0); 1052 hdmi.ip_data.irq = platform_get_irq(pdev, 0);
1099 if (hdmi.ip_data.irq < 0) { 1053 if (hdmi.ip_data.irq < 0) {
1100 DSSERR("platform_get_irq failed\n"); 1054 DSSERR("platform_get_irq failed\n");
@@ -1111,7 +1065,6 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
1111 1065
1112 hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS; 1066 hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS;
1113 hdmi.ip_data.core_av_offset = HDMI_CORE_AV; 1067 hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
1114 hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
1115 hdmi.ip_data.phy_offset = HDMI_PHY; 1068 hdmi.ip_data.phy_offset = HDMI_PHY;
1116 1069
1117 hdmi_init_output(pdev); 1070 hdmi_init_output(pdev);
diff --git a/drivers/video/omap2/dss/hdmi_pll.c b/drivers/video/omap2/dss/hdmi_pll.c
new file mode 100644
index 000000000000..e12fa6ada58f
--- /dev/null
+++ b/drivers/video/omap2/dss/hdmi_pll.c
@@ -0,0 +1,261 @@
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
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/platform_device.h>
17#include <video/omapdss.h>
18
19#include "dss.h"
20#include "ti_hdmi.h"
21#include "ti_hdmi_4xxx_ip.h"
22
23#define HDMI_DEFAULT_REGN 16
24#define HDMI_DEFAULT_REGM2 1
25
26static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx,
27 u32 val)
28{
29 __raw_writel(val, base_addr + idx);
30}
31
32static inline u32 hdmi_read_reg(void __iomem *base_addr, const u16 idx)
33{
34 return __raw_readl(base_addr + idx);
35}
36
37#define REG_FLD_MOD(base, idx, val, start, end) \
38 hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\
39 val, start, end))
40#define REG_GET(base, idx, start, end) \
41 FLD_GET(hdmi_read_reg(base, idx), start, end)
42
43static inline int hdmi_wait_for_bit_change(void __iomem *base_addr,
44 const u16 idx, int b2, int b1, u32 val)
45{
46 u32 t = 0;
47 while (val != REG_GET(base_addr, idx, b2, b1)) {
48 udelay(1);
49 if (t++ > 10000)
50 return !val;
51 }
52 return val;
53}
54
55void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
56{
57#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
58 hdmi_read_reg(pll->base, r))
59
60 DUMPPLL(PLLCTRL_PLL_CONTROL);
61 DUMPPLL(PLLCTRL_PLL_STATUS);
62 DUMPPLL(PLLCTRL_PLL_GO);
63 DUMPPLL(PLLCTRL_CFG1);
64 DUMPPLL(PLLCTRL_CFG2);
65 DUMPPLL(PLLCTRL_CFG3);
66 DUMPPLL(PLLCTRL_SSC_CFG1);
67 DUMPPLL(PLLCTRL_SSC_CFG2);
68 DUMPPLL(PLLCTRL_CFG4);
69}
70
71void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
72{
73 struct hdmi_pll_info *pi = &pll->info;
74 unsigned long refclk;
75 u32 mf;
76
77 /* use our funky units */
78 clkin /= 10000;
79
80 /*
81 * Input clock is predivided by N + 1
82 * out put of which is reference clk
83 */
84
85 pi->regn = HDMI_DEFAULT_REGN;
86
87 refclk = clkin / pi->regn;
88
89 pi->regm2 = HDMI_DEFAULT_REGM2;
90
91 /*
92 * multiplier is pixel_clk/ref_clk
93 * Multiplying by 100 to avoid fractional part removal
94 */
95 pi->regm = phy * pi->regm2 / refclk;
96
97 /*
98 * fractional multiplier is remainder of the difference between
99 * multiplier and actual phy(required pixel clock thus should be
100 * multiplied by 2^18(262144) divided by the reference clock
101 */
102 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
103 pi->regmf = pi->regm2 * mf / refclk;
104
105 /*
106 * Dcofreq should be set to 1 if required pixel clock
107 * is greater than 1000MHz
108 */
109 pi->dcofreq = phy > 1000 * 100;
110 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
111
112 /* Set the reference clock to sysclk reference */
113 pi->refsel = HDMI_REFSEL_SYSCLK;
114
115 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
116 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
117}
118
119
120static int hdmi_pll_config(struct hdmi_pll_data *pll)
121{
122 u32 r;
123 struct hdmi_pll_info *fmt = &pll->info;
124
125 /* PLL start always use manual mode */
126 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
127
128 r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
129 r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
130 r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
131 hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
132
133 r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
134
135 r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
136 r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
137 r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
138 r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
139
140 if (fmt->dcofreq) {
141 /* divider programming for frequency beyond 1000Mhz */
142 REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
143 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
144 } else {
145 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
146 }
147
148 hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
149
150 r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
151 r = FLD_MOD(r, fmt->regm2, 24, 18);
152 r = FLD_MOD(r, fmt->regmf, 17, 0);
153 hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
154
155 /* go now */
156 REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
157
158 /* wait for bit change */
159 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
160 0, 0, 1) != 1) {
161 pr_err("PLL GO bit not set\n");
162 return -ETIMEDOUT;
163 }
164
165 /* Wait till the lock bit is set in PLL status */
166 if (hdmi_wait_for_bit_change(pll->base,
167 PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
168 pr_err("cannot lock PLL\n");
169 pr_err("CFG1 0x%x\n",
170 hdmi_read_reg(pll->base, PLLCTRL_CFG1));
171 pr_err("CFG2 0x%x\n",
172 hdmi_read_reg(pll->base, PLLCTRL_CFG2));
173 pr_err("CFG4 0x%x\n",
174 hdmi_read_reg(pll->base, PLLCTRL_CFG4));
175 return -ETIMEDOUT;
176 }
177
178 pr_debug("PLL locked!\n");
179
180 return 0;
181}
182
183static int hdmi_pll_reset(struct hdmi_pll_data *pll)
184{
185 /* SYSRESET controlled by power FSM */
186 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
187
188 /* READ 0x0 reset is in progress */
189 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
190 != 1) {
191 pr_err("Failed to sysreset PLL\n");
192 return -ETIMEDOUT;
193 }
194
195 return 0;
196}
197
198int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
199{
200 u16 r = 0;
201
202 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
203 if (r)
204 return r;
205
206 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
207 if (r)
208 return r;
209
210 r = hdmi_pll_reset(pll);
211 if (r)
212 return r;
213
214 r = hdmi_pll_config(pll);
215 if (r)
216 return r;
217
218 return 0;
219}
220
221void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
222{
223 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
224}
225
226#define PLL_OFFSET 0x200
227#define PLL_SIZE 0x100
228
229int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
230{
231 struct resource *res;
232 struct resource temp_res;
233
234 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi_pllctrl");
235 if (!res) {
236 DSSDBG("can't get PLL mem resource by name\n");
237 /*
238 * if hwmod/DT doesn't have the memory resource information
239 * split into HDMI sub blocks by name, we try again by getting
240 * the platform's first resource. this code will be removed when
241 * the driver can get the mem resources by name
242 */
243 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
244 if (!res) {
245 DSSERR("can't get PLL mem resource\n");
246 return -EINVAL;
247 }
248
249 temp_res.start = res->start + PLL_OFFSET;
250 temp_res.end = temp_res.start + PLL_SIZE - 1;
251 res = &temp_res;
252 }
253
254 pll->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
255 if (!pll->base) {
256 DSSERR("can't ioremap PLLCTRL\n");
257 return -ENOMEM;
258 }
259
260 return 0;
261}
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
index d16f28de1272..62a83c79628e 100644
--- a/drivers/video/omap2/dss/ti_hdmi.h
+++ b/drivers/video/omap2/dss/ti_hdmi.h
@@ -155,14 +155,8 @@ struct ti_hdmi_ip_ops {
155 155
156 int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len); 156 int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len);
157 157
158 int (*pll_enable)(struct hdmi_ip_data *ip_data);
159
160 void (*pll_disable)(struct hdmi_ip_data *ip_data);
161
162 void (*dump_core)(struct hdmi_ip_data *ip_data, struct seq_file *s); 158 void (*dump_core)(struct hdmi_ip_data *ip_data, struct seq_file *s);
163 159
164 void (*dump_pll)(struct hdmi_ip_data *ip_data, struct seq_file *s);
165
166 void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); 160 void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
167 161
168#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) 162#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
@@ -223,17 +217,22 @@ struct hdmi_wp_data {
223 void __iomem *base; 217 void __iomem *base;
224}; 218};
225 219
220struct hdmi_pll_data {
221 void __iomem *base;
222
223 struct hdmi_pll_info info;
224};
225
226struct hdmi_ip_data { 226struct hdmi_ip_data {
227 struct hdmi_wp_data wp; 227 struct hdmi_wp_data wp;
228 struct hdmi_pll_data pll;
228 229
229 unsigned long core_sys_offset; 230 unsigned long core_sys_offset;
230 unsigned long core_av_offset; 231 unsigned long core_av_offset;
231 unsigned long pll_offset;
232 unsigned long phy_offset; 232 unsigned long phy_offset;
233 int irq; 233 int irq;
234 const struct ti_hdmi_ip_ops *ops; 234 const struct ti_hdmi_ip_ops *ops;
235 struct hdmi_config cfg; 235 struct hdmi_config cfg;
236 struct hdmi_pll_info pll_data;
237 struct hdmi_core_infoframe_avi avi_cfg; 236 struct hdmi_core_infoframe_avi avi_cfg;
238 237
239 /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ 238 /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */
@@ -260,13 +259,17 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
260 struct omap_video_timings *timings, struct hdmi_config *param); 259 struct omap_video_timings *timings, struct hdmi_config *param);
261int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp); 260int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
262 261
262/* HDMI PLL funcs */
263int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
264void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
265void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
266void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
267int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
268
263int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); 269int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);
264void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); 270void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data);
265int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); 271int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len);
266int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data);
267void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data);
268void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); 272void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data);
269void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
270void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 273void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
271void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); 274void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
272#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) 275#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index d4b8883ecac0..8cfb54b39688 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -75,11 +75,6 @@ static inline void __iomem *hdmi_phy_base(struct hdmi_ip_data *ip_data)
75 return ip_data->wp.base + ip_data->phy_offset; 75 return ip_data->wp.base + ip_data->phy_offset;
76} 76}
77 77
78static inline void __iomem *hdmi_pll_base(struct hdmi_ip_data *ip_data)
79{
80 return ip_data->wp.base + ip_data->pll_offset;
81}
82
83static inline void __iomem *hdmi_av_base(struct hdmi_ip_data *ip_data) 78static inline void __iomem *hdmi_av_base(struct hdmi_ip_data *ip_data)
84{ 79{
85 return ip_data->wp.base + ip_data->core_av_offset; 80 return ip_data->wp.base + ip_data->core_av_offset;
@@ -90,117 +85,6 @@ static inline void __iomem *hdmi_core_sys_base(struct hdmi_ip_data *ip_data)
90 return ip_data->wp.base + ip_data->core_sys_offset; 85 return ip_data->wp.base + ip_data->core_sys_offset;
91} 86}
92 87
93
94static int hdmi_pll_init(struct hdmi_ip_data *ip_data)
95{
96 u32 r;
97 void __iomem *pll_base = hdmi_pll_base(ip_data);
98 struct hdmi_pll_info *fmt = &ip_data->pll_data;
99
100 /* PLL start always use manual mode */
101 REG_FLD_MOD(pll_base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
102
103 r = hdmi_read_reg(pll_base, PLLCTRL_CFG1);
104 r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
105 r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
106
107 hdmi_write_reg(pll_base, PLLCTRL_CFG1, r);
108
109 r = hdmi_read_reg(pll_base, PLLCTRL_CFG2);
110
111 r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
112 r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
113 r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
114 r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
115
116 if (fmt->dcofreq) {
117 /* divider programming for frequency beyond 1000Mhz */
118 REG_FLD_MOD(pll_base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
119 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
120 } else {
121 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
122 }
123
124 hdmi_write_reg(pll_base, PLLCTRL_CFG2, r);
125
126 r = hdmi_read_reg(pll_base, PLLCTRL_CFG4);
127 r = FLD_MOD(r, fmt->regm2, 24, 18);
128 r = FLD_MOD(r, fmt->regmf, 17, 0);
129
130 hdmi_write_reg(pll_base, PLLCTRL_CFG4, r);
131
132 /* go now */
133 REG_FLD_MOD(pll_base, PLLCTRL_PLL_GO, 0x1, 0, 0);
134
135 /* wait for bit change */
136 if (hdmi_wait_for_bit_change(pll_base, PLLCTRL_PLL_GO,
137 0, 0, 1) != 1) {
138 pr_err("PLL GO bit not set\n");
139 return -ETIMEDOUT;
140 }
141
142 /* Wait till the lock bit is set in PLL status */
143 if (hdmi_wait_for_bit_change(pll_base,
144 PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
145 pr_err("cannot lock PLL\n");
146 pr_err("CFG1 0x%x\n",
147 hdmi_read_reg(pll_base, PLLCTRL_CFG1));
148 pr_err("CFG2 0x%x\n",
149 hdmi_read_reg(pll_base, PLLCTRL_CFG2));
150 pr_err("CFG4 0x%x\n",
151 hdmi_read_reg(pll_base, PLLCTRL_CFG4));
152 return -ETIMEDOUT;
153 }
154
155 pr_debug("PLL locked!\n");
156
157 return 0;
158}
159
160
161static int hdmi_pll_reset(struct hdmi_ip_data *ip_data)
162{
163 /* SYSRESET controlled by power FSM */
164 REG_FLD_MOD(hdmi_pll_base(ip_data), PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
165
166 /* READ 0x0 reset is in progress */
167 if (hdmi_wait_for_bit_change(hdmi_pll_base(ip_data),
168 PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) {
169 pr_err("Failed to sysreset PLL\n");
170 return -ETIMEDOUT;
171 }
172
173 return 0;
174}
175
176int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data)
177{
178 u16 r = 0;
179
180 r = hdmi_wp_set_pll_pwr(&ip_data->wp, HDMI_PLLPWRCMD_ALLOFF);
181 if (r)
182 return r;
183
184 r = hdmi_wp_set_pll_pwr(&ip_data->wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
185 if (r)
186 return r;
187
188 r = hdmi_pll_reset(ip_data);
189 if (r)
190 return r;
191
192 r = hdmi_pll_init(ip_data);
193 if (r)
194 return r;
195
196 return 0;
197}
198
199void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data)
200{
201 hdmi_wp_set_pll_pwr(&ip_data->wp, HDMI_PLLPWRCMD_ALLOFF);
202}
203
204static irqreturn_t hdmi_irq_handler(int irq, void *data) 88static irqreturn_t hdmi_irq_handler(int irq, void *data)
205{ 89{
206 struct hdmi_ip_data *ip_data = data; 90 struct hdmi_ip_data *ip_data = data;
@@ -717,22 +601,6 @@ void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data)
717 hdmi_core_av_packet_config(ip_data, repeat_cfg); 601 hdmi_core_av_packet_config(ip_data, repeat_cfg);
718} 602}
719 603
720void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
721{
722#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
723 hdmi_read_reg(hdmi_pll_base(ip_data), r))
724
725 DUMPPLL(PLLCTRL_PLL_CONTROL);
726 DUMPPLL(PLLCTRL_PLL_STATUS);
727 DUMPPLL(PLLCTRL_PLL_GO);
728 DUMPPLL(PLLCTRL_CFG1);
729 DUMPPLL(PLLCTRL_CFG2);
730 DUMPPLL(PLLCTRL_CFG3);
731 DUMPPLL(PLLCTRL_SSC_CFG1);
732 DUMPPLL(PLLCTRL_SSC_CFG2);
733 DUMPPLL(PLLCTRL_CFG4);
734}
735
736void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) 604void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
737{ 605{
738 int i; 606 int i;