18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * rcar_du_kms.c -- R-Car Display Unit Mode Setting 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#include <drm/drm_atomic.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_fb_cma_helper.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h> 168c2ecf20Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h> 178c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 188c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/device.h> 218c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 228c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 238c2ecf20Sopenharmony_ci#include <linux/wait.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "rcar_du_crtc.h" 268c2ecf20Sopenharmony_ci#include "rcar_du_drv.h" 278c2ecf20Sopenharmony_ci#include "rcar_du_encoder.h" 288c2ecf20Sopenharmony_ci#include "rcar_du_kms.h" 298c2ecf20Sopenharmony_ci#include "rcar_du_regs.h" 308c2ecf20Sopenharmony_ci#include "rcar_du_vsp.h" 318c2ecf20Sopenharmony_ci#include "rcar_du_writeback.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 348c2ecf20Sopenharmony_ci * Format helpers 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const struct rcar_du_format_info rcar_du_format_infos[] = { 388c2ecf20Sopenharmony_ci { 398c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGB565, 408c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGB565, 418c2ecf20Sopenharmony_ci .bpp = 16, 428c2ecf20Sopenharmony_ci .planes = 1, 438c2ecf20Sopenharmony_ci .hsub = 1, 448c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, 458c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 468c2ecf20Sopenharmony_ci }, { 478c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_ARGB1555, 488c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_ARGB555, 498c2ecf20Sopenharmony_ci .bpp = 16, 508c2ecf20Sopenharmony_ci .planes = 1, 518c2ecf20Sopenharmony_ci .hsub = 1, 528c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, 538c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 548c2ecf20Sopenharmony_ci }, { 558c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_XRGB1555, 568c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_XRGB555, 578c2ecf20Sopenharmony_ci .bpp = 16, 588c2ecf20Sopenharmony_ci .planes = 1, 598c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, 608c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 618c2ecf20Sopenharmony_ci }, { 628c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_XRGB8888, 638c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_XBGR32, 648c2ecf20Sopenharmony_ci .bpp = 32, 658c2ecf20Sopenharmony_ci .planes = 1, 668c2ecf20Sopenharmony_ci .hsub = 1, 678c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, 688c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_RGB888, 698c2ecf20Sopenharmony_ci }, { 708c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_ARGB8888, 718c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_ABGR32, 728c2ecf20Sopenharmony_ci .bpp = 32, 738c2ecf20Sopenharmony_ci .planes = 1, 748c2ecf20Sopenharmony_ci .hsub = 1, 758c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP, 768c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_ARGB8888, 778c2ecf20Sopenharmony_ci }, { 788c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_UYVY, 798c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_UYVY, 808c2ecf20Sopenharmony_ci .bpp = 16, 818c2ecf20Sopenharmony_ci .planes = 1, 828c2ecf20Sopenharmony_ci .hsub = 2, 838c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 848c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 858c2ecf20Sopenharmony_ci }, { 868c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YUYV, 878c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YUYV, 888c2ecf20Sopenharmony_ci .bpp = 16, 898c2ecf20Sopenharmony_ci .planes = 1, 908c2ecf20Sopenharmony_ci .hsub = 2, 918c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 928c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 938c2ecf20Sopenharmony_ci }, { 948c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_NV12, 958c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_NV12M, 968c2ecf20Sopenharmony_ci .bpp = 12, 978c2ecf20Sopenharmony_ci .planes = 2, 988c2ecf20Sopenharmony_ci .hsub = 2, 998c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 1008c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 1018c2ecf20Sopenharmony_ci }, { 1028c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_NV21, 1038c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_NV21M, 1048c2ecf20Sopenharmony_ci .bpp = 12, 1058c2ecf20Sopenharmony_ci .planes = 2, 1068c2ecf20Sopenharmony_ci .hsub = 2, 1078c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 1088c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 1098c2ecf20Sopenharmony_ci }, { 1108c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_NV16, 1118c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_NV16M, 1128c2ecf20Sopenharmony_ci .bpp = 16, 1138c2ecf20Sopenharmony_ci .planes = 2, 1148c2ecf20Sopenharmony_ci .hsub = 2, 1158c2ecf20Sopenharmony_ci .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 1168c2ecf20Sopenharmony_ci .edf = PnDDCR4_EDF_NONE, 1178c2ecf20Sopenharmony_ci }, 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * The following formats are not supported on Gen2 and thus have no 1208c2ecf20Sopenharmony_ci * associated .pnmr or .edf settings. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGB332, 1248c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGB332, 1258c2ecf20Sopenharmony_ci .bpp = 8, 1268c2ecf20Sopenharmony_ci .planes = 1, 1278c2ecf20Sopenharmony_ci .hsub = 1, 1288c2ecf20Sopenharmony_ci }, { 1298c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_ARGB4444, 1308c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_ARGB444, 1318c2ecf20Sopenharmony_ci .bpp = 16, 1328c2ecf20Sopenharmony_ci .planes = 1, 1338c2ecf20Sopenharmony_ci .hsub = 1, 1348c2ecf20Sopenharmony_ci }, { 1358c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_XRGB4444, 1368c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_XRGB444, 1378c2ecf20Sopenharmony_ci .bpp = 16, 1388c2ecf20Sopenharmony_ci .planes = 1, 1398c2ecf20Sopenharmony_ci .hsub = 1, 1408c2ecf20Sopenharmony_ci }, { 1418c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGBA4444, 1428c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGBA444, 1438c2ecf20Sopenharmony_ci .bpp = 16, 1448c2ecf20Sopenharmony_ci .planes = 1, 1458c2ecf20Sopenharmony_ci .hsub = 1, 1468c2ecf20Sopenharmony_ci }, { 1478c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGBX4444, 1488c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGBX444, 1498c2ecf20Sopenharmony_ci .bpp = 16, 1508c2ecf20Sopenharmony_ci .planes = 1, 1518c2ecf20Sopenharmony_ci .hsub = 1, 1528c2ecf20Sopenharmony_ci }, { 1538c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_ABGR4444, 1548c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_ABGR444, 1558c2ecf20Sopenharmony_ci .bpp = 16, 1568c2ecf20Sopenharmony_ci .planes = 1, 1578c2ecf20Sopenharmony_ci .hsub = 1, 1588c2ecf20Sopenharmony_ci }, { 1598c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_XBGR4444, 1608c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_XBGR444, 1618c2ecf20Sopenharmony_ci .bpp = 16, 1628c2ecf20Sopenharmony_ci .planes = 1, 1638c2ecf20Sopenharmony_ci .hsub = 1, 1648c2ecf20Sopenharmony_ci }, { 1658c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGRA4444, 1668c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGRA444, 1678c2ecf20Sopenharmony_ci .bpp = 16, 1688c2ecf20Sopenharmony_ci .planes = 1, 1698c2ecf20Sopenharmony_ci .hsub = 1, 1708c2ecf20Sopenharmony_ci }, { 1718c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGRX4444, 1728c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGRX444, 1738c2ecf20Sopenharmony_ci .bpp = 16, 1748c2ecf20Sopenharmony_ci .planes = 1, 1758c2ecf20Sopenharmony_ci .hsub = 1, 1768c2ecf20Sopenharmony_ci }, { 1778c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGBA5551, 1788c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGBA555, 1798c2ecf20Sopenharmony_ci .bpp = 16, 1808c2ecf20Sopenharmony_ci .planes = 1, 1818c2ecf20Sopenharmony_ci .hsub = 1, 1828c2ecf20Sopenharmony_ci }, { 1838c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGBX5551, 1848c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGBX555, 1858c2ecf20Sopenharmony_ci .bpp = 16, 1868c2ecf20Sopenharmony_ci .planes = 1, 1878c2ecf20Sopenharmony_ci .hsub = 1, 1888c2ecf20Sopenharmony_ci }, { 1898c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_ABGR1555, 1908c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_ABGR555, 1918c2ecf20Sopenharmony_ci .bpp = 16, 1928c2ecf20Sopenharmony_ci .planes = 1, 1938c2ecf20Sopenharmony_ci .hsub = 1, 1948c2ecf20Sopenharmony_ci }, { 1958c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_XBGR1555, 1968c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_XBGR555, 1978c2ecf20Sopenharmony_ci .bpp = 16, 1988c2ecf20Sopenharmony_ci .planes = 1, 1998c2ecf20Sopenharmony_ci .hsub = 1, 2008c2ecf20Sopenharmony_ci }, { 2018c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGRA5551, 2028c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGRA555, 2038c2ecf20Sopenharmony_ci .bpp = 16, 2048c2ecf20Sopenharmony_ci .planes = 1, 2058c2ecf20Sopenharmony_ci .hsub = 1, 2068c2ecf20Sopenharmony_ci }, { 2078c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGRX5551, 2088c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGRX555, 2098c2ecf20Sopenharmony_ci .bpp = 16, 2108c2ecf20Sopenharmony_ci .planes = 1, 2118c2ecf20Sopenharmony_ci .hsub = 1, 2128c2ecf20Sopenharmony_ci }, { 2138c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGR888, 2148c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGB24, 2158c2ecf20Sopenharmony_ci .bpp = 24, 2168c2ecf20Sopenharmony_ci .planes = 1, 2178c2ecf20Sopenharmony_ci .hsub = 1, 2188c2ecf20Sopenharmony_ci }, { 2198c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGB888, 2208c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGR24, 2218c2ecf20Sopenharmony_ci .bpp = 24, 2228c2ecf20Sopenharmony_ci .planes = 1, 2238c2ecf20Sopenharmony_ci .hsub = 1, 2248c2ecf20Sopenharmony_ci }, { 2258c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGBA8888, 2268c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGRA32, 2278c2ecf20Sopenharmony_ci .bpp = 32, 2288c2ecf20Sopenharmony_ci .planes = 1, 2298c2ecf20Sopenharmony_ci .hsub = 1, 2308c2ecf20Sopenharmony_ci }, { 2318c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_RGBX8888, 2328c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_BGRX32, 2338c2ecf20Sopenharmony_ci .bpp = 32, 2348c2ecf20Sopenharmony_ci .planes = 1, 2358c2ecf20Sopenharmony_ci .hsub = 1, 2368c2ecf20Sopenharmony_ci }, { 2378c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_ABGR8888, 2388c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGBA32, 2398c2ecf20Sopenharmony_ci .bpp = 32, 2408c2ecf20Sopenharmony_ci .planes = 1, 2418c2ecf20Sopenharmony_ci .hsub = 1, 2428c2ecf20Sopenharmony_ci }, { 2438c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_XBGR8888, 2448c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_RGBX32, 2458c2ecf20Sopenharmony_ci .bpp = 32, 2468c2ecf20Sopenharmony_ci .planes = 1, 2478c2ecf20Sopenharmony_ci .hsub = 1, 2488c2ecf20Sopenharmony_ci }, { 2498c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGRA8888, 2508c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_ARGB32, 2518c2ecf20Sopenharmony_ci .bpp = 32, 2528c2ecf20Sopenharmony_ci .planes = 1, 2538c2ecf20Sopenharmony_ci .hsub = 1, 2548c2ecf20Sopenharmony_ci }, { 2558c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_BGRX8888, 2568c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_XRGB32, 2578c2ecf20Sopenharmony_ci .bpp = 32, 2588c2ecf20Sopenharmony_ci .planes = 1, 2598c2ecf20Sopenharmony_ci .hsub = 1, 2608c2ecf20Sopenharmony_ci }, { 2618c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YVYU, 2628c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YVYU, 2638c2ecf20Sopenharmony_ci .bpp = 16, 2648c2ecf20Sopenharmony_ci .planes = 1, 2658c2ecf20Sopenharmony_ci .hsub = 2, 2668c2ecf20Sopenharmony_ci }, { 2678c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_NV61, 2688c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_NV61M, 2698c2ecf20Sopenharmony_ci .bpp = 16, 2708c2ecf20Sopenharmony_ci .planes = 2, 2718c2ecf20Sopenharmony_ci .hsub = 2, 2728c2ecf20Sopenharmony_ci }, { 2738c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YUV420, 2748c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YUV420M, 2758c2ecf20Sopenharmony_ci .bpp = 12, 2768c2ecf20Sopenharmony_ci .planes = 3, 2778c2ecf20Sopenharmony_ci .hsub = 2, 2788c2ecf20Sopenharmony_ci }, { 2798c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YVU420, 2808c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YVU420M, 2818c2ecf20Sopenharmony_ci .bpp = 12, 2828c2ecf20Sopenharmony_ci .planes = 3, 2838c2ecf20Sopenharmony_ci .hsub = 2, 2848c2ecf20Sopenharmony_ci }, { 2858c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YUV422, 2868c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YUV422M, 2878c2ecf20Sopenharmony_ci .bpp = 16, 2888c2ecf20Sopenharmony_ci .planes = 3, 2898c2ecf20Sopenharmony_ci .hsub = 2, 2908c2ecf20Sopenharmony_ci }, { 2918c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YVU422, 2928c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YVU422M, 2938c2ecf20Sopenharmony_ci .bpp = 16, 2948c2ecf20Sopenharmony_ci .planes = 3, 2958c2ecf20Sopenharmony_ci .hsub = 2, 2968c2ecf20Sopenharmony_ci }, { 2978c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YUV444, 2988c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YUV444M, 2998c2ecf20Sopenharmony_ci .bpp = 24, 3008c2ecf20Sopenharmony_ci .planes = 3, 3018c2ecf20Sopenharmony_ci .hsub = 1, 3028c2ecf20Sopenharmony_ci }, { 3038c2ecf20Sopenharmony_ci .fourcc = DRM_FORMAT_YVU444, 3048c2ecf20Sopenharmony_ci .v4l2 = V4L2_PIX_FMT_YVU444M, 3058c2ecf20Sopenharmony_ci .bpp = 24, 3068c2ecf20Sopenharmony_ci .planes = 3, 3078c2ecf20Sopenharmony_ci .hsub = 1, 3088c2ecf20Sopenharmony_ci }, 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciconst struct rcar_du_format_info *rcar_du_format_info(u32 fourcc) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci unsigned int i; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) { 3168c2ecf20Sopenharmony_ci if (rcar_du_format_infos[i].fourcc == fourcc) 3178c2ecf20Sopenharmony_ci return &rcar_du_format_infos[i]; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return NULL; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 3248c2ecf20Sopenharmony_ci * Frame buffer 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciint rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, 3288c2ecf20Sopenharmony_ci struct drm_mode_create_dumb *args) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = dev->dev_private; 3318c2ecf20Sopenharmony_ci unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 3328c2ecf20Sopenharmony_ci unsigned int align; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * The R8A7779 DU requires a 16 pixels pitch alignment as documented, 3368c2ecf20Sopenharmony_ci * but the R8A7790 DU seems to require a 128 bytes pitch alignment. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) 3398c2ecf20Sopenharmony_ci align = 128; 3408c2ecf20Sopenharmony_ci else 3418c2ecf20Sopenharmony_ci align = 16 * args->bpp / 8; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci args->pitch = roundup(min_pitch, align); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return drm_gem_cma_dumb_create_internal(file, dev, args); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic struct drm_framebuffer * 3498c2ecf20Sopenharmony_circar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, 3508c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = dev->dev_private; 3538c2ecf20Sopenharmony_ci const struct rcar_du_format_info *format; 3548c2ecf20Sopenharmony_ci unsigned int chroma_pitch; 3558c2ecf20Sopenharmony_ci unsigned int max_pitch; 3568c2ecf20Sopenharmony_ci unsigned int align; 3578c2ecf20Sopenharmony_ci unsigned int i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci format = rcar_du_format_info(mode_cmd->pixel_format); 3608c2ecf20Sopenharmony_ci if (format == NULL) { 3618c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "unsupported pixel format %08x\n", 3628c2ecf20Sopenharmony_ci mode_cmd->pixel_format); 3638c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (rcdu->info->gen < 3) { 3678c2ecf20Sopenharmony_ci /* 3688c2ecf20Sopenharmony_ci * On Gen2 the DU limits the pitch to 4095 pixels and requires 3698c2ecf20Sopenharmony_ci * buffers to be aligned to a 16 pixels boundary (or 128 bytes 3708c2ecf20Sopenharmony_ci * on some platforms). 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci unsigned int bpp = format->planes == 1 ? format->bpp / 8 : 1; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci max_pitch = 4095 * bpp; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) 3778c2ecf20Sopenharmony_ci align = 128; 3788c2ecf20Sopenharmony_ci else 3798c2ecf20Sopenharmony_ci align = 16 * bpp; 3808c2ecf20Sopenharmony_ci } else { 3818c2ecf20Sopenharmony_ci /* 3828c2ecf20Sopenharmony_ci * On Gen3 the memory interface is handled by the VSP that 3838c2ecf20Sopenharmony_ci * limits the pitch to 65535 bytes and has no alignment 3848c2ecf20Sopenharmony_ci * constraint. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci max_pitch = 65535; 3878c2ecf20Sopenharmony_ci align = 1; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (mode_cmd->pitches[0] & (align - 1) || 3918c2ecf20Sopenharmony_ci mode_cmd->pitches[0] > max_pitch) { 3928c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "invalid pitch value %u\n", 3938c2ecf20Sopenharmony_ci mode_cmd->pitches[0]); 3948c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* 3988c2ecf20Sopenharmony_ci * Calculate the chroma plane(s) pitch using the horizontal subsampling 3998c2ecf20Sopenharmony_ci * factor. For semi-planar formats, the U and V planes are combined, the 4008c2ecf20Sopenharmony_ci * pitch must thus be doubled. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci chroma_pitch = mode_cmd->pitches[0] / format->hsub; 4038c2ecf20Sopenharmony_ci if (format->planes == 2) 4048c2ecf20Sopenharmony_ci chroma_pitch *= 2; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (i = 1; i < format->planes; ++i) { 4078c2ecf20Sopenharmony_ci if (mode_cmd->pitches[i] != chroma_pitch) { 4088c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 4098c2ecf20Sopenharmony_ci "luma and chroma pitches are not compatible\n"); 4108c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return drm_gem_fb_create(dev, file_priv, mode_cmd); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 4188c2ecf20Sopenharmony_ci * Atomic Check and Update 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int rcar_du_atomic_check(struct drm_device *dev, 4228c2ecf20Sopenharmony_ci struct drm_atomic_state *state) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = dev->dev_private; 4258c2ecf20Sopenharmony_ci int ret; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = drm_atomic_helper_check(dev, state); 4288c2ecf20Sopenharmony_ci if (ret) 4298c2ecf20Sopenharmony_ci return ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return rcar_du_atomic_check_planes(dev, state); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct drm_device *dev = old_state->dev; 4408c2ecf20Sopenharmony_ci struct rcar_du_device *rcdu = dev->dev_private; 4418c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 4428c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 4438c2ecf20Sopenharmony_ci unsigned int i; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* 4468c2ecf20Sopenharmony_ci * Store RGB routing to DPAD0 and DPAD1, the hardware will be configured 4478c2ecf20Sopenharmony_ci * when starting the CRTCs. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci rcdu->dpad1_source = -1; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci for_each_new_crtc_in_state(old_state, crtc, crtc_state, i) { 4528c2ecf20Sopenharmony_ci struct rcar_du_crtc_state *rcrtc_state = 4538c2ecf20Sopenharmony_ci to_rcar_crtc_state(crtc_state); 4548c2ecf20Sopenharmony_ci struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD0)) 4578c2ecf20Sopenharmony_ci rcdu->dpad0_source = rcrtc->index; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD1)) 4608c2ecf20Sopenharmony_ci rcdu->dpad1_source = rcrtc->index; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Apply the atomic update. */ 4648c2ecf20Sopenharmony_ci drm_atomic_helper_commit_modeset_disables(dev, old_state); 4658c2ecf20Sopenharmony_ci drm_atomic_helper_commit_planes(dev, old_state, 4668c2ecf20Sopenharmony_ci DRM_PLANE_COMMIT_ACTIVE_ONLY); 4678c2ecf20Sopenharmony_ci drm_atomic_helper_commit_modeset_enables(dev, old_state); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci drm_atomic_helper_commit_hw_done(old_state); 4708c2ecf20Sopenharmony_ci drm_atomic_helper_wait_for_flip_done(dev, old_state); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci drm_atomic_helper_cleanup_planes(dev, old_state); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 4768c2ecf20Sopenharmony_ci * Initialization 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = { 4808c2ecf20Sopenharmony_ci .atomic_commit_tail = rcar_du_atomic_commit_tail, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { 4848c2ecf20Sopenharmony_ci .fb_create = rcar_du_fb_create, 4858c2ecf20Sopenharmony_ci .atomic_check = rcar_du_atomic_check, 4868c2ecf20Sopenharmony_ci .atomic_commit = drm_atomic_helper_commit, 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, 4908c2ecf20Sopenharmony_ci enum rcar_du_output output, 4918c2ecf20Sopenharmony_ci struct of_endpoint *ep) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct device_node *entity; 4948c2ecf20Sopenharmony_ci int ret; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* Locate the connected entity and initialize the encoder. */ 4978c2ecf20Sopenharmony_ci entity = of_graph_get_remote_port_parent(ep->local_node); 4988c2ecf20Sopenharmony_ci if (!entity) { 4998c2ecf20Sopenharmony_ci dev_dbg(rcdu->dev, "unconnected endpoint %pOF, skipping\n", 5008c2ecf20Sopenharmony_ci ep->local_node); 5018c2ecf20Sopenharmony_ci return -ENODEV; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (!of_device_is_available(entity)) { 5058c2ecf20Sopenharmony_ci dev_dbg(rcdu->dev, 5068c2ecf20Sopenharmony_ci "connected entity %pOF is disabled, skipping\n", 5078c2ecf20Sopenharmony_ci entity); 5088c2ecf20Sopenharmony_ci of_node_put(entity); 5098c2ecf20Sopenharmony_ci return -ENODEV; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci ret = rcar_du_encoder_init(rcdu, output, entity); 5138c2ecf20Sopenharmony_ci if (ret && ret != -EPROBE_DEFER && ret != -ENOLINK) 5148c2ecf20Sopenharmony_ci dev_warn(rcdu->dev, 5158c2ecf20Sopenharmony_ci "failed to initialize encoder %pOF on output %u (%d), skipping\n", 5168c2ecf20Sopenharmony_ci entity, output, ret); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci of_node_put(entity); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return ret; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int rcar_du_encoders_init(struct rcar_du_device *rcdu) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct device_node *np = rcdu->dev->of_node; 5268c2ecf20Sopenharmony_ci struct device_node *ep_node; 5278c2ecf20Sopenharmony_ci unsigned int num_encoders = 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* 5308c2ecf20Sopenharmony_ci * Iterate over the endpoints and create one encoder for each output 5318c2ecf20Sopenharmony_ci * pipeline. 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ci for_each_endpoint_of_node(np, ep_node) { 5348c2ecf20Sopenharmony_ci enum rcar_du_output output; 5358c2ecf20Sopenharmony_ci struct of_endpoint ep; 5368c2ecf20Sopenharmony_ci unsigned int i; 5378c2ecf20Sopenharmony_ci int ret; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci ret = of_graph_parse_endpoint(ep_node, &ep); 5408c2ecf20Sopenharmony_ci if (ret < 0) { 5418c2ecf20Sopenharmony_ci of_node_put(ep_node); 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* Find the output route corresponding to the port number. */ 5468c2ecf20Sopenharmony_ci for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) { 5478c2ecf20Sopenharmony_ci if (rcdu->info->routes[i].possible_crtcs && 5488c2ecf20Sopenharmony_ci rcdu->info->routes[i].port == ep.port) { 5498c2ecf20Sopenharmony_ci output = i; 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (i == RCAR_DU_OUTPUT_MAX) { 5558c2ecf20Sopenharmony_ci dev_warn(rcdu->dev, 5568c2ecf20Sopenharmony_ci "port %u references unexisting output, skipping\n", 5578c2ecf20Sopenharmony_ci ep.port); 5588c2ecf20Sopenharmony_ci continue; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Process the output pipeline. */ 5628c2ecf20Sopenharmony_ci ret = rcar_du_encoders_init_one(rcdu, output, &ep); 5638c2ecf20Sopenharmony_ci if (ret < 0) { 5648c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) { 5658c2ecf20Sopenharmony_ci of_node_put(ep_node); 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci continue; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci num_encoders++; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return num_encoders; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic int rcar_du_properties_init(struct rcar_du_device *rcdu) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci /* 5818c2ecf20Sopenharmony_ci * The color key is expressed as an RGB888 triplet stored in a 32-bit 5828c2ecf20Sopenharmony_ci * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0) 5838c2ecf20Sopenharmony_ci * or enable source color keying (1). 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_ci rcdu->props.colorkey = 5868c2ecf20Sopenharmony_ci drm_property_create_range(rcdu->ddev, 0, "colorkey", 5878c2ecf20Sopenharmony_ci 0, 0x01ffffff); 5888c2ecf20Sopenharmony_ci if (rcdu->props.colorkey == NULL) 5898c2ecf20Sopenharmony_ci return -ENOMEM; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int rcar_du_vsps_init(struct rcar_du_device *rcdu) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci const struct device_node *np = rcdu->dev->of_node; 5978c2ecf20Sopenharmony_ci const char *vsps_prop_name = "renesas,vsps"; 5988c2ecf20Sopenharmony_ci struct of_phandle_args args; 5998c2ecf20Sopenharmony_ci struct { 6008c2ecf20Sopenharmony_ci struct device_node *np; 6018c2ecf20Sopenharmony_ci unsigned int crtcs_mask; 6028c2ecf20Sopenharmony_ci } vsps[RCAR_DU_MAX_VSPS] = { { NULL, }, }; 6038c2ecf20Sopenharmony_ci unsigned int vsps_count = 0; 6048c2ecf20Sopenharmony_ci unsigned int cells; 6058c2ecf20Sopenharmony_ci unsigned int i; 6068c2ecf20Sopenharmony_ci int ret; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* 6098c2ecf20Sopenharmony_ci * First parse the DT vsps property to populate the list of VSPs. Each 6108c2ecf20Sopenharmony_ci * entry contains a pointer to the VSP DT node and a bitmask of the 6118c2ecf20Sopenharmony_ci * connected DU CRTCs. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci ret = of_property_count_u32_elems(np, vsps_prop_name); 6148c2ecf20Sopenharmony_ci if (ret < 0) { 6158c2ecf20Sopenharmony_ci /* Backward compatibility with old DTBs. */ 6168c2ecf20Sopenharmony_ci vsps_prop_name = "vsps"; 6178c2ecf20Sopenharmony_ci ret = of_property_count_u32_elems(np, vsps_prop_name); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci cells = ret / rcdu->num_crtcs - 1; 6208c2ecf20Sopenharmony_ci if (cells > 1) 6218c2ecf20Sopenharmony_ci return -EINVAL; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci for (i = 0; i < rcdu->num_crtcs; ++i) { 6248c2ecf20Sopenharmony_ci unsigned int j; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(np, vsps_prop_name, 6278c2ecf20Sopenharmony_ci cells, i, &args); 6288c2ecf20Sopenharmony_ci if (ret < 0) 6298c2ecf20Sopenharmony_ci goto error; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* 6328c2ecf20Sopenharmony_ci * Add the VSP to the list or update the corresponding existing 6338c2ecf20Sopenharmony_ci * entry if the VSP has already been added. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci for (j = 0; j < vsps_count; ++j) { 6368c2ecf20Sopenharmony_ci if (vsps[j].np == args.np) 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (j < vsps_count) 6418c2ecf20Sopenharmony_ci of_node_put(args.np); 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci vsps[vsps_count++].np = args.np; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci vsps[j].crtcs_mask |= BIT(i); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Store the VSP pointer and pipe index in the CRTC. If the 6498c2ecf20Sopenharmony_ci * second cell of the 'renesas,vsps' specifier isn't present, 6508c2ecf20Sopenharmony_ci * default to 0 to remain compatible with older DT bindings. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_ci rcdu->crtcs[i].vsp = &rcdu->vsps[j]; 6538c2ecf20Sopenharmony_ci rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* 6578c2ecf20Sopenharmony_ci * Then initialize all the VSPs from the node pointers and CRTCs bitmask 6588c2ecf20Sopenharmony_ci * computed previously. 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_ci for (i = 0; i < vsps_count; ++i) { 6618c2ecf20Sopenharmony_ci struct rcar_du_vsp *vsp = &rcdu->vsps[i]; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci vsp->index = i; 6648c2ecf20Sopenharmony_ci vsp->dev = rcdu; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask); 6678c2ecf20Sopenharmony_ci if (ret < 0) 6688c2ecf20Sopenharmony_ci goto error; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cierror: 6748c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vsps); ++i) 6758c2ecf20Sopenharmony_ci of_node_put(vsps[i].np); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return ret; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int rcar_du_cmm_init(struct rcar_du_device *rcdu) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci const struct device_node *np = rcdu->dev->of_node; 6838c2ecf20Sopenharmony_ci unsigned int i; 6848c2ecf20Sopenharmony_ci int cells; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci cells = of_property_count_u32_elems(np, "renesas,cmms"); 6878c2ecf20Sopenharmony_ci if (cells == -EINVAL) 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (cells > rcdu->num_crtcs) { 6918c2ecf20Sopenharmony_ci dev_err(rcdu->dev, 6928c2ecf20Sopenharmony_ci "Invalid number of entries in 'renesas,cmms'\n"); 6938c2ecf20Sopenharmony_ci return -EINVAL; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci for (i = 0; i < cells; ++i) { 6978c2ecf20Sopenharmony_ci struct platform_device *pdev; 6988c2ecf20Sopenharmony_ci struct device_link *link; 6998c2ecf20Sopenharmony_ci struct device_node *cmm; 7008c2ecf20Sopenharmony_ci int ret; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci cmm = of_parse_phandle(np, "renesas,cmms", i); 7038c2ecf20Sopenharmony_ci if (!cmm) { 7048c2ecf20Sopenharmony_ci dev_err(rcdu->dev, 7058c2ecf20Sopenharmony_ci "Failed to parse 'renesas,cmms' property\n"); 7068c2ecf20Sopenharmony_ci return -EINVAL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (!of_device_is_available(cmm)) { 7108c2ecf20Sopenharmony_ci /* It's fine to have a phandle to a non-enabled CMM. */ 7118c2ecf20Sopenharmony_ci of_node_put(cmm); 7128c2ecf20Sopenharmony_ci continue; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci pdev = of_find_device_by_node(cmm); 7168c2ecf20Sopenharmony_ci if (!pdev) { 7178c2ecf20Sopenharmony_ci dev_err(rcdu->dev, "No device found for CMM%u\n", i); 7188c2ecf20Sopenharmony_ci of_node_put(cmm); 7198c2ecf20Sopenharmony_ci return -EINVAL; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci of_node_put(cmm); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* 7258c2ecf20Sopenharmony_ci * -ENODEV is used to report that the CMM config option is 7268c2ecf20Sopenharmony_ci * disabled: return 0 and let the DU continue probing. 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci ret = rcar_cmm_init(pdev); 7298c2ecf20Sopenharmony_ci if (ret) 7308c2ecf20Sopenharmony_ci return ret == -ENODEV ? 0 : ret; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* 7338c2ecf20Sopenharmony_ci * Enforce suspend/resume ordering by making the CMM a provider 7348c2ecf20Sopenharmony_ci * of the DU: CMM is suspended after and resumed before the DU. 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_ci link = device_link_add(rcdu->dev, &pdev->dev, DL_FLAG_STATELESS); 7378c2ecf20Sopenharmony_ci if (!link) { 7388c2ecf20Sopenharmony_ci dev_err(rcdu->dev, 7398c2ecf20Sopenharmony_ci "Failed to create device link to CMM%u\n", i); 7408c2ecf20Sopenharmony_ci return -EINVAL; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci rcdu->cmms[i] = pdev; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciint rcar_du_modeset_init(struct rcar_du_device *rcdu) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci static const unsigned int mmio_offsets[] = { 7528c2ecf20Sopenharmony_ci DU0_REG_OFFSET, DU2_REG_OFFSET 7538c2ecf20Sopenharmony_ci }; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci struct drm_device *dev = rcdu->ddev; 7568c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 7578c2ecf20Sopenharmony_ci unsigned int dpad0_sources; 7588c2ecf20Sopenharmony_ci unsigned int num_encoders; 7598c2ecf20Sopenharmony_ci unsigned int num_groups; 7608c2ecf20Sopenharmony_ci unsigned int swindex; 7618c2ecf20Sopenharmony_ci unsigned int hwindex; 7628c2ecf20Sopenharmony_ci unsigned int i; 7638c2ecf20Sopenharmony_ci int ret; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci ret = drmm_mode_config_init(dev); 7668c2ecf20Sopenharmony_ci if (ret) 7678c2ecf20Sopenharmony_ci return ret; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci dev->mode_config.min_width = 0; 7708c2ecf20Sopenharmony_ci dev->mode_config.min_height = 0; 7718c2ecf20Sopenharmony_ci dev->mode_config.normalize_zpos = true; 7728c2ecf20Sopenharmony_ci dev->mode_config.funcs = &rcar_du_mode_config_funcs; 7738c2ecf20Sopenharmony_ci dev->mode_config.helper_private = &rcar_du_mode_config_helper; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (rcdu->info->gen < 3) { 7768c2ecf20Sopenharmony_ci dev->mode_config.max_width = 4095; 7778c2ecf20Sopenharmony_ci dev->mode_config.max_height = 2047; 7788c2ecf20Sopenharmony_ci } else { 7798c2ecf20Sopenharmony_ci /* 7808c2ecf20Sopenharmony_ci * The Gen3 DU uses the VSP1 for memory access, and is limited 7818c2ecf20Sopenharmony_ci * to frame sizes of 8190x8190. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci dev->mode_config.max_width = 8190; 7848c2ecf20Sopenharmony_ci dev->mode_config.max_height = 8190; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci rcdu->num_crtcs = hweight8(rcdu->info->channels_mask); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci ret = rcar_du_properties_init(rcdu); 7908c2ecf20Sopenharmony_ci if (ret < 0) 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * Initialize vertical blanking interrupts handling. Start with vblank 7958c2ecf20Sopenharmony_ci * disabled for all CRTCs. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci ret = drm_vblank_init(dev, rcdu->num_crtcs); 7988c2ecf20Sopenharmony_ci if (ret < 0) 7998c2ecf20Sopenharmony_ci return ret; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* Initialize the groups. */ 8028c2ecf20Sopenharmony_ci num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci for (i = 0; i < num_groups; ++i) { 8058c2ecf20Sopenharmony_ci struct rcar_du_group *rgrp = &rcdu->groups[i]; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci mutex_init(&rgrp->lock); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci rgrp->dev = rcdu; 8108c2ecf20Sopenharmony_ci rgrp->mmio_offset = mmio_offsets[i]; 8118c2ecf20Sopenharmony_ci rgrp->index = i; 8128c2ecf20Sopenharmony_ci /* Extract the channel mask for this group only. */ 8138c2ecf20Sopenharmony_ci rgrp->channels_mask = (rcdu->info->channels_mask >> (2 * i)) 8148c2ecf20Sopenharmony_ci & GENMASK(1, 0); 8158c2ecf20Sopenharmony_ci rgrp->num_crtcs = hweight8(rgrp->channels_mask); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* 8188c2ecf20Sopenharmony_ci * If we have more than one CRTCs in this group pre-associate 8198c2ecf20Sopenharmony_ci * the low-order planes with CRTC 0 and the high-order planes 8208c2ecf20Sopenharmony_ci * with CRTC 1 to minimize flicker occurring when the 8218c2ecf20Sopenharmony_ci * association is changed. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci rgrp->dptsr_planes = rgrp->num_crtcs > 1 8248c2ecf20Sopenharmony_ci ? (rcdu->info->gen >= 3 ? 0x04 : 0xf0) 8258c2ecf20Sopenharmony_ci : 0; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { 8288c2ecf20Sopenharmony_ci ret = rcar_du_planes_init(rgrp); 8298c2ecf20Sopenharmony_ci if (ret < 0) 8308c2ecf20Sopenharmony_ci return ret; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Initialize the compositors. */ 8358c2ecf20Sopenharmony_ci if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { 8368c2ecf20Sopenharmony_ci ret = rcar_du_vsps_init(rcdu); 8378c2ecf20Sopenharmony_ci if (ret < 0) 8388c2ecf20Sopenharmony_ci return ret; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Initialize the Color Management Modules. */ 8428c2ecf20Sopenharmony_ci ret = rcar_du_cmm_init(rcdu); 8438c2ecf20Sopenharmony_ci if (ret) 8448c2ecf20Sopenharmony_ci return ret; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* Create the CRTCs. */ 8478c2ecf20Sopenharmony_ci for (swindex = 0, hwindex = 0; swindex < rcdu->num_crtcs; ++hwindex) { 8488c2ecf20Sopenharmony_ci struct rcar_du_group *rgrp; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Skip unpopulated DU channels. */ 8518c2ecf20Sopenharmony_ci if (!(rcdu->info->channels_mask & BIT(hwindex))) 8528c2ecf20Sopenharmony_ci continue; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci rgrp = &rcdu->groups[hwindex / 2]; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci ret = rcar_du_crtc_create(rgrp, swindex++, hwindex); 8578c2ecf20Sopenharmony_ci if (ret < 0) 8588c2ecf20Sopenharmony_ci return ret; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Initialize the encoders. */ 8628c2ecf20Sopenharmony_ci ret = rcar_du_encoders_init(rcdu); 8638c2ecf20Sopenharmony_ci if (ret < 0) 8648c2ecf20Sopenharmony_ci return ret; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (ret == 0) { 8678c2ecf20Sopenharmony_ci dev_err(rcdu->dev, "error: no encoder could be initialized\n"); 8688c2ecf20Sopenharmony_ci return -EINVAL; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci num_encoders = ret; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * Set the possible CRTCs and possible clones. There's always at least 8758c2ecf20Sopenharmony_ci * one way for all encoders to clone each other, set all bits in the 8768c2ecf20Sopenharmony_ci * possible clones field. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_ci list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 8798c2ecf20Sopenharmony_ci struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 8808c2ecf20Sopenharmony_ci const struct rcar_du_output_routing *route = 8818c2ecf20Sopenharmony_ci &rcdu->info->routes[renc->output]; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci encoder->possible_crtcs = route->possible_crtcs; 8848c2ecf20Sopenharmony_ci encoder->possible_clones = (1 << num_encoders) - 1; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Create the writeback connectors. */ 8888c2ecf20Sopenharmony_ci if (rcdu->info->gen >= 3) { 8898c2ecf20Sopenharmony_ci for (i = 0; i < rcdu->num_crtcs; ++i) { 8908c2ecf20Sopenharmony_ci struct rcar_du_crtc *rcrtc = &rcdu->crtcs[i]; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ret = rcar_du_writeback_init(rcdu, rcrtc); 8938c2ecf20Sopenharmony_ci if (ret < 0) 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* 8998c2ecf20Sopenharmony_ci * Initialize the default DPAD0 source to the index of the first DU 9008c2ecf20Sopenharmony_ci * channel that can be connected to DPAD0. The exact value doesn't 9018c2ecf20Sopenharmony_ci * matter as it should be overwritten by mode setting for the RGB 9028c2ecf20Sopenharmony_ci * output, but it is nonetheless required to ensure a valid initial 9038c2ecf20Sopenharmony_ci * hardware configuration on Gen3 where DU0 can't always be connected to 9048c2ecf20Sopenharmony_ci * DPAD0. 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_ci dpad0_sources = rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs; 9078c2ecf20Sopenharmony_ci rcdu->dpad0_source = ffs(dpad0_sources) - 1; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci drm_mode_config_reset(dev); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci drm_kms_helper_poll_init(dev); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 915