18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * rcar_du_group.c -- R-Car Display Unit Channels Pair 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Renesas Electronics Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * The R8A7779 DU is split in per-CRTC resources (scan-out engine, blending 128c2ecf20Sopenharmony_ci * unit, timings generator, ...) and device-global resources (start/stop 138c2ecf20Sopenharmony_ci * control, planes, ...) shared between the two CRTCs. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * The R8A7790 introduced a third CRTC with its own set of global resources. 168c2ecf20Sopenharmony_ci * This would be modeled as two separate DU device instances if it wasn't for 178c2ecf20Sopenharmony_ci * a handful or resources that are shared between the three CRTCs (mostly 188c2ecf20Sopenharmony_ci * related to input and output routing). For this reason the R8A7790 DU must be 198c2ecf20Sopenharmony_ci * modeled as a single device with three CRTCs, two sets of "semi-global" 208c2ecf20Sopenharmony_ci * resources, and a few device-global resources. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * The rcar_du_group object is a driver specific object, without any real 238c2ecf20Sopenharmony_ci * counterpart in the DU documentation, that models those semi-global resources. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/clk.h> 278c2ecf20Sopenharmony_ci#include <linux/io.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "rcar_du_drv.h" 308c2ecf20Sopenharmony_ci#include "rcar_du_group.h" 318c2ecf20Sopenharmony_ci#include "rcar_du_regs.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciu32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_civoid rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void rcar_du_group_setup_pins(struct rcar_du_group *rgrp) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci u32 defr6 = DEFR6_CODE; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (rgrp->channels_mask & BIT(0)) 488c2ecf20Sopenharmony_ci defr6 |= DEFR6_ODPM02_DISP; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (rgrp->channels_mask & BIT(1)) 518c2ecf20Sopenharmony_ci defr6 |= DEFR6_ODPM12_DISP; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR6, defr6); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = rgrp->dev; 598c2ecf20Sopenharmony_ci u32 defr8 = DEFR8_CODE; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (rcdu->info->gen < 3) { 628c2ecf20Sopenharmony_ci defr8 |= DEFR8_DEFE8; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * On Gen2 the DEFR8 register for the first group also controls 668c2ecf20Sopenharmony_ci * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 for 678c2ecf20Sopenharmony_ci * DU instances that support it. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci if (rgrp->index == 0) { 708c2ecf20Sopenharmony_ci defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); 718c2ecf20Sopenharmony_ci if (rgrp->dev->vspd1_sink == 2) 728c2ecf20Sopenharmony_ci defr8 |= DEFR8_VSCS; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * On Gen3 VSPD routing can't be configured, and DPAD routing 778c2ecf20Sopenharmony_ci * is set in the group corresponding to the DPAD output (no Gen3 788c2ecf20Sopenharmony_ci * SoC has multiple DPAD sources belonging to separate groups). 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci if (rgrp->index == rcdu->dpad0_source / 2) 818c2ecf20Sopenharmony_ci defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR8, defr8); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = rgrp->dev; 908c2ecf20Sopenharmony_ci struct rcar_du_crtc *rcrtc; 918c2ecf20Sopenharmony_ci unsigned int num_crtcs = 0; 928c2ecf20Sopenharmony_ci unsigned int i; 938c2ecf20Sopenharmony_ci u32 didsr; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * Configure input dot clock routing with a hardcoded configuration. If 978c2ecf20Sopenharmony_ci * the DU channel can use the LVDS encoder output clock as the dot 988c2ecf20Sopenharmony_ci * clock, do so. Otherwise route DU_DOTCLKINn signal to DUn. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Each channel can then select between the dot clock configured here 1018c2ecf20Sopenharmony_ci * and the clock provided by the CPG through the ESCR register. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci if (rcdu->info->gen < 3 && rgrp->index == 0) { 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * On Gen2 a single register in the first group controls dot 1068c2ecf20Sopenharmony_ci * clock selection for all channels. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci rcrtc = rcdu->crtcs; 1098c2ecf20Sopenharmony_ci num_crtcs = rcdu->num_crtcs; 1108c2ecf20Sopenharmony_ci } else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) { 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * On Gen3 dot clocks are setup through per-group registers, 1138c2ecf20Sopenharmony_ci * only available when the group has two channels. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci rcrtc = &rcdu->crtcs[rgrp->index * 2]; 1168c2ecf20Sopenharmony_ci num_crtcs = rgrp->num_crtcs; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (!num_crtcs) 1208c2ecf20Sopenharmony_ci return; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci didsr = DIDSR_CODE; 1238c2ecf20Sopenharmony_ci for (i = 0; i < num_crtcs; ++i, ++rcrtc) { 1248c2ecf20Sopenharmony_ci if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) 1258c2ecf20Sopenharmony_ci didsr |= DIDSR_LCDS_LVDS0(i) 1268c2ecf20Sopenharmony_ci | DIDSR_PDCS_CLK(i, 0); 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci didsr |= DIDSR_LCDS_DCLKIN(i) 1298c2ecf20Sopenharmony_ci | DIDSR_PDCS_CLK(i, 0); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DIDSR, didsr); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void rcar_du_group_setup(struct rcar_du_group *rgrp) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = rgrp->dev; 1388c2ecf20Sopenharmony_ci u32 defr7 = DEFR7_CODE; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Enable extended features */ 1418c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR, DEFR_CODE | DEFR_DEFE); 1428c2ecf20Sopenharmony_ci if (rcdu->info->gen < 3) { 1438c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR2, DEFR2_CODE | DEFR2_DEFE2G); 1448c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR3, DEFR3_CODE | DEFR3_DEFE3); 1458c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci rcar_du_group_setup_pins(rgrp); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * TODO: Handle routing of the DU output to CMM dynamically, as we 1538c2ecf20Sopenharmony_ci * should bypass CMM completely when no color management feature is 1548c2ecf20Sopenharmony_ci * used. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci defr7 |= (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) | 1578c2ecf20Sopenharmony_ci (rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0); 1588c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR7, defr7); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (rcdu->info->gen >= 2) { 1618c2ecf20Sopenharmony_ci rcar_du_group_setup_defr8(rgrp); 1628c2ecf20Sopenharmony_ci rcar_du_group_setup_didsr(rgrp); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (rcdu->info->gen >= 3) 1668c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Use DS1PR and DS2PR to configure planes priorities and connects the 1708c2ecf20Sopenharmony_ci * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Apply planes to CRTCs association. */ 1758c2ecf20Sopenharmony_ci mutex_lock(&rgrp->lock); 1768c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DPTSR, (rgrp->dptsr_planes << 16) | 1778c2ecf20Sopenharmony_ci rgrp->dptsr_planes); 1788c2ecf20Sopenharmony_ci mutex_unlock(&rgrp->lock); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * rcar_du_group_get - Acquire a reference to the DU channels group 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * Acquiring the first reference setups core registers. A reference must be held 1858c2ecf20Sopenharmony_ci * before accessing any hardware registers. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * This function must be called with the DRM mode_config lock held. 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * Return 0 in case of success or a negative error code otherwise. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ciint rcar_du_group_get(struct rcar_du_group *rgrp) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci if (rgrp->use_count) 1948c2ecf20Sopenharmony_ci goto done; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci rcar_du_group_setup(rgrp); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cidone: 1998c2ecf20Sopenharmony_ci rgrp->use_count++; 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/* 2048c2ecf20Sopenharmony_ci * rcar_du_group_put - Release a reference to the DU 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * This function must be called with the DRM mode_config lock held. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_civoid rcar_du_group_put(struct rcar_du_group *rgrp) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci --rgrp->use_count; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = rgrp->dev; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * Group start/stop is controlled by the DRES and DEN bits of DSYSR0 2198c2ecf20Sopenharmony_ci * for the first group and DSYSR2 for the second group. On most DU 2208c2ecf20Sopenharmony_ci * instances, this maps to the first CRTC of the group, and we can just 2218c2ecf20Sopenharmony_ci * use rcar_du_crtc_dsysr_clr_set() to access the correct DSYSR. On 2228c2ecf20Sopenharmony_ci * M3-N, however, DU2 doesn't exist, but DSYSR2 does. We thus need to 2238c2ecf20Sopenharmony_ci * access the register directly using group read/write. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci if (rcdu->info->channels_mask & BIT(rgrp->index * 2)) { 2268c2ecf20Sopenharmony_ci struct rcar_du_crtc *rcrtc = &rgrp->dev->crtcs[rgrp->index * 2]; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_DRES | DSYSR_DEN, 2298c2ecf20Sopenharmony_ci start ? DSYSR_DEN : DSYSR_DRES); 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DSYSR, 2328c2ecf20Sopenharmony_ci start ? DSYSR_DEN : DSYSR_DRES); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_civoid rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * Many of the configuration bits are only updated when the display 2408c2ecf20Sopenharmony_ci * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some 2418c2ecf20Sopenharmony_ci * of those bits could be pre-configured, but others (especially the 2428c2ecf20Sopenharmony_ci * bits related to plane assignment to display timing controllers) need 2438c2ecf20Sopenharmony_ci * to be modified at runtime. 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * Restart the display controller if a start is requested. Sorry for the 2468c2ecf20Sopenharmony_ci * flicker. It should be possible to move most of the "DRES-update" bits 2478c2ecf20Sopenharmony_ci * setup to driver initialization time and minimize the number of cases 2488c2ecf20Sopenharmony_ci * when the display controller will have to be restarted. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci if (start) { 2518c2ecf20Sopenharmony_ci if (rgrp->used_crtcs++ != 0) 2528c2ecf20Sopenharmony_ci __rcar_du_group_start_stop(rgrp, false); 2538c2ecf20Sopenharmony_ci __rcar_du_group_start_stop(rgrp, true); 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci if (--rgrp->used_crtcs == 0) 2568c2ecf20Sopenharmony_ci __rcar_du_group_start_stop(rgrp, false); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid rcar_du_group_restart(struct rcar_du_group *rgrp) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci rgrp->need_restart = false; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci __rcar_du_group_start_stop(rgrp, false); 2658c2ecf20Sopenharmony_ci __rcar_du_group_start_stop(rgrp, true); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ciint rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct rcar_du_group *rgrp; 2718c2ecf20Sopenharmony_ci struct rcar_du_crtc *crtc; 2728c2ecf20Sopenharmony_ci unsigned int index; 2738c2ecf20Sopenharmony_ci int ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (rcdu->info->gen < 2) 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are 2808c2ecf20Sopenharmony_ci * configured in the DEFR8 register of the first group on Gen2 and the 2818c2ecf20Sopenharmony_ci * last group on Gen3. As this function can be called with the DU 2828c2ecf20Sopenharmony_ci * channels of the corresponding CRTCs disabled, we need to enable the 2838c2ecf20Sopenharmony_ci * group clock before accessing the register. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci index = rcdu->info->gen < 3 ? 0 : DIV_ROUND_UP(rcdu->num_crtcs, 2) - 1; 2868c2ecf20Sopenharmony_ci rgrp = &rcdu->groups[index]; 2878c2ecf20Sopenharmony_ci crtc = &rcdu->crtcs[index * 2]; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ret = clk_prepare_enable(crtc->clock); 2908c2ecf20Sopenharmony_ci if (ret < 0) 2918c2ecf20Sopenharmony_ci return ret; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rcar_du_group_setup_defr8(rgrp); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci clk_disable_unprepare(crtc->clock); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void rcar_du_group_set_dpad_levels(struct rcar_du_group *rgrp) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci static const u32 doflr_values[2] = { 3038c2ecf20Sopenharmony_ci DOFLR_HSYCFL0 | DOFLR_VSYCFL0 | DOFLR_ODDFL0 | 3048c2ecf20Sopenharmony_ci DOFLR_DISPFL0 | DOFLR_CDEFL0 | DOFLR_RGBFL0, 3058c2ecf20Sopenharmony_ci DOFLR_HSYCFL1 | DOFLR_VSYCFL1 | DOFLR_ODDFL1 | 3068c2ecf20Sopenharmony_ci DOFLR_DISPFL1 | DOFLR_CDEFL1 | DOFLR_RGBFL1, 3078c2ecf20Sopenharmony_ci }; 3088c2ecf20Sopenharmony_ci static const u32 dpad_mask = BIT(RCAR_DU_OUTPUT_DPAD1) 3098c2ecf20Sopenharmony_ci | BIT(RCAR_DU_OUTPUT_DPAD0); 3108c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = rgrp->dev; 3118c2ecf20Sopenharmony_ci u32 doflr = DOFLR_CODE; 3128c2ecf20Sopenharmony_ci unsigned int i; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (rcdu->info->gen < 2) 3158c2ecf20Sopenharmony_ci return; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* 3188c2ecf20Sopenharmony_ci * The DPAD outputs can't be controlled directly. However, the parallel 3198c2ecf20Sopenharmony_ci * output of the DU channels routed to DPAD can be set to fixed levels 3208c2ecf20Sopenharmony_ci * through the DOFLR group register. Use this to turn the DPAD on or off 3218c2ecf20Sopenharmony_ci * by driving fixed low-level signals at the output of any DU channel 3228c2ecf20Sopenharmony_ci * not routed to a DPAD output. This doesn't affect the DU output 3238c2ecf20Sopenharmony_ci * signals going to other outputs, such as the internal LVDS and HDMI 3248c2ecf20Sopenharmony_ci * encoders. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci for (i = 0; i < rgrp->num_crtcs; ++i) { 3288c2ecf20Sopenharmony_ci struct rcar_du_crtc_state *rstate; 3298c2ecf20Sopenharmony_ci struct rcar_du_crtc *rcrtc; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rcrtc = &rcdu->crtcs[rgrp->index * 2 + i]; 3328c2ecf20Sopenharmony_ci rstate = to_rcar_crtc_state(rcrtc->crtc.state); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!(rstate->outputs & dpad_mask)) 3358c2ecf20Sopenharmony_ci doflr |= doflr_values[i]; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DOFLR, doflr); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciint rcar_du_group_set_routing(struct rcar_du_group *rgrp) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = rgrp->dev; 3448c2ecf20Sopenharmony_ci u32 dorcr = rcar_du_group_read(rgrp, DORCR); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and 3508c2ecf20Sopenharmony_ci * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1 3518c2ecf20Sopenharmony_ci * by default. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci if (rcdu->dpad1_source == rgrp->index * 2) 3548c2ecf20Sopenharmony_ci dorcr |= DORCR_PG2D_DS1; 3558c2ecf20Sopenharmony_ci else 3568c2ecf20Sopenharmony_ci dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci rcar_du_group_write(rgrp, DORCR, dorcr); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci rcar_du_group_set_dpad_levels(rgrp); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return rcar_du_set_dpad0_vsp1_routing(rgrp->dev); 3638c2ecf20Sopenharmony_ci} 364