]>
Commit | Line | Data |
---|---|---|
0bbce9eb | 1 | // SPDX-License-Identifier: GPL-2.0+ |
cb2025d2 LP |
2 | /* |
3 | * rcar_du_group.c -- R-Car Display Unit Channels Pair | |
4 | * | |
2427b303 | 5 | * Copyright (C) 2013-2015 Renesas Electronics Corporation |
cb2025d2 LP |
6 | * |
7 | * Contact: Laurent Pinchart ([email protected]) | |
cb2025d2 LP |
8 | */ |
9 | ||
10 | /* | |
11 | * The R8A7779 DU is split in per-CRTC resources (scan-out engine, blending | |
12 | * unit, timings generator, ...) and device-global resources (start/stop | |
13 | * control, planes, ...) shared between the two CRTCs. | |
14 | * | |
15 | * The R8A7790 introduced a third CRTC with its own set of global resources. | |
16 | * This would be modeled as two separate DU device instances if it wasn't for | |
17 | * a handful or resources that are shared between the three CRTCs (mostly | |
18 | * related to input and output routing). For this reason the R8A7790 DU must be | |
19 | * modeled as a single device with three CRTCs, two sets of "semi-global" | |
20 | * resources, and a few device-global resources. | |
21 | * | |
22 | * The rcar_du_group object is a driver specific object, without any real | |
23 | * counterpart in the DU documentation, that models those semi-global resources. | |
24 | */ | |
25 | ||
7cbc05cb | 26 | #include <linux/clk.h> |
cb2025d2 LP |
27 | #include <linux/io.h> |
28 | ||
29 | #include "rcar_du_drv.h" | |
30 | #include "rcar_du_group.h" | |
31 | #include "rcar_du_regs.h" | |
32 | ||
a5f0ef59 | 33 | u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg) |
cb2025d2 LP |
34 | { |
35 | return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg); | |
36 | } | |
37 | ||
a5f0ef59 | 38 | void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data) |
cb2025d2 LP |
39 | { |
40 | rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data); | |
41 | } | |
42 | ||
a5e18b2b LP |
43 | static void rcar_du_group_setup_pins(struct rcar_du_group *rgrp) |
44 | { | |
7ae90455 | 45 | u32 defr6 = DEFR6_CODE; |
a5e18b2b | 46 | |
7ae90455 KB |
47 | if (rgrp->channels_mask & BIT(0)) |
48 | defr6 |= DEFR6_ODPM02_DISP; | |
49 | ||
50 | if (rgrp->channels_mask & BIT(1)) | |
4012532e | 51 | defr6 |= DEFR6_ODPM12_DISP; |
a5e18b2b LP |
52 | |
53 | rcar_du_group_write(rgrp, DEFR6, defr6); | |
54 | } | |
55 | ||
7cbc05cb LP |
56 | static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) |
57 | { | |
2427b303 | 58 | struct rcar_du_device *rcdu = rgrp->dev; |
2427b303 | 59 | u32 defr8 = DEFR8_CODE; |
7cbc05cb | 60 | |
2427b303 LP |
61 | if (rcdu->info->gen < 3) { |
62 | defr8 |= DEFR8_DEFE8; | |
63 | ||
f3bafc12 LP |
64 | /* |
65 | * On Gen2 the DEFR8 register for the first group also controls | |
2427b303 LP |
66 | * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 for |
67 | * DU instances that support it. | |
68 | */ | |
69 | if (rgrp->index == 0) { | |
1f98b2a4 | 70 | defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); |
2427b303 LP |
71 | if (rgrp->dev->vspd1_sink == 2) |
72 | defr8 |= DEFR8_VSCS; | |
73 | } | |
74 | } else { | |
f3bafc12 | 75 | /* |
1f98b2a4 LP |
76 | * On Gen3 VSPD routing can't be configured, and DPAD routing |
77 | * is set in the group corresponding to the DPAD output (no Gen3 | |
78 | * SoC has multiple DPAD sources belonging to separate groups). | |
2427b303 | 79 | */ |
1f98b2a4 LP |
80 | if (rgrp->index == rcdu->dpad0_source / 2) |
81 | defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); | |
34a04f2b | 82 | } |
7cbc05cb LP |
83 | |
84 | rcar_du_group_write(rgrp, DEFR8, defr8); | |
85 | } | |
86 | ||
b4734f43 LP |
87 | static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp) |
88 | { | |
89 | struct rcar_du_device *rcdu = rgrp->dev; | |
90 | struct rcar_du_crtc *rcrtc; | |
91 | unsigned int num_crtcs = 0; | |
92 | unsigned int i; | |
93 | u32 didsr; | |
94 | ||
95 | /* | |
96 | * Configure input dot clock routing with a hardcoded configuration. If | |
97 | * the DU channel can use the LVDS encoder output clock as the dot | |
98 | * clock, do so. Otherwise route DU_DOTCLKINn signal to DUn. | |
99 | * | |
100 | * Each channel can then select between the dot clock configured here | |
101 | * and the clock provided by the CPG through the ESCR register. | |
102 | */ | |
103 | if (rcdu->info->gen < 3 && rgrp->index == 0) { | |
104 | /* | |
105 | * On Gen2 a single register in the first group controls dot | |
106 | * clock selection for all channels. | |
107 | */ | |
108 | rcrtc = rcdu->crtcs; | |
109 | num_crtcs = rcdu->num_crtcs; | |
110 | } else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) { | |
111 | /* | |
112 | * On Gen3 dot clocks are setup through per-group registers, | |
113 | * only available when the group has two channels. | |
114 | */ | |
115 | rcrtc = &rcdu->crtcs[rgrp->index * 2]; | |
116 | num_crtcs = rgrp->num_crtcs; | |
117 | } | |
118 | ||
119 | if (!num_crtcs) | |
120 | return; | |
121 | ||
122 | didsr = DIDSR_CODE; | |
123 | for (i = 0; i < num_crtcs; ++i, ++rcrtc) { | |
124 | if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) | |
125 | didsr |= DIDSR_LCDS_LVDS0(i) | |
126 | | DIDSR_PDCS_CLK(i, 0); | |
127 | else | |
128 | didsr |= DIDSR_LCDS_DCLKIN(i) | |
129 | | DIDSR_PDCS_CLK(i, 0); | |
130 | } | |
131 | ||
132 | rcar_du_group_write(rgrp, DIDSR, didsr); | |
133 | } | |
134 | ||
cb2025d2 LP |
135 | static void rcar_du_group_setup(struct rcar_du_group *rgrp) |
136 | { | |
2427b303 LP |
137 | struct rcar_du_device *rcdu = rgrp->dev; |
138 | ||
cb2025d2 LP |
139 | /* Enable extended features */ |
140 | rcar_du_group_write(rgrp, DEFR, DEFR_CODE | DEFR_DEFE); | |
2427b303 LP |
141 | if (rcdu->info->gen < 3) { |
142 | rcar_du_group_write(rgrp, DEFR2, DEFR2_CODE | DEFR2_DEFE2G); | |
143 | rcar_du_group_write(rgrp, DEFR3, DEFR3_CODE | DEFR3_DEFE3); | |
144 | rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); | |
145 | } | |
cb2025d2 | 146 | rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); |
7cbc05cb | 147 | |
a5e18b2b LP |
148 | rcar_du_group_setup_pins(rgrp); |
149 | ||
1b30dbde | 150 | if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { |
0c1c8776 | 151 | rcar_du_group_setup_defr8(rgrp); |
b4734f43 | 152 | rcar_du_group_setup_didsr(rgrp); |
1b30dbde LP |
153 | } |
154 | ||
2427b303 LP |
155 | if (rcdu->info->gen >= 3) |
156 | rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10); | |
157 | ||
f3bafc12 LP |
158 | /* |
159 | * Use DS1PR and DS2PR to configure planes priorities and connects the | |
cb2025d2 LP |
160 | * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. |
161 | */ | |
162 | rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS); | |
2a57e9b5 LP |
163 | |
164 | /* Apply planes to CRTCs association. */ | |
165 | mutex_lock(&rgrp->lock); | |
166 | rcar_du_group_write(rgrp, DPTSR, (rgrp->dptsr_planes << 16) | | |
167 | rgrp->dptsr_planes); | |
168 | mutex_unlock(&rgrp->lock); | |
cb2025d2 LP |
169 | } |
170 | ||
171 | /* | |
172 | * rcar_du_group_get - Acquire a reference to the DU channels group | |
173 | * | |
174 | * Acquiring the first reference setups core registers. A reference must be held | |
175 | * before accessing any hardware registers. | |
176 | * | |
177 | * This function must be called with the DRM mode_config lock held. | |
178 | * | |
179 | * Return 0 in case of success or a negative error code otherwise. | |
180 | */ | |
181 | int rcar_du_group_get(struct rcar_du_group *rgrp) | |
182 | { | |
183 | if (rgrp->use_count) | |
184 | goto done; | |
185 | ||
186 | rcar_du_group_setup(rgrp); | |
187 | ||
188 | done: | |
189 | rgrp->use_count++; | |
190 | return 0; | |
191 | } | |
192 | ||
193 | /* | |
194 | * rcar_du_group_put - Release a reference to the DU | |
195 | * | |
196 | * This function must be called with the DRM mode_config lock held. | |
197 | */ | |
198 | void rcar_du_group_put(struct rcar_du_group *rgrp) | |
199 | { | |
200 | --rgrp->use_count; | |
201 | } | |
202 | ||
203 | static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) | |
204 | { | |
0bc3544a LP |
205 | struct rcar_du_device *rcdu = rgrp->dev; |
206 | ||
207 | /* | |
208 | * Group start/stop is controlled by the DRES and DEN bits of DSYSR0 | |
209 | * for the first group and DSYSR2 for the second group. On most DU | |
210 | * instances, this maps to the first CRTC of the group, and we can just | |
211 | * use rcar_du_crtc_dsysr_clr_set() to access the correct DSYSR. On | |
212 | * M3-N, however, DU2 doesn't exist, but DSYSR2 does. We thus need to | |
213 | * access the register directly using group read/write. | |
214 | */ | |
215 | if (rcdu->info->channels_mask & BIT(rgrp->index * 2)) { | |
216 | struct rcar_du_crtc *rcrtc = &rgrp->dev->crtcs[rgrp->index * 2]; | |
9144adc5 | 217 | |
0bc3544a LP |
218 | rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_DRES | DSYSR_DEN, |
219 | start ? DSYSR_DEN : DSYSR_DRES); | |
220 | } else { | |
221 | rcar_du_group_write(rgrp, DSYSR, | |
222 | start ? DSYSR_DEN : DSYSR_DRES); | |
223 | } | |
cb2025d2 LP |
224 | } |
225 | ||
226 | void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) | |
227 | { | |
f3bafc12 LP |
228 | /* |
229 | * Many of the configuration bits are only updated when the display | |
cb2025d2 LP |
230 | * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some |
231 | * of those bits could be pre-configured, but others (especially the | |
232 | * bits related to plane assignment to display timing controllers) need | |
233 | * to be modified at runtime. | |
234 | * | |
235 | * Restart the display controller if a start is requested. Sorry for the | |
236 | * flicker. It should be possible to move most of the "DRES-update" bits | |
237 | * setup to driver initialization time and minimize the number of cases | |
238 | * when the display controller will have to be restarted. | |
239 | */ | |
240 | if (start) { | |
241 | if (rgrp->used_crtcs++ != 0) | |
242 | __rcar_du_group_start_stop(rgrp, false); | |
243 | __rcar_du_group_start_stop(rgrp, true); | |
244 | } else { | |
245 | if (--rgrp->used_crtcs == 0) | |
246 | __rcar_du_group_start_stop(rgrp, false); | |
247 | } | |
248 | } | |
249 | ||
250 | void rcar_du_group_restart(struct rcar_du_group *rgrp) | |
251 | { | |
2af03944 LP |
252 | rgrp->need_restart = false; |
253 | ||
cb2025d2 LP |
254 | __rcar_du_group_start_stop(rgrp, false); |
255 | __rcar_du_group_start_stop(rgrp, true); | |
256 | } | |
2fd22dba | 257 | |
34a04f2b | 258 | int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) |
7cbc05cb | 259 | { |
d99a6b5e LP |
260 | struct rcar_du_group *rgrp; |
261 | struct rcar_du_crtc *crtc; | |
262 | unsigned int index; | |
7cbc05cb LP |
263 | int ret; |
264 | ||
0c1c8776 LP |
265 | if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS)) |
266 | return 0; | |
267 | ||
f3bafc12 LP |
268 | /* |
269 | * RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are | |
d99a6b5e LP |
270 | * configured in the DEFR8 register of the first group on Gen2 and the |
271 | * last group on Gen3. As this function can be called with the DU | |
272 | * channels of the corresponding CRTCs disabled, we need to enable the | |
273 | * group clock before accessing the register. | |
7cbc05cb | 274 | */ |
d99a6b5e LP |
275 | index = rcdu->info->gen < 3 ? 0 : DIV_ROUND_UP(rcdu->num_crtcs, 2) - 1; |
276 | rgrp = &rcdu->groups[index]; | |
277 | crtc = &rcdu->crtcs[index * 2]; | |
278 | ||
279 | ret = clk_prepare_enable(crtc->clock); | |
7cbc05cb LP |
280 | if (ret < 0) |
281 | return ret; | |
282 | ||
d99a6b5e | 283 | rcar_du_group_setup_defr8(rgrp); |
7cbc05cb | 284 | |
d99a6b5e | 285 | clk_disable_unprepare(crtc->clock); |
7cbc05cb LP |
286 | |
287 | return 0; | |
288 | } | |
289 | ||
290 | int rcar_du_group_set_routing(struct rcar_du_group *rgrp) | |
2fd22dba LP |
291 | { |
292 | struct rcar_du_crtc *crtc0 = &rgrp->dev->crtcs[rgrp->index * 2]; | |
293 | u32 dorcr = rcar_du_group_read(rgrp, DORCR); | |
294 | ||
295 | dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK); | |
296 | ||
f3bafc12 LP |
297 | /* |
298 | * Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and | |
ef67a902 LP |
299 | * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1 |
300 | * by default. | |
2fd22dba | 301 | */ |
ef67a902 | 302 | if (crtc0->outputs & BIT(RCAR_DU_OUTPUT_DPAD1)) |
2fd22dba LP |
303 | dorcr |= DORCR_PG2D_DS1; |
304 | else | |
305 | dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2; | |
306 | ||
307 | rcar_du_group_write(rgrp, DORCR, dorcr); | |
7cbc05cb | 308 | |
34a04f2b | 309 | return rcar_du_set_dpad0_vsp1_routing(rgrp->dev); |
2fd22dba | 310 | } |