aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAjay Kumar <ajaykumar.rs@samsung.com>2015-01-20 11:38:44 -0500
committerThierry Reding <treding@nvidia.com>2015-01-28 02:45:40 -0500
commit3d3f8b1f8b62c3a010976269df454baa9246fc65 (patch)
tree855bd2b86afa52afbd7b872959789b028ff630ce
parentb07b90fd178a4797b0454ead491b717b41046bee (diff)
drm/bridge: make bridge registration independent of drm flow
Currently, third party bridge drivers(ptn3460) are dependent on the corresponding encoder driver init, since bridge driver needs a drm_device pointer to finish drm initializations. The encoder driver passes the drm_device pointer to the bridge driver. Because of this dependency, third party drivers like ptn3460 doesn't adhere to the driver model. In this patch, we reframe the bridge registration framework so that bridge initialization is split into 2 steps, and bridge registration happens independent of drm flow: --Step 1: gather all the bridge settings independent of drm and add the bridge onto a global list of bridges. --Step 2: when the encoder driver is probed, call drm_bridge_attach for the corresponding bridge so that the bridge receives drm_device pointer and continues with connector and other drm initializations. The old set of bridge helpers are removed, and a set of new helpers are added to accomplish the 2 step initialization. The bridge devices register themselves onto global list of bridges when they get probed by calling "drm_bridge_add". The parent encoder driver waits till the bridge is available in the lookup table(by calling "of_drm_find_bridge") and then continues with its initialization. The encoder driver should also call "drm_bridge_attach" to pass on the drm_device to the bridge object. drm_bridge_attach inturn calls "bridge->funcs->attach" so that bridge can continue with drm related initializations. Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com> Acked-by: Inki Dae <inki.dae@samsung.com> Tested-by: Rahul Sharma <rahul.sharma@samsung.com> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Tested-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk> Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/bridge/ptn3460.c27
-rw-r--r--drivers/gpu/drm/drm_bridge.c91
-rw-r--r--drivers/gpu/drm/drm_crtc.c67
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c4
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h1
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_bridge.c6
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c10
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c10
-rw-r--r--include/drm/bridge/ptn3460.h8
-rw-r--r--include/drm/drm_crtc.h26
11 files changed, 133 insertions, 119 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index cf0eed8208b5..2c239b99de64 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
14 drm_info.o drm_debugfs.o drm_encoder_slave.o \ 14 drm_info.o drm_debugfs.o drm_encoder_slave.o \
15 drm_trace_points.o drm_global.o drm_prime.o \ 15 drm_trace_points.o drm_global.o drm_prime.o \
16 drm_rect.o drm_vma_manager.o drm_flip_work.o \ 16 drm_rect.o drm_vma_manager.o drm_flip_work.o \
17 drm_modeset_lock.o drm_atomic.o 17 drm_modeset_lock.o drm_atomic.o drm_bridge.o
18 18
19drm-$(CONFIG_COMPAT) += drm_ioc32.o 19drm-$(CONFIG_COMPAT) += drm_ioc32.o
20drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o 20drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index a2ddc8d73c6a..4a818c1b62e0 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge)
176{ 176{
177} 177}
178 178
179static void ptn3460_bridge_destroy(struct drm_bridge *bridge)
180{
181 struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
182
183 drm_bridge_cleanup(bridge);
184 if (gpio_is_valid(ptn_bridge->gpio_pd_n))
185 gpio_free(ptn_bridge->gpio_pd_n);
186 if (gpio_is_valid(ptn_bridge->gpio_rst_n))
187 gpio_free(ptn_bridge->gpio_rst_n);
188 /* Nothing else to free, we've got devm allocated memory */
189}
190
191static struct drm_bridge_funcs ptn3460_bridge_funcs = { 179static struct drm_bridge_funcs ptn3460_bridge_funcs = {
192 .pre_enable = ptn3460_pre_enable, 180 .pre_enable = ptn3460_pre_enable,
193 .enable = ptn3460_enable, 181 .enable = ptn3460_enable,
194 .disable = ptn3460_disable, 182 .disable = ptn3460_disable,
195 .post_disable = ptn3460_post_disable, 183 .post_disable = ptn3460_post_disable,
196 .destroy = ptn3460_bridge_destroy,
197}; 184};
198 185
199static int ptn3460_get_modes(struct drm_connector *connector) 186static int ptn3460_get_modes(struct drm_connector *connector)
@@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
314 } 301 }
315 302
316 ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; 303 ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
317 ret = drm_bridge_init(dev, &ptn_bridge->bridge); 304 ret = drm_bridge_attach(dev, &ptn_bridge->bridge);
318 if (ret) { 305 if (ret) {
319 DRM_ERROR("Failed to initialize bridge with drm\n"); 306 DRM_ERROR("Failed to initialize bridge with drm\n");
320 goto err; 307 goto err;
@@ -343,3 +330,15 @@ err:
343 return ret; 330 return ret;
344} 331}
345EXPORT_SYMBOL(ptn3460_init); 332EXPORT_SYMBOL(ptn3460_init);
333
334void ptn3460_destroy(struct drm_bridge *bridge)
335{
336 struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
337
338 if (gpio_is_valid(ptn_bridge->gpio_pd_n))
339 gpio_free(ptn_bridge->gpio_pd_n);
340 if (gpio_is_valid(ptn_bridge->gpio_rst_n))
341 gpio_free(ptn_bridge->gpio_rst_n);
342 /* Nothing else to free, we've got devm allocated memory */
343}
344EXPORT_SYMBOL(ptn3460_destroy);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
new file mode 100644
index 000000000000..d1187e571c6d
--- /dev/null
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright (c) 2014 Samsung Electronics Co., Ltd
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include <linux/err.h>
25#include <linux/module.h>
26
27#include <drm/drm_crtc.h>
28
29#include "drm/drmP.h"
30
31static DEFINE_MUTEX(bridge_lock);
32static LIST_HEAD(bridge_list);
33
34int drm_bridge_add(struct drm_bridge *bridge)
35{
36 mutex_lock(&bridge_lock);
37 list_add_tail(&bridge->list, &bridge_list);
38 mutex_unlock(&bridge_lock);
39
40 return 0;
41}
42EXPORT_SYMBOL(drm_bridge_add);
43
44void drm_bridge_remove(struct drm_bridge *bridge)
45{
46 mutex_lock(&bridge_lock);
47 list_del_init(&bridge->list);
48 mutex_unlock(&bridge_lock);
49}
50EXPORT_SYMBOL(drm_bridge_remove);
51
52extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
53{
54 if (!dev || !bridge)
55 return -EINVAL;
56
57 if (bridge->dev)
58 return -EBUSY;
59
60 bridge->dev = dev;
61
62 if (bridge->funcs->attach)
63 return bridge->funcs->attach(bridge);
64
65 return 0;
66}
67EXPORT_SYMBOL(drm_bridge_attach);
68
69#ifdef CONFIG_OF
70struct drm_bridge *of_drm_find_bridge(struct device_node *np)
71{
72 struct drm_bridge *bridge;
73
74 mutex_lock(&bridge_lock);
75
76 list_for_each_entry(bridge, &bridge_list, list) {
77 if (bridge->of_node == np) {
78 mutex_unlock(&bridge_lock);
79 return bridge;
80 }
81 }
82
83 mutex_unlock(&bridge_lock);
84 return NULL;
85}
86EXPORT_SYMBOL(of_drm_find_bridge);
87#endif
88
89MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
90MODULE_DESCRIPTION("DRM bridge infrastructure");
91MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7936c5c2314c..0e4ec700b0a6 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1066,58 +1066,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
1066EXPORT_SYMBOL(drm_connector_unplug_all); 1066EXPORT_SYMBOL(drm_connector_unplug_all);
1067 1067
1068/** 1068/**
1069 * drm_bridge_init - initialize a drm transcoder/bridge
1070 * @dev: drm device
1071 * @bridge: transcoder/bridge to set up
1072 *
1073 * Initialises a preallocated bridge. Bridges should be
1074 * subclassed as part of driver connector objects.
1075 *
1076 * Returns:
1077 * Zero on success, error code on failure.
1078 */
1079int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge)
1080{
1081 int ret;
1082
1083 drm_modeset_lock_all(dev);
1084
1085 ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
1086 if (ret)
1087 goto out;
1088
1089 bridge->dev = dev;
1090
1091 list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
1092 dev->mode_config.num_bridge++;
1093
1094 out:
1095 drm_modeset_unlock_all(dev);
1096 return ret;
1097}
1098EXPORT_SYMBOL(drm_bridge_init);
1099
1100/**
1101 * drm_bridge_cleanup - cleans up an initialised bridge
1102 * @bridge: bridge to cleanup
1103 *
1104 * Cleans up the bridge but doesn't free the object.
1105 */
1106void drm_bridge_cleanup(struct drm_bridge *bridge)
1107{
1108 struct drm_device *dev = bridge->dev;
1109
1110 drm_modeset_lock_all(dev);
1111 drm_mode_object_put(dev, &bridge->base);
1112 list_del(&bridge->head);
1113 dev->mode_config.num_bridge--;
1114 drm_modeset_unlock_all(dev);
1115
1116 memset(bridge, 0, sizeof(*bridge));
1117}
1118EXPORT_SYMBOL(drm_bridge_cleanup);
1119
1120/**
1121 * drm_encoder_init - Init a preallocated encoder 1069 * drm_encoder_init - Init a preallocated encoder
1122 * @dev: drm device 1070 * @dev: drm device
1123 * @encoder: the encoder to init 1071 * @encoder: the encoder to init
@@ -1712,7 +1660,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
1712 total_objects += dev->mode_config.num_crtc; 1660 total_objects += dev->mode_config.num_crtc;
1713 total_objects += dev->mode_config.num_connector; 1661 total_objects += dev->mode_config.num_connector;
1714 total_objects += dev->mode_config.num_encoder; 1662 total_objects += dev->mode_config.num_encoder;
1715 total_objects += dev->mode_config.num_bridge;
1716 1663
1717 group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); 1664 group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL);
1718 if (!group->id_list) 1665 if (!group->id_list)
@@ -1721,7 +1668,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
1721 group->num_crtcs = 0; 1668 group->num_crtcs = 0;
1722 group->num_connectors = 0; 1669 group->num_connectors = 0;
1723 group->num_encoders = 0; 1670 group->num_encoders = 0;
1724 group->num_bridges = 0;
1725 return 0; 1671 return 0;
1726} 1672}
1727 1673
@@ -1741,7 +1687,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
1741 struct drm_crtc *crtc; 1687 struct drm_crtc *crtc;
1742 struct drm_encoder *encoder; 1688 struct drm_encoder *encoder;
1743 struct drm_connector *connector; 1689 struct drm_connector *connector;
1744 struct drm_bridge *bridge;
1745 int ret; 1690 int ret;
1746 1691
1747 ret = drm_mode_group_init(dev, group); 1692 ret = drm_mode_group_init(dev, group);
@@ -1759,11 +1704,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
1759 group->id_list[group->num_crtcs + group->num_encoders + 1704 group->id_list[group->num_crtcs + group->num_encoders +
1760 group->num_connectors++] = connector->base.id; 1705 group->num_connectors++] = connector->base.id;
1761 1706
1762 list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
1763 group->id_list[group->num_crtcs + group->num_encoders +
1764 group->num_connectors + group->num_bridges++] =
1765 bridge->base.id;
1766
1767 return 0; 1707 return 0;
1768} 1708}
1769EXPORT_SYMBOL(drm_mode_group_init_legacy_group); 1709EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
@@ -5440,7 +5380,6 @@ void drm_mode_config_init(struct drm_device *dev)
5440 INIT_LIST_HEAD(&dev->mode_config.fb_list); 5380 INIT_LIST_HEAD(&dev->mode_config.fb_list);
5441 INIT_LIST_HEAD(&dev->mode_config.crtc_list); 5381 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
5442 INIT_LIST_HEAD(&dev->mode_config.connector_list); 5382 INIT_LIST_HEAD(&dev->mode_config.connector_list);
5443 INIT_LIST_HEAD(&dev->mode_config.bridge_list);
5444 INIT_LIST_HEAD(&dev->mode_config.encoder_list); 5383 INIT_LIST_HEAD(&dev->mode_config.encoder_list);
5445 INIT_LIST_HEAD(&dev->mode_config.property_list); 5384 INIT_LIST_HEAD(&dev->mode_config.property_list);
5446 INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 5385 INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
@@ -5480,7 +5419,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
5480 struct drm_connector *connector, *ot; 5419 struct drm_connector *connector, *ot;
5481 struct drm_crtc *crtc, *ct; 5420 struct drm_crtc *crtc, *ct;
5482 struct drm_encoder *encoder, *enct; 5421 struct drm_encoder *encoder, *enct;
5483 struct drm_bridge *bridge, *brt;
5484 struct drm_framebuffer *fb, *fbt; 5422 struct drm_framebuffer *fb, *fbt;
5485 struct drm_property *property, *pt; 5423 struct drm_property *property, *pt;
5486 struct drm_property_blob *blob, *bt; 5424 struct drm_property_blob *blob, *bt;
@@ -5491,11 +5429,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
5491 encoder->funcs->destroy(encoder); 5429 encoder->funcs->destroy(encoder);
5492 } 5430 }
5493 5431
5494 list_for_each_entry_safe(bridge, brt,
5495 &dev->mode_config.bridge_list, head) {
5496 bridge->funcs->destroy(bridge);
5497 }
5498
5499 list_for_each_entry_safe(connector, ot, 5432 list_for_each_entry_safe(connector, ot,
5500 &dev->mode_config.connector_list, head) { 5433 &dev->mode_config.connector_list, head) {
5501 connector->funcs->destroy(connector); 5434 connector->funcs->destroy(connector);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 062c68725376..95f7b8d0f3ef 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
247 return 0; 247 return 0;
248 248
249fail: 249fail:
250 /* bridge/connector are normally destroyed by drm: */ 250 /* bridge is normally destroyed by drm: */
251 if (hdmi->bridge) { 251 if (hdmi->bridge) {
252 hdmi->bridge->funcs->destroy(hdmi->bridge); 252 hdmi_bridge_destroy(hdmi->bridge);
253 hdmi->bridge = NULL; 253 hdmi->bridge = NULL;
254 } 254 }
255 if (hdmi->connector) { 255 if (hdmi->connector) {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 43e654f751b7..4d4cad42a776 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
146 */ 146 */
147 147
148struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi); 148struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
149void hdmi_bridge_destroy(struct drm_bridge *bridge);
149 150
150/* 151/*
151 * hdmi connector: 152 * hdmi connector:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 52ed2b53b246..d6f8d5818e18 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -23,10 +23,9 @@ struct hdmi_bridge {
23}; 23};
24#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) 24#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
25 25
26static void hdmi_bridge_destroy(struct drm_bridge *bridge) 26void hdmi_bridge_destroy(struct drm_bridge *bridge)
27{ 27{
28 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 28 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
29 drm_bridge_cleanup(bridge);
30 kfree(hdmi_bridge); 29 kfree(hdmi_bridge);
31} 30}
32 31
@@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
200 .disable = hdmi_bridge_disable, 199 .disable = hdmi_bridge_disable,
201 .post_disable = hdmi_bridge_post_disable, 200 .post_disable = hdmi_bridge_post_disable,
202 .mode_set = hdmi_bridge_mode_set, 201 .mode_set = hdmi_bridge_mode_set,
203 .destroy = hdmi_bridge_destroy,
204}; 202};
205 203
206 204
@@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
222 bridge = &hdmi_bridge->base; 220 bridge = &hdmi_bridge->base;
223 bridge->funcs = &hdmi_bridge_funcs; 221 bridge->funcs = &hdmi_bridge_funcs;
224 222
225 drm_bridge_init(hdmi->dev, bridge); 223 drm_bridge_attach(hdmi->dev, bridge);
226 224
227 return bridge; 225 return bridge;
228 226
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 6cf145de9b41..a9bbb081ecad 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
508 /* do nothing */ 508 /* do nothing */
509} 509}
510 510
511static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
512{
513 drm_bridge_cleanup(bridge);
514 kfree(bridge);
515}
516
517static const struct drm_bridge_funcs sti_hda_bridge_funcs = { 511static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
518 .pre_enable = sti_hda_pre_enable, 512 .pre_enable = sti_hda_pre_enable,
519 .enable = sti_hda_bridge_nope, 513 .enable = sti_hda_bridge_nope,
520 .disable = sti_hda_disable, 514 .disable = sti_hda_disable,
521 .post_disable = sti_hda_bridge_nope, 515 .post_disable = sti_hda_bridge_nope,
522 .mode_set = sti_hda_set_mode, 516 .mode_set = sti_hda_set_mode,
523 .destroy = sti_hda_brigde_destroy,
524}; 517};
525 518
526static int sti_hda_connector_get_modes(struct drm_connector *connector) 519static int sti_hda_connector_get_modes(struct drm_connector *connector)
@@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
665 658
666 bridge->driver_private = hda; 659 bridge->driver_private = hda;
667 bridge->funcs = &sti_hda_bridge_funcs; 660 bridge->funcs = &sti_hda_bridge_funcs;
668 drm_bridge_init(drm_dev, bridge); 661 drm_bridge_attach(drm_dev, bridge);
669 662
670 encoder->bridge = bridge; 663 encoder->bridge = bridge;
671 connector->encoder = encoder; 664 connector->encoder = encoder;
@@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
694err_sysfs: 687err_sysfs:
695 drm_connector_unregister(drm_connector); 688 drm_connector_unregister(drm_connector);
696err_connector: 689err_connector:
697 drm_bridge_cleanup(bridge);
698 drm_connector_cleanup(drm_connector); 690 drm_connector_cleanup(drm_connector);
699 return -EINVAL; 691 return -EINVAL;
700} 692}
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 74e943e655d1..e840ca5de401 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
463 /* do nothing */ 463 /* do nothing */
464} 464}
465 465
466static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
467{
468 drm_bridge_cleanup(bridge);
469 kfree(bridge);
470}
471
472static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { 466static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
473 .pre_enable = sti_hdmi_pre_enable, 467 .pre_enable = sti_hdmi_pre_enable,
474 .enable = sti_hdmi_bridge_nope, 468 .enable = sti_hdmi_bridge_nope,
475 .disable = sti_hdmi_disable, 469 .disable = sti_hdmi_disable,
476 .post_disable = sti_hdmi_bridge_nope, 470 .post_disable = sti_hdmi_bridge_nope,
477 .mode_set = sti_hdmi_set_mode, 471 .mode_set = sti_hdmi_set_mode,
478 .destroy = sti_hdmi_brigde_destroy,
479}; 472};
480 473
481static int sti_hdmi_connector_get_modes(struct drm_connector *connector) 474static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
636 629
637 bridge->driver_private = hdmi; 630 bridge->driver_private = hdmi;
638 bridge->funcs = &sti_hdmi_bridge_funcs; 631 bridge->funcs = &sti_hdmi_bridge_funcs;
639 drm_bridge_init(drm_dev, bridge); 632 drm_bridge_attach(drm_dev, bridge);
640 633
641 encoder->bridge = bridge; 634 encoder->bridge = bridge;
642 connector->encoder = encoder; 635 connector->encoder = encoder;
@@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
668err_sysfs: 661err_sysfs:
669 drm_connector_unregister(drm_connector); 662 drm_connector_unregister(drm_connector);
670err_connector: 663err_connector:
671 drm_bridge_cleanup(bridge);
672 drm_connector_cleanup(drm_connector); 664 drm_connector_cleanup(drm_connector);
673err_adapt: 665err_adapt:
674 put_device(&hdmi->ddc_adapt->dev); 666 put_device(&hdmi->ddc_adapt->dev);
diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
index ff62344fec6c..b11f8e17e72f 100644
--- a/include/drm/bridge/ptn3460.h
+++ b/include/drm/bridge/ptn3460.h
@@ -15,6 +15,7 @@
15#define _DRM_BRIDGE_PTN3460_H_ 15#define _DRM_BRIDGE_PTN3460_H_
16 16
17struct drm_device; 17struct drm_device;
18struct drm_bridge;
18struct drm_encoder; 19struct drm_encoder;
19struct i2c_client; 20struct i2c_client;
20struct device_node; 21struct device_node;
@@ -23,6 +24,9 @@ struct device_node;
23 24
24int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, 25int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
25 struct i2c_client *client, struct device_node *node); 26 struct i2c_client *client, struct device_node *node);
27
28void ptn3460_destroy(struct drm_bridge *bridge);
29
26#else 30#else
27 31
28static inline int ptn3460_init(struct drm_device *dev, 32static inline int ptn3460_init(struct drm_device *dev,
@@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
32 return 0; 36 return 0;
33} 37}
34 38
39static inline void ptn3460_destroy(struct drm_bridge *bridge)
40{
41}
42
35#endif 43#endif
36 44
37#endif 45#endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 15bb762fb316..920e21a8f3fd 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -868,15 +868,16 @@ struct drm_plane {
868 868
869/** 869/**
870 * struct drm_bridge_funcs - drm_bridge control functions 870 * struct drm_bridge_funcs - drm_bridge control functions
871 * @attach: Called during drm_bridge_attach
871 * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge 872 * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
872 * @disable: Called right before encoder prepare, disables the bridge 873 * @disable: Called right before encoder prepare, disables the bridge
873 * @post_disable: Called right after encoder prepare, for lockstepped disable 874 * @post_disable: Called right after encoder prepare, for lockstepped disable
874 * @mode_set: Set this mode to the bridge 875 * @mode_set: Set this mode to the bridge
875 * @pre_enable: Called right before encoder commit, for lockstepped commit 876 * @pre_enable: Called right before encoder commit, for lockstepped commit
876 * @enable: Called right after encoder commit, enables the bridge 877 * @enable: Called right after encoder commit, enables the bridge
877 * @destroy: make object go away
878 */ 878 */
879struct drm_bridge_funcs { 879struct drm_bridge_funcs {
880 int (*attach)(struct drm_bridge *bridge);
880 bool (*mode_fixup)(struct drm_bridge *bridge, 881 bool (*mode_fixup)(struct drm_bridge *bridge,
881 const struct drm_display_mode *mode, 882 const struct drm_display_mode *mode,
882 struct drm_display_mode *adjusted_mode); 883 struct drm_display_mode *adjusted_mode);
@@ -887,22 +888,24 @@ struct drm_bridge_funcs {
887 struct drm_display_mode *adjusted_mode); 888 struct drm_display_mode *adjusted_mode);
888 void (*pre_enable)(struct drm_bridge *bridge); 889 void (*pre_enable)(struct drm_bridge *bridge);
889 void (*enable)(struct drm_bridge *bridge); 890 void (*enable)(struct drm_bridge *bridge);
890 void (*destroy)(struct drm_bridge *bridge);
891}; 891};
892 892
893/** 893/**
894 * struct drm_bridge - central DRM bridge control structure 894 * struct drm_bridge - central DRM bridge control structure
895 * @dev: DRM device this bridge belongs to 895 * @dev: DRM device this bridge belongs to
896 * @head: list management 896 * @of_node: device node pointer to the bridge
897 * @list: to keep track of all added bridges
897 * @base: base mode object 898 * @base: base mode object
898 * @funcs: control functions 899 * @funcs: control functions
899 * @driver_private: pointer to the bridge driver's internal context 900 * @driver_private: pointer to the bridge driver's internal context
900 */ 901 */
901struct drm_bridge { 902struct drm_bridge {
902 struct drm_device *dev; 903 struct drm_device *dev;
903 struct list_head head; 904 struct drm_encoder *encoder;
904 905#ifdef CONFIG_OF
905 struct drm_mode_object base; 906 struct device_node *of_node;
907#endif
908 struct list_head list;
906 909
907 const struct drm_bridge_funcs *funcs; 910 const struct drm_bridge_funcs *funcs;
908 void *driver_private; 911 void *driver_private;
@@ -1007,7 +1010,6 @@ struct drm_mode_group {
1007 uint32_t num_crtcs; 1010 uint32_t num_crtcs;
1008 uint32_t num_encoders; 1011 uint32_t num_encoders;
1009 uint32_t num_connectors; 1012 uint32_t num_connectors;
1010 uint32_t num_bridges;
1011 1013
1012 /* list of object IDs for this group */ 1014 /* list of object IDs for this group */
1013 uint32_t *id_list; 1015 uint32_t *id_list;
@@ -1026,8 +1028,6 @@ struct drm_mode_group {
1026 * @fb_list: list of framebuffers available 1028 * @fb_list: list of framebuffers available
1027 * @num_connector: number of connectors on this device 1029 * @num_connector: number of connectors on this device
1028 * @connector_list: list of connector objects 1030 * @connector_list: list of connector objects
1029 * @num_bridge: number of bridges on this device
1030 * @bridge_list: list of bridge objects
1031 * @num_encoder: number of encoders on this device 1031 * @num_encoder: number of encoders on this device
1032 * @encoder_list: list of encoder objects 1032 * @encoder_list: list of encoder objects
1033 * @num_overlay_plane: number of overlay planes on this device 1033 * @num_overlay_plane: number of overlay planes on this device
@@ -1072,8 +1072,6 @@ struct drm_mode_config {
1072 1072
1073 int num_connector; 1073 int num_connector;
1074 struct list_head connector_list; 1074 struct list_head connector_list;
1075 int num_bridge;
1076 struct list_head bridge_list;
1077 int num_encoder; 1075 int num_encoder;
1078 struct list_head encoder_list; 1076 struct list_head encoder_list;
1079 1077
@@ -1222,8 +1220,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
1222/* helper to unplug all connectors from sysfs for device */ 1220/* helper to unplug all connectors from sysfs for device */
1223extern void drm_connector_unplug_all(struct drm_device *dev); 1221extern void drm_connector_unplug_all(struct drm_device *dev);
1224 1222
1225extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge); 1223extern int drm_bridge_add(struct drm_bridge *bridge);
1226extern void drm_bridge_cleanup(struct drm_bridge *bridge); 1224extern void drm_bridge_remove(struct drm_bridge *bridge);
1225extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
1226extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
1227 1227
1228extern int drm_encoder_init(struct drm_device *dev, 1228extern int drm_encoder_init(struct drm_device *dev,
1229 struct drm_encoder *encoder, 1229 struct drm_encoder *encoder,