Kuninori Morimoto | 0bbce9e | 2018-07-26 02:37:32 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 2 | /* |
| 3 | * rcar_du_group.c -- R-Car Display Unit Channels Pair |
| 4 | * |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 5 | * Copyright (C) 2013-2015 Renesas Electronics Corporation |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 6 | * |
| 7 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 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 | |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 26 | #include <linux/clk.h> |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 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 | |
Laurent Pinchart | a5f0ef5 | 2013-06-17 00:29:25 +0200 | [diff] [blame] | 33 | u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg) |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 34 | { |
| 35 | return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg); |
| 36 | } |
| 37 | |
Laurent Pinchart | a5f0ef5 | 2013-06-17 00:29:25 +0200 | [diff] [blame] | 38 | void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data) |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 39 | { |
| 40 | rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data); |
| 41 | } |
| 42 | |
Laurent Pinchart | a5e18b2 | 2015-09-07 18:09:55 +0300 | [diff] [blame] | 43 | static void rcar_du_group_setup_pins(struct rcar_du_group *rgrp) |
| 44 | { |
Kieran Bingham | 7ae9045 | 2018-04-27 23:21:53 +0100 | [diff] [blame] | 45 | u32 defr6 = DEFR6_CODE; |
Laurent Pinchart | a5e18b2 | 2015-09-07 18:09:55 +0300 | [diff] [blame] | 46 | |
Kieran Bingham | 7ae9045 | 2018-04-27 23:21:53 +0100 | [diff] [blame] | 47 | if (rgrp->channels_mask & BIT(0)) |
| 48 | defr6 |= DEFR6_ODPM02_DISP; |
| 49 | |
| 50 | if (rgrp->channels_mask & BIT(1)) |
Kieran Bingham | 4012532 | 2018-04-26 17:53:33 +0100 | [diff] [blame] | 51 | defr6 |= DEFR6_ODPM12_DISP; |
Laurent Pinchart | a5e18b2 | 2015-09-07 18:09:55 +0300 | [diff] [blame] | 52 | |
| 53 | rcar_du_group_write(rgrp, DEFR6, defr6); |
| 54 | } |
| 55 | |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 56 | static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) |
| 57 | { |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 58 | struct rcar_du_device *rcdu = rgrp->dev; |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 59 | u32 defr8 = DEFR8_CODE; |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 60 | |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 61 | if (rcdu->info->gen < 3) { |
| 62 | defr8 |= DEFR8_DEFE8; |
| 63 | |
Laurent Pinchart | f3bafc1 | 2017-07-11 01:13:20 +0300 | [diff] [blame] | 64 | /* |
| 65 | * On Gen2 the DEFR8 register for the first group also controls |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 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) { |
Laurent Pinchart | 1f98b2a | 2018-08-22 00:01:07 +0300 | [diff] [blame] | 70 | defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 71 | if (rgrp->dev->vspd1_sink == 2) |
| 72 | defr8 |= DEFR8_VSCS; |
| 73 | } |
| 74 | } else { |
Laurent Pinchart | f3bafc1 | 2017-07-11 01:13:20 +0300 | [diff] [blame] | 75 | /* |
Laurent Pinchart | 1f98b2a | 2018-08-22 00:01:07 +0300 | [diff] [blame] | 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). |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 79 | */ |
Laurent Pinchart | 1f98b2a | 2018-08-22 00:01:07 +0300 | [diff] [blame] | 80 | if (rgrp->index == rcdu->dpad0_source / 2) |
| 81 | defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); |
Laurent Pinchart | 34a04f2 | 2013-06-21 17:54:50 +0200 | [diff] [blame] | 82 | } |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 83 | |
| 84 | rcar_du_group_write(rgrp, DEFR8, defr8); |
| 85 | } |
| 86 | |
Laurent Pinchart | b4734f4 | 2018-08-21 21:31:04 +0300 | [diff] [blame] | 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 | |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 135 | static void rcar_du_group_setup(struct rcar_du_group *rgrp) |
| 136 | { |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 137 | struct rcar_du_device *rcdu = rgrp->dev; |
| 138 | |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 139 | /* Enable extended features */ |
| 140 | rcar_du_group_write(rgrp, DEFR, DEFR_CODE | DEFR_DEFE); |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 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 | } |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 146 | rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 147 | |
Laurent Pinchart | a5e18b2 | 2015-09-07 18:09:55 +0300 | [diff] [blame] | 148 | rcar_du_group_setup_pins(rgrp); |
| 149 | |
Laurent Pinchart | cef0d9c | 2018-11-24 19:57:17 +0200 | [diff] [blame] | 150 | if (rcdu->info->gen >= 2) { |
Laurent Pinchart | 0c1c877 | 2014-12-09 00:21:12 +0200 | [diff] [blame] | 151 | rcar_du_group_setup_defr8(rgrp); |
Laurent Pinchart | b4734f4 | 2018-08-21 21:31:04 +0300 | [diff] [blame] | 152 | rcar_du_group_setup_didsr(rgrp); |
Laurent Pinchart | 1b30dbd | 2014-12-09 00:24:49 +0200 | [diff] [blame] | 153 | } |
| 154 | |
Laurent Pinchart | 2427b30 | 2015-09-07 17:34:26 +0300 | [diff] [blame] | 155 | if (rcdu->info->gen >= 3) |
| 156 | rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10); |
| 157 | |
Laurent Pinchart | f3bafc1 | 2017-07-11 01:13:20 +0300 | [diff] [blame] | 158 | /* |
| 159 | * Use DS1PR and DS2PR to configure planes priorities and connects the |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 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); |
Laurent Pinchart | 2a57e9b | 2015-04-28 18:01:45 +0300 | [diff] [blame] | 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); |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 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 | { |
Laurent Pinchart | 0bc3544 | 2018-11-23 13:38:17 +0200 | [diff] [blame] | 205 | struct rcar_du_device *rcdu = rgrp->dev; |
Laurent Pinchart | 9144adc | 2018-08-22 16:05:02 +0300 | [diff] [blame] | 206 | |
Laurent Pinchart | 0bc3544 | 2018-11-23 13:38:17 +0200 | [diff] [blame] | 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]; |
| 217 | |
| 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 | } |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 224 | } |
| 225 | |
| 226 | void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) |
| 227 | { |
Laurent Pinchart | f3bafc1 | 2017-07-11 01:13:20 +0300 | [diff] [blame] | 228 | /* |
| 229 | * Many of the configuration bits are only updated when the display |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 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 | { |
Laurent Pinchart | 2af0394 | 2013-08-24 02:17:03 +0200 | [diff] [blame] | 252 | rgrp->need_restart = false; |
| 253 | |
Laurent Pinchart | cb2025d | 2013-06-16 21:01:02 +0200 | [diff] [blame] | 254 | __rcar_du_group_start_stop(rgrp, false); |
| 255 | __rcar_du_group_start_stop(rgrp, true); |
| 256 | } |
Laurent Pinchart | 2fd22db | 2013-06-17 00:11:05 +0200 | [diff] [blame] | 257 | |
Laurent Pinchart | 34a04f2 | 2013-06-21 17:54:50 +0200 | [diff] [blame] | 258 | int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 259 | { |
Laurent Pinchart | d99a6b5 | 2017-06-26 16:41:47 +0300 | [diff] [blame] | 260 | struct rcar_du_group *rgrp; |
| 261 | struct rcar_du_crtc *crtc; |
| 262 | unsigned int index; |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 263 | int ret; |
| 264 | |
Laurent Pinchart | cef0d9c | 2018-11-24 19:57:17 +0200 | [diff] [blame] | 265 | if (rcdu->info->gen < 2) |
Laurent Pinchart | 0c1c877 | 2014-12-09 00:21:12 +0200 | [diff] [blame] | 266 | return 0; |
| 267 | |
Laurent Pinchart | f3bafc1 | 2017-07-11 01:13:20 +0300 | [diff] [blame] | 268 | /* |
| 269 | * RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are |
Laurent Pinchart | d99a6b5 | 2017-06-26 16:41:47 +0300 | [diff] [blame] | 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. |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 274 | */ |
Laurent Pinchart | d99a6b5 | 2017-06-26 16:41:47 +0300 | [diff] [blame] | 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); |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 280 | if (ret < 0) |
| 281 | return ret; |
| 282 | |
Laurent Pinchart | d99a6b5 | 2017-06-26 16:41:47 +0300 | [diff] [blame] | 283 | rcar_du_group_setup_defr8(rgrp); |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 284 | |
Laurent Pinchart | d99a6b5 | 2017-06-26 16:41:47 +0300 | [diff] [blame] | 285 | clk_disable_unprepare(crtc->clock); |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 286 | |
| 287 | return 0; |
| 288 | } |
| 289 | |
Laurent Pinchart | dedd876 | 2018-11-25 00:17:39 +0200 | [diff] [blame] | 290 | static void rcar_du_group_set_dpad_levels(struct rcar_du_group *rgrp) |
| 291 | { |
| 292 | static const u32 doflr_values[2] = { |
| 293 | DOFLR_HSYCFL0 | DOFLR_VSYCFL0 | DOFLR_ODDFL0 | |
| 294 | DOFLR_DISPFL0 | DOFLR_CDEFL0 | DOFLR_RGBFL0, |
| 295 | DOFLR_HSYCFL1 | DOFLR_VSYCFL1 | DOFLR_ODDFL1 | |
| 296 | DOFLR_DISPFL1 | DOFLR_CDEFL1 | DOFLR_RGBFL1, |
| 297 | }; |
| 298 | static const u32 dpad_mask = BIT(RCAR_DU_OUTPUT_DPAD1) |
| 299 | | BIT(RCAR_DU_OUTPUT_DPAD0); |
| 300 | struct rcar_du_device *rcdu = rgrp->dev; |
| 301 | u32 doflr = DOFLR_CODE; |
| 302 | unsigned int i; |
| 303 | |
| 304 | if (rcdu->info->gen < 2) |
| 305 | return; |
| 306 | |
| 307 | /* |
| 308 | * The DPAD outputs can't be controlled directly. However, the parallel |
| 309 | * output of the DU channels routed to DPAD can be set to fixed levels |
| 310 | * through the DOFLR group register. Use this to turn the DPAD on or off |
| 311 | * by driving fixed low-level signals at the output of any DU channel |
| 312 | * not routed to a DPAD output. This doesn't affect the DU output |
| 313 | * signals going to other outputs, such as the internal LVDS and HDMI |
| 314 | * encoders. |
| 315 | */ |
| 316 | |
| 317 | for (i = 0; i < rgrp->num_crtcs; ++i) { |
| 318 | struct rcar_du_crtc_state *rstate; |
| 319 | struct rcar_du_crtc *rcrtc; |
| 320 | |
| 321 | rcrtc = &rcdu->crtcs[rgrp->index * 2 + i]; |
| 322 | rstate = to_rcar_crtc_state(rcrtc->crtc.state); |
| 323 | |
| 324 | if (!(rstate->outputs & dpad_mask)) |
| 325 | doflr |= doflr_values[i]; |
| 326 | } |
| 327 | |
| 328 | rcar_du_group_write(rgrp, DOFLR, doflr); |
| 329 | } |
| 330 | |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 331 | int rcar_du_group_set_routing(struct rcar_du_group *rgrp) |
Laurent Pinchart | 2fd22db | 2013-06-17 00:11:05 +0200 | [diff] [blame] | 332 | { |
Laurent Pinchart | b8a4303 | 2018-11-24 20:19:52 +0200 | [diff] [blame] | 333 | struct rcar_du_device *rcdu = rgrp->dev; |
Laurent Pinchart | 2fd22db | 2013-06-17 00:11:05 +0200 | [diff] [blame] | 334 | u32 dorcr = rcar_du_group_read(rgrp, DORCR); |
| 335 | |
| 336 | dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK); |
| 337 | |
Laurent Pinchart | f3bafc1 | 2017-07-11 01:13:20 +0300 | [diff] [blame] | 338 | /* |
| 339 | * Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and |
Laurent Pinchart | ef67a90 | 2013-06-17 03:13:11 +0200 | [diff] [blame] | 340 | * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1 |
| 341 | * by default. |
Laurent Pinchart | 2fd22db | 2013-06-17 00:11:05 +0200 | [diff] [blame] | 342 | */ |
Laurent Pinchart | b8a4303 | 2018-11-24 20:19:52 +0200 | [diff] [blame] | 343 | if (rcdu->dpad1_source == rgrp->index * 2) |
Laurent Pinchart | 2fd22db | 2013-06-17 00:11:05 +0200 | [diff] [blame] | 344 | dorcr |= DORCR_PG2D_DS1; |
| 345 | else |
| 346 | dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2; |
| 347 | |
| 348 | rcar_du_group_write(rgrp, DORCR, dorcr); |
Laurent Pinchart | 7cbc05c | 2013-06-17 03:20:08 +0200 | [diff] [blame] | 349 | |
Laurent Pinchart | dedd876 | 2018-11-25 00:17:39 +0200 | [diff] [blame] | 350 | rcar_du_group_set_dpad_levels(rgrp); |
| 351 | |
Laurent Pinchart | 34a04f2 | 2013-06-21 17:54:50 +0200 | [diff] [blame] | 352 | return rcar_du_set_dpad0_vsp1_routing(rgrp->dev); |
Laurent Pinchart | 2fd22db | 2013-06-17 00:11:05 +0200 | [diff] [blame] | 353 | } |