aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-10-29 19:49:06 -0400
committerDave Airlie <airlied@redhat.com>2015-10-29 19:49:06 -0400
commita76edb8cec0cc864c8b72fa7e84a72336e033e23 (patch)
tree3d680a904cc835aeb56f32d8814af7d8fd9a7767
parentf1a04d82585032d906e6a7d5b16d38a369033bd0 (diff)
parent48aa1e748f29373fdcc2bc341eac08ef16bff269 (diff)
Merge tag 'topic/drm-misc-2015-10-22' of git://anongit.freedesktop.org/drm-intel into drm-next
Few more drm-misc stragglers for 4.4. Big thing is the generic probe for imx/rockchip/armada (but the variant for msm/rpi/exynos is still missing). Also the hdmi clocking fixes from Ville which was a lot of confusion about which tree it should be applied to ;-) * tag 'topic/drm-misc-2015-10-22' of git://anongit.freedesktop.org/drm-intel: drm: correctly check failed allocation vga_switcheroo: Constify vga_switcheroo_handler drm/armada: Convert the probe function to the generic drm_of_component_probe() drm/rockchip: Convert the probe function to the generic drm_of_component_probe() drm/imx: Convert the probe function to the generic drm_of_component_probe() drm: Introduce generic probe function for component based masters. drm/edid: Round to closest when computing the CEA/HDMI alternate clock drm/edid: Fix up clock for CEA/HDMI modes specified via detailed timings
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c2
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c68
-rw-r--r--drivers/gpu/drm/drm_crtc.c30
-rw-r--r--drivers/gpu/drm/drm_edid.c52
-rw-r--r--drivers/gpu/drm/drm_of.c88
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c55
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_atpx_handler.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c81
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c4
-rw-r--r--drivers/platform/x86/apple-gmux.c2
-rw-r--r--include/drm/drm_of.h13
-rw-r--r--include/linux/vga_switcheroo.h4
13 files changed, 218 insertions, 185 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
index 1a6b239baab9..5a8fbadbd27b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -501,7 +501,7 @@ static int amdgpu_atpx_get_client_id(struct pci_dev *pdev)
501 return VGA_SWITCHEROO_DIS; 501 return VGA_SWITCHEROO_DIS;
502} 502}
503 503
504static struct vga_switcheroo_handler amdgpu_atpx_handler = { 504static const struct vga_switcheroo_handler amdgpu_atpx_handler = {
505 .switchto = amdgpu_atpx_switchto, 505 .switchto = amdgpu_atpx_switchto,
506 .power_state = amdgpu_atpx_power_state, 506 .power_state = amdgpu_atpx_power_state,
507 .init = amdgpu_atpx_init, 507 .init = amdgpu_atpx_init,
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 1cbb080f0c4a..77ab93d60125 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -11,6 +11,7 @@
11#include <linux/of_graph.h> 11#include <linux/of_graph.h>
12#include <drm/drmP.h> 12#include <drm/drmP.h>
13#include <drm/drm_crtc_helper.h> 13#include <drm/drm_crtc_helper.h>
14#include <drm/drm_of.h>
14#include "armada_crtc.h" 15#include "armada_crtc.h"
15#include "armada_drm.h" 16#include "armada_drm.h"
16#include "armada_gem.h" 17#include "armada_gem.h"
@@ -262,43 +263,29 @@ static void armada_add_endpoints(struct device *dev,
262 } 263 }
263} 264}
264 265
265static int armada_drm_find_components(struct device *dev, 266static const struct component_master_ops armada_master_ops = {
266 struct component_match **match) 267 .bind = armada_drm_bind,
267{ 268 .unbind = armada_drm_unbind,
268 struct device_node *port; 269};
269 int i;
270
271 if (dev->of_node) {
272 struct device_node *np = dev->of_node;
273
274 for (i = 0; ; i++) {
275 port = of_parse_phandle(np, "ports", i);
276 if (!port)
277 break;
278
279 component_match_add(dev, match, compare_of, port);
280 of_node_put(port);
281 }
282 270
283 if (i == 0) { 271static int armada_drm_probe(struct platform_device *pdev)
284 dev_err(dev, "missing 'ports' property\n"); 272{
285 return -ENODEV; 273 struct component_match *match = NULL;
286 } 274 struct device *dev = &pdev->dev;
275 int ret;
287 276
288 for (i = 0; ; i++) { 277 ret = drm_of_component_probe(dev, compare_dev_name, &armada_master_ops);
289 port = of_parse_phandle(np, "ports", i); 278 if (ret != -EINVAL)
290 if (!port) 279 return ret;
291 break;
292 280
293 armada_add_endpoints(dev, match, port); 281 if (dev->platform_data) {
294 of_node_put(port);
295 }
296 } else if (dev->platform_data) {
297 char **devices = dev->platform_data; 282 char **devices = dev->platform_data;
283 struct device_node *port;
298 struct device *d; 284 struct device *d;
285 int i;
299 286
300 for (i = 0; devices[i]; i++) 287 for (i = 0; devices[i]; i++)
301 component_match_add(dev, match, compare_dev_name, 288 component_match_add(dev, &match, compare_dev_name,
302 devices[i]); 289 devices[i]);
303 290
304 if (i == 0) { 291 if (i == 0) {
@@ -308,32 +295,15 @@ static int armada_drm_find_components(struct device *dev,
308 295
309 for (i = 0; devices[i]; i++) { 296 for (i = 0; devices[i]; i++) {
310 d = bus_find_device_by_name(&platform_bus_type, NULL, 297 d = bus_find_device_by_name(&platform_bus_type, NULL,
311 devices[i]); 298 devices[i]);
312 if (d && d->of_node) { 299 if (d && d->of_node) {
313 for_each_child_of_node(d->of_node, port) 300 for_each_child_of_node(d->of_node, port)
314 armada_add_endpoints(dev, match, port); 301 armada_add_endpoints(dev, &match, port);
315 } 302 }
316 put_device(d); 303 put_device(d);
317 } 304 }
318 } 305 }
319 306
320 return 0;
321}
322
323static const struct component_master_ops armada_master_ops = {
324 .bind = armada_drm_bind,
325 .unbind = armada_drm_unbind,
326};
327
328static int armada_drm_probe(struct platform_device *pdev)
329{
330 struct component_match *match = NULL;
331 int ret;
332
333 ret = armada_drm_find_components(&pdev->dev, &match);
334 if (ret < 0)
335 return ret;
336
337 return component_master_add_with_match(&pdev->dev, &armada_master_ops, 307 return component_master_add_with_match(&pdev->dev, &armada_master_ops,
338 match); 308 match);
339} 309}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e54660a858e1..720a153d1a46 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1533,6 +1533,9 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
1533 "select subconnector", 1533 "select subconnector",
1534 drm_tv_select_enum_list, 1534 drm_tv_select_enum_list,
1535 ARRAY_SIZE(drm_tv_select_enum_list)); 1535 ARRAY_SIZE(drm_tv_select_enum_list));
1536 if (!tv_selector)
1537 goto nomem;
1538
1536 dev->mode_config.tv_select_subconnector_property = tv_selector; 1539 dev->mode_config.tv_select_subconnector_property = tv_selector;
1537 1540
1538 tv_subconnector = 1541 tv_subconnector =
@@ -1540,6 +1543,8 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
1540 "subconnector", 1543 "subconnector",
1541 drm_tv_subconnector_enum_list, 1544 drm_tv_subconnector_enum_list,
1542 ARRAY_SIZE(drm_tv_subconnector_enum_list)); 1545 ARRAY_SIZE(drm_tv_subconnector_enum_list));
1546 if (!tv_subconnector)
1547 goto nomem;
1543 dev->mode_config.tv_subconnector_property = tv_subconnector; 1548 dev->mode_config.tv_subconnector_property = tv_subconnector;
1544 1549
1545 /* 1550 /*
@@ -1547,42 +1552,67 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
1547 */ 1552 */
1548 dev->mode_config.tv_left_margin_property = 1553 dev->mode_config.tv_left_margin_property =
1549 drm_property_create_range(dev, 0, "left margin", 0, 100); 1554 drm_property_create_range(dev, 0, "left margin", 0, 100);
1555 if (!dev->mode_config.tv_left_margin_property)
1556 goto nomem;
1550 1557
1551 dev->mode_config.tv_right_margin_property = 1558 dev->mode_config.tv_right_margin_property =
1552 drm_property_create_range(dev, 0, "right margin", 0, 100); 1559 drm_property_create_range(dev, 0, "right margin", 0, 100);
1560 if (!dev->mode_config.tv_right_margin_property)
1561 goto nomem;
1553 1562
1554 dev->mode_config.tv_top_margin_property = 1563 dev->mode_config.tv_top_margin_property =
1555 drm_property_create_range(dev, 0, "top margin", 0, 100); 1564 drm_property_create_range(dev, 0, "top margin", 0, 100);
1565 if (!dev->mode_config.tv_top_margin_property)
1566 goto nomem;
1556 1567
1557 dev->mode_config.tv_bottom_margin_property = 1568 dev->mode_config.tv_bottom_margin_property =
1558 drm_property_create_range(dev, 0, "bottom margin", 0, 100); 1569 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
1570 if (!dev->mode_config.tv_bottom_margin_property)
1571 goto nomem;
1559 1572
1560 dev->mode_config.tv_mode_property = 1573 dev->mode_config.tv_mode_property =
1561 drm_property_create(dev, DRM_MODE_PROP_ENUM, 1574 drm_property_create(dev, DRM_MODE_PROP_ENUM,
1562 "mode", num_modes); 1575 "mode", num_modes);
1576 if (!dev->mode_config.tv_mode_property)
1577 goto nomem;
1578
1563 for (i = 0; i < num_modes; i++) 1579 for (i = 0; i < num_modes; i++)
1564 drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1580 drm_property_add_enum(dev->mode_config.tv_mode_property, i,
1565 i, modes[i]); 1581 i, modes[i]);
1566 1582
1567 dev->mode_config.tv_brightness_property = 1583 dev->mode_config.tv_brightness_property =
1568 drm_property_create_range(dev, 0, "brightness", 0, 100); 1584 drm_property_create_range(dev, 0, "brightness", 0, 100);
1585 if (!dev->mode_config.tv_brightness_property)
1586 goto nomem;
1569 1587
1570 dev->mode_config.tv_contrast_property = 1588 dev->mode_config.tv_contrast_property =
1571 drm_property_create_range(dev, 0, "contrast", 0, 100); 1589 drm_property_create_range(dev, 0, "contrast", 0, 100);
1590 if (!dev->mode_config.tv_contrast_property)
1591 goto nomem;
1572 1592
1573 dev->mode_config.tv_flicker_reduction_property = 1593 dev->mode_config.tv_flicker_reduction_property =
1574 drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 1594 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
1595 if (!dev->mode_config.tv_flicker_reduction_property)
1596 goto nomem;
1575 1597
1576 dev->mode_config.tv_overscan_property = 1598 dev->mode_config.tv_overscan_property =
1577 drm_property_create_range(dev, 0, "overscan", 0, 100); 1599 drm_property_create_range(dev, 0, "overscan", 0, 100);
1600 if (!dev->mode_config.tv_overscan_property)
1601 goto nomem;
1578 1602
1579 dev->mode_config.tv_saturation_property = 1603 dev->mode_config.tv_saturation_property =
1580 drm_property_create_range(dev, 0, "saturation", 0, 100); 1604 drm_property_create_range(dev, 0, "saturation", 0, 100);
1605 if (!dev->mode_config.tv_saturation_property)
1606 goto nomem;
1581 1607
1582 dev->mode_config.tv_hue_property = 1608 dev->mode_config.tv_hue_property =
1583 drm_property_create_range(dev, 0, "hue", 0, 100); 1609 drm_property_create_range(dev, 0, "hue", 0, 100);
1610 if (!dev->mode_config.tv_hue_property)
1611 goto nomem;
1584 1612
1585 return 0; 1613 return 0;
1614nomem:
1615 return -ENOMEM;
1586} 1616}
1587EXPORT_SYMBOL(drm_mode_create_tv_properties); 1617EXPORT_SYMBOL(drm_mode_create_tv_properties);
1588 1618
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d895556be4f0..d5d2c03fd136 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2418,6 +2418,8 @@ add_cvt_modes(struct drm_connector *connector, struct edid *edid)
2418 return closure.modes; 2418 return closure.modes;
2419} 2419}
2420 2420
2421static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode);
2422
2421static void 2423static void
2422do_detailed_mode(struct detailed_timing *timing, void *c) 2424do_detailed_mode(struct detailed_timing *timing, void *c)
2423{ 2425{
@@ -2434,6 +2436,13 @@ do_detailed_mode(struct detailed_timing *timing, void *c)
2434 if (closure->preferred) 2436 if (closure->preferred)
2435 newmode->type |= DRM_MODE_TYPE_PREFERRED; 2437 newmode->type |= DRM_MODE_TYPE_PREFERRED;
2436 2438
2439 /*
2440 * Detailed modes are limited to 10kHz pixel clock resolution,
2441 * so fix up anything that looks like CEA/HDMI mode, but the clock
2442 * is just slightly off.
2443 */
2444 fixup_detailed_cea_mode_clock(newmode);
2445
2437 drm_mode_probed_add(closure->connector, newmode); 2446 drm_mode_probed_add(closure->connector, newmode);
2438 closure->modes++; 2447 closure->modes++;
2439 closure->preferred = 0; 2448 closure->preferred = 0;
@@ -2529,9 +2538,9 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
2529 * and the 60Hz variant otherwise. 2538 * and the 60Hz variant otherwise.
2530 */ 2539 */
2531 if (cea_mode->vdisplay == 240 || cea_mode->vdisplay == 480) 2540 if (cea_mode->vdisplay == 240 || cea_mode->vdisplay == 480)
2532 clock = clock * 1001 / 1000; 2541 clock = DIV_ROUND_CLOSEST(clock * 1001, 1000);
2533 else 2542 else
2534 clock = DIV_ROUND_UP(clock * 1000, 1001); 2543 clock = DIV_ROUND_CLOSEST(clock * 1000, 1001);
2535 2544
2536 return clock; 2545 return clock;
2537} 2546}
@@ -3103,6 +3112,45 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
3103 return modes; 3112 return modes;
3104} 3113}
3105 3114
3115static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
3116{
3117 const struct drm_display_mode *cea_mode;
3118 int clock1, clock2, clock;
3119 u8 mode_idx;
3120 const char *type;
3121
3122 mode_idx = drm_match_cea_mode(mode) - 1;
3123 if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
3124 type = "CEA";
3125 cea_mode = &edid_cea_modes[mode_idx];
3126 clock1 = cea_mode->clock;
3127 clock2 = cea_mode_alternate_clock(cea_mode);
3128 } else {
3129 mode_idx = drm_match_hdmi_mode(mode) - 1;
3130 if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
3131 type = "HDMI";
3132 cea_mode = &edid_4k_modes[mode_idx];
3133 clock1 = cea_mode->clock;
3134 clock2 = hdmi_mode_alternate_clock(cea_mode);
3135 } else {
3136 return;
3137 }
3138 }
3139
3140 /* pick whichever is closest */
3141 if (abs(mode->clock - clock1) < abs(mode->clock - clock2))
3142 clock = clock1;
3143 else
3144 clock = clock2;
3145
3146 if (mode->clock == clock)
3147 return;
3148
3149 DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n",
3150 type, mode_idx + 1, mode->clock, clock);
3151 mode->clock = clock;
3152}
3153
3106static void 3154static void
3107parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) 3155parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
3108{ 3156{
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index be3884073ea4..493c05c9ce4f 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -1,3 +1,4 @@
1#include <linux/component.h>
1#include <linux/export.h> 2#include <linux/export.h>
2#include <linux/list.h> 3#include <linux/list.h>
3#include <linux/of_graph.h> 4#include <linux/of_graph.h>
@@ -61,3 +62,90 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
61 return possible_crtcs; 62 return possible_crtcs;
62} 63}
63EXPORT_SYMBOL(drm_of_find_possible_crtcs); 64EXPORT_SYMBOL(drm_of_find_possible_crtcs);
65
66/**
67 * drm_of_component_probe - Generic probe function for a component based master
68 * @dev: master device containing the OF node
69 * @compare_of: compare function used for matching components
70 * @master_ops: component master ops to be used
71 *
72 * Parse the platform device OF node and bind all the components associated
73 * with the master. Interface ports are added before the encoders in order to
74 * satisfy their .bind requirements
75 * See Documentation/devicetree/bindings/graph.txt for the bindings.
76 *
77 * Returns zero if successful, or one of the standard error codes if it fails.
78 */
79int drm_of_component_probe(struct device *dev,
80 int (*compare_of)(struct device *, void *),
81 const struct component_master_ops *m_ops)
82{
83 struct device_node *ep, *port, *remote;
84 struct component_match *match = NULL;
85 int i;
86
87 if (!dev->of_node)
88 return -EINVAL;
89
90 /*
91 * Bind the crtc's ports first, so that drm_of_find_possible_crtcs()
92 * called from encoder's .bind callbacks works as expected
93 */
94 for (i = 0; ; i++) {
95 port = of_parse_phandle(dev->of_node, "ports", i);
96 if (!port)
97 break;
98
99 if (!of_device_is_available(port->parent)) {
100 of_node_put(port);
101 continue;
102 }
103
104 component_match_add(dev, &match, compare_of, port);
105 of_node_put(port);
106 }
107
108 if (i == 0) {
109 dev_err(dev, "missing 'ports' property\n");
110 return -ENODEV;
111 }
112
113 if (!match) {
114 dev_err(dev, "no available port\n");
115 return -ENODEV;
116 }
117
118 /*
119 * For bound crtcs, bind the encoders attached to their remote endpoint
120 */
121 for (i = 0; ; i++) {
122 port = of_parse_phandle(dev->of_node, "ports", i);
123 if (!port)
124 break;
125
126 if (!of_device_is_available(port->parent)) {
127 of_node_put(port);
128 continue;
129 }
130
131 for_each_child_of_node(port, ep) {
132 remote = of_graph_get_remote_port_parent(ep);
133 if (!remote || !of_device_is_available(remote)) {
134 of_node_put(remote);
135 continue;
136 } else if (!of_device_is_available(remote->parent)) {
137 dev_warn(dev, "parent device of %s is not available\n",
138 remote->full_name);
139 of_node_put(remote);
140 continue;
141 }
142
143 component_match_add(dev, &match, compare_of, remote);
144 of_node_put(remote);
145 }
146 of_node_put(port);
147 }
148
149 return component_master_add_with_match(dev, m_ops, match);
150}
151EXPORT_SYMBOL(drm_of_component_probe);
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index de00a6c31ab6..64f16ea779ef 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -531,59 +531,12 @@ static const struct component_master_ops imx_drm_ops = {
531 531
532static int imx_drm_platform_probe(struct platform_device *pdev) 532static int imx_drm_platform_probe(struct platform_device *pdev)
533{ 533{
534 struct device_node *ep, *port, *remote; 534 int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops);
535 struct component_match *match = NULL;
536 int ret;
537 int i;
538
539 /*
540 * Bind the IPU display interface ports first, so that
541 * imx_drm_encoder_parse_of called from encoder .bind callbacks
542 * works as expected.
543 */
544 for (i = 0; ; i++) {
545 port = of_parse_phandle(pdev->dev.of_node, "ports", i);
546 if (!port)
547 break;
548
549 component_match_add(&pdev->dev, &match, compare_of, port);
550 }
551 535
552 if (i == 0) { 536 if (!ret)
553 dev_err(&pdev->dev, "missing 'ports' property\n"); 537 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
554 return -ENODEV;
555 }
556 538
557 /* Then bind all encoders */ 539 return ret;
558 for (i = 0; ; i++) {
559 port = of_parse_phandle(pdev->dev.of_node, "ports", i);
560 if (!port)
561 break;
562
563 for_each_child_of_node(port, ep) {
564 remote = of_graph_get_remote_port_parent(ep);
565 if (!remote || !of_device_is_available(remote)) {
566 of_node_put(remote);
567 continue;
568 } else if (!of_device_is_available(remote->parent)) {
569 dev_warn(&pdev->dev, "parent device of %s is not available\n",
570 remote->full_name);
571 of_node_put(remote);
572 continue;
573 }
574
575 component_match_add(&pdev->dev, &match, compare_of,
576 remote);
577 of_node_put(remote);
578 }
579 of_node_put(port);
580 }
581
582 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
583 if (ret)
584 return ret;
585
586 return component_master_add_with_match(&pdev->dev, &imx_drm_ops, match);
587} 540}
588 541
589static int imx_drm_platform_remove(struct platform_device *pdev) 542static int imx_drm_platform_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index df2d9818aba3..8b8332e46f24 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -206,7 +206,7 @@ static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
206 return VGA_SWITCHEROO_DIS; 206 return VGA_SWITCHEROO_DIS;
207} 207}
208 208
209static struct vga_switcheroo_handler nouveau_dsm_handler = { 209static const struct vga_switcheroo_handler nouveau_dsm_handler = {
210 .switchto = nouveau_dsm_switchto, 210 .switchto = nouveau_dsm_switchto,
211 .power_state = nouveau_dsm_power_state, 211 .power_state = nouveau_dsm_power_state,
212 .get_client_id = nouveau_dsm_get_client_id, 212 .get_client_id = nouveau_dsm_get_client_id,
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
index a771b9f0bf98..c4b4f298a283 100644
--- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -499,7 +499,7 @@ static int radeon_atpx_get_client_id(struct pci_dev *pdev)
499 return VGA_SWITCHEROO_DIS; 499 return VGA_SWITCHEROO_DIS;
500} 500}
501 501
502static struct vga_switcheroo_handler radeon_atpx_handler = { 502static const struct vga_switcheroo_handler radeon_atpx_handler = {
503 .switchto = radeon_atpx_switchto, 503 .switchto = radeon_atpx_switchto,
504 .power_state = radeon_atpx_power_state, 504 .power_state = radeon_atpx_power_state,
505 .init = radeon_atpx_init, 505 .init = radeon_atpx_init,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index f22e1e1ee64a..d26e0cc7dc4b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -19,6 +19,7 @@
19#include <drm/drmP.h> 19#include <drm/drmP.h>
20#include <drm/drm_crtc_helper.h> 20#include <drm/drm_crtc_helper.h>
21#include <drm/drm_fb_helper.h> 21#include <drm/drm_fb_helper.h>
22#include <drm/drm_of.h>
22#include <linux/dma-mapping.h> 23#include <linux/dma-mapping.h>
23#include <linux/pm_runtime.h> 24#include <linux/pm_runtime.h>
24#include <linux/module.h> 25#include <linux/module.h>
@@ -418,29 +419,6 @@ static int compare_of(struct device *dev, void *data)
418 return dev->of_node == np; 419 return dev->of_node == np;
419} 420}
420 421
421static void rockchip_add_endpoints(struct device *dev,
422 struct component_match **match,
423 struct device_node *port)
424{
425 struct device_node *ep, *remote;
426
427 for_each_child_of_node(port, ep) {
428 remote = of_graph_get_remote_port_parent(ep);
429 if (!remote || !of_device_is_available(remote)) {
430 of_node_put(remote);
431 continue;
432 } else if (!of_device_is_available(remote->parent)) {
433 dev_warn(dev, "parent device of %s is not available\n",
434 remote->full_name);
435 of_node_put(remote);
436 continue;
437 }
438
439 component_match_add(dev, match, compare_of, remote);
440 of_node_put(remote);
441 }
442}
443
444static int rockchip_drm_bind(struct device *dev) 422static int rockchip_drm_bind(struct device *dev)
445{ 423{
446 struct drm_device *drm; 424 struct drm_device *drm;
@@ -483,61 +461,14 @@ static const struct component_master_ops rockchip_drm_ops = {
483 461
484static int rockchip_drm_platform_probe(struct platform_device *pdev) 462static int rockchip_drm_platform_probe(struct platform_device *pdev)
485{ 463{
486 struct device *dev = &pdev->dev; 464 int ret = drm_of_component_probe(&pdev->dev, compare_of,
487 struct component_match *match = NULL; 465 &rockchip_drm_ops);
488 struct device_node *np = dev->of_node;
489 struct device_node *port;
490 int i;
491
492 if (!np)
493 return -ENODEV;
494 /*
495 * Bind the crtc ports first, so that
496 * drm_of_find_possible_crtcs called from encoder .bind callbacks
497 * works as expected.
498 */
499 for (i = 0;; i++) {
500 port = of_parse_phandle(np, "ports", i);
501 if (!port)
502 break;
503
504 if (!of_device_is_available(port->parent)) {
505 of_node_put(port);
506 continue;
507 }
508
509 component_match_add(dev, &match, compare_of, port->parent);
510 of_node_put(port);
511 }
512 466
513 if (i == 0) { 467 /* keep compatibility with old code that was returning -ENODEV */
514 dev_err(dev, "missing 'ports' property\n"); 468 if (ret == -EINVAL)
515 return -ENODEV; 469 return -ENODEV;
516 }
517 470
518 if (!match) { 471 return ret;
519 dev_err(dev, "No available vop found for display-subsystem.\n");
520 return -ENODEV;
521 }
522 /*
523 * For each bound crtc, bind the encoders attached to its
524 * remote endpoint.
525 */
526 for (i = 0;; i++) {
527 port = of_parse_phandle(np, "ports", i);
528 if (!port)
529 break;
530
531 if (!of_device_is_available(port->parent)) {
532 of_node_put(port);
533 continue;
534 }
535
536 rockchip_add_endpoints(dev, &match, port);
537 of_node_put(port);
538 }
539
540 return component_master_add_with_match(dev, &rockchip_drm_ops, match);
541} 472}
542 473
543static int rockchip_drm_platform_remove(struct platform_device *pdev) 474static int rockchip_drm_platform_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index af0d372ff7d4..56bbbd65ae8a 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -140,7 +140,7 @@ struct vgasr_priv {
140 int registered_clients; 140 int registered_clients;
141 struct list_head clients; 141 struct list_head clients;
142 142
143 struct vga_switcheroo_handler *handler; 143 const struct vga_switcheroo_handler *handler;
144}; 144};
145 145
146#define ID_BIT_AUDIO 0x100 146#define ID_BIT_AUDIO 0x100
@@ -195,7 +195,7 @@ static void vga_switcheroo_enable(void)
195 * 195 *
196 * Return: 0 on success, -EINVAL if a handler was already registered. 196 * Return: 0 on success, -EINVAL if a handler was already registered.
197 */ 197 */
198int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) 198int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler)
199{ 199{
200 mutex_lock(&vgasr_mutex); 200 mutex_lock(&vgasr_mutex);
201 if (vgasr_priv.handler) { 201 if (vgasr_priv.handler) {
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 0dec3f59917a..976efeb3f2ba 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -346,7 +346,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
346 return VGA_SWITCHEROO_DIS; 346 return VGA_SWITCHEROO_DIS;
347} 347}
348 348
349static struct vga_switcheroo_handler gmux_handler = { 349static const struct vga_switcheroo_handler gmux_handler = {
350 .switchto = gmux_switchto, 350 .switchto = gmux_switchto,
351 .power_state = gmux_set_power_state, 351 .power_state = gmux_set_power_state,
352 .get_client_id = gmux_get_client_id, 352 .get_client_id = gmux_get_client_id,
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index 2441f7112074..8544665ee4f4 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -1,18 +1,31 @@
1#ifndef __DRM_OF_H__ 1#ifndef __DRM_OF_H__
2#define __DRM_OF_H__ 2#define __DRM_OF_H__
3 3
4struct component_master_ops;
5struct device;
4struct drm_device; 6struct drm_device;
5struct device_node; 7struct device_node;
6 8
7#ifdef CONFIG_OF 9#ifdef CONFIG_OF
8extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, 10extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
9 struct device_node *port); 11 struct device_node *port);
12extern int drm_of_component_probe(struct device *dev,
13 int (*compare_of)(struct device *, void *),
14 const struct component_master_ops *m_ops);
10#else 15#else
11static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, 16static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
12 struct device_node *port) 17 struct device_node *port)
13{ 18{
14 return 0; 19 return 0;
15} 20}
21
22static inline int
23drm_of_component_probe(struct device *dev,
24 int (*compare_of)(struct device *, void *),
25 const struct component_master_ops *m_ops)
26{
27 return -EINVAL;
28}
16#endif 29#endif
17 30
18#endif /* __DRM_OF_H__ */ 31#endif /* __DRM_OF_H__ */
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index c55751155631..786bc931dbd1 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -137,7 +137,7 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
137void vga_switcheroo_client_fb_set(struct pci_dev *dev, 137void vga_switcheroo_client_fb_set(struct pci_dev *dev,
138 struct fb_info *info); 138 struct fb_info *info);
139 139
140int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler); 140int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler);
141void vga_switcheroo_unregister_handler(void); 141void vga_switcheroo_unregister_handler(void);
142 142
143int vga_switcheroo_process_delayed_switch(void); 143int vga_switcheroo_process_delayed_switch(void);
@@ -155,7 +155,7 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
155static inline int vga_switcheroo_register_client(struct pci_dev *dev, 155static inline int vga_switcheroo_register_client(struct pci_dev *dev,
156 const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; } 156 const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
157static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {} 157static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
158static inline int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) { return 0; } 158static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) { return 0; }
159static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev, 159static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
160 const struct vga_switcheroo_client_ops *ops, 160 const struct vga_switcheroo_client_ops *ops,
161 enum vga_switcheroo_client_id id) { return 0; } 161 enum vga_switcheroo_client_id id) { return 0; }