diff options
author | Dave Airlie <airlied@redhat.com> | 2015-10-29 19:49:06 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-10-29 19:49:06 -0400 |
commit | a76edb8cec0cc864c8b72fa7e84a72336e033e23 (patch) | |
tree | 3d680a904cc835aeb56f32d8814af7d8fd9a7767 | |
parent | f1a04d82585032d906e6a7d5b16d38a369033bd0 (diff) | |
parent | 48aa1e748f29373fdcc2bc341eac08ef16bff269 (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.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_drv.c | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 52 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_of.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atpx_handler.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 81 | ||||
-rw-r--r-- | drivers/gpu/vga/vga_switcheroo.c | 4 | ||||
-rw-r--r-- | drivers/platform/x86/apple-gmux.c | 2 | ||||
-rw-r--r-- | include/drm/drm_of.h | 13 | ||||
-rw-r--r-- | include/linux/vga_switcheroo.h | 4 |
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 | ||
504 | static struct vga_switcheroo_handler amdgpu_atpx_handler = { | 504 | static 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 | ||
265 | static int armada_drm_find_components(struct device *dev, | 266 | static 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) { | 271 | static 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 | |||
323 | static const struct component_master_ops armada_master_ops = { | ||
324 | .bind = armada_drm_bind, | ||
325 | .unbind = armada_drm_unbind, | ||
326 | }; | ||
327 | |||
328 | static 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; |
1614 | nomem: | ||
1615 | return -ENOMEM; | ||
1586 | } | 1616 | } |
1587 | EXPORT_SYMBOL(drm_mode_create_tv_properties); | 1617 | EXPORT_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 | ||
2421 | static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode); | ||
2422 | |||
2421 | static void | 2423 | static void |
2422 | do_detailed_mode(struct detailed_timing *timing, void *c) | 2424 | do_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 | ||
3115 | static 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 | |||
3106 | static void | 3154 | static void |
3107 | parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) | 3155 | parse_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 | } |
63 | EXPORT_SYMBOL(drm_of_find_possible_crtcs); | 64 | EXPORT_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 | */ | ||
79 | int 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 | } | ||
151 | EXPORT_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 | ||
532 | static int imx_drm_platform_probe(struct platform_device *pdev) | 532 | static 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 | ||
589 | static int imx_drm_platform_remove(struct platform_device *pdev) | 542 | static 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 | ||
209 | static struct vga_switcheroo_handler nouveau_dsm_handler = { | 209 | static 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 | ||
502 | static struct vga_switcheroo_handler radeon_atpx_handler = { | 502 | static 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 | ||
421 | static 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 | |||
444 | static int rockchip_drm_bind(struct device *dev) | 422 | static 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 | ||
484 | static int rockchip_drm_platform_probe(struct platform_device *pdev) | 462 | static 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 | ||
543 | static int rockchip_drm_platform_remove(struct platform_device *pdev) | 474 | static 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 | */ |
198 | int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) | 198 | int 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 | ||
349 | static struct vga_switcheroo_handler gmux_handler = { | 349 | static 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 | ||
4 | struct component_master_ops; | ||
5 | struct device; | ||
4 | struct drm_device; | 6 | struct drm_device; |
5 | struct device_node; | 7 | struct device_node; |
6 | 8 | ||
7 | #ifdef CONFIG_OF | 9 | #ifdef CONFIG_OF |
8 | extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, | 10 | extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, |
9 | struct device_node *port); | 11 | struct device_node *port); |
12 | extern 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 |
11 | static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, | 16 | static 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 | |||
22 | static inline int | ||
23 | drm_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, | |||
137 | void vga_switcheroo_client_fb_set(struct pci_dev *dev, | 137 | void vga_switcheroo_client_fb_set(struct pci_dev *dev, |
138 | struct fb_info *info); | 138 | struct fb_info *info); |
139 | 139 | ||
140 | int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler); | 140 | int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler); |
141 | void vga_switcheroo_unregister_handler(void); | 141 | void vga_switcheroo_unregister_handler(void); |
142 | 142 | ||
143 | int vga_switcheroo_process_delayed_switch(void); | 143 | int vga_switcheroo_process_delayed_switch(void); |
@@ -155,7 +155,7 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {} | |||
155 | static inline int vga_switcheroo_register_client(struct pci_dev *dev, | 155 | static 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; } |
157 | static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {} | 157 | static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {} |
158 | static inline int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) { return 0; } | 158 | static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler) { return 0; } |
159 | static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev, | 159 | static 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; } |