aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-06-16 21:13:11 -0400
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-08-09 17:17:52 -0400
commitef67a902e946ad1ef51040cf287a45cc4714e2b5 (patch)
tree8539a95cefc69a1c2553ec8d987a40e6048feedd
parent38b62fb3808e6b57dbd7728e897e4f7674d1c998 (diff)
drm/rcar-du: Rework output routing support
Split the output routing specification between SoC-internal data, specified in the rcar_du_device_info structure, and board data, passed through platform data. The DU has 5 possible outputs (DPAD0/1, LVDS0/1, TCON). SoC-internal output routing data specify which output are valid, which CRTCs can be connected to the valid outputs, and the type of in-SoC encoder for the output. Platform data then specifies external encoders and the output they are connected to. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h4
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c30
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h16
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c26
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.h5
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c8
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c17
-rw-r--r--include/linux/platform_data/rcar-du.h17
9 files changed, 107 insertions, 22 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index a340224e08e6..680606ef11d8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -129,14 +129,16 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
129 rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); 129 rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
130} 130}
131 131
132void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output) 132void rcar_du_crtc_route_output(struct drm_crtc *crtc,
133 enum rcar_du_output output)
133{ 134{
134 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); 135 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
136 struct rcar_du_device *rcdu = rcrtc->group->dev;
135 137
136 /* Store the route from the CRTC output to the DU output. The DU will be 138 /* Store the route from the CRTC output to the DU output. The DU will be
137 * configured when starting the CRTC. 139 * configured when starting the CRTC.
138 */ 140 */
139 rcrtc->outputs |= 1 << output; 141 rcrtc->outputs |= BIT(output);
140} 142}
141 143
142void rcar_du_crtc_update_planes(struct drm_crtc *crtc) 144void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 542a7feceb20..39a983d13afb 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -15,6 +15,7 @@
15#define __RCAR_DU_CRTC_H__ 15#define __RCAR_DU_CRTC_H__
16 16
17#include <linux/mutex.h> 17#include <linux/mutex.h>
18#include <linux/platform_data/rcar-du.h>
18 19
19#include <drm/drmP.h> 20#include <drm/drmP.h>
20#include <drm/drm_crtc.h> 21#include <drm/drm_crtc.h>
@@ -45,7 +46,8 @@ void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
45void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc); 46void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
46void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc); 47void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
47 48
48void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output); 49void rcar_du_crtc_route_output(struct drm_crtc *crtc,
50 enum rcar_du_output output);
49void rcar_du_crtc_update_planes(struct drm_crtc *crtc); 51void rcar_du_crtc_update_planes(struct drm_crtc *crtc);
50 52
51#endif /* __RCAR_DU_CRTC_H__ */ 53#endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index f8785357b599..4bc399734490 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -219,12 +219,42 @@ static int rcar_du_remove(struct platform_device *pdev)
219static const struct rcar_du_device_info rcar_du_r8a7779_info = { 219static const struct rcar_du_device_info rcar_du_r8a7779_info = {
220 .features = 0, 220 .features = 0,
221 .num_crtcs = 2, 221 .num_crtcs = 2,
222 .routes = {
223 /* R8A7779 has two RGB outputs and one (currently unsupported)
224 * TCON output.
225 */
226 [RCAR_DU_OUTPUT_DPAD0] = {
227 .possible_crtcs = BIT(0),
228 .encoder_type = DRM_MODE_ENCODER_NONE,
229 },
230 [RCAR_DU_OUTPUT_DPAD1] = {
231 .possible_crtcs = BIT(1) | BIT(0),
232 .encoder_type = DRM_MODE_ENCODER_NONE,
233 },
234 },
222}; 235};
223 236
224static const struct rcar_du_device_info rcar_du_r8a7790_info = { 237static const struct rcar_du_device_info rcar_du_r8a7790_info = {
225 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B 238 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B
226 | RCAR_DU_FEATURE_DEFR8, 239 | RCAR_DU_FEATURE_DEFR8,
227 .num_crtcs = 3, 240 .num_crtcs = 3,
241 .routes = {
242 /* R8A7790 has one RGB output, two LVDS outputs and one
243 * (currently unsupported) TCON output.
244 */
245 [RCAR_DU_OUTPUT_DPAD0] = {
246 .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
247 .encoder_type = DRM_MODE_ENCODER_NONE,
248 },
249 [RCAR_DU_OUTPUT_LVDS0] = {
250 .possible_crtcs = BIT(0),
251 .encoder_type = DRM_MODE_ENCODER_LVDS,
252 },
253 [RCAR_DU_OUTPUT_LVDS1] = {
254 .possible_crtcs = BIT(2) | BIT(1),
255 .encoder_type = DRM_MODE_ENCODER_LVDS,
256 },
257 },
228}; 258};
229 259
230static const struct platform_device_id rcar_du_id_table[] = { 260static const struct platform_device_id rcar_du_id_table[] = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 70c335f51136..d5243f493903 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -30,13 +30,29 @@ struct rcar_du_device;
30#define RCAR_DU_FEATURE_DEFR8 (1 << 2) /* Has DEFR8 register */ 30#define RCAR_DU_FEATURE_DEFR8 (1 << 2) /* Has DEFR8 register */
31 31
32/* 32/*
33 * struct rcar_du_output_routing - Output routing specification
34 * @possible_crtcs: bitmask of possible CRTCs for the output
35 * @encoder_type: DRM type of the internal encoder associated with the output
36 *
37 * The DU has 5 possible outputs (DPAD0/1, LVDS0/1, TCON). Output routing data
38 * specify the valid SoC outputs, which CRTCs can drive the output, and the type
39 * of in-SoC encoder for the output.
40 */
41struct rcar_du_output_routing {
42 unsigned int possible_crtcs;
43 unsigned int encoder_type;
44};
45
46/*
33 * struct rcar_du_device_info - DU model-specific information 47 * struct rcar_du_device_info - DU model-specific information
34 * @features: device features (RCAR_DU_FEATURE_*) 48 * @features: device features (RCAR_DU_FEATURE_*)
35 * @num_crtcs: total number of CRTCs 49 * @num_crtcs: total number of CRTCs
50 * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*)
36 */ 51 */
37struct rcar_du_device_info { 52struct rcar_du_device_info {
38 unsigned int features; 53 unsigned int features;
39 unsigned int num_crtcs; 54 unsigned int num_crtcs;
55 struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
40}; 56};
41 57
42struct rcar_du_device { 58struct rcar_du_device {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index 0d0375c7ee44..2aac28d21f87 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -115,10 +115,12 @@ static const struct drm_encoder_funcs encoder_funcs = {
115}; 115};
116 116
117int rcar_du_encoder_init(struct rcar_du_device *rcdu, 117int rcar_du_encoder_init(struct rcar_du_device *rcdu,
118 enum rcar_du_encoder_type type, unsigned int output, 118 enum rcar_du_encoder_type type,
119 enum rcar_du_output output,
119 const struct rcar_du_encoder_data *data) 120 const struct rcar_du_encoder_data *data)
120{ 121{
121 struct rcar_du_encoder *renc; 122 struct rcar_du_encoder *renc;
123 unsigned int encoder_type;
122 int ret; 124 int ret;
123 125
124 renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); 126 renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
@@ -127,19 +129,33 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
127 129
128 renc->output = output; 130 renc->output = output;
129 131
132 switch (type) {
133 case RCAR_DU_ENCODER_VGA:
134 encoder_type = DRM_MODE_ENCODER_DAC;
135 break;
136 case RCAR_DU_ENCODER_LVDS:
137 encoder_type = DRM_MODE_ENCODER_LVDS;
138 break;
139 case RCAR_DU_ENCODER_NONE:
140 default:
141 /* No external encoder, use the internal encoder type. */
142 encoder_type = rcdu->info->routes[output].encoder_type;
143 break;
144 }
145
130 ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, 146 ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs,
131 type); 147 encoder_type);
132 if (ret < 0) 148 if (ret < 0)
133 return ret; 149 return ret;
134 150
135 drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); 151 drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
136 152
137 switch (type) { 153 switch (encoder_type) {
138 case RCAR_DU_ENCODER_LVDS: 154 case DRM_MODE_ENCODER_LVDS:
139 return rcar_du_lvds_connector_init(rcdu, renc, 155 return rcar_du_lvds_connector_init(rcdu, renc,
140 &data->connector.lvds.panel); 156 &data->connector.lvds.panel);
141 157
142 case RCAR_DU_ENCODER_VGA: 158 case DRM_MODE_ENCODER_DAC:
143 return rcar_du_vga_connector_init(rcdu, renc); 159 return rcar_du_vga_connector_init(rcdu, renc);
144 160
145 default: 161 default:
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
index 08cde1293892..2310416ea21f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h
@@ -22,7 +22,7 @@ struct rcar_du_device;
22 22
23struct rcar_du_encoder { 23struct rcar_du_encoder {
24 struct drm_encoder encoder; 24 struct drm_encoder encoder;
25 unsigned int output; 25 enum rcar_du_output output;
26}; 26};
27 27
28#define to_rcar_encoder(e) \ 28#define to_rcar_encoder(e) \
@@ -40,7 +40,8 @@ struct drm_encoder *
40rcar_du_connector_best_encoder(struct drm_connector *connector); 40rcar_du_connector_best_encoder(struct drm_connector *connector);
41 41
42int rcar_du_encoder_init(struct rcar_du_device *rcdu, 42int rcar_du_encoder_init(struct rcar_du_device *rcdu,
43 enum rcar_du_encoder_type type, unsigned int output, 43 enum rcar_du_encoder_type type,
44 enum rcar_du_output output,
44 const struct rcar_du_encoder_data *data); 45 const struct rcar_du_encoder_data *data);
45 46
46#endif /* __RCAR_DU_ENCODER_H__ */ 47#endif /* __RCAR_DU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index f3ba0ca845e2..9df6fb635c96 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -135,11 +135,11 @@ void rcar_du_group_set_routing(struct rcar_du_group *rgrp)
135 135
136 dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK); 136 dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK);
137 137
138 /* Set the DU1 pins sources. Select CRTC 0 if explicitly requested and 138 /* Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and
139 * CRTC 1 in all other cases to avoid cloning CRTC 0 to DU0 and DU1 by 139 * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1
140 * default. 140 * by default.
141 */ 141 */
142 if (crtc0->outputs & (1 << 1)) 142 if (crtc0->outputs & BIT(RCAR_DU_OUTPUT_DPAD1))
143 dorcr |= DORCR_PG2D_DS1; 143 dorcr |= DORCR_PG2D_DS1;
144 else 144 else
145 dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2; 145 dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 816963ca1626..2b92e68a09f0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -220,11 +220,14 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
220 for (i = 0; i < rcdu->pdata->num_encoders; ++i) { 220 for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
221 const struct rcar_du_encoder_data *pdata = 221 const struct rcar_du_encoder_data *pdata =
222 &rcdu->pdata->encoders[i]; 222 &rcdu->pdata->encoders[i];
223 const struct rcar_du_output_routing *route =
224 &rcdu->info->routes[pdata->output];
223 225
224 if (pdata->type == RCAR_DU_ENCODER_UNUSED) 226 if (pdata->type == RCAR_DU_ENCODER_UNUSED)
225 continue; 227 continue;
226 228
227 if (pdata->output >= rcdu->num_crtcs) { 229 if (pdata->output >= RCAR_DU_OUTPUT_MAX ||
230 route->possible_crtcs == 0) {
228 dev_warn(rcdu->dev, 231 dev_warn(rcdu->dev,
229 "encoder %u references unexisting output %u, skipping\n", 232 "encoder %u references unexisting output %u, skipping\n",
230 i, pdata->output); 233 i, pdata->output);
@@ -234,15 +237,17 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
234 rcar_du_encoder_init(rcdu, pdata->type, pdata->output, pdata); 237 rcar_du_encoder_init(rcdu, pdata->type, pdata->output, pdata);
235 } 238 }
236 239
237 /* Set the possible CRTCs and possible clones. All encoders can be 240 /* Set the possible CRTCs and possible clones. There's always at least
238 * driven by the CRTC associated with the output they're connected to, 241 * one way for all encoders to clone each other, set all bits in the
239 * as well as by CRTC 0. 242 * possible clones field.
240 */ 243 */
241 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 244 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
242 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 245 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
246 const struct rcar_du_output_routing *route =
247 &rcdu->info->routes[renc->output];
243 248
244 encoder->possible_crtcs = (1 << 0) | (1 << renc->output); 249 encoder->possible_crtcs = route->possible_crtcs;
245 encoder->possible_clones = 1 << 0; 250 encoder->possible_clones = (1 << rcdu->pdata->num_encoders) - 1;
246 } 251 }
247 252
248 /* Now that the CRTCs have been initialized register the planes. */ 253 /* Now that the CRTCs have been initialized register the planes. */
diff --git a/include/linux/platform_data/rcar-du.h b/include/linux/platform_data/rcar-du.h
index 64cd8635e6e6..1a2e9901a22e 100644
--- a/include/linux/platform_data/rcar-du.h
+++ b/include/linux/platform_data/rcar-du.h
@@ -16,8 +16,18 @@
16 16
17#include <drm/drm_mode.h> 17#include <drm/drm_mode.h>
18 18
19enum rcar_du_output {
20 RCAR_DU_OUTPUT_DPAD0,
21 RCAR_DU_OUTPUT_DPAD1,
22 RCAR_DU_OUTPUT_LVDS0,
23 RCAR_DU_OUTPUT_LVDS1,
24 RCAR_DU_OUTPUT_TCON,
25 RCAR_DU_OUTPUT_MAX,
26};
27
19enum rcar_du_encoder_type { 28enum rcar_du_encoder_type {
20 RCAR_DU_ENCODER_UNUSED = 0, 29 RCAR_DU_ENCODER_UNUSED = 0,
30 RCAR_DU_ENCODER_NONE,
21 RCAR_DU_ENCODER_VGA, 31 RCAR_DU_ENCODER_VGA,
22 RCAR_DU_ENCODER_LVDS, 32 RCAR_DU_ENCODER_LVDS,
23}; 33};
@@ -39,13 +49,16 @@ struct rcar_du_connector_vga_data {
39/* 49/*
40 * struct rcar_du_encoder_data - Encoder platform data 50 * struct rcar_du_encoder_data - Encoder platform data
41 * @type: the encoder type (RCAR_DU_ENCODER_*) 51 * @type: the encoder type (RCAR_DU_ENCODER_*)
42 * @output: the DU output the connector is connected to 52 * @output: the DU output the connector is connected to (RCAR_DU_OUTPUT_*)
43 * @connector.lvds: platform data for LVDS connectors 53 * @connector.lvds: platform data for LVDS connectors
44 * @connector.vga: platform data for VGA connectors 54 * @connector.vga: platform data for VGA connectors
55 *
56 * Encoder platform data describes an on-board encoder, its associated DU SoC
57 * output, and the connector.
45 */ 58 */
46struct rcar_du_encoder_data { 59struct rcar_du_encoder_data {
47 enum rcar_du_encoder_type type; 60 enum rcar_du_encoder_type type;
48 unsigned int output; 61 enum rcar_du_output output;
49 62
50 union { 63 union {
51 struct rcar_du_connector_lvds_data lvds; 64 struct rcar_du_connector_lvds_data lvds;