diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_group.c | 64 |
3 files changed, 59 insertions, 15 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index c89751c26f9c..2f8776c1ec8f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c | |||
@@ -261,6 +261,14 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) | |||
261 | rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr); | 261 | rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr); |
262 | 262 | ||
263 | escr = ESCR_DCLKSEL_DCLKIN | div; | 263 | escr = ESCR_DCLKSEL_DCLKIN | div; |
264 | } else if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) { | ||
265 | /* | ||
266 | * Use the LVDS PLL output as the dot clock when outputting to | ||
267 | * the LVDS encoder on an SoC that supports this clock routing | ||
268 | * option. We use the clock directly in that case, without any | ||
269 | * additional divider. | ||
270 | */ | ||
271 | escr = ESCR_DCLKSEL_DCLKIN; | ||
264 | } else { | 272 | } else { |
265 | struct du_clk_params params = { .diff = (unsigned long)-1 }; | 273 | struct du_clk_params params = { .diff = (unsigned long)-1 }; |
266 | 274 | ||
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index fef9ea5c22f3..ebba9aefba6a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h | |||
@@ -53,6 +53,7 @@ struct rcar_du_output_routing { | |||
53 | * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) | 53 | * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) |
54 | * @num_lvds: number of internal LVDS encoders | 54 | * @num_lvds: number of internal LVDS encoders |
55 | * @dpll_mask: bit mask of DU channels equipped with a DPLL | 55 | * @dpll_mask: bit mask of DU channels equipped with a DPLL |
56 | * @lvds_clk_mask: bitmask of channels that can use the LVDS clock as dot clock | ||
56 | */ | 57 | */ |
57 | struct rcar_du_device_info { | 58 | struct rcar_du_device_info { |
58 | unsigned int gen; | 59 | unsigned int gen; |
@@ -62,6 +63,7 @@ struct rcar_du_device_info { | |||
62 | struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; | 63 | struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; |
63 | unsigned int num_lvds; | 64 | unsigned int num_lvds; |
64 | unsigned int dpll_mask; | 65 | unsigned int dpll_mask; |
66 | unsigned int lvds_clk_mask; | ||
65 | }; | 67 | }; |
66 | 68 | ||
67 | #define RCAR_DU_MAX_CRTCS 4 | 69 | #define RCAR_DU_MAX_CRTCS 4 |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index ef2c177afb6d..4c62841eff2f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c | |||
@@ -89,6 +89,54 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) | |||
89 | rcar_du_group_write(rgrp, DEFR8, defr8); | 89 | rcar_du_group_write(rgrp, DEFR8, defr8); |
90 | } | 90 | } |
91 | 91 | ||
92 | static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp) | ||
93 | { | ||
94 | struct rcar_du_device *rcdu = rgrp->dev; | ||
95 | struct rcar_du_crtc *rcrtc; | ||
96 | unsigned int num_crtcs = 0; | ||
97 | unsigned int i; | ||
98 | u32 didsr; | ||
99 | |||
100 | /* | ||
101 | * Configure input dot clock routing with a hardcoded configuration. If | ||
102 | * the DU channel can use the LVDS encoder output clock as the dot | ||
103 | * clock, do so. Otherwise route DU_DOTCLKINn signal to DUn. | ||
104 | * | ||
105 | * Each channel can then select between the dot clock configured here | ||
106 | * and the clock provided by the CPG through the ESCR register. | ||
107 | */ | ||
108 | if (rcdu->info->gen < 3 && rgrp->index == 0) { | ||
109 | /* | ||
110 | * On Gen2 a single register in the first group controls dot | ||
111 | * clock selection for all channels. | ||
112 | */ | ||
113 | rcrtc = rcdu->crtcs; | ||
114 | num_crtcs = rcdu->num_crtcs; | ||
115 | } else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) { | ||
116 | /* | ||
117 | * On Gen3 dot clocks are setup through per-group registers, | ||
118 | * only available when the group has two channels. | ||
119 | */ | ||
120 | rcrtc = &rcdu->crtcs[rgrp->index * 2]; | ||
121 | num_crtcs = rgrp->num_crtcs; | ||
122 | } | ||
123 | |||
124 | if (!num_crtcs) | ||
125 | return; | ||
126 | |||
127 | didsr = DIDSR_CODE; | ||
128 | for (i = 0; i < num_crtcs; ++i, ++rcrtc) { | ||
129 | if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) | ||
130 | didsr |= DIDSR_LCDS_LVDS0(i) | ||
131 | | DIDSR_PDCS_CLK(i, 0); | ||
132 | else | ||
133 | didsr |= DIDSR_LCDS_DCLKIN(i) | ||
134 | | DIDSR_PDCS_CLK(i, 0); | ||
135 | } | ||
136 | |||
137 | rcar_du_group_write(rgrp, DIDSR, didsr); | ||
138 | } | ||
139 | |||
92 | static void rcar_du_group_setup(struct rcar_du_group *rgrp) | 140 | static void rcar_du_group_setup(struct rcar_du_group *rgrp) |
93 | { | 141 | { |
94 | struct rcar_du_device *rcdu = rgrp->dev; | 142 | struct rcar_du_device *rcdu = rgrp->dev; |
@@ -106,21 +154,7 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) | |||
106 | 154 | ||
107 | if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { | 155 | if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { |
108 | rcar_du_group_setup_defr8(rgrp); | 156 | rcar_du_group_setup_defr8(rgrp); |
109 | 157 | rcar_du_group_setup_didsr(rgrp); | |
110 | /* | ||
111 | * Configure input dot clock routing. We currently hardcode the | ||
112 | * configuration to routing DOTCLKINn to DUn. Register fields | ||
113 | * depend on the DU generation, but the resulting value is 0 in | ||
114 | * all cases. | ||
115 | * | ||
116 | * On Gen2 a single register in the first group controls dot | ||
117 | * clock selection for all channels, while on Gen3 dot clocks | ||
118 | * are setup through per-group registers, only available when | ||
119 | * the group has two channels. | ||
120 | */ | ||
121 | if ((rcdu->info->gen < 3 && rgrp->index == 0) || | ||
122 | (rcdu->info->gen == 3 && rgrp->num_crtcs > 1)) | ||
123 | rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE); | ||
124 | } | 158 | } |
125 | 159 | ||
126 | if (rcdu->info->gen >= 3) | 160 | if (rcdu->info->gen >= 3) |