Commit | Line | Data |
---|---|---|
56c5dd00 LP |
1 | /* |
2 | * rcar_du_lvdscon.c -- R-Car Display Unit LVDS Connector | |
3 | * | |
36d50464 | 4 | * Copyright (C) 2013-2014 Renesas Electronics Corporation |
56c5dd00 LP |
5 | * |
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | */ | |
13 | ||
14 | #include <drm/drmP.h> | |
3e8da87d | 15 | #include <drm/drm_atomic_helper.h> |
56c5dd00 LP |
16 | #include <drm/drm_crtc.h> |
17 | #include <drm/drm_crtc_helper.h> | |
18 | ||
96c02691 LP |
19 | #include <video/display_timing.h> |
20 | #include <video/of_display_timing.h> | |
21 | #include <video/videomode.h> | |
22 | ||
56c5dd00 | 23 | #include "rcar_du_drv.h" |
6978f123 | 24 | #include "rcar_du_encoder.h" |
56c5dd00 LP |
25 | #include "rcar_du_kms.h" |
26 | #include "rcar_du_lvdscon.h" | |
27 | ||
28 | struct rcar_du_lvds_connector { | |
29 | struct rcar_du_connector connector; | |
30 | ||
2378ad12 LP |
31 | struct { |
32 | unsigned int width_mm; /* Panel width in mm */ | |
33 | unsigned int height_mm; /* Panel height in mm */ | |
34 | struct videomode mode; | |
35 | } panel; | |
56c5dd00 LP |
36 | }; |
37 | ||
38 | #define to_rcar_lvds_connector(c) \ | |
39 | container_of(c, struct rcar_du_lvds_connector, connector.connector) | |
40 | ||
41 | static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector) | |
42 | { | |
43 | struct rcar_du_lvds_connector *lvdscon = | |
44 | to_rcar_lvds_connector(connector); | |
45 | struct drm_display_mode *mode; | |
46 | ||
47 | mode = drm_mode_create(connector->dev); | |
48 | if (mode == NULL) | |
49 | return 0; | |
50 | ||
51 | mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; | |
1d46fea7 | 52 | |
96c02691 | 53 | drm_display_mode_from_videomode(&lvdscon->panel.mode, mode); |
1d46fea7 | 54 | |
56c5dd00 LP |
55 | drm_mode_probed_add(connector, mode); |
56 | ||
57 | return 1; | |
58 | } | |
59 | ||
56c5dd00 LP |
60 | static const struct drm_connector_helper_funcs connector_helper_funcs = { |
61 | .get_modes = rcar_du_lvds_connector_get_modes, | |
56c5dd00 LP |
62 | }; |
63 | ||
56c5dd00 LP |
64 | static enum drm_connector_status |
65 | rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force) | |
66 | { | |
67 | return connector_status_connected; | |
68 | } | |
69 | ||
70 | static const struct drm_connector_funcs connector_funcs = { | |
f3483232 | 71 | .dpms = drm_atomic_helper_connector_dpms, |
3e8da87d | 72 | .reset = drm_atomic_helper_connector_reset, |
56c5dd00 LP |
73 | .detect = rcar_du_lvds_connector_detect, |
74 | .fill_modes = drm_helper_probe_single_connector_modes, | |
c1d4b38c | 75 | .destroy = drm_connector_cleanup, |
3e8da87d LP |
76 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
77 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
56c5dd00 LP |
78 | }; |
79 | ||
80 | int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, | |
81 | struct rcar_du_encoder *renc, | |
96c02691 | 82 | /* TODO const */ struct device_node *np) |
56c5dd00 | 83 | { |
4b96b70c | 84 | struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); |
56c5dd00 LP |
85 | struct rcar_du_lvds_connector *lvdscon; |
86 | struct drm_connector *connector; | |
2378ad12 | 87 | struct display_timing timing; |
56c5dd00 LP |
88 | int ret; |
89 | ||
90 | lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL); | |
91 | if (lvdscon == NULL) | |
92 | return -ENOMEM; | |
93 | ||
2378ad12 LP |
94 | ret = of_get_display_timing(np, "panel-timing", &timing); |
95 | if (ret < 0) | |
96 | return ret; | |
96c02691 | 97 | |
2378ad12 | 98 | videomode_from_timing(&timing, &lvdscon->panel.mode); |
96c02691 | 99 | |
2378ad12 LP |
100 | of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm); |
101 | of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm); | |
56c5dd00 LP |
102 | |
103 | connector = &lvdscon->connector.connector; | |
96c02691 LP |
104 | connector->display_info.width_mm = lvdscon->panel.width_mm; |
105 | connector->display_info.height_mm = lvdscon->panel.height_mm; | |
56c5dd00 LP |
106 | |
107 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, | |
108 | DRM_MODE_CONNECTOR_LVDS); | |
109 | if (ret < 0) | |
110 | return ret; | |
111 | ||
112 | drm_connector_helper_add(connector, &connector_helper_funcs); | |
56c5dd00 | 113 | |
f3483232 | 114 | connector->dpms = DRM_MODE_DPMS_OFF; |
56c5dd00 LP |
115 | drm_object_property_set_value(&connector->base, |
116 | rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); | |
117 | ||
4b96b70c | 118 | ret = drm_mode_connector_attach_encoder(connector, encoder); |
56c5dd00 LP |
119 | if (ret < 0) |
120 | return ret; | |
121 | ||
56c5dd00 LP |
122 | lvdscon->connector.encoder = renc; |
123 | ||
124 | return 0; | |
125 | } |