aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-08-30 13:02:15 -0400
committerDave Airlie <airlied@redhat.com>2013-09-01 20:23:35 -0400
commita3376e3ec81c5dd0622cbc187db76d2824d31c1c (patch)
tree22e4e13c73905a624692cbfd7c7a560d79597b67
parent3b336ec4c5460833ad7573d0b6e22793f6a389ab (diff)
drm/msm: convert to drm_bridge
Drop the msm_connector base class, and special calls to base class methods from the encoder, and use instead drm_bridge. This allows for a cleaner division between the hdmi (and in future dsi) blocks, from the mdp block. Signed-off-by: Rob Clark <robdclark@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/msm/Makefile2
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c49
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h31
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_bridge.c167
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c156
-rw-r--r--drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c12
-rw-r--r--drivers/gpu/drm/msm/mdp4/mdp4_kms.c9
-rw-r--r--drivers/gpu/drm/msm/msm_connector.c34
-rw-r--r--drivers/gpu/drm/msm/msm_connector.h68
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h6
10 files changed, 274 insertions, 260 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 439dfb5b417b..e17914889e54 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -7,6 +7,7 @@ msm-y := \
7 adreno/adreno_gpu.o \ 7 adreno/adreno_gpu.o \
8 adreno/a3xx_gpu.o \ 8 adreno/a3xx_gpu.o \
9 hdmi/hdmi.o \ 9 hdmi/hdmi.o \
10 hdmi/hdmi_bridge.o \
10 hdmi/hdmi_connector.o \ 11 hdmi/hdmi_connector.o \
11 hdmi/hdmi_i2c.o \ 12 hdmi/hdmi_i2c.o \
12 hdmi/hdmi_phy_8960.o \ 13 hdmi/hdmi_phy_8960.o \
@@ -17,7 +18,6 @@ msm-y := \
17 mdp4/mdp4_irq.o \ 18 mdp4/mdp4_irq.o \
18 mdp4/mdp4_kms.o \ 19 mdp4/mdp4_kms.o \
19 mdp4/mdp4_plane.o \ 20 mdp4/mdp4_plane.o \
20 msm_connector.o \
21 msm_drv.o \ 21 msm_drv.o \
22 msm_fb.o \ 22 msm_fb.o \
23 msm_gem.o \ 23 msm_gem.o \
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 12ecfb928f75..50d11df35b21 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -56,8 +56,9 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id)
56 return IRQ_HANDLED; 56 return IRQ_HANDLED;
57} 57}
58 58
59void hdmi_destroy(struct hdmi *hdmi) 59void hdmi_destroy(struct kref *kref)
60{ 60{
61 struct hdmi *hdmi = container_of(kref, struct hdmi, refcount);
61 struct hdmi_phy *phy = hdmi->phy; 62 struct hdmi_phy *phy = hdmi->phy;
62 63
63 if (phy) 64 if (phy)
@@ -70,9 +71,10 @@ void hdmi_destroy(struct hdmi *hdmi)
70} 71}
71 72
72/* initialize connector */ 73/* initialize connector */
73int hdmi_init(struct hdmi *hdmi, struct drm_device *dev, 74int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
74 struct drm_connector *connector)
75{ 75{
76 struct hdmi *hdmi = NULL;
77 struct msm_drm_private *priv = dev->dev_private;
76 struct platform_device *pdev = hdmi_pdev; 78 struct platform_device *pdev = hdmi_pdev;
77 struct hdmi_platform_config *config; 79 struct hdmi_platform_config *config;
78 int ret; 80 int ret;
@@ -85,11 +87,19 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
85 87
86 config = pdev->dev.platform_data; 88 config = pdev->dev.platform_data;
87 89
90 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
91 if (!hdmi) {
92 ret = -ENOMEM;
93 goto fail;
94 }
95
96 kref_init(&hdmi->refcount);
97
88 get_device(&pdev->dev); 98 get_device(&pdev->dev);
89 99
90 hdmi->dev = dev; 100 hdmi->dev = dev;
91 hdmi->pdev = pdev; 101 hdmi->pdev = pdev;
92 hdmi->connector = connector; 102 hdmi->encoder = encoder;
93 103
94 /* not sure about which phy maps to which msm.. probably I miss some */ 104 /* not sure about which phy maps to which msm.. probably I miss some */
95 if (config->phy_init) 105 if (config->phy_init)
@@ -152,6 +162,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
152 goto fail; 162 goto fail;
153 } 163 }
154 164
165 hdmi->bridge = hdmi_bridge_init(hdmi);
166 if (IS_ERR(hdmi->bridge)) {
167 ret = PTR_ERR(hdmi->bridge);
168 dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret);
169 hdmi->bridge = NULL;
170 goto fail;
171 }
172
173 hdmi->connector = hdmi_connector_init(hdmi);
174 if (IS_ERR(hdmi->connector)) {
175 ret = PTR_ERR(hdmi->connector);
176 dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret);
177 hdmi->connector = NULL;
178 goto fail;
179 }
180
155 hdmi->irq = platform_get_irq(pdev, 0); 181 hdmi->irq = platform_get_irq(pdev, 0);
156 if (hdmi->irq < 0) { 182 if (hdmi->irq < 0) {
157 ret = hdmi->irq; 183 ret = hdmi->irq;
@@ -168,11 +194,22 @@ int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
168 goto fail; 194 goto fail;
169 } 195 }
170 196
197 encoder->bridge = hdmi->bridge;
198
199 priv->bridges[priv->num_bridges++] = hdmi->bridge;
200 priv->connectors[priv->num_connectors++] = hdmi->connector;
201
171 return 0; 202 return 0;
172 203
173fail: 204fail:
174 if (hdmi) 205 if (hdmi) {
175 hdmi_destroy(hdmi); 206 /* bridge/connector are normally destroyed by drm: */
207 if (hdmi->bridge)
208 hdmi->bridge->funcs->destroy(hdmi->bridge);
209 if (hdmi->connector)
210 hdmi->connector->funcs->destroy(hdmi->connector);
211 hdmi_destroy(&hdmi->refcount);
212 }
176 213
177 return ret; 214 return ret;
178} 215}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 34703fea22ca..2c2ec566394c 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -30,6 +30,8 @@
30struct hdmi_phy; 30struct hdmi_phy;
31 31
32struct hdmi { 32struct hdmi {
33 struct kref refcount;
34
33 struct drm_device *dev; 35 struct drm_device *dev;
34 struct platform_device *pdev; 36 struct platform_device *pdev;
35 37
@@ -45,6 +47,10 @@ struct hdmi {
45 struct hdmi_phy *phy; 47 struct hdmi_phy *phy;
46 struct i2c_adapter *i2c; 48 struct i2c_adapter *i2c;
47 struct drm_connector *connector; 49 struct drm_connector *connector;
50 struct drm_bridge *bridge;
51
52 /* the encoder we are hooked to (outside of hdmi block) */
53 struct drm_encoder *encoder;
48 54
49 bool hdmi_mode; /* are we in hdmi mode? */ 55 bool hdmi_mode; /* are we in hdmi mode? */
50 56
@@ -58,9 +64,7 @@ struct hdmi_platform_config {
58}; 64};
59 65
60void hdmi_set_mode(struct hdmi *hdmi, bool power_on); 66void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
61void hdmi_destroy(struct hdmi *hdmi); 67void hdmi_destroy(struct kref *kref);
62int hdmi_init(struct hdmi *hdmi, struct drm_device *dev,
63 struct drm_connector *connector);
64 68
65static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data) 69static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data)
66{ 70{
@@ -72,6 +76,17 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
72 return msm_readl(hdmi->mmio + reg); 76 return msm_readl(hdmi->mmio + reg);
73} 77}
74 78
79static inline struct hdmi * hdmi_reference(struct hdmi *hdmi)
80{
81 kref_get(&hdmi->refcount);
82 return hdmi;
83}
84
85static inline void hdmi_unreference(struct hdmi *hdmi)
86{
87 kref_put(&hdmi->refcount, hdmi_destroy);
88}
89
75/* 90/*
76 * The phy appears to be different, for example between 8960 and 8x60, 91 * The phy appears to be different, for example between 8960 and 8x60,
77 * so split the phy related functions out and load the correct one at 92 * so split the phy related functions out and load the correct one at
@@ -89,17 +104,21 @@ struct hdmi_phy {
89 const struct hdmi_phy_funcs *funcs; 104 const struct hdmi_phy_funcs *funcs;
90}; 105};
91 106
92/*
93 * phy can be different on different generations:
94 */
95struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi); 107struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
96struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi); 108struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
97 109
98/* 110/*
111 * hdmi bridge:
112 */
113
114struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
115
116/*
99 * hdmi connector: 117 * hdmi connector:
100 */ 118 */
101 119
102void hdmi_connector_irq(struct drm_connector *connector); 120void hdmi_connector_irq(struct drm_connector *connector);
121struct drm_connector *hdmi_connector_init(struct hdmi *hdmi);
103 122
104/* 123/*
105 * i2c adapter for ddc: 124 * i2c adapter for ddc:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
new file mode 100644
index 000000000000..5a8ee3473cf5
--- /dev/null
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -0,0 +1,167 @@
1/*
2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "hdmi.h"
19
20struct hdmi_bridge {
21 struct drm_bridge base;
22
23 struct hdmi *hdmi;
24
25 unsigned long int pixclock;
26};
27#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
28
29static void hdmi_bridge_destroy(struct drm_bridge *bridge)
30{
31 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
32 hdmi_unreference(hdmi_bridge->hdmi);
33 drm_bridge_cleanup(bridge);
34 kfree(hdmi_bridge);
35}
36
37static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
38{
39 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
40 struct hdmi *hdmi = hdmi_bridge->hdmi;
41 struct hdmi_phy *phy = hdmi->phy;
42
43 DBG("power up");
44 phy->funcs->powerup(phy, hdmi_bridge->pixclock);
45 hdmi_set_mode(hdmi, true);
46}
47
48static void hdmi_bridge_enable(struct drm_bridge *bridge)
49{
50}
51
52static void hdmi_bridge_disable(struct drm_bridge *bridge)
53{
54}
55
56static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
57{
58 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
59 struct hdmi *hdmi = hdmi_bridge->hdmi;
60 struct hdmi_phy *phy = hdmi->phy;
61
62 DBG("power down");
63 hdmi_set_mode(hdmi, false);
64 phy->funcs->powerdown(phy);
65}
66
67static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
68 struct drm_display_mode *mode,
69 struct drm_display_mode *adjusted_mode)
70{
71 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
72 struct hdmi *hdmi = hdmi_bridge->hdmi;
73 int hstart, hend, vstart, vend;
74 uint32_t frame_ctrl;
75
76 mode = adjusted_mode;
77
78 hdmi_bridge->pixclock = mode->clock * 1000;
79
80 hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
81
82 hstart = mode->htotal - mode->hsync_start;
83 hend = mode->htotal - mode->hsync_start + mode->hdisplay;
84
85 vstart = mode->vtotal - mode->vsync_start - 1;
86 vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
87
88 DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
89 mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
90
91 hdmi_write(hdmi, REG_HDMI_TOTAL,
92 HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
93 HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
94
95 hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
96 HDMI_ACTIVE_HSYNC_START(hstart) |
97 HDMI_ACTIVE_HSYNC_END(hend));
98 hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
99 HDMI_ACTIVE_VSYNC_START(vstart) |
100 HDMI_ACTIVE_VSYNC_END(vend));
101
102 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
103 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
104 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
105 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
106 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
107 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
108 } else {
109 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
110 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
111 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
112 HDMI_VSYNC_ACTIVE_F2_START(0) |
113 HDMI_VSYNC_ACTIVE_F2_END(0));
114 }
115
116 frame_ctrl = 0;
117 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
118 frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
119 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
120 frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
121 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
122 frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
123 DBG("frame_ctrl=%08x", frame_ctrl);
124 hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
125
126 // TODO until we have audio, this might be safest:
127 if (hdmi->hdmi_mode)
128 hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
129}
130
131static const struct drm_bridge_funcs hdmi_bridge_funcs = {
132 .pre_enable = hdmi_bridge_pre_enable,
133 .enable = hdmi_bridge_enable,
134 .disable = hdmi_bridge_disable,
135 .post_disable = hdmi_bridge_post_disable,
136 .mode_set = hdmi_bridge_mode_set,
137 .destroy = hdmi_bridge_destroy,
138};
139
140
141/* initialize bridge */
142struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
143{
144 struct drm_bridge *bridge = NULL;
145 struct hdmi_bridge *hdmi_bridge;
146 int ret;
147
148 hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL);
149 if (!hdmi_bridge) {
150 ret = -ENOMEM;
151 goto fail;
152 }
153
154 hdmi_bridge->hdmi = hdmi_reference(hdmi);
155
156 bridge = &hdmi_bridge->base;
157
158 drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
159
160 return bridge;
161
162fail:
163 if (bridge)
164 hdmi_bridge_destroy(bridge);
165
166 return ERR_PTR(ret);
167}
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index 7d63f5ffa7ba..823eee521a31 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -17,14 +17,11 @@
17 17
18#include <linux/gpio.h> 18#include <linux/gpio.h>
19 19
20#include "msm_connector.h"
21#include "hdmi.h" 20#include "hdmi.h"
22 21
23struct hdmi_connector { 22struct hdmi_connector {
24 struct msm_connector base; 23 struct drm_connector base;
25 struct hdmi hdmi; 24 struct hdmi *hdmi;
26 unsigned long int pixclock;
27 bool enabled;
28}; 25};
29#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base) 26#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
30 27
@@ -90,8 +87,8 @@ error1:
90 87
91static int hpd_enable(struct hdmi_connector *hdmi_connector) 88static int hpd_enable(struct hdmi_connector *hdmi_connector)
92{ 89{
93 struct hdmi *hdmi = &hdmi_connector->hdmi; 90 struct hdmi *hdmi = hdmi_connector->hdmi;
94 struct drm_device *dev = hdmi_connector->base.base.dev; 91 struct drm_device *dev = hdmi_connector->base.dev;
95 struct hdmi_phy *phy = hdmi->phy; 92 struct hdmi_phy *phy = hdmi->phy;
96 uint32_t hpd_ctrl; 93 uint32_t hpd_ctrl;
97 int ret; 94 int ret;
@@ -158,8 +155,8 @@ fail:
158 155
159static int hdp_disable(struct hdmi_connector *hdmi_connector) 156static int hdp_disable(struct hdmi_connector *hdmi_connector)
160{ 157{
161 struct hdmi *hdmi = &hdmi_connector->hdmi; 158 struct hdmi *hdmi = hdmi_connector->hdmi;
162 struct drm_device *dev = hdmi_connector->base.base.dev; 159 struct drm_device *dev = hdmi_connector->base.dev;
163 int ret = 0; 160 int ret = 0;
164 161
165 /* Disable HPD interrupt */ 162 /* Disable HPD interrupt */
@@ -194,9 +191,8 @@ fail:
194 191
195void hdmi_connector_irq(struct drm_connector *connector) 192void hdmi_connector_irq(struct drm_connector *connector)
196{ 193{
197 struct msm_connector *msm_connector = to_msm_connector(connector); 194 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
198 struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector); 195 struct hdmi *hdmi = hdmi_connector->hdmi;
199 struct hdmi *hdmi = &hdmi_connector->hdmi;
200 uint32_t hpd_int_status, hpd_int_ctrl; 196 uint32_t hpd_int_status, hpd_int_ctrl;
201 197
202 /* Process HPD: */ 198 /* Process HPD: */
@@ -226,9 +222,8 @@ void hdmi_connector_irq(struct drm_connector *connector)
226static enum drm_connector_status hdmi_connector_detect( 222static enum drm_connector_status hdmi_connector_detect(
227 struct drm_connector *connector, bool force) 223 struct drm_connector *connector, bool force)
228{ 224{
229 struct msm_connector *msm_connector = to_msm_connector(connector); 225 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
230 struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector); 226 struct hdmi *hdmi = hdmi_connector->hdmi;
231 struct hdmi *hdmi = &hdmi_connector->hdmi;
232 uint32_t hpd_int_status; 227 uint32_t hpd_int_status;
233 int retry = 20; 228 int retry = 20;
234 229
@@ -249,24 +244,22 @@ static enum drm_connector_status hdmi_connector_detect(
249 244
250static void hdmi_connector_destroy(struct drm_connector *connector) 245static void hdmi_connector_destroy(struct drm_connector *connector)
251{ 246{
252 struct msm_connector *msm_connector = to_msm_connector(connector); 247 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
253 struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
254 248
255 hdp_disable(hdmi_connector); 249 hdp_disable(hdmi_connector);
256 250
257 drm_sysfs_connector_remove(connector); 251 drm_sysfs_connector_remove(connector);
258 drm_connector_cleanup(connector); 252 drm_connector_cleanup(connector);
259 253
260 hdmi_destroy(&hdmi_connector->hdmi); 254 hdmi_unreference(hdmi_connector->hdmi);
261 255
262 kfree(hdmi_connector); 256 kfree(hdmi_connector);
263} 257}
264 258
265static int hdmi_connector_get_modes(struct drm_connector *connector) 259static int hdmi_connector_get_modes(struct drm_connector *connector)
266{ 260{
267 struct msm_connector *msm_connector = to_msm_connector(connector); 261 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
268 struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector); 262 struct hdmi *hdmi = hdmi_connector->hdmi;
269 struct hdmi *hdmi = &hdmi_connector->hdmi;
270 struct edid *edid; 263 struct edid *edid;
271 uint32_t hdmi_ctrl; 264 uint32_t hdmi_ctrl;
272 int ret = 0; 265 int ret = 0;
@@ -291,14 +284,14 @@ static int hdmi_connector_get_modes(struct drm_connector *connector)
291static int hdmi_connector_mode_valid(struct drm_connector *connector, 284static int hdmi_connector_mode_valid(struct drm_connector *connector,
292 struct drm_display_mode *mode) 285 struct drm_display_mode *mode)
293{ 286{
294 struct msm_connector *msm_connector = to_msm_connector(connector); 287 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
295 struct msm_drm_private *priv = connector->dev->dev_private; 288 struct msm_drm_private *priv = connector->dev->dev_private;
296 struct msm_kms *kms = priv->kms; 289 struct msm_kms *kms = priv->kms;
297 long actual, requested; 290 long actual, requested;
298 291
299 requested = 1000 * mode->clock; 292 requested = 1000 * mode->clock;
300 actual = kms->funcs->round_pixclk(kms, 293 actual = kms->funcs->round_pixclk(kms,
301 requested, msm_connector->encoder); 294 requested, hdmi_connector->hdmi->encoder);
302 295
303 DBG("requested=%ld, actual=%ld", requested, actual); 296 DBG("requested=%ld, actual=%ld", requested, actual);
304 297
@@ -308,6 +301,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
308 return 0; 301 return 0;
309} 302}
310 303
304static struct drm_encoder *
305hdmi_connector_best_encoder(struct drm_connector *connector)
306{
307 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
308 return hdmi_connector->hdmi->encoder;
309}
310
311static const struct drm_connector_funcs hdmi_connector_funcs = { 311static const struct drm_connector_funcs hdmi_connector_funcs = {
312 .dpms = drm_helper_connector_dpms, 312 .dpms = drm_helper_connector_dpms,
313 .detect = hdmi_connector_detect, 313 .detect = hdmi_connector_detect,
@@ -318,101 +318,11 @@ static const struct drm_connector_funcs hdmi_connector_funcs = {
318static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { 318static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
319 .get_modes = hdmi_connector_get_modes, 319 .get_modes = hdmi_connector_get_modes,
320 .mode_valid = hdmi_connector_mode_valid, 320 .mode_valid = hdmi_connector_mode_valid,
321 .best_encoder = msm_connector_attached_encoder, 321 .best_encoder = hdmi_connector_best_encoder,
322};
323
324static void hdmi_connector_dpms(struct msm_connector *msm_connector, int mode)
325{
326 struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
327 struct hdmi *hdmi = &hdmi_connector->hdmi;
328 struct hdmi_phy *phy = hdmi->phy;
329 bool enabled = (mode == DRM_MODE_DPMS_ON);
330
331 DBG("mode=%d", mode);
332
333 if (enabled == hdmi_connector->enabled)
334 return;
335
336 if (enabled) {
337 phy->funcs->powerup(phy, hdmi_connector->pixclock);
338 hdmi_set_mode(hdmi, true);
339 } else {
340 hdmi_set_mode(hdmi, false);
341 phy->funcs->powerdown(phy);
342 }
343
344 hdmi_connector->enabled = enabled;
345}
346
347static void hdmi_connector_mode_set(struct msm_connector *msm_connector,
348 struct drm_display_mode *mode)
349{
350 struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
351 struct hdmi *hdmi = &hdmi_connector->hdmi;
352 int hstart, hend, vstart, vend;
353 uint32_t frame_ctrl;
354
355 hdmi_connector->pixclock = mode->clock * 1000;
356
357 hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
358
359 hstart = mode->htotal - mode->hsync_start;
360 hend = mode->htotal - mode->hsync_start + mode->hdisplay;
361
362 vstart = mode->vtotal - mode->vsync_start - 1;
363 vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
364
365 DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
366 mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
367
368 hdmi_write(hdmi, REG_HDMI_TOTAL,
369 HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
370 HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
371
372 hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
373 HDMI_ACTIVE_HSYNC_START(hstart) |
374 HDMI_ACTIVE_HSYNC_END(hend));
375 hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
376 HDMI_ACTIVE_VSYNC_START(vstart) |
377 HDMI_ACTIVE_VSYNC_END(vend));
378
379 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
380 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
381 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
382 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
383 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
384 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
385 } else {
386 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
387 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
388 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
389 HDMI_VSYNC_ACTIVE_F2_START(0) |
390 HDMI_VSYNC_ACTIVE_F2_END(0));
391 }
392
393 frame_ctrl = 0;
394 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
395 frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
396 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
397 frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
398 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
399 frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
400 DBG("frame_ctrl=%08x", frame_ctrl);
401 hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
402
403 // TODO until we have audio, this might be safest:
404 if (hdmi->hdmi_mode)
405 hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
406}
407
408static const struct msm_connector_funcs msm_connector_funcs = {
409 .dpms = hdmi_connector_dpms,
410 .mode_set = hdmi_connector_mode_set,
411}; 322};
412 323
413/* initialize connector */ 324/* initialize connector */
414struct drm_connector *hdmi_connector_init(struct drm_device *dev, 325struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
415 struct drm_encoder *encoder)
416{ 326{
417 struct drm_connector *connector = NULL; 327 struct drm_connector *connector = NULL;
418 struct hdmi_connector *hdmi_connector; 328 struct hdmi_connector *hdmi_connector;
@@ -424,11 +334,11 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev,
424 goto fail; 334 goto fail;
425 } 335 }
426 336
427 connector = &hdmi_connector->base.base; 337 hdmi_connector->hdmi = hdmi_reference(hdmi);
338
339 connector = &hdmi_connector->base;
428 340
429 msm_connector_init(&hdmi_connector->base, 341 drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
430 &msm_connector_funcs, encoder);
431 drm_connector_init(dev, connector, &hdmi_connector_funcs,
432 DRM_MODE_CONNECTOR_HDMIA); 342 DRM_MODE_CONNECTOR_HDMIA);
433 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); 343 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
434 344
@@ -439,17 +349,13 @@ struct drm_connector *hdmi_connector_init(struct drm_device *dev,
439 349
440 drm_sysfs_connector_add(connector); 350 drm_sysfs_connector_add(connector);
441 351
442 ret = hdmi_init(&hdmi_connector->hdmi, dev, connector);
443 if (ret)
444 goto fail;
445
446 ret = hpd_enable(hdmi_connector); 352 ret = hpd_enable(hdmi_connector);
447 if (ret) { 353 if (ret) {
448 dev_err(dev->dev, "failed to enable HPD: %d\n", ret); 354 dev_err(hdmi->dev->dev, "failed to enable HPD: %d\n", ret);
449 goto fail; 355 goto fail;
450 } 356 }
451 357
452 drm_mode_connector_attach_encoder(connector, encoder); 358 drm_mode_connector_attach_encoder(connector, hdmi->encoder);
453 359
454 return connector; 360 return connector;
455 361
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
index 06d49e309d34..5e0dcae70ab5 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
@@ -18,7 +18,6 @@
18#include <mach/clk.h> 18#include <mach/clk.h>
19 19
20#include "mdp4_kms.h" 20#include "mdp4_kms.h"
21#include "msm_connector.h"
22 21
23#include "drm_crtc.h" 22#include "drm_crtc.h"
24#include "drm_crtc_helper.h" 23#include "drm_crtc_helper.h"
@@ -101,7 +100,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
101{ 100{
102 struct drm_device *dev = encoder->dev; 101 struct drm_device *dev = encoder->dev;
103 struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); 102 struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
104 struct msm_connector *msm_connector = get_connector(encoder);
105 struct mdp4_kms *mdp4_kms = get_kms(encoder); 103 struct mdp4_kms *mdp4_kms = get_kms(encoder);
106 bool enabled = (mode == DRM_MODE_DPMS_ON); 104 bool enabled = (mode == DRM_MODE_DPMS_ON);
107 105
@@ -116,9 +114,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
116 114
117 bs_set(mdp4_dtv_encoder, 1); 115 bs_set(mdp4_dtv_encoder, 1);
118 116
119 if (msm_connector)
120 msm_connector->funcs->dpms(msm_connector, mode);
121
122 DBG("setting src_clk=%lu", pc); 117 DBG("setting src_clk=%lu", pc);
123 118
124 ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc); 119 ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
@@ -150,9 +145,6 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
150 clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk); 145 clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
151 clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk); 146 clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
152 147
153 if (msm_connector)
154 msm_connector->funcs->dpms(msm_connector, mode);
155
156 bs_set(mdp4_dtv_encoder, 0); 148 bs_set(mdp4_dtv_encoder, 0);
157 } 149 }
158 150
@@ -171,7 +163,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
171 struct drm_display_mode *adjusted_mode) 163 struct drm_display_mode *adjusted_mode)
172{ 164{
173 struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); 165 struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
174 struct msm_connector *msm_connector = get_connector(encoder);
175 struct mdp4_kms *mdp4_kms = get_kms(encoder); 166 struct mdp4_kms *mdp4_kms = get_kms(encoder);
176 uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; 167 uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
177 uint32_t display_v_start, display_v_end; 168 uint32_t display_v_start, display_v_end;
@@ -230,9 +221,6 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
230 MDP4_DTV_ACTIVE_HCTL_END(0)); 221 MDP4_DTV_ACTIVE_HCTL_END(0));
231 mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0); 222 mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VSTART, 0);
232 mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0); 223 mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
233
234 if (msm_connector)
235 msm_connector->funcs->mode_set(msm_connector, mode);
236} 224}
237 225
238static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder) 226static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c
index 960cd894da78..5db5bbaedae2 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c
@@ -191,7 +191,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
191 struct drm_plane *plane; 191 struct drm_plane *plane;
192 struct drm_crtc *crtc; 192 struct drm_crtc *crtc;
193 struct drm_encoder *encoder; 193 struct drm_encoder *encoder;
194 struct drm_connector *connector;
195 int ret; 194 int ret;
196 195
197 /* 196 /*
@@ -224,13 +223,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
224 encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */ 223 encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */
225 priv->encoders[priv->num_encoders++] = encoder; 224 priv->encoders[priv->num_encoders++] = encoder;
226 225
227 connector = hdmi_connector_init(dev, encoder); 226 ret = hdmi_init(dev, encoder);
228 if (IS_ERR(connector)) { 227 if (ret) {
229 dev_err(dev->dev, "failed to construct HDMI connector\n"); 228 dev_err(dev->dev, "failed to initialize HDMI\n");
230 ret = PTR_ERR(connector);
231 goto fail; 229 goto fail;
232 } 230 }
233 priv->connectors[priv->num_connectors++] = connector;
234 231
235 return 0; 232 return 0;
236 233
diff --git a/drivers/gpu/drm/msm/msm_connector.c b/drivers/gpu/drm/msm/msm_connector.c
deleted file mode 100644
index aeea8879e36f..000000000000
--- a/drivers/gpu/drm/msm/msm_connector.c
+++ /dev/null
@@ -1,34 +0,0 @@
1/*
2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "msm_drv.h"
19#include "msm_connector.h"
20
21void msm_connector_init(struct msm_connector *connector,
22 const struct msm_connector_funcs *funcs,
23 struct drm_encoder *encoder)
24{
25 connector->funcs = funcs;
26 connector->encoder = encoder;
27}
28
29struct drm_encoder *msm_connector_attached_encoder(
30 struct drm_connector *connector)
31{
32 struct msm_connector *msm_connector = to_msm_connector(connector);
33 return msm_connector->encoder;
34}
diff --git a/drivers/gpu/drm/msm/msm_connector.h b/drivers/gpu/drm/msm/msm_connector.h
deleted file mode 100644
index 0b41866adc08..000000000000
--- a/drivers/gpu/drm/msm/msm_connector.h
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef __MSM_CONNECTOR_H__
19#define __MSM_CONNECTOR_H__
20
21#include "msm_drv.h"
22
23/*
24 * Base class for MSM connectors. Typically a connector is a bit more
25 * passive. But with the split between (for example) DTV within MDP4,
26 * and HDMI encoder, we really need two parts to an encoder. Instead
27 * what we do is have the part external to the display controller block
28 * in the connector, which is called from the encoder to delegate the
29 * appropriate parts of modeset.
30 */
31
32struct msm_connector;
33
34struct msm_connector_funcs {
35 void (*dpms)(struct msm_connector *connector, int mode);
36 void (*mode_set)(struct msm_connector *connector,
37 struct drm_display_mode *mode);
38};
39
40struct msm_connector {
41 struct drm_connector base;
42 struct drm_encoder *encoder;
43 const struct msm_connector_funcs *funcs;
44};
45#define to_msm_connector(x) container_of(x, struct msm_connector, base)
46
47void msm_connector_init(struct msm_connector *connector,
48 const struct msm_connector_funcs *funcs,
49 struct drm_encoder *encoder);
50
51struct drm_encoder *msm_connector_attached_encoder(
52 struct drm_connector *connector);
53
54static inline struct msm_connector *get_connector(struct drm_encoder *encoder)
55{
56 struct msm_drm_private *priv = encoder->dev->dev_private;
57 int i;
58
59 for (i = 0; i < priv->num_connectors; i++) {
60 struct drm_connector *connector = priv->connectors[i];
61 if (msm_connector_attached_encoder(connector) == encoder)
62 return to_msm_connector(connector);
63 }
64
65 return NULL;
66}
67
68#endif /* __MSM_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 34c36b2911d9..80d75094bf0a 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -83,6 +83,9 @@ struct msm_drm_private {
83 unsigned int num_encoders; 83 unsigned int num_encoders;
84 struct drm_encoder *encoders[8]; 84 struct drm_encoder *encoders[8];
85 85
86 unsigned int num_bridges;
87 struct drm_bridge *bridges[8];
88
86 unsigned int num_connectors; 89 unsigned int num_connectors;
87 struct drm_connector *connectors[8]; 90 struct drm_connector *connectors[8];
88}; 91};
@@ -170,8 +173,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
170 173
171struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); 174struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
172 175
173struct drm_connector *hdmi_connector_init(struct drm_device *dev, 176int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
174 struct drm_encoder *encoder);
175void __init hdmi_register(void); 177void __init hdmi_register(void);
176void __exit hdmi_unregister(void); 178void __exit hdmi_unregister(void);
177 179