diff options
-rw-r--r-- | drivers/video/omap2/dss/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 65 | ||||
-rw-r--r-- | drivers/video/omap2/dss/hdmi_pll.c | 261 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi.h | 25 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 132 |
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 | |||
10 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o | 10 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o |
11 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o | 11 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o |
12 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o | 12 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o |
13 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o hdmi_wp.o ti_hdmi_4xxx_ip.o | 13 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o hdmi_wp.o hdmi_pll.o ti_hdmi_4xxx_ip.o |
14 | ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG | 14 | ccflags-$(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 | |||
59 | static struct { | 55 | static 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 | ||
431 | static 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 | |||
477 | static int hdmi_power_on_core(struct omap_dss_device *dssdev) | 427 | static 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: | |||
566 | err_vid_enable: | 516 | err_vid_enable: |
567 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 517 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
568 | err_phy_enable: | 518 | err_phy_enable: |
569 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 519 | hdmi_pll_disable(&hdmi.ip_data.pll, &hdmi.ip_data.wp); |
570 | err_pll_enable: | 520 | err_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 | |||
26 | static 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 | |||
32 | static 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 | |||
43 | static 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 | |||
55 | void 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 | |||
71 | void 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 | |||
120 | static 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 | |||
183 | static 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 | |||
198 | int 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 | |||
221 | void 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 | |||
229 | int 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 | ||
220 | struct hdmi_pll_data { | ||
221 | void __iomem *base; | ||
222 | |||
223 | struct hdmi_pll_info info; | ||
224 | }; | ||
225 | |||
226 | struct hdmi_ip_data { | 226 | struct 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); |
261 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp); | 260 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp); |
262 | 261 | ||
262 | /* HDMI PLL funcs */ | ||
263 | int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); | ||
264 | void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); | ||
265 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); | ||
266 | void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy); | ||
267 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll); | ||
268 | |||
263 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); | 269 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); |
264 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); | 270 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); |
265 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); | 271 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); |
266 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); | ||
267 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); | ||
268 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); | 272 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); |
269 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
270 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 273 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
271 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 274 | void 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 | ||
78 | static 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 | |||
83 | static inline void __iomem *hdmi_av_base(struct hdmi_ip_data *ip_data) | 78 | static 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 | |||
94 | static 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 | |||
161 | static 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 | |||
176 | int 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 | |||
199 | void 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 | |||
204 | static irqreturn_t hdmi_irq_handler(int irq, void *data) | 88 | static 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 | ||
720 | void 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 | |||
736 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | 604 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) |
737 | { | 605 | { |
738 | int i; | 606 | int i; |