diff options
-rw-r--r-- | drivers/gpu/drm/rcar-du/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_encoder.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | 68 |
4 files changed, 50 insertions, 44 deletions
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 4c2fd056dd6d..2bab449add76 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig | |||
@@ -20,6 +20,7 @@ config DRM_RCAR_HDMI | |||
20 | config DRM_RCAR_LVDS | 20 | config DRM_RCAR_LVDS |
21 | bool "R-Car DU LVDS Encoder Support" | 21 | bool "R-Car DU LVDS Encoder Support" |
22 | depends on DRM_RCAR_DU | 22 | depends on DRM_RCAR_DU |
23 | select DRM_PANEL | ||
23 | help | 24 | help |
24 | Enable support for the R-Car Display Unit embedded LVDS encoders. | 25 | Enable support for the R-Car Display Unit embedded LVDS encoders. |
25 | 26 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 3974d9495f37..31f878ad099d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <drm/drm_crtc.h> | 17 | #include <drm/drm_crtc.h> |
18 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
19 | #include <drm/drm_panel.h> | ||
19 | 20 | ||
20 | #include "rcar_du_drv.h" | 21 | #include "rcar_du_drv.h" |
21 | #include "rcar_du_encoder.h" | 22 | #include "rcar_du_encoder.h" |
@@ -33,6 +34,11 @@ static void rcar_du_encoder_disable(struct drm_encoder *encoder) | |||
33 | { | 34 | { |
34 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); | 35 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); |
35 | 36 | ||
37 | if (renc->connector && renc->connector->panel) { | ||
38 | drm_panel_disable(renc->connector->panel); | ||
39 | drm_panel_unprepare(renc->connector->panel); | ||
40 | } | ||
41 | |||
36 | if (renc->lvds) | 42 | if (renc->lvds) |
37 | rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false); | 43 | rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false); |
38 | } | 44 | } |
@@ -43,6 +49,11 @@ static void rcar_du_encoder_enable(struct drm_encoder *encoder) | |||
43 | 49 | ||
44 | if (renc->lvds) | 50 | if (renc->lvds) |
45 | rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true); | 51 | rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true); |
52 | |||
53 | if (renc->connector && renc->connector->panel) { | ||
54 | drm_panel_prepare(renc->connector->panel); | ||
55 | drm_panel_enable(renc->connector->panel); | ||
56 | } | ||
46 | } | 57 | } |
47 | 58 | ||
48 | static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder, | 59 | static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder, |
@@ -89,6 +100,17 @@ static void rcar_du_encoder_mode_set(struct drm_encoder *encoder, | |||
89 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); | 100 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); |
90 | 101 | ||
91 | rcar_du_crtc_route_output(crtc_state->crtc, renc->output); | 102 | rcar_du_crtc_route_output(crtc_state->crtc, renc->output); |
103 | |||
104 | if (!renc->lvds) { | ||
105 | /* | ||
106 | * The DU driver creates connectors only for the outputs of the | ||
107 | * internal LVDS encoders. | ||
108 | */ | ||
109 | renc->connector = NULL; | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | renc->connector = to_rcar_connector(conn_state->connector); | ||
92 | } | 114 | } |
93 | 115 | ||
94 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | 116 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h index a050a3699857..b79b2f075a74 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <drm/drm_crtc.h> | 17 | #include <drm/drm_crtc.h> |
18 | #include <drm/drm_encoder.h> | 18 | #include <drm/drm_encoder.h> |
19 | 19 | ||
20 | struct drm_panel; | ||
20 | struct rcar_du_device; | 21 | struct rcar_du_device; |
21 | struct rcar_du_hdmienc; | 22 | struct rcar_du_hdmienc; |
22 | struct rcar_du_lvdsenc; | 23 | struct rcar_du_lvdsenc; |
@@ -32,6 +33,7 @@ enum rcar_du_encoder_type { | |||
32 | struct rcar_du_encoder { | 33 | struct rcar_du_encoder { |
33 | struct drm_encoder base; | 34 | struct drm_encoder base; |
34 | enum rcar_du_output output; | 35 | enum rcar_du_output output; |
36 | struct rcar_du_connector *connector; | ||
35 | struct rcar_du_hdmienc *hdmi; | 37 | struct rcar_du_hdmienc *hdmi; |
36 | struct rcar_du_lvdsenc *lvds; | 38 | struct rcar_du_lvdsenc *lvds; |
37 | }; | 39 | }; |
@@ -44,6 +46,7 @@ struct rcar_du_encoder { | |||
44 | struct rcar_du_connector { | 46 | struct rcar_du_connector { |
45 | struct drm_connector connector; | 47 | struct drm_connector connector; |
46 | struct rcar_du_encoder *encoder; | 48 | struct rcar_du_encoder *encoder; |
49 | struct drm_panel *panel; | ||
47 | }; | 50 | }; |
48 | 51 | ||
49 | #define to_rcar_connector(c) \ | 52 | #define to_rcar_connector(c) \ |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c index 3bcfd161c53f..ee91481131ad 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <drm/drm_atomic_helper.h> | 15 | #include <drm/drm_atomic_helper.h> |
16 | #include <drm/drm_crtc.h> | 16 | #include <drm/drm_crtc.h> |
17 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
18 | #include <drm/drm_panel.h> | ||
18 | 19 | ||
19 | #include <video/display_timing.h> | 20 | #include <video/display_timing.h> |
20 | #include <video/of_display_timing.h> | 21 | #include <video/of_display_timing.h> |
@@ -25,47 +26,30 @@ | |||
25 | #include "rcar_du_kms.h" | 26 | #include "rcar_du_kms.h" |
26 | #include "rcar_du_lvdscon.h" | 27 | #include "rcar_du_lvdscon.h" |
27 | 28 | ||
28 | struct rcar_du_lvds_connector { | ||
29 | struct rcar_du_connector connector; | ||
30 | |||
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; | ||
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) | 29 | static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector) |
42 | { | 30 | { |
43 | struct rcar_du_lvds_connector *lvdscon = | 31 | struct rcar_du_connector *rcon = to_rcar_connector(connector); |
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 | 32 | ||
51 | mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; | 33 | return drm_panel_get_modes(rcon->panel); |
52 | |||
53 | drm_display_mode_from_videomode(&lvdscon->panel.mode, mode); | ||
54 | |||
55 | drm_mode_probed_add(connector, mode); | ||
56 | |||
57 | return 1; | ||
58 | } | 34 | } |
59 | 35 | ||
60 | static const struct drm_connector_helper_funcs connector_helper_funcs = { | 36 | static const struct drm_connector_helper_funcs connector_helper_funcs = { |
61 | .get_modes = rcar_du_lvds_connector_get_modes, | 37 | .get_modes = rcar_du_lvds_connector_get_modes, |
62 | }; | 38 | }; |
63 | 39 | ||
40 | static void rcar_du_lvds_connector_destroy(struct drm_connector *connector) | ||
41 | { | ||
42 | struct rcar_du_connector *rcon = to_rcar_connector(connector); | ||
43 | |||
44 | drm_panel_detach(rcon->panel); | ||
45 | drm_connector_cleanup(connector); | ||
46 | } | ||
47 | |||
64 | static const struct drm_connector_funcs connector_funcs = { | 48 | static const struct drm_connector_funcs connector_funcs = { |
65 | .dpms = drm_atomic_helper_connector_dpms, | 49 | .dpms = drm_atomic_helper_connector_dpms, |
66 | .reset = drm_atomic_helper_connector_reset, | 50 | .reset = drm_atomic_helper_connector_reset, |
67 | .fill_modes = drm_helper_probe_single_connector_modes, | 51 | .fill_modes = drm_helper_probe_single_connector_modes, |
68 | .destroy = drm_connector_cleanup, | 52 | .destroy = rcar_du_lvds_connector_destroy, |
69 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 53 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
70 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 54 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
71 | }; | 55 | }; |
@@ -75,27 +59,19 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, | |||
75 | const struct device_node *np) | 59 | const struct device_node *np) |
76 | { | 60 | { |
77 | struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); | 61 | struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); |
78 | struct rcar_du_lvds_connector *lvdscon; | 62 | struct rcar_du_connector *rcon; |
79 | struct drm_connector *connector; | 63 | struct drm_connector *connector; |
80 | struct display_timing timing; | ||
81 | int ret; | 64 | int ret; |
82 | 65 | ||
83 | lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL); | 66 | rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL); |
84 | if (lvdscon == NULL) | 67 | if (rcon == NULL) |
85 | return -ENOMEM; | 68 | return -ENOMEM; |
86 | 69 | ||
87 | ret = of_get_display_timing(np, "panel-timing", &timing); | 70 | connector = &rcon->connector; |
88 | if (ret < 0) | ||
89 | return ret; | ||
90 | |||
91 | videomode_from_timing(&timing, &lvdscon->panel.mode); | ||
92 | 71 | ||
93 | of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm); | 72 | rcon->panel = of_drm_find_panel(np); |
94 | of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm); | 73 | if (!rcon->panel) |
95 | 74 | return -EPROBE_DEFER; | |
96 | connector = &lvdscon->connector.connector; | ||
97 | connector->display_info.width_mm = lvdscon->panel.width_mm; | ||
98 | connector->display_info.height_mm = lvdscon->panel.height_mm; | ||
99 | 75 | ||
100 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, | 76 | ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, |
101 | DRM_MODE_CONNECTOR_LVDS); | 77 | DRM_MODE_CONNECTOR_LVDS); |
@@ -112,7 +88,11 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, | |||
112 | if (ret < 0) | 88 | if (ret < 0) |
113 | return ret; | 89 | return ret; |
114 | 90 | ||
115 | lvdscon->connector.encoder = renc; | 91 | ret = drm_panel_attach(rcon->panel, connector); |
92 | if (ret < 0) | ||
93 | return ret; | ||
94 | |||
95 | rcon->encoder = renc; | ||
116 | 96 | ||
117 | return 0; | 97 | return 0; |
118 | } | 98 | } |