aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Yan <andy.yan@rock-chips.com>2015-01-07 02:48:27 -0500
committerPhilipp Zabel <p.zabel@pengutronix.de>2015-01-07 12:32:00 -0500
commit12b9f204e804b2a6c65a6662b1fbe2449bca677f (patch)
tree83cc469366dae142129fdc7e4d5fd1429b5d1bb1
parent74af9e4d03b80c79ee0c21be0a35ec348ffc74ea (diff)
drm: bridge/dw_hdmi: add rockchip rk3288 support
Rockchip RK3288 hdmi is compatible with dw_hdmi Signed-off-by: Andy Yan <andy.yan@rock-chips.com> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r--drivers/gpu/drm/bridge/dw_hdmi.c3
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig10
-rw-r--r--drivers/gpu/drm/rockchip/Makefile2
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c341
-rw-r--r--include/drm/bridge/dw_hdmi.h1
5 files changed, 357 insertions, 0 deletions
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 3a97c8419d4f..80bb512a869f 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -852,6 +852,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
852 dw_hdmi_phy_gen2_txpwron(hdmi, 1); 852 dw_hdmi_phy_gen2_txpwron(hdmi, 1);
853 dw_hdmi_phy_gen2_pddq(hdmi, 0); 853 dw_hdmi_phy_gen2_pddq(hdmi, 0);
854 854
855 if (hdmi->dev_type == RK3288_HDMI)
856 dw_hdmi_phy_enable_spare(hdmi, 1);
857
855 /*Wait for PHY PLL lock */ 858 /*Wait for PHY PLL lock */
856 msec = 5; 859 msec = 5;
857 do { 860 do {
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index ca9f085efa92..0d87bf6ddd96 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -15,3 +15,13 @@ config DRM_ROCKCHIP
15 management to userspace. This driver does not provide 15 management to userspace. This driver does not provide
16 2D or 3D acceleration; acceleration is performed by other 16 2D or 3D acceleration; acceleration is performed by other
17 IP found on the SoC. 17 IP found on the SoC.
18
19config ROCKCHIP_DW_HDMI
20 tristate "Rockchip specific extensions for Synopsys DW HDMI"
21 depends on DRM_ROCKCHIP
22 select DRM_DW_HDMI
23 help
24 This selects support for Rockchip SoC specific extensions
25 for the Synopsys DesignWare HDMI driver. If you want to
26 enable HDMI on RK3288 based SoC, you should selet this
27 option.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 2cb0672f57ed..f3d8a19c641f 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -5,4 +5,6 @@
5rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \ 5rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
6 rockchip_drm_gem.o 6 rockchip_drm_gem.o
7 7
8obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
9
8obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o 10obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 000000000000..d236faa05b19
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,341 @@
1/*
2 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/mfd/syscon.h>
13#include <linux/regmap.h>
14#include <drm/drm_of.h>
15#include <drm/drmP.h>
16#include <drm/drm_crtc_helper.h>
17#include <drm/drm_edid.h>
18#include <drm/drm_encoder_slave.h>
19#include <drm/bridge/dw_hdmi.h>
20
21#include "rockchip_drm_drv.h"
22#include "rockchip_drm_vop.h"
23
24#define GRF_SOC_CON6 0x025c
25#define HDMI_SEL_VOP_LIT (1 << 4)
26
27struct rockchip_hdmi {
28 struct device *dev;
29 struct regmap *regmap;
30 struct drm_encoder encoder;
31};
32
33#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
34
35static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
36 {
37 27000000, {
38 { 0x00b3, 0x0000},
39 { 0x2153, 0x0000},
40 { 0x40f3, 0x0000}
41 },
42 }, {
43 36000000, {
44 { 0x00b3, 0x0000},
45 { 0x2153, 0x0000},
46 { 0x40f3, 0x0000}
47 },
48 }, {
49 40000000, {
50 { 0x00b3, 0x0000},
51 { 0x2153, 0x0000},
52 { 0x40f3, 0x0000}
53 },
54 }, {
55 54000000, {
56 { 0x0072, 0x0001},
57 { 0x2142, 0x0001},
58 { 0x40a2, 0x0001},
59 },
60 }, {
61 65000000, {
62 { 0x0072, 0x0001},
63 { 0x2142, 0x0001},
64 { 0x40a2, 0x0001},
65 },
66 }, {
67 66000000, {
68 { 0x013e, 0x0003},
69 { 0x217e, 0x0002},
70 { 0x4061, 0x0002}
71 },
72 }, {
73 74250000, {
74 { 0x0072, 0x0001},
75 { 0x2145, 0x0002},
76 { 0x4061, 0x0002}
77 },
78 }, {
79 83500000, {
80 { 0x0072, 0x0001},
81 },
82 }, {
83 108000000, {
84 { 0x0051, 0x0002},
85 { 0x2145, 0x0002},
86 { 0x4061, 0x0002}
87 },
88 }, {
89 106500000, {
90 { 0x0051, 0x0002},
91 { 0x2145, 0x0002},
92 { 0x4061, 0x0002}
93 },
94 }, {
95 146250000, {
96 { 0x0051, 0x0002},
97 { 0x2145, 0x0002},
98 { 0x4061, 0x0002}
99 },
100 }, {
101 148500000, {
102 { 0x0051, 0x0003},
103 { 0x214c, 0x0003},
104 { 0x4064, 0x0003}
105 },
106 }, {
107 ~0UL, {
108 { 0x00a0, 0x000a },
109 { 0x2001, 0x000f },
110 { 0x4002, 0x000f },
111 },
112 }
113};
114
115static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
116 /* pixelclk bpp8 bpp10 bpp12 */
117 {
118 40000000, { 0x0018, 0x0018, 0x0018 },
119 }, {
120 65000000, { 0x0028, 0x0028, 0x0028 },
121 }, {
122 66000000, { 0x0038, 0x0038, 0x0038 },
123 }, {
124 74250000, { 0x0028, 0x0038, 0x0038 },
125 }, {
126 83500000, { 0x0028, 0x0038, 0x0038 },
127 }, {
128 146250000, { 0x0038, 0x0038, 0x0038 },
129 }, {
130 148500000, { 0x0000, 0x0038, 0x0038 },
131 }, {
132 ~0UL, { 0x0000, 0x0000, 0x0000},
133 }
134};
135
136static const struct dw_hdmi_sym_term rockchip_sym_term[] = {
137 /*pixelclk symbol term*/
138 { 74250000, 0x8009, 0x0004 },
139 { 148500000, 0x8029, 0x0004 },
140 { 297000000, 0x8039, 0x0005 },
141 { ~0UL, 0x0000, 0x0000 }
142};
143
144static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
145{
146 struct device_node *np = hdmi->dev->of_node;
147
148 hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
149 if (IS_ERR(hdmi->regmap)) {
150 dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
151 return PTR_ERR(hdmi->regmap);
152 }
153
154 return 0;
155}
156
157static enum drm_mode_status
158dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
159 struct drm_display_mode *mode)
160{
161 const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
162 int pclk = mode->clock * 1000;
163 bool valid = false;
164 int i;
165
166 for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
167 if (pclk == mpll_cfg[i].mpixelclock) {
168 valid = true;
169 break;
170 }
171 }
172
173 return (valid) ? MODE_OK : MODE_BAD;
174}
175
176static struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
177 .destroy = drm_encoder_cleanup,
178};
179
180static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
181{
182}
183
184static bool
185dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
186 const struct drm_display_mode *mode,
187 struct drm_display_mode *adj_mode)
188{
189 return true;
190}
191
192static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
193 struct drm_display_mode *mode,
194 struct drm_display_mode *adj_mode)
195{
196}
197
198static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
199{
200 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
201 u32 val;
202 int mux;
203
204 mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
205 if (mux)
206 val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
207 else
208 val = HDMI_SEL_VOP_LIT << 16;
209
210 regmap_write(hdmi->regmap, GRF_SOC_CON6, val);
211 dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
212 (mux) ? "LIT" : "BIG");
213}
214
215static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
216{
217 rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
218 ROCKCHIP_OUT_MODE_AAAA);
219}
220
221static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
222 .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
223 .mode_set = dw_hdmi_rockchip_encoder_mode_set,
224 .prepare = dw_hdmi_rockchip_encoder_prepare,
225 .commit = dw_hdmi_rockchip_encoder_commit,
226 .disable = dw_hdmi_rockchip_encoder_disable,
227};
228
229static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
230 .mode_valid = dw_hdmi_rockchip_mode_valid,
231 .mpll_cfg = rockchip_mpll_cfg,
232 .cur_ctr = rockchip_cur_ctr,
233 .sym_term = rockchip_sym_term,
234 .dev_type = RK3288_HDMI,
235};
236
237static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
238 { .compatible = "rockchip,rk3288-dw-hdmi",
239 .data = &rockchip_hdmi_drv_data
240 },
241 {},
242};
243MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
244
245static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
246 void *data)
247{
248 struct platform_device *pdev = to_platform_device(dev);
249 const struct dw_hdmi_plat_data *plat_data;
250 const struct of_device_id *match;
251 struct drm_device *drm = data;
252 struct drm_encoder *encoder;
253 struct rockchip_hdmi *hdmi;
254 struct resource *iores;
255 int irq;
256 int ret;
257
258 if (!pdev->dev.of_node)
259 return -ENODEV;
260
261 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
262 if (!hdmi)
263 return -ENOMEM;
264
265 match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
266 plat_data = match->data;
267 hdmi->dev = &pdev->dev;
268 encoder = &hdmi->encoder;
269
270 irq = platform_get_irq(pdev, 0);
271 if (irq < 0)
272 return irq;
273
274 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
275 if (!iores)
276 return -ENXIO;
277
278 platform_set_drvdata(pdev, hdmi);
279
280 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
281 /*
282 * If we failed to find the CRTC(s) which this encoder is
283 * supposed to be connected to, it's because the CRTC has
284 * not been registered yet. Defer probing, and hope that
285 * the required CRTC is added later.
286 */
287 if (encoder->possible_crtcs == 0)
288 return -EPROBE_DEFER;
289
290 ret = rockchip_hdmi_parse_dt(hdmi);
291 if (ret) {
292 dev_err(hdmi->dev, "Unable to parse OF data\n");
293 return ret;
294 }
295
296 drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
297 drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
298 DRM_MODE_ENCODER_TMDS);
299
300 return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
301}
302
303static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
304 void *data)
305{
306 return dw_hdmi_unbind(dev, master, data);
307}
308
309static const struct component_ops dw_hdmi_rockchip_ops = {
310 .bind = dw_hdmi_rockchip_bind,
311 .unbind = dw_hdmi_rockchip_unbind,
312};
313
314static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
315{
316 return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
317}
318
319static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
320{
321 component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
322
323 return 0;
324}
325
326static struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
327 .probe = dw_hdmi_rockchip_probe,
328 .remove = dw_hdmi_rockchip_remove,
329 .driver = {
330 .name = "dwhdmi-rockchip",
331 .of_match_table = dw_hdmi_rockchip_dt_ids,
332 },
333};
334
335module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
336
337MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
338MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
339MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
340MODULE_LICENSE("GPL");
341MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index b64e58a92057..5a4f49005169 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,7 @@ enum {
22enum dw_hdmi_devtype { 22enum dw_hdmi_devtype {
23 IMX6Q_HDMI, 23 IMX6Q_HDMI,
24 IMX6DL_HDMI, 24 IMX6DL_HDMI,
25 RK3288_HDMI,
25}; 26};
26 27
27struct dw_hdmi_mpll_config { 28struct dw_hdmi_mpll_config {