aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2014-07-04 04:08:27 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-02-04 05:32:05 -0500
commit99767548b128dae8eb46b7039958b2b6a5483c66 (patch)
tree00639b260e3be010e0d69c59d6baf881033a1dec
parentbe40eecf8dea217a3f3b9df5c2d7235e91e25fb0 (diff)
OMAPDSS: Add Video PLLs for DRA7xx
DRA7xx SoCs have one (DRA72x) or two (DRA74x) video PLLs. They are basically the same as DSI PLLs on OMAPs, but without the rest of the DSI hardware. The video PLLs also require some configuration via the CONTROL module. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/video/fbdev/omap2/dss/Makefile2
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c58
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h8
-rw-r--r--drivers/video/fbdev/omap2/dss/video-pll.c211
4 files changed, 273 insertions, 6 deletions
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile
index 2ea9d382354c..b5136d3d4b77 100644
--- a/drivers/video/fbdev/omap2/dss/Makefile
+++ b/drivers/video/fbdev/omap2/dss/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
2obj-$(CONFIG_OMAP2_DSS) += omapdss.o 2obj-$(CONFIG_OMAP2_DSS) += omapdss.o
3# Core DSS files 3# Core DSS files
4omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ 4omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
5 output.o dss-of.o pll.o 5 output.o dss-of.o pll.o video-pll.o
6# DSS compat layer files 6# DSS compat layer files
7omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ 7omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
8 dispc-compat.o display-sysfs.o 8 dispc-compat.o display-sysfs.o
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
index d75238f2c537..a6d10d4279f3 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -37,6 +37,7 @@
37#include <linux/mfd/syscon.h> 37#include <linux/mfd/syscon.h>
38#include <linux/regmap.h> 38#include <linux/regmap.h>
39#include <linux/of.h> 39#include <linux/of.h>
40#include <linux/regulator/consumer.h>
40 41
41#include <video/omapdss.h> 42#include <video/omapdss.h>
42 43
@@ -65,9 +66,6 @@ struct dss_reg {
65#define REG_FLD_MOD(idx, val, start, end) \ 66#define REG_FLD_MOD(idx, val, start, end) \
66 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) 67 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
67 68
68static int dss_runtime_get(void);
69static void dss_runtime_put(void);
70
71struct dss_features { 69struct dss_features {
72 u8 fck_div_max; 70 u8 fck_div_max;
73 u8 dss_fck_multiplier; 71 u8 dss_fck_multiplier;
@@ -99,6 +97,9 @@ static struct {
99 u32 ctx[DSS_SZ_REGS / sizeof(u32)]; 97 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
100 98
101 const struct dss_features *feat; 99 const struct dss_features *feat;
100
101 struct dss_pll *video1_pll;
102 struct dss_pll *video2_pll;
102} dss; 103} dss;
103 104
104static const char * const dss_generic_clk_source_names[] = { 105static const char * const dss_generic_clk_source_names[] = {
@@ -760,7 +761,7 @@ static void dss_put_clocks(void)
760 clk_put(dss.parent_clk); 761 clk_put(dss.parent_clk);
761} 762}
762 763
763static int dss_runtime_get(void) 764int dss_runtime_get(void)
764{ 765{
765 int r; 766 int r;
766 767
@@ -771,7 +772,7 @@ static int dss_runtime_get(void)
771 return r < 0 ? r : 0; 772 return r < 0 ? r : 0;
772} 773}
773 774
774static void dss_runtime_put(void) 775void dss_runtime_put(void)
775{ 776{
776 int r; 777 int r;
777 778
@@ -1023,6 +1024,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
1023 struct device_node *np = pdev->dev.of_node; 1024 struct device_node *np = pdev->dev.of_node;
1024 u32 rev; 1025 u32 rev;
1025 int r; 1026 int r;
1027 struct regulator *pll_regulator;
1026 1028
1027 dss.pdev = pdev; 1029 dss.pdev = pdev;
1028 1030
@@ -1094,6 +1096,40 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
1094 } 1096 }
1095 } 1097 }
1096 1098
1099 pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
1100 if (IS_ERR(pll_regulator)) {
1101 r = PTR_ERR(pll_regulator);
1102
1103 switch (r) {
1104 case -ENOENT:
1105 pll_regulator = NULL;
1106 break;
1107
1108 case -EPROBE_DEFER:
1109 return -EPROBE_DEFER;
1110
1111 default:
1112 DSSERR("can't get DPLL VDDA regulator\n");
1113 return r;
1114 }
1115 }
1116
1117 if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
1118 dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
1119 if (IS_ERR(dss.video1_pll)) {
1120 r = PTR_ERR(dss.video1_pll);
1121 goto err_pll_init;
1122 }
1123 }
1124
1125 if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
1126 dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
1127 if (IS_ERR(dss.video2_pll)) {
1128 r = PTR_ERR(dss.video2_pll);
1129 goto err_pll_init;
1130 }
1131 }
1132
1097 rev = dss_read_reg(DSS_REVISION); 1133 rev = dss_read_reg(DSS_REVISION);
1098 printk(KERN_INFO "OMAP DSS rev %d.%d\n", 1134 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
1099 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); 1135 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
@@ -1104,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
1104 1140
1105 return 0; 1141 return 0;
1106 1142
1143err_pll_init:
1144 if (dss.video1_pll)
1145 dss_video_pll_uninit(dss.video1_pll);
1146
1147 if (dss.video2_pll)
1148 dss_video_pll_uninit(dss.video2_pll);
1107err_runtime_get: 1149err_runtime_get:
1108 pm_runtime_disable(&pdev->dev); 1150 pm_runtime_disable(&pdev->dev);
1109err_setup_clocks: 1151err_setup_clocks:
@@ -1113,6 +1155,12 @@ err_setup_clocks:
1113 1155
1114static int __exit omap_dsshw_remove(struct platform_device *pdev) 1156static int __exit omap_dsshw_remove(struct platform_device *pdev)
1115{ 1157{
1158 if (dss.video1_pll)
1159 dss_video_pll_uninit(dss.video1_pll);
1160
1161 if (dss.video2_pll)
1162 dss_video_pll_uninit(dss.video2_pll);
1163
1116 dss_uninit_ports(pdev); 1164 dss_uninit_ports(pdev);
1117 1165
1118 pm_runtime_disable(&pdev->dev); 1166 pm_runtime_disable(&pdev->dev);
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h
index 76a6eb1da090..4812eee2622a 100644
--- a/drivers/video/fbdev/omap2/dss/dss.h
+++ b/drivers/video/fbdev/omap2/dss/dss.h
@@ -259,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
259int dss_init_platform_driver(void) __init; 259int dss_init_platform_driver(void) __init;
260void dss_uninit_platform_driver(void); 260void dss_uninit_platform_driver(void);
261 261
262int dss_runtime_get(void);
263void dss_runtime_put(void);
264
262unsigned long dss_get_dispc_clk_rate(void); 265unsigned long dss_get_dispc_clk_rate(void);
263int dss_dpi_select_source(int port, enum omap_channel channel); 266int dss_dpi_select_source(int port, enum omap_channel channel);
264void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); 267void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
@@ -266,6 +269,11 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
266const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); 269const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
267void dss_dump_clocks(struct seq_file *s); 270void dss_dump_clocks(struct seq_file *s);
268 271
272/* DSS VIDEO PLL */
273struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
274 struct regulator *regulator);
275void dss_video_pll_uninit(struct dss_pll *pll);
276
269/* dss-of */ 277/* dss-of */
270struct device_node *dss_of_port_get_parent_device(struct device_node *port); 278struct device_node *dss_of_port_get_parent_device(struct device_node *port);
271u32 dss_of_port_get_port_number(struct device_node *port); 279u32 dss_of_port_get_port_number(struct device_node *port);
diff --git a/drivers/video/fbdev/omap2/dss/video-pll.c b/drivers/video/fbdev/omap2/dss/video-pll.c
new file mode 100644
index 000000000000..b1ec59e42940
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/video-pll.c
@@ -0,0 +1,211 @@
1/*
2* Copyright (C) 2014 Texas Instruments Ltd
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms of the GNU General Public License version 2 as published by
6* the Free Software Foundation.
7*
8* You should have received a copy of the GNU General Public License along with
9* this program. If not, see <http://www.gnu.org/licenses/>.
10*/
11
12#include <linux/clk.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/kernel.h>
17#include <linux/platform_device.h>
18#include <linux/sched.h>
19
20#include <video/omapdss.h>
21
22#include "dss.h"
23#include "dss_features.h"
24
25struct dss_video_pll {
26 struct dss_pll pll;
27
28 struct device *dev;
29
30 void __iomem *clkctrl_base;
31};
32
33#define REG_MOD(reg, val, start, end) \
34 writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg)
35
36static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll)
37{
38 REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */
39}
40
41static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll)
42{
43 REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */
44}
45
46static void dss_dpll_power_enable(struct dss_video_pll *vpll)
47{
48 REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */
49
50 /*
51 * DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0,
52 * so we have to use fixed delay here.
53 */
54 msleep(1);
55}
56
57static void dss_dpll_power_disable(struct dss_video_pll *vpll)
58{
59 REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */
60}
61
62static int dss_video_pll_enable(struct dss_pll *pll)
63{
64 struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
65 int r;
66
67 r = dss_runtime_get();
68 if (r)
69 return r;
70
71 dss_ctrl_pll_enable(pll->id, true);
72
73 dss_dpll_enable_scp_clk(vpll);
74
75 r = dss_pll_wait_reset_done(pll);
76 if (r)
77 goto err_reset;
78
79 dss_dpll_power_enable(vpll);
80
81 return 0;
82
83err_reset:
84 dss_dpll_disable_scp_clk(vpll);
85 dss_ctrl_pll_enable(pll->id, false);
86 dss_runtime_put();
87
88 return r;
89}
90
91static void dss_video_pll_disable(struct dss_pll *pll)
92{
93 struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
94
95 dss_dpll_power_disable(vpll);
96
97 dss_dpll_disable_scp_clk(vpll);
98
99 dss_ctrl_pll_enable(pll->id, false);
100
101 dss_runtime_put();
102}
103
104static const struct dss_pll_ops dss_pll_ops = {
105 .enable = dss_video_pll_enable,
106 .disable = dss_video_pll_disable,
107 .set_config = dss_pll_write_config_type_a,
108};
109
110static const struct dss_pll_hw dss_dra7_video_pll_hw = {
111 .n_max = (1 << 8) - 1,
112 .m_max = (1 << 12) - 1,
113 .mX_max = (1 << 5) - 1,
114 .fint_min = 500000,
115 .fint_max = 2500000,
116 .clkdco_max = 1800000000,
117
118 .n_msb = 8,
119 .n_lsb = 1,
120 .m_msb = 20,
121 .m_lsb = 9,
122
123 .mX_msb[0] = 25,
124 .mX_lsb[0] = 21,
125 .mX_msb[1] = 30,
126 .mX_lsb[1] = 26,
127
128 .has_refsel = true,
129};
130
131struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
132 struct regulator *regulator)
133{
134 const char * const reg_name[] = { "pll1", "pll2" };
135 const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" };
136 const char * const clkin_name[] = { "video1_clk", "video2_clk" };
137
138 struct resource *res;
139 struct dss_video_pll *vpll;
140 void __iomem *pll_base, *clkctrl_base;
141 struct clk *clk;
142 struct dss_pll *pll;
143 int r;
144
145 /* PLL CONTROL */
146
147 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]);
148 if (!res) {
149 dev_err(&pdev->dev,
150 "missing platform resource data for pll%d\n", id);
151 return ERR_PTR(-ENODEV);
152 }
153
154 pll_base = devm_ioremap_resource(&pdev->dev, res);
155 if (IS_ERR(pll_base)) {
156 dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id);
157 return ERR_CAST(pll_base);
158 }
159
160 /* CLOCK CONTROL */
161
162 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
163 clkctrl_name[id]);
164 if (!res) {
165 dev_err(&pdev->dev,
166 "missing platform resource data for pll%d\n", id);
167 return ERR_PTR(-ENODEV);
168 }
169
170 clkctrl_base = devm_ioremap_resource(&pdev->dev, res);
171 if (IS_ERR(clkctrl_base)) {
172 dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id);
173 return ERR_CAST(clkctrl_base);
174 }
175
176 /* CLKIN */
177
178 clk = devm_clk_get(&pdev->dev, clkin_name[id]);
179 if (IS_ERR(clk)) {
180 DSSERR("can't get video pll clkin\n");
181 return ERR_CAST(clk);
182 }
183
184 vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL);
185 if (!vpll)
186 return ERR_PTR(-ENOMEM);
187
188 vpll->dev = &pdev->dev;
189 vpll->clkctrl_base = clkctrl_base;
190
191 pll = &vpll->pll;
192
193 pll->name = id == 0 ? "video0" : "video1";
194 pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2;
195 pll->clkin = clk;
196 pll->regulator = regulator;
197 pll->base = pll_base;
198 pll->hw = &dss_dra7_video_pll_hw;
199 pll->ops = &dss_pll_ops;
200
201 r = dss_pll_register(pll);
202 if (r)
203 return ERR_PTR(r);
204
205 return pll;
206}
207
208void dss_video_pll_uninit(struct dss_pll *pll)
209{
210 dss_pll_unregister(pll);
211}