1dee8268fSThierry Reding /* 2dee8268fSThierry Reding * Copyright (C) 2012 Avionic Design GmbH 3dee8268fSThierry Reding * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 4dee8268fSThierry Reding * 5dee8268fSThierry Reding * This program is free software; you can redistribute it and/or modify 6dee8268fSThierry Reding * it under the terms of the GNU General Public License version 2 as 7dee8268fSThierry Reding * published by the Free Software Foundation. 8dee8268fSThierry Reding */ 9dee8268fSThierry Reding 10dee8268fSThierry Reding #include <linux/clk.h> 11dee8268fSThierry Reding #include <linux/debugfs.h> 12df06b759SThierry Reding #include <linux/iommu.h> 13b9ff7aeaSThierry Reding #include <linux/of_device.h> 1433a8eb8dSThierry Reding #include <linux/pm_runtime.h> 15ca48080aSStephen Warren #include <linux/reset.h> 16dee8268fSThierry Reding 179c012700SThierry Reding #include <soc/tegra/pmc.h> 189c012700SThierry Reding 19dee8268fSThierry Reding #include "dc.h" 20dee8268fSThierry Reding #include "drm.h" 21dee8268fSThierry Reding #include "gem.h" 2247307954SThierry Reding #include "hub.h" 235acd3514SThierry Reding #include "plane.h" 24dee8268fSThierry Reding 259d44189fSThierry Reding #include <drm/drm_atomic.h> 264aa3df71SThierry Reding #include <drm/drm_atomic_helper.h> 273cb9ae4fSDaniel Vetter #include <drm/drm_plane_helper.h> 283cb9ae4fSDaniel Vetter 29791ddb1eSThierry Reding static void tegra_dc_stats_reset(struct tegra_dc_stats *stats) 30791ddb1eSThierry Reding { 31791ddb1eSThierry Reding stats->frames = 0; 32791ddb1eSThierry Reding stats->vblank = 0; 33791ddb1eSThierry Reding stats->underflow = 0; 34791ddb1eSThierry Reding stats->overflow = 0; 35791ddb1eSThierry Reding } 36791ddb1eSThierry Reding 37*1087fac1SThierry Reding /* Reads the active copy of a register. */ 3886df256fSThierry Reding static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset) 3986df256fSThierry Reding { 4086df256fSThierry Reding u32 value; 4186df256fSThierry Reding 4286df256fSThierry Reding tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); 4386df256fSThierry Reding value = tegra_dc_readl(dc, offset); 4486df256fSThierry Reding tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); 4586df256fSThierry Reding 4686df256fSThierry Reding return value; 4786df256fSThierry Reding } 4886df256fSThierry Reding 49*1087fac1SThierry Reding static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, 50*1087fac1SThierry Reding unsigned int offset) 51*1087fac1SThierry Reding { 52*1087fac1SThierry Reding if (offset >= 0x500 && offset <= 0x638) { 53*1087fac1SThierry Reding offset = 0x000 + (offset - 0x500); 54*1087fac1SThierry Reding return plane->offset + offset; 55*1087fac1SThierry Reding } 56*1087fac1SThierry Reding 57*1087fac1SThierry Reding if (offset >= 0x700 && offset <= 0x719) { 58*1087fac1SThierry Reding offset = 0x180 + (offset - 0x700); 59*1087fac1SThierry Reding return plane->offset + offset; 60*1087fac1SThierry Reding } 61*1087fac1SThierry Reding 62*1087fac1SThierry Reding if (offset >= 0x800 && offset <= 0x839) { 63*1087fac1SThierry Reding offset = 0x1c0 + (offset - 0x800); 64*1087fac1SThierry Reding return plane->offset + offset; 65*1087fac1SThierry Reding } 66*1087fac1SThierry Reding 67*1087fac1SThierry Reding dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset); 68*1087fac1SThierry Reding 69*1087fac1SThierry Reding return plane->offset + offset; 70*1087fac1SThierry Reding } 71*1087fac1SThierry Reding 72*1087fac1SThierry Reding static inline u32 tegra_plane_readl(struct tegra_plane *plane, 73*1087fac1SThierry Reding unsigned int offset) 74*1087fac1SThierry Reding { 75*1087fac1SThierry Reding return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset)); 76*1087fac1SThierry Reding } 77*1087fac1SThierry Reding 78*1087fac1SThierry Reding static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value, 79*1087fac1SThierry Reding unsigned int offset) 80*1087fac1SThierry Reding { 81*1087fac1SThierry Reding tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset)); 82*1087fac1SThierry Reding } 83*1087fac1SThierry Reding 84c57997bcSThierry Reding bool tegra_dc_has_output(struct tegra_dc *dc, struct device *dev) 85c57997bcSThierry Reding { 86c57997bcSThierry Reding struct device_node *np = dc->dev->of_node; 87c57997bcSThierry Reding struct of_phandle_iterator it; 88c57997bcSThierry Reding int err; 89c57997bcSThierry Reding 90c57997bcSThierry Reding of_for_each_phandle(&it, err, np, "nvidia,outputs", NULL, 0) 91c57997bcSThierry Reding if (it.node == dev->of_node) 92c57997bcSThierry Reding return true; 93c57997bcSThierry Reding 94c57997bcSThierry Reding return false; 95c57997bcSThierry Reding } 96c57997bcSThierry Reding 9786df256fSThierry Reding /* 98d700ba7aSThierry Reding * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the 99d700ba7aSThierry Reding * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy. 100d700ba7aSThierry Reding * Latching happens mmediately if the display controller is in STOP mode or 101d700ba7aSThierry Reding * on the next frame boundary otherwise. 102d700ba7aSThierry Reding * 103d700ba7aSThierry Reding * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The 104d700ba7aSThierry Reding * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits 105d700ba7aSThierry Reding * are written. When the *_ACT_REQ bits are written, the ARM copy is latched 106d700ba7aSThierry Reding * into the ACTIVE copy, either immediately if the display controller is in 107d700ba7aSThierry Reding * STOP mode, or at the next frame boundary otherwise. 108d700ba7aSThierry Reding */ 10962b9e063SThierry Reding void tegra_dc_commit(struct tegra_dc *dc) 110205d48edSThierry Reding { 111205d48edSThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); 112205d48edSThierry Reding tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); 113205d48edSThierry Reding } 114205d48edSThierry Reding 11510288eeaSThierry Reding static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, 11610288eeaSThierry Reding unsigned int bpp) 11710288eeaSThierry Reding { 11810288eeaSThierry Reding fixed20_12 outf = dfixed_init(out); 11910288eeaSThierry Reding fixed20_12 inf = dfixed_init(in); 12010288eeaSThierry Reding u32 dda_inc; 12110288eeaSThierry Reding int max; 12210288eeaSThierry Reding 12310288eeaSThierry Reding if (v) 12410288eeaSThierry Reding max = 15; 12510288eeaSThierry Reding else { 12610288eeaSThierry Reding switch (bpp) { 12710288eeaSThierry Reding case 2: 12810288eeaSThierry Reding max = 8; 12910288eeaSThierry Reding break; 13010288eeaSThierry Reding 13110288eeaSThierry Reding default: 13210288eeaSThierry Reding WARN_ON_ONCE(1); 13310288eeaSThierry Reding /* fallthrough */ 13410288eeaSThierry Reding case 4: 13510288eeaSThierry Reding max = 4; 13610288eeaSThierry Reding break; 13710288eeaSThierry Reding } 13810288eeaSThierry Reding } 13910288eeaSThierry Reding 14010288eeaSThierry Reding outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); 14110288eeaSThierry Reding inf.full -= dfixed_const(1); 14210288eeaSThierry Reding 14310288eeaSThierry Reding dda_inc = dfixed_div(inf, outf); 14410288eeaSThierry Reding dda_inc = min_t(u32, dda_inc, dfixed_const(max)); 14510288eeaSThierry Reding 14610288eeaSThierry Reding return dda_inc; 14710288eeaSThierry Reding } 14810288eeaSThierry Reding 14910288eeaSThierry Reding static inline u32 compute_initial_dda(unsigned int in) 15010288eeaSThierry Reding { 15110288eeaSThierry Reding fixed20_12 inf = dfixed_init(in); 15210288eeaSThierry Reding return dfixed_frac(inf); 15310288eeaSThierry Reding } 15410288eeaSThierry Reding 155*1087fac1SThierry Reding static void tegra_dc_setup_window(struct tegra_plane *plane, 15610288eeaSThierry Reding const struct tegra_dc_window *window) 15710288eeaSThierry Reding { 15810288eeaSThierry Reding unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; 159*1087fac1SThierry Reding struct tegra_dc *dc = plane->dc; 16010288eeaSThierry Reding bool yuv, planar; 161*1087fac1SThierry Reding u32 value; 16210288eeaSThierry Reding 16310288eeaSThierry Reding /* 16410288eeaSThierry Reding * For YUV planar modes, the number of bytes per pixel takes into 16510288eeaSThierry Reding * account only the luma component and therefore is 1. 16610288eeaSThierry Reding */ 1675acd3514SThierry Reding yuv = tegra_plane_format_is_yuv(window->format, &planar); 16810288eeaSThierry Reding if (!yuv) 16910288eeaSThierry Reding bpp = window->bits_per_pixel / 8; 17010288eeaSThierry Reding else 17110288eeaSThierry Reding bpp = planar ? 1 : 2; 17210288eeaSThierry Reding 173*1087fac1SThierry Reding tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH); 174*1087fac1SThierry Reding tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP); 17510288eeaSThierry Reding 17610288eeaSThierry Reding value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); 177*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_POSITION); 17810288eeaSThierry Reding 17910288eeaSThierry Reding value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); 180*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_SIZE); 18110288eeaSThierry Reding 18210288eeaSThierry Reding h_offset = window->src.x * bpp; 18310288eeaSThierry Reding v_offset = window->src.y; 18410288eeaSThierry Reding h_size = window->src.w * bpp; 18510288eeaSThierry Reding v_size = window->src.h; 18610288eeaSThierry Reding 18710288eeaSThierry Reding value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); 188*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE); 18910288eeaSThierry Reding 19010288eeaSThierry Reding /* 19110288eeaSThierry Reding * For DDA computations the number of bytes per pixel for YUV planar 19210288eeaSThierry Reding * modes needs to take into account all Y, U and V components. 19310288eeaSThierry Reding */ 19410288eeaSThierry Reding if (yuv && planar) 19510288eeaSThierry Reding bpp = 2; 19610288eeaSThierry Reding 19710288eeaSThierry Reding h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); 19810288eeaSThierry Reding v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); 19910288eeaSThierry Reding 20010288eeaSThierry Reding value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); 201*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_DDA_INC); 20210288eeaSThierry Reding 20310288eeaSThierry Reding h_dda = compute_initial_dda(window->src.x); 20410288eeaSThierry Reding v_dda = compute_initial_dda(window->src.y); 20510288eeaSThierry Reding 206*1087fac1SThierry Reding tegra_plane_writel(plane, h_dda, DC_WIN_H_INITIAL_DDA); 207*1087fac1SThierry Reding tegra_plane_writel(plane, v_dda, DC_WIN_V_INITIAL_DDA); 20810288eeaSThierry Reding 209*1087fac1SThierry Reding tegra_plane_writel(plane, 0, DC_WIN_UV_BUF_STRIDE); 210*1087fac1SThierry Reding tegra_plane_writel(plane, 0, DC_WIN_BUF_STRIDE); 21110288eeaSThierry Reding 212*1087fac1SThierry Reding tegra_plane_writel(plane, window->base[0], DC_WINBUF_START_ADDR); 21310288eeaSThierry Reding 21410288eeaSThierry Reding if (yuv && planar) { 215*1087fac1SThierry Reding tegra_plane_writel(plane, window->base[1], DC_WINBUF_START_ADDR_U); 216*1087fac1SThierry Reding tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V); 21710288eeaSThierry Reding value = window->stride[1] << 16 | window->stride[0]; 218*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_LINE_STRIDE); 21910288eeaSThierry Reding } else { 220*1087fac1SThierry Reding tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE); 22110288eeaSThierry Reding } 22210288eeaSThierry Reding 22310288eeaSThierry Reding if (window->bottom_up) 22410288eeaSThierry Reding v_offset += window->src.h - 1; 22510288eeaSThierry Reding 226*1087fac1SThierry Reding tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET); 227*1087fac1SThierry Reding tegra_plane_writel(plane, v_offset, DC_WINBUF_ADDR_V_OFFSET); 22810288eeaSThierry Reding 229c134f019SThierry Reding if (dc->soc->supports_block_linear) { 230c134f019SThierry Reding unsigned long height = window->tiling.value; 231c134f019SThierry Reding 232c134f019SThierry Reding switch (window->tiling.mode) { 233c134f019SThierry Reding case TEGRA_BO_TILING_MODE_PITCH: 234c134f019SThierry Reding value = DC_WINBUF_SURFACE_KIND_PITCH; 235c134f019SThierry Reding break; 236c134f019SThierry Reding 237c134f019SThierry Reding case TEGRA_BO_TILING_MODE_TILED: 238c134f019SThierry Reding value = DC_WINBUF_SURFACE_KIND_TILED; 239c134f019SThierry Reding break; 240c134f019SThierry Reding 241c134f019SThierry Reding case TEGRA_BO_TILING_MODE_BLOCK: 242c134f019SThierry Reding value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) | 243c134f019SThierry Reding DC_WINBUF_SURFACE_KIND_BLOCK; 244c134f019SThierry Reding break; 245c134f019SThierry Reding } 246c134f019SThierry Reding 247*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WINBUF_SURFACE_KIND); 24810288eeaSThierry Reding } else { 249c134f019SThierry Reding switch (window->tiling.mode) { 250c134f019SThierry Reding case TEGRA_BO_TILING_MODE_PITCH: 25110288eeaSThierry Reding value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV | 25210288eeaSThierry Reding DC_WIN_BUFFER_ADDR_MODE_LINEAR; 253c134f019SThierry Reding break; 254c134f019SThierry Reding 255c134f019SThierry Reding case TEGRA_BO_TILING_MODE_TILED: 256c134f019SThierry Reding value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV | 257c134f019SThierry Reding DC_WIN_BUFFER_ADDR_MODE_TILE; 258c134f019SThierry Reding break; 259c134f019SThierry Reding 260c134f019SThierry Reding case TEGRA_BO_TILING_MODE_BLOCK: 2614aa3df71SThierry Reding /* 2624aa3df71SThierry Reding * No need to handle this here because ->atomic_check 2634aa3df71SThierry Reding * will already have filtered it out. 2644aa3df71SThierry Reding */ 2654aa3df71SThierry Reding break; 26610288eeaSThierry Reding } 26710288eeaSThierry Reding 268*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_BUFFER_ADDR_MODE); 269c134f019SThierry Reding } 27010288eeaSThierry Reding 27110288eeaSThierry Reding value = WIN_ENABLE; 27210288eeaSThierry Reding 27310288eeaSThierry Reding if (yuv) { 27410288eeaSThierry Reding /* setup default colorspace conversion coefficients */ 275*1087fac1SThierry Reding tegra_plane_writel(plane, 0x00f0, DC_WIN_CSC_YOF); 276*1087fac1SThierry Reding tegra_plane_writel(plane, 0x012a, DC_WIN_CSC_KYRGB); 277*1087fac1SThierry Reding tegra_plane_writel(plane, 0x0000, DC_WIN_CSC_KUR); 278*1087fac1SThierry Reding tegra_plane_writel(plane, 0x0198, DC_WIN_CSC_KVR); 279*1087fac1SThierry Reding tegra_plane_writel(plane, 0x039b, DC_WIN_CSC_KUG); 280*1087fac1SThierry Reding tegra_plane_writel(plane, 0x032f, DC_WIN_CSC_KVG); 281*1087fac1SThierry Reding tegra_plane_writel(plane, 0x0204, DC_WIN_CSC_KUB); 282*1087fac1SThierry Reding tegra_plane_writel(plane, 0x0000, DC_WIN_CSC_KVB); 28310288eeaSThierry Reding 28410288eeaSThierry Reding value |= CSC_ENABLE; 28510288eeaSThierry Reding } else if (window->bits_per_pixel < 24) { 28610288eeaSThierry Reding value |= COLOR_EXPAND; 28710288eeaSThierry Reding } 28810288eeaSThierry Reding 28910288eeaSThierry Reding if (window->bottom_up) 29010288eeaSThierry Reding value |= V_DIRECTION; 29110288eeaSThierry Reding 292*1087fac1SThierry Reding tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS); 29310288eeaSThierry Reding 29410288eeaSThierry Reding /* 29510288eeaSThierry Reding * Disable blending and assume Window A is the bottom-most window, 29610288eeaSThierry Reding * Window C is the top-most window and Window B is in the middle. 29710288eeaSThierry Reding */ 298*1087fac1SThierry Reding tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY); 299*1087fac1SThierry Reding tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN); 30010288eeaSThierry Reding 301*1087fac1SThierry Reding switch (plane->index) { 30210288eeaSThierry Reding case 0: 303*1087fac1SThierry Reding tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X); 304*1087fac1SThierry Reding tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y); 305*1087fac1SThierry Reding tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY); 30610288eeaSThierry Reding break; 30710288eeaSThierry Reding 30810288eeaSThierry Reding case 1: 309*1087fac1SThierry Reding tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X); 310*1087fac1SThierry Reding tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y); 311*1087fac1SThierry Reding tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY); 31210288eeaSThierry Reding break; 31310288eeaSThierry Reding 31410288eeaSThierry Reding case 2: 315*1087fac1SThierry Reding tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X); 316*1087fac1SThierry Reding tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y); 317*1087fac1SThierry Reding tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY); 31810288eeaSThierry Reding break; 31910288eeaSThierry Reding } 320c7679306SThierry Reding } 321c7679306SThierry Reding 322511c7023SThierry Reding static const u32 tegra20_primary_formats[] = { 323511c7023SThierry Reding DRM_FORMAT_ARGB4444, 324511c7023SThierry Reding DRM_FORMAT_ARGB1555, 325c7679306SThierry Reding DRM_FORMAT_RGB565, 326511c7023SThierry Reding DRM_FORMAT_RGBA5551, 327511c7023SThierry Reding DRM_FORMAT_ABGR8888, 328511c7023SThierry Reding DRM_FORMAT_ARGB8888, 329511c7023SThierry Reding }; 330511c7023SThierry Reding 331511c7023SThierry Reding static const u32 tegra114_primary_formats[] = { 332511c7023SThierry Reding DRM_FORMAT_ARGB4444, 333511c7023SThierry Reding DRM_FORMAT_ARGB1555, 334511c7023SThierry Reding DRM_FORMAT_RGB565, 335511c7023SThierry Reding DRM_FORMAT_RGBA5551, 336511c7023SThierry Reding DRM_FORMAT_ABGR8888, 337511c7023SThierry Reding DRM_FORMAT_ARGB8888, 338511c7023SThierry Reding /* new on Tegra114 */ 339511c7023SThierry Reding DRM_FORMAT_ABGR4444, 340511c7023SThierry Reding DRM_FORMAT_ABGR1555, 341511c7023SThierry Reding DRM_FORMAT_BGRA5551, 342511c7023SThierry Reding DRM_FORMAT_XRGB1555, 343511c7023SThierry Reding DRM_FORMAT_RGBX5551, 344511c7023SThierry Reding DRM_FORMAT_XBGR1555, 345511c7023SThierry Reding DRM_FORMAT_BGRX5551, 346511c7023SThierry Reding DRM_FORMAT_BGR565, 347511c7023SThierry Reding DRM_FORMAT_BGRA8888, 348511c7023SThierry Reding DRM_FORMAT_RGBA8888, 349511c7023SThierry Reding DRM_FORMAT_XRGB8888, 350511c7023SThierry Reding DRM_FORMAT_XBGR8888, 351511c7023SThierry Reding }; 352511c7023SThierry Reding 353511c7023SThierry Reding static const u32 tegra124_primary_formats[] = { 354511c7023SThierry Reding DRM_FORMAT_ARGB4444, 355511c7023SThierry Reding DRM_FORMAT_ARGB1555, 356511c7023SThierry Reding DRM_FORMAT_RGB565, 357511c7023SThierry Reding DRM_FORMAT_RGBA5551, 358511c7023SThierry Reding DRM_FORMAT_ABGR8888, 359511c7023SThierry Reding DRM_FORMAT_ARGB8888, 360511c7023SThierry Reding /* new on Tegra114 */ 361511c7023SThierry Reding DRM_FORMAT_ABGR4444, 362511c7023SThierry Reding DRM_FORMAT_ABGR1555, 363511c7023SThierry Reding DRM_FORMAT_BGRA5551, 364511c7023SThierry Reding DRM_FORMAT_XRGB1555, 365511c7023SThierry Reding DRM_FORMAT_RGBX5551, 366511c7023SThierry Reding DRM_FORMAT_XBGR1555, 367511c7023SThierry Reding DRM_FORMAT_BGRX5551, 368511c7023SThierry Reding DRM_FORMAT_BGR565, 369511c7023SThierry Reding DRM_FORMAT_BGRA8888, 370511c7023SThierry Reding DRM_FORMAT_RGBA8888, 371511c7023SThierry Reding DRM_FORMAT_XRGB8888, 372511c7023SThierry Reding DRM_FORMAT_XBGR8888, 373511c7023SThierry Reding /* new on Tegra124 */ 374511c7023SThierry Reding DRM_FORMAT_RGBX8888, 375511c7023SThierry Reding DRM_FORMAT_BGRX8888, 376c7679306SThierry Reding }; 377c7679306SThierry Reding 3784aa3df71SThierry Reding static int tegra_plane_atomic_check(struct drm_plane *plane, 3794aa3df71SThierry Reding struct drm_plane_state *state) 3804aa3df71SThierry Reding { 3818f604f8cSThierry Reding struct tegra_plane_state *plane_state = to_tegra_plane_state(state); 3828f604f8cSThierry Reding struct tegra_bo_tiling *tiling = &plane_state->tiling; 38347802b09SThierry Reding struct tegra_plane *tegra = to_tegra_plane(plane); 3844aa3df71SThierry Reding struct tegra_dc *dc = to_tegra_dc(state->crtc); 385c7679306SThierry Reding int err; 386c7679306SThierry Reding 3874aa3df71SThierry Reding /* no need for further checks if the plane is being disabled */ 3884aa3df71SThierry Reding if (!state->crtc) 3894aa3df71SThierry Reding return 0; 3904aa3df71SThierry Reding 3915acd3514SThierry Reding err = tegra_plane_format(state->fb->format->format, 3925acd3514SThierry Reding &plane_state->format, 3938f604f8cSThierry Reding &plane_state->swap); 3944aa3df71SThierry Reding if (err < 0) 3954aa3df71SThierry Reding return err; 3964aa3df71SThierry Reding 3978f604f8cSThierry Reding err = tegra_fb_get_tiling(state->fb, tiling); 3988f604f8cSThierry Reding if (err < 0) 3998f604f8cSThierry Reding return err; 4008f604f8cSThierry Reding 4018f604f8cSThierry Reding if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK && 4024aa3df71SThierry Reding !dc->soc->supports_block_linear) { 4034aa3df71SThierry Reding DRM_ERROR("hardware doesn't support block linear mode\n"); 4044aa3df71SThierry Reding return -EINVAL; 4054aa3df71SThierry Reding } 4064aa3df71SThierry Reding 4074aa3df71SThierry Reding /* 4084aa3df71SThierry Reding * Tegra doesn't support different strides for U and V planes so we 4094aa3df71SThierry Reding * error out if the user tries to display a framebuffer with such a 4104aa3df71SThierry Reding * configuration. 4114aa3df71SThierry Reding */ 412bcb0b461SVille Syrjälä if (state->fb->format->num_planes > 2) { 4134aa3df71SThierry Reding if (state->fb->pitches[2] != state->fb->pitches[1]) { 4144aa3df71SThierry Reding DRM_ERROR("unsupported UV-plane configuration\n"); 4154aa3df71SThierry Reding return -EINVAL; 4164aa3df71SThierry Reding } 4174aa3df71SThierry Reding } 4184aa3df71SThierry Reding 41947802b09SThierry Reding err = tegra_plane_state_add(tegra, state); 42047802b09SThierry Reding if (err < 0) 42147802b09SThierry Reding return err; 42247802b09SThierry Reding 4234aa3df71SThierry Reding return 0; 4244aa3df71SThierry Reding } 4254aa3df71SThierry Reding 426a4bfa096SThierry Reding static void tegra_plane_atomic_disable(struct drm_plane *plane, 427a4bfa096SThierry Reding struct drm_plane_state *old_state) 42880d3eef1SDmitry Osipenko { 429a4bfa096SThierry Reding struct tegra_plane *p = to_tegra_plane(plane); 43080d3eef1SDmitry Osipenko u32 value; 43180d3eef1SDmitry Osipenko 432a4bfa096SThierry Reding /* rien ne va plus */ 433a4bfa096SThierry Reding if (!old_state || !old_state->crtc) 434a4bfa096SThierry Reding return; 435a4bfa096SThierry Reding 436*1087fac1SThierry Reding value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); 43780d3eef1SDmitry Osipenko value &= ~WIN_ENABLE; 438*1087fac1SThierry Reding tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); 43980d3eef1SDmitry Osipenko } 44080d3eef1SDmitry Osipenko 4414aa3df71SThierry Reding static void tegra_plane_atomic_update(struct drm_plane *plane, 4424aa3df71SThierry Reding struct drm_plane_state *old_state) 4434aa3df71SThierry Reding { 4448f604f8cSThierry Reding struct tegra_plane_state *state = to_tegra_plane_state(plane->state); 4454aa3df71SThierry Reding struct drm_framebuffer *fb = plane->state->fb; 4464aa3df71SThierry Reding struct tegra_plane *p = to_tegra_plane(plane); 4474aa3df71SThierry Reding struct tegra_dc_window window; 4484aa3df71SThierry Reding unsigned int i; 4494aa3df71SThierry Reding 4504aa3df71SThierry Reding /* rien ne va plus */ 4514aa3df71SThierry Reding if (!plane->state->crtc || !plane->state->fb) 4524aa3df71SThierry Reding return; 4534aa3df71SThierry Reding 45480d3eef1SDmitry Osipenko if (!plane->state->visible) 455a4bfa096SThierry Reding return tegra_plane_atomic_disable(plane, old_state); 45680d3eef1SDmitry Osipenko 457c7679306SThierry Reding memset(&window, 0, sizeof(window)); 4587d205857SDmitry Osipenko window.src.x = plane->state->src.x1 >> 16; 4597d205857SDmitry Osipenko window.src.y = plane->state->src.y1 >> 16; 4607d205857SDmitry Osipenko window.src.w = drm_rect_width(&plane->state->src) >> 16; 4617d205857SDmitry Osipenko window.src.h = drm_rect_height(&plane->state->src) >> 16; 4627d205857SDmitry Osipenko window.dst.x = plane->state->dst.x1; 4637d205857SDmitry Osipenko window.dst.y = plane->state->dst.y1; 4647d205857SDmitry Osipenko window.dst.w = drm_rect_width(&plane->state->dst); 4657d205857SDmitry Osipenko window.dst.h = drm_rect_height(&plane->state->dst); 466272725c7SVille Syrjälä window.bits_per_pixel = fb->format->cpp[0] * 8; 467c7679306SThierry Reding window.bottom_up = tegra_fb_is_bottom_up(fb); 468c7679306SThierry Reding 4698f604f8cSThierry Reding /* copy from state */ 4708f604f8cSThierry Reding window.tiling = state->tiling; 4718f604f8cSThierry Reding window.format = state->format; 4728f604f8cSThierry Reding window.swap = state->swap; 473c7679306SThierry Reding 474bcb0b461SVille Syrjälä for (i = 0; i < fb->format->num_planes; i++) { 4754aa3df71SThierry Reding struct tegra_bo *bo = tegra_fb_get_plane(fb, i); 476c7679306SThierry Reding 4774aa3df71SThierry Reding window.base[i] = bo->paddr + fb->offsets[i]; 47808ee0178SDmitry Osipenko 47908ee0178SDmitry Osipenko /* 48008ee0178SDmitry Osipenko * Tegra uses a shared stride for UV planes. Framebuffers are 48108ee0178SDmitry Osipenko * already checked for this in the tegra_plane_atomic_check() 48208ee0178SDmitry Osipenko * function, so it's safe to ignore the V-plane pitch here. 48308ee0178SDmitry Osipenko */ 48408ee0178SDmitry Osipenko if (i < 2) 4854aa3df71SThierry Reding window.stride[i] = fb->pitches[i]; 486c7679306SThierry Reding } 487c7679306SThierry Reding 488*1087fac1SThierry Reding tegra_dc_setup_window(p, &window); 4894aa3df71SThierry Reding } 4904aa3df71SThierry Reding 491a4bfa096SThierry Reding static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = { 4924aa3df71SThierry Reding .atomic_check = tegra_plane_atomic_check, 4934aa3df71SThierry Reding .atomic_disable = tegra_plane_atomic_disable, 494a4bfa096SThierry Reding .atomic_update = tegra_plane_atomic_update, 495c7679306SThierry Reding }; 496c7679306SThierry Reding 49747307954SThierry Reding static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, 498c7679306SThierry Reding struct tegra_dc *dc) 499c7679306SThierry Reding { 500518e6227SThierry Reding /* 501518e6227SThierry Reding * Ideally this would use drm_crtc_mask(), but that would require the 502518e6227SThierry Reding * CRTC to already be in the mode_config's list of CRTCs. However, it 503518e6227SThierry Reding * will only be added to that list in the drm_crtc_init_with_planes() 504518e6227SThierry Reding * (in tegra_dc_init()), which in turn requires registration of these 505518e6227SThierry Reding * planes. So we have ourselves a nice little chicken and egg problem 506518e6227SThierry Reding * here. 507518e6227SThierry Reding * 508518e6227SThierry Reding * We work around this by manually creating the mask from the number 509518e6227SThierry Reding * of CRTCs that have been registered, and should therefore always be 510518e6227SThierry Reding * the same as drm_crtc_index() after registration. 511518e6227SThierry Reding */ 512518e6227SThierry Reding unsigned long possible_crtcs = 1 << drm->mode_config.num_crtc; 51347307954SThierry Reding enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY; 514c7679306SThierry Reding struct tegra_plane *plane; 515c7679306SThierry Reding unsigned int num_formats; 516c7679306SThierry Reding const u32 *formats; 517c7679306SThierry Reding int err; 518c7679306SThierry Reding 519c7679306SThierry Reding plane = kzalloc(sizeof(*plane), GFP_KERNEL); 520c7679306SThierry Reding if (!plane) 521c7679306SThierry Reding return ERR_PTR(-ENOMEM); 522c7679306SThierry Reding 523*1087fac1SThierry Reding /* Always use window A as primary window */ 524*1087fac1SThierry Reding plane->offset = 0xa00; 525c4755fb9SThierry Reding plane->index = 0; 526c4755fb9SThierry Reding plane->depth = 255; 527*1087fac1SThierry Reding plane->dc = dc; 528*1087fac1SThierry Reding 529*1087fac1SThierry Reding num_formats = dc->soc->num_primary_formats; 530*1087fac1SThierry Reding formats = dc->soc->primary_formats; 531c4755fb9SThierry Reding 532518e6227SThierry Reding err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, 533c1cb4b61SThierry Reding &tegra_plane_funcs, formats, 53447307954SThierry Reding num_formats, NULL, type, NULL); 535c7679306SThierry Reding if (err < 0) { 536c7679306SThierry Reding kfree(plane); 537c7679306SThierry Reding return ERR_PTR(err); 538c7679306SThierry Reding } 539c7679306SThierry Reding 540a4bfa096SThierry Reding drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); 5414aa3df71SThierry Reding 542c7679306SThierry Reding return &plane->base; 543c7679306SThierry Reding } 544c7679306SThierry Reding 545c7679306SThierry Reding static const u32 tegra_cursor_plane_formats[] = { 546c7679306SThierry Reding DRM_FORMAT_RGBA8888, 547c7679306SThierry Reding }; 548c7679306SThierry Reding 5494aa3df71SThierry Reding static int tegra_cursor_atomic_check(struct drm_plane *plane, 5504aa3df71SThierry Reding struct drm_plane_state *state) 551c7679306SThierry Reding { 55247802b09SThierry Reding struct tegra_plane *tegra = to_tegra_plane(plane); 55347802b09SThierry Reding int err; 55447802b09SThierry Reding 5554aa3df71SThierry Reding /* no need for further checks if the plane is being disabled */ 5564aa3df71SThierry Reding if (!state->crtc) 5574aa3df71SThierry Reding return 0; 558c7679306SThierry Reding 559c7679306SThierry Reding /* scaling not supported for cursor */ 5604aa3df71SThierry Reding if ((state->src_w >> 16 != state->crtc_w) || 5614aa3df71SThierry Reding (state->src_h >> 16 != state->crtc_h)) 562c7679306SThierry Reding return -EINVAL; 563c7679306SThierry Reding 564c7679306SThierry Reding /* only square cursors supported */ 5654aa3df71SThierry Reding if (state->src_w != state->src_h) 566c7679306SThierry Reding return -EINVAL; 567c7679306SThierry Reding 5684aa3df71SThierry Reding if (state->crtc_w != 32 && state->crtc_w != 64 && 5694aa3df71SThierry Reding state->crtc_w != 128 && state->crtc_w != 256) 5704aa3df71SThierry Reding return -EINVAL; 5714aa3df71SThierry Reding 57247802b09SThierry Reding err = tegra_plane_state_add(tegra, state); 57347802b09SThierry Reding if (err < 0) 57447802b09SThierry Reding return err; 57547802b09SThierry Reding 5764aa3df71SThierry Reding return 0; 5774aa3df71SThierry Reding } 5784aa3df71SThierry Reding 5794aa3df71SThierry Reding static void tegra_cursor_atomic_update(struct drm_plane *plane, 5804aa3df71SThierry Reding struct drm_plane_state *old_state) 5814aa3df71SThierry Reding { 5824aa3df71SThierry Reding struct tegra_bo *bo = tegra_fb_get_plane(plane->state->fb, 0); 5834aa3df71SThierry Reding struct tegra_dc *dc = to_tegra_dc(plane->state->crtc); 5844aa3df71SThierry Reding struct drm_plane_state *state = plane->state; 5854aa3df71SThierry Reding u32 value = CURSOR_CLIP_DISPLAY; 5864aa3df71SThierry Reding 5874aa3df71SThierry Reding /* rien ne va plus */ 5884aa3df71SThierry Reding if (!plane->state->crtc || !plane->state->fb) 5894aa3df71SThierry Reding return; 5904aa3df71SThierry Reding 5914aa3df71SThierry Reding switch (state->crtc_w) { 592c7679306SThierry Reding case 32: 593c7679306SThierry Reding value |= CURSOR_SIZE_32x32; 594c7679306SThierry Reding break; 595c7679306SThierry Reding 596c7679306SThierry Reding case 64: 597c7679306SThierry Reding value |= CURSOR_SIZE_64x64; 598c7679306SThierry Reding break; 599c7679306SThierry Reding 600c7679306SThierry Reding case 128: 601c7679306SThierry Reding value |= CURSOR_SIZE_128x128; 602c7679306SThierry Reding break; 603c7679306SThierry Reding 604c7679306SThierry Reding case 256: 605c7679306SThierry Reding value |= CURSOR_SIZE_256x256; 606c7679306SThierry Reding break; 607c7679306SThierry Reding 608c7679306SThierry Reding default: 6094aa3df71SThierry Reding WARN(1, "cursor size %ux%u not supported\n", state->crtc_w, 6104aa3df71SThierry Reding state->crtc_h); 6114aa3df71SThierry Reding return; 612c7679306SThierry Reding } 613c7679306SThierry Reding 614c7679306SThierry Reding value |= (bo->paddr >> 10) & 0x3fffff; 615c7679306SThierry Reding tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR); 616c7679306SThierry Reding 617c7679306SThierry Reding #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 618c7679306SThierry Reding value = (bo->paddr >> 32) & 0x3; 619c7679306SThierry Reding tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); 620c7679306SThierry Reding #endif 621c7679306SThierry Reding 622c7679306SThierry Reding /* enable cursor and set blend mode */ 623c7679306SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 624c7679306SThierry Reding value |= CURSOR_ENABLE; 625c7679306SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 626c7679306SThierry Reding 627c7679306SThierry Reding value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL); 628c7679306SThierry Reding value &= ~CURSOR_DST_BLEND_MASK; 629c7679306SThierry Reding value &= ~CURSOR_SRC_BLEND_MASK; 630c7679306SThierry Reding value |= CURSOR_MODE_NORMAL; 631c7679306SThierry Reding value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC; 632c7679306SThierry Reding value |= CURSOR_SRC_BLEND_K1_TIMES_SRC; 633c7679306SThierry Reding value |= CURSOR_ALPHA; 634c7679306SThierry Reding tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); 635c7679306SThierry Reding 636c7679306SThierry Reding /* position the cursor */ 6374aa3df71SThierry Reding value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff); 638c7679306SThierry Reding tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); 639c7679306SThierry Reding } 640c7679306SThierry Reding 6414aa3df71SThierry Reding static void tegra_cursor_atomic_disable(struct drm_plane *plane, 6424aa3df71SThierry Reding struct drm_plane_state *old_state) 643c7679306SThierry Reding { 6444aa3df71SThierry Reding struct tegra_dc *dc; 645c7679306SThierry Reding u32 value; 646c7679306SThierry Reding 6474aa3df71SThierry Reding /* rien ne va plus */ 6484aa3df71SThierry Reding if (!old_state || !old_state->crtc) 6494aa3df71SThierry Reding return; 6504aa3df71SThierry Reding 6514aa3df71SThierry Reding dc = to_tegra_dc(old_state->crtc); 652c7679306SThierry Reding 653c7679306SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 654c7679306SThierry Reding value &= ~CURSOR_ENABLE; 655c7679306SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 656c7679306SThierry Reding } 657c7679306SThierry Reding 6584aa3df71SThierry Reding static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = { 6594aa3df71SThierry Reding .atomic_check = tegra_cursor_atomic_check, 6604aa3df71SThierry Reding .atomic_update = tegra_cursor_atomic_update, 6614aa3df71SThierry Reding .atomic_disable = tegra_cursor_atomic_disable, 662c7679306SThierry Reding }; 663c7679306SThierry Reding 664c7679306SThierry Reding static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, 665c7679306SThierry Reding struct tegra_dc *dc) 666c7679306SThierry Reding { 667c7679306SThierry Reding struct tegra_plane *plane; 668c7679306SThierry Reding unsigned int num_formats; 669c7679306SThierry Reding const u32 *formats; 670c7679306SThierry Reding int err; 671c7679306SThierry Reding 672c7679306SThierry Reding plane = kzalloc(sizeof(*plane), GFP_KERNEL); 673c7679306SThierry Reding if (!plane) 674c7679306SThierry Reding return ERR_PTR(-ENOMEM); 675c7679306SThierry Reding 67647802b09SThierry Reding /* 677a1df3b24SThierry Reding * This index is kind of fake. The cursor isn't a regular plane, but 678a1df3b24SThierry Reding * its update and activation request bits in DC_CMD_STATE_CONTROL do 679a1df3b24SThierry Reding * use the same programming. Setting this fake index here allows the 680a1df3b24SThierry Reding * code in tegra_add_plane_state() to do the right thing without the 681a1df3b24SThierry Reding * need to special-casing the cursor plane. 68247802b09SThierry Reding */ 68347802b09SThierry Reding plane->index = 6; 684*1087fac1SThierry Reding plane->dc = dc; 68547802b09SThierry Reding 686c7679306SThierry Reding num_formats = ARRAY_SIZE(tegra_cursor_plane_formats); 687c7679306SThierry Reding formats = tegra_cursor_plane_formats; 688c7679306SThierry Reding 689c7679306SThierry Reding err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, 690c1cb4b61SThierry Reding &tegra_plane_funcs, formats, 691e6fc3b68SBen Widawsky num_formats, NULL, 692e6fc3b68SBen Widawsky DRM_PLANE_TYPE_CURSOR, NULL); 693c7679306SThierry Reding if (err < 0) { 694c7679306SThierry Reding kfree(plane); 695c7679306SThierry Reding return ERR_PTR(err); 696c7679306SThierry Reding } 697c7679306SThierry Reding 6984aa3df71SThierry Reding drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs); 6994aa3df71SThierry Reding 700c7679306SThierry Reding return &plane->base; 701c7679306SThierry Reding } 702c7679306SThierry Reding 703511c7023SThierry Reding static const u32 tegra20_overlay_formats[] = { 704511c7023SThierry Reding DRM_FORMAT_ARGB4444, 705511c7023SThierry Reding DRM_FORMAT_ARGB1555, 706dee8268fSThierry Reding DRM_FORMAT_RGB565, 707511c7023SThierry Reding DRM_FORMAT_RGBA5551, 708511c7023SThierry Reding DRM_FORMAT_ABGR8888, 709511c7023SThierry Reding DRM_FORMAT_ARGB8888, 710511c7023SThierry Reding /* planar formats */ 711511c7023SThierry Reding DRM_FORMAT_UYVY, 712511c7023SThierry Reding DRM_FORMAT_YUYV, 713511c7023SThierry Reding DRM_FORMAT_YUV420, 714511c7023SThierry Reding DRM_FORMAT_YUV422, 715511c7023SThierry Reding }; 716511c7023SThierry Reding 717511c7023SThierry Reding static const u32 tegra114_overlay_formats[] = { 718511c7023SThierry Reding DRM_FORMAT_ARGB4444, 719511c7023SThierry Reding DRM_FORMAT_ARGB1555, 720511c7023SThierry Reding DRM_FORMAT_RGB565, 721511c7023SThierry Reding DRM_FORMAT_RGBA5551, 722511c7023SThierry Reding DRM_FORMAT_ABGR8888, 723511c7023SThierry Reding DRM_FORMAT_ARGB8888, 724511c7023SThierry Reding /* new on Tegra114 */ 725511c7023SThierry Reding DRM_FORMAT_ABGR4444, 726511c7023SThierry Reding DRM_FORMAT_ABGR1555, 727511c7023SThierry Reding DRM_FORMAT_BGRA5551, 728511c7023SThierry Reding DRM_FORMAT_XRGB1555, 729511c7023SThierry Reding DRM_FORMAT_RGBX5551, 730511c7023SThierry Reding DRM_FORMAT_XBGR1555, 731511c7023SThierry Reding DRM_FORMAT_BGRX5551, 732511c7023SThierry Reding DRM_FORMAT_BGR565, 733511c7023SThierry Reding DRM_FORMAT_BGRA8888, 734511c7023SThierry Reding DRM_FORMAT_RGBA8888, 735511c7023SThierry Reding DRM_FORMAT_XRGB8888, 736511c7023SThierry Reding DRM_FORMAT_XBGR8888, 737511c7023SThierry Reding /* planar formats */ 738511c7023SThierry Reding DRM_FORMAT_UYVY, 739511c7023SThierry Reding DRM_FORMAT_YUYV, 740511c7023SThierry Reding DRM_FORMAT_YUV420, 741511c7023SThierry Reding DRM_FORMAT_YUV422, 742511c7023SThierry Reding }; 743511c7023SThierry Reding 744511c7023SThierry Reding static const u32 tegra124_overlay_formats[] = { 745511c7023SThierry Reding DRM_FORMAT_ARGB4444, 746511c7023SThierry Reding DRM_FORMAT_ARGB1555, 747511c7023SThierry Reding DRM_FORMAT_RGB565, 748511c7023SThierry Reding DRM_FORMAT_RGBA5551, 749511c7023SThierry Reding DRM_FORMAT_ABGR8888, 750511c7023SThierry Reding DRM_FORMAT_ARGB8888, 751511c7023SThierry Reding /* new on Tegra114 */ 752511c7023SThierry Reding DRM_FORMAT_ABGR4444, 753511c7023SThierry Reding DRM_FORMAT_ABGR1555, 754511c7023SThierry Reding DRM_FORMAT_BGRA5551, 755511c7023SThierry Reding DRM_FORMAT_XRGB1555, 756511c7023SThierry Reding DRM_FORMAT_RGBX5551, 757511c7023SThierry Reding DRM_FORMAT_XBGR1555, 758511c7023SThierry Reding DRM_FORMAT_BGRX5551, 759511c7023SThierry Reding DRM_FORMAT_BGR565, 760511c7023SThierry Reding DRM_FORMAT_BGRA8888, 761511c7023SThierry Reding DRM_FORMAT_RGBA8888, 762511c7023SThierry Reding DRM_FORMAT_XRGB8888, 763511c7023SThierry Reding DRM_FORMAT_XBGR8888, 764511c7023SThierry Reding /* new on Tegra124 */ 765511c7023SThierry Reding DRM_FORMAT_RGBX8888, 766511c7023SThierry Reding DRM_FORMAT_BGRX8888, 767511c7023SThierry Reding /* planar formats */ 768dee8268fSThierry Reding DRM_FORMAT_UYVY, 769f925390eSThierry Reding DRM_FORMAT_YUYV, 770dee8268fSThierry Reding DRM_FORMAT_YUV420, 771dee8268fSThierry Reding DRM_FORMAT_YUV422, 772dee8268fSThierry Reding }; 773dee8268fSThierry Reding 774c7679306SThierry Reding static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, 775c7679306SThierry Reding struct tegra_dc *dc, 776c7679306SThierry Reding unsigned int index) 777dee8268fSThierry Reding { 778dee8268fSThierry Reding struct tegra_plane *plane; 779c7679306SThierry Reding unsigned int num_formats; 780c7679306SThierry Reding const u32 *formats; 781c7679306SThierry Reding int err; 782dee8268fSThierry Reding 783f002abc1SThierry Reding plane = kzalloc(sizeof(*plane), GFP_KERNEL); 784dee8268fSThierry Reding if (!plane) 785c7679306SThierry Reding return ERR_PTR(-ENOMEM); 786dee8268fSThierry Reding 787*1087fac1SThierry Reding plane->offset = 0xa00 + 0x200 * index; 788c7679306SThierry Reding plane->index = index; 789c4755fb9SThierry Reding plane->depth = 0; 790*1087fac1SThierry Reding plane->dc = dc; 791dee8268fSThierry Reding 792511c7023SThierry Reding num_formats = dc->soc->num_overlay_formats; 793511c7023SThierry Reding formats = dc->soc->overlay_formats; 794c7679306SThierry Reding 795c7679306SThierry Reding err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe, 796301e0ddbSThierry Reding &tegra_plane_funcs, formats, 797e6fc3b68SBen Widawsky num_formats, NULL, 798e6fc3b68SBen Widawsky DRM_PLANE_TYPE_OVERLAY, NULL); 799f002abc1SThierry Reding if (err < 0) { 800f002abc1SThierry Reding kfree(plane); 801c7679306SThierry Reding return ERR_PTR(err); 802dee8268fSThierry Reding } 803c7679306SThierry Reding 804a4bfa096SThierry Reding drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); 8054aa3df71SThierry Reding 806c7679306SThierry Reding return &plane->base; 807c7679306SThierry Reding } 808c7679306SThierry Reding 80947307954SThierry Reding static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm, 81047307954SThierry Reding struct tegra_dc *dc) 811c7679306SThierry Reding { 81247307954SThierry Reding struct drm_plane *plane, *primary = NULL; 81347307954SThierry Reding unsigned int i, j; 81447307954SThierry Reding 81547307954SThierry Reding for (i = 0; i < dc->soc->num_wgrps; i++) { 81647307954SThierry Reding const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i]; 81747307954SThierry Reding 81847307954SThierry Reding if (wgrp->dc == dc->pipe) { 81947307954SThierry Reding for (j = 0; j < wgrp->num_windows; j++) { 82047307954SThierry Reding unsigned int index = wgrp->windows[j]; 82147307954SThierry Reding 82247307954SThierry Reding plane = tegra_shared_plane_create(drm, dc, 82347307954SThierry Reding wgrp->index, 82447307954SThierry Reding index); 82547307954SThierry Reding if (IS_ERR(plane)) 82647307954SThierry Reding return plane; 82747307954SThierry Reding 82847307954SThierry Reding /* 82947307954SThierry Reding * Choose the first shared plane owned by this 83047307954SThierry Reding * head as the primary plane. 83147307954SThierry Reding */ 83247307954SThierry Reding if (!primary) { 83347307954SThierry Reding plane->type = DRM_PLANE_TYPE_PRIMARY; 83447307954SThierry Reding primary = plane; 83547307954SThierry Reding } 83647307954SThierry Reding } 83747307954SThierry Reding } 83847307954SThierry Reding } 83947307954SThierry Reding 84047307954SThierry Reding return primary; 84147307954SThierry Reding } 84247307954SThierry Reding 84347307954SThierry Reding static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, 84447307954SThierry Reding struct tegra_dc *dc) 84547307954SThierry Reding { 84647307954SThierry Reding struct drm_plane *plane, *primary; 847c7679306SThierry Reding unsigned int i; 848c7679306SThierry Reding 84947307954SThierry Reding primary = tegra_primary_plane_create(drm, dc); 85047307954SThierry Reding if (IS_ERR(primary)) 85147307954SThierry Reding return primary; 85247307954SThierry Reding 853c7679306SThierry Reding for (i = 0; i < 2; i++) { 854c7679306SThierry Reding plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i); 85547307954SThierry Reding if (IS_ERR(plane)) { 85647307954SThierry Reding /* XXX tegra_plane_destroy() */ 85747307954SThierry Reding drm_plane_cleanup(primary); 85847307954SThierry Reding kfree(primary); 85947307954SThierry Reding return plane; 86047307954SThierry Reding } 861f002abc1SThierry Reding } 862dee8268fSThierry Reding 86347307954SThierry Reding return primary; 864dee8268fSThierry Reding } 865dee8268fSThierry Reding 866f002abc1SThierry Reding static void tegra_dc_destroy(struct drm_crtc *crtc) 867f002abc1SThierry Reding { 868f002abc1SThierry Reding drm_crtc_cleanup(crtc); 869f002abc1SThierry Reding } 870f002abc1SThierry Reding 871ca915b10SThierry Reding static void tegra_crtc_reset(struct drm_crtc *crtc) 872ca915b10SThierry Reding { 873ca915b10SThierry Reding struct tegra_dc_state *state; 874ca915b10SThierry Reding 8753b59b7acSThierry Reding if (crtc->state) 876ec2dc6a0SDaniel Vetter __drm_atomic_helper_crtc_destroy_state(crtc->state); 8773b59b7acSThierry Reding 878ca915b10SThierry Reding kfree(crtc->state); 879ca915b10SThierry Reding crtc->state = NULL; 880ca915b10SThierry Reding 881ca915b10SThierry Reding state = kzalloc(sizeof(*state), GFP_KERNEL); 882332bbe70SThierry Reding if (state) { 883ca915b10SThierry Reding crtc->state = &state->base; 884332bbe70SThierry Reding crtc->state->crtc = crtc; 885332bbe70SThierry Reding } 88631930d4dSThierry Reding 88731930d4dSThierry Reding drm_crtc_vblank_reset(crtc); 888ca915b10SThierry Reding } 889ca915b10SThierry Reding 890ca915b10SThierry Reding static struct drm_crtc_state * 891ca915b10SThierry Reding tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) 892ca915b10SThierry Reding { 893ca915b10SThierry Reding struct tegra_dc_state *state = to_dc_state(crtc->state); 894ca915b10SThierry Reding struct tegra_dc_state *copy; 895ca915b10SThierry Reding 8963b59b7acSThierry Reding copy = kmalloc(sizeof(*copy), GFP_KERNEL); 897ca915b10SThierry Reding if (!copy) 898ca915b10SThierry Reding return NULL; 899ca915b10SThierry Reding 9003b59b7acSThierry Reding __drm_atomic_helper_crtc_duplicate_state(crtc, ©->base); 9013b59b7acSThierry Reding copy->clk = state->clk; 9023b59b7acSThierry Reding copy->pclk = state->pclk; 9033b59b7acSThierry Reding copy->div = state->div; 9043b59b7acSThierry Reding copy->planes = state->planes; 905ca915b10SThierry Reding 906ca915b10SThierry Reding return ©->base; 907ca915b10SThierry Reding } 908ca915b10SThierry Reding 909ca915b10SThierry Reding static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, 910ca915b10SThierry Reding struct drm_crtc_state *state) 911ca915b10SThierry Reding { 912ec2dc6a0SDaniel Vetter __drm_atomic_helper_crtc_destroy_state(state); 913ca915b10SThierry Reding kfree(state); 914ca915b10SThierry Reding } 915ca915b10SThierry Reding 916b95800eeSThierry Reding #define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name } 917b95800eeSThierry Reding 918b95800eeSThierry Reding static const struct debugfs_reg32 tegra_dc_regs[] = { 919b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_GENERAL_INCR_SYNCPT), 920b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL), 921b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_GENERAL_INCR_SYNCPT_ERROR), 922b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_A_INCR_SYNCPT), 923b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL), 924b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_A_INCR_SYNCPT_ERROR), 925b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_B_INCR_SYNCPT), 926b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL), 927b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_B_INCR_SYNCPT_ERROR), 928b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_C_INCR_SYNCPT), 929b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL), 930b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_WIN_C_INCR_SYNCPT_ERROR), 931b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_CONT_SYNCPT_VSYNC), 932b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_DISPLAY_COMMAND_OPTION0), 933b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_DISPLAY_COMMAND), 934b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE), 935b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_DISPLAY_POWER_CONTROL), 936b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_INT_STATUS), 937b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_INT_MASK), 938b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_INT_ENABLE), 939b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_INT_TYPE), 940b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_INT_POLARITY), 941b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE1), 942b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE2), 943b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE3), 944b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_STATE_ACCESS), 945b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_STATE_CONTROL), 946b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_DISPLAY_WINDOW_HEADER), 947b95800eeSThierry Reding DEBUGFS_REG32(DC_CMD_REG_ACT_CONTROL), 948b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_CRC_CONTROL), 949b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_CRC_CHECKSUM), 950b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(0)), 951b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(1)), 952b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(2)), 953b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(3)), 954b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(0)), 955b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(1)), 956b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(2)), 957b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(3)), 958b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(0)), 959b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(1)), 960b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(2)), 961b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(3)), 962b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(0)), 963b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(1)), 964b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(2)), 965b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(3)), 966b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_INPUT_DATA(0)), 967b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_INPUT_DATA(1)), 968b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(0)), 969b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(1)), 970b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(2)), 971b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(3)), 972b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(4)), 973b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(5)), 974b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(6)), 975b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_MISC_CONTROL), 976b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_PM0_CONTROL), 977b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_PM0_DUTY_CYCLE), 978b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_PM1_CONTROL), 979b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_PIN_PM1_DUTY_CYCLE), 980b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_SPI_CONTROL), 981b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_SPI_START_BYTE), 982b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_HSPI_WRITE_DATA_AB), 983b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_HSPI_WRITE_DATA_CD), 984b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_HSPI_CS_DC), 985b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_SCRATCH_REGISTER_A), 986b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_SCRATCH_REGISTER_B), 987b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_GPIO_CTRL), 988b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_GPIO_DEBOUNCE_COUNTER), 989b95800eeSThierry Reding DEBUGFS_REG32(DC_COM_CRC_CHECKSUM_LATCHED), 990b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_SIGNAL_OPTIONS0), 991b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_SIGNAL_OPTIONS1), 992b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_WIN_OPTIONS), 993b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_MEM_HIGH_PRIORITY), 994b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER), 995b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_TIMING_OPTIONS), 996b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_REF_TO_SYNC), 997b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SYNC_WIDTH), 998b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_BACK_PORCH), 999b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_ACTIVE), 1000b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_FRONT_PORCH), 1001b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE0_CONTROL), 1002b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_A), 1003b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_B), 1004b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_C), 1005b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_D), 1006b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE1_CONTROL), 1007b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_A), 1008b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_B), 1009b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_C), 1010b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_D), 1011b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE2_CONTROL), 1012b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_A), 1013b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_B), 1014b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_C), 1015b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_D), 1016b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE0_CONTROL), 1017b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE0_POSITION_A), 1018b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE0_POSITION_B), 1019b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE0_POSITION_C), 1020b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE1_CONTROL), 1021b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE1_POSITION_A), 1022b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE1_POSITION_B), 1023b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE1_POSITION_C), 1024b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE2_CONTROL), 1025b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE2_POSITION_A), 1026b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE3_CONTROL), 1027b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_V_PULSE3_POSITION_A), 1028b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_M0_CONTROL), 1029b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_M1_CONTROL), 1030b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DI_CONTROL), 1031b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_PP_CONTROL), 1032b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_PP_SELECT_A), 1033b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_PP_SELECT_B), 1034b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_PP_SELECT_C), 1035b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_PP_SELECT_D), 1036b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_CLOCK_CONTROL), 1037b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_INTERFACE_CONTROL), 1038b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_COLOR_CONTROL), 1039b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SHIFT_CLOCK_OPTIONS), 1040b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DATA_ENABLE_OPTIONS), 1041b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SERIAL_INTERFACE_OPTIONS), 1042b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_LCD_SPI_OPTIONS), 1043b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_BORDER_COLOR), 1044b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_COLOR_KEY0_LOWER), 1045b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_COLOR_KEY0_UPPER), 1046b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_COLOR_KEY1_LOWER), 1047b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_COLOR_KEY1_UPPER), 1048b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_FOREGROUND), 1049b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_BACKGROUND), 1050b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_START_ADDR), 1051b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_START_ADDR_NS), 1052b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_POSITION), 1053b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_POSITION_NS), 1054b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_INIT_SEQ_CONTROL), 1055b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_A), 1056b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_B), 1057b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_C), 1058b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_D), 1059b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DC_MCCIF_FIFOCTRL), 1060b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY0A_HYST), 1061b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY0B_HYST), 1062b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY1A_HYST), 1063b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY1B_HYST), 1064b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DAC_CRT_CTRL), 1065b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DISP_MISC_CONTROL), 1066b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_CONTROL), 1067b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_CSC_COEFF), 1068b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(0)), 1069b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(1)), 1070b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(2)), 1071b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(3)), 1072b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(4)), 1073b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(5)), 1074b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(6)), 1075b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(7)), 1076b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_LUT(8)), 1077b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_FLICKER_CONTROL), 1078b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_DC_PIXEL_COUNT), 1079b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(0)), 1080b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(1)), 1081b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(2)), 1082b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(3)), 1083b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(4)), 1084b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(5)), 1085b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(6)), 1086b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(7)), 1087b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_BL_TF(0)), 1088b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_BL_TF(1)), 1089b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_BL_TF(2)), 1090b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_BL_TF(3)), 1091b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_BL_CONTROL), 1092b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_HW_K_VALUES), 1093b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_SD_MAN_K_VALUES), 1094b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_CURSOR_START_ADDR_HI), 1095b95800eeSThierry Reding DEBUGFS_REG32(DC_DISP_BLEND_CURSOR_CONTROL), 1096b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_WIN_OPTIONS), 1097b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BYTE_SWAP), 1098b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BUFFER_CONTROL), 1099b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_COLOR_DEPTH), 1100b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_POSITION), 1101b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_SIZE), 1102b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_PRESCALED_SIZE), 1103b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_H_INITIAL_DDA), 1104b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_V_INITIAL_DDA), 1105b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_DDA_INC), 1106b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_LINE_STRIDE), 1107b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BUF_STRIDE), 1108b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_UV_BUF_STRIDE), 1109b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BUFFER_ADDR_MODE), 1110b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_DV_CONTROL), 1111b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BLEND_NOKEY), 1112b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BLEND_1WIN), 1113b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BLEND_2WIN_X), 1114b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BLEND_2WIN_Y), 1115b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_BLEND_3WIN_XY), 1116b95800eeSThierry Reding DEBUGFS_REG32(DC_WIN_HP_FETCH_CONTROL), 1117b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_START_ADDR), 1118b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_START_ADDR_NS), 1119b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_START_ADDR_U), 1120b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_START_ADDR_U_NS), 1121b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_START_ADDR_V), 1122b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_START_ADDR_V_NS), 1123b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_ADDR_H_OFFSET), 1124b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_ADDR_H_OFFSET_NS), 1125b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_ADDR_V_OFFSET), 1126b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_ADDR_V_OFFSET_NS), 1127b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_UFLOW_STATUS), 1128b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_AD_UFLOW_STATUS), 1129b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_BD_UFLOW_STATUS), 1130b95800eeSThierry Reding DEBUGFS_REG32(DC_WINBUF_CD_UFLOW_STATUS), 1131b95800eeSThierry Reding }; 1132b95800eeSThierry Reding 1133b95800eeSThierry Reding static int tegra_dc_show_regs(struct seq_file *s, void *data) 1134b95800eeSThierry Reding { 1135b95800eeSThierry Reding struct drm_info_node *node = s->private; 1136b95800eeSThierry Reding struct tegra_dc *dc = node->info_ent->data; 1137b95800eeSThierry Reding unsigned int i; 1138b95800eeSThierry Reding int err = 0; 1139b95800eeSThierry Reding 1140b95800eeSThierry Reding drm_modeset_lock(&dc->base.mutex, NULL); 1141b95800eeSThierry Reding 1142b95800eeSThierry Reding if (!dc->base.state->active) { 1143b95800eeSThierry Reding err = -EBUSY; 1144b95800eeSThierry Reding goto unlock; 1145b95800eeSThierry Reding } 1146b95800eeSThierry Reding 1147b95800eeSThierry Reding for (i = 0; i < ARRAY_SIZE(tegra_dc_regs); i++) { 1148b95800eeSThierry Reding unsigned int offset = tegra_dc_regs[i].offset; 1149b95800eeSThierry Reding 1150b95800eeSThierry Reding seq_printf(s, "%-40s %#05x %08x\n", tegra_dc_regs[i].name, 1151b95800eeSThierry Reding offset, tegra_dc_readl(dc, offset)); 1152b95800eeSThierry Reding } 1153b95800eeSThierry Reding 1154b95800eeSThierry Reding unlock: 1155b95800eeSThierry Reding drm_modeset_unlock(&dc->base.mutex); 1156b95800eeSThierry Reding return err; 1157b95800eeSThierry Reding } 1158b95800eeSThierry Reding 1159b95800eeSThierry Reding static int tegra_dc_show_crc(struct seq_file *s, void *data) 1160b95800eeSThierry Reding { 1161b95800eeSThierry Reding struct drm_info_node *node = s->private; 1162b95800eeSThierry Reding struct tegra_dc *dc = node->info_ent->data; 1163b95800eeSThierry Reding int err = 0; 1164b95800eeSThierry Reding u32 value; 1165b95800eeSThierry Reding 1166b95800eeSThierry Reding drm_modeset_lock(&dc->base.mutex, NULL); 1167b95800eeSThierry Reding 1168b95800eeSThierry Reding if (!dc->base.state->active) { 1169b95800eeSThierry Reding err = -EBUSY; 1170b95800eeSThierry Reding goto unlock; 1171b95800eeSThierry Reding } 1172b95800eeSThierry Reding 1173b95800eeSThierry Reding value = DC_COM_CRC_CONTROL_ACTIVE_DATA | DC_COM_CRC_CONTROL_ENABLE; 1174b95800eeSThierry Reding tegra_dc_writel(dc, value, DC_COM_CRC_CONTROL); 1175b95800eeSThierry Reding tegra_dc_commit(dc); 1176b95800eeSThierry Reding 1177b95800eeSThierry Reding drm_crtc_wait_one_vblank(&dc->base); 1178b95800eeSThierry Reding drm_crtc_wait_one_vblank(&dc->base); 1179b95800eeSThierry Reding 1180b95800eeSThierry Reding value = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM); 1181b95800eeSThierry Reding seq_printf(s, "%08x\n", value); 1182b95800eeSThierry Reding 1183b95800eeSThierry Reding tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL); 1184b95800eeSThierry Reding 1185b95800eeSThierry Reding unlock: 1186b95800eeSThierry Reding drm_modeset_unlock(&dc->base.mutex); 1187b95800eeSThierry Reding return err; 1188b95800eeSThierry Reding } 1189b95800eeSThierry Reding 1190b95800eeSThierry Reding static int tegra_dc_show_stats(struct seq_file *s, void *data) 1191b95800eeSThierry Reding { 1192b95800eeSThierry Reding struct drm_info_node *node = s->private; 1193b95800eeSThierry Reding struct tegra_dc *dc = node->info_ent->data; 1194b95800eeSThierry Reding 1195b95800eeSThierry Reding seq_printf(s, "frames: %lu\n", dc->stats.frames); 1196b95800eeSThierry Reding seq_printf(s, "vblank: %lu\n", dc->stats.vblank); 1197b95800eeSThierry Reding seq_printf(s, "underflow: %lu\n", dc->stats.underflow); 1198b95800eeSThierry Reding seq_printf(s, "overflow: %lu\n", dc->stats.overflow); 1199b95800eeSThierry Reding 1200b95800eeSThierry Reding return 0; 1201b95800eeSThierry Reding } 1202b95800eeSThierry Reding 1203b95800eeSThierry Reding static struct drm_info_list debugfs_files[] = { 1204b95800eeSThierry Reding { "regs", tegra_dc_show_regs, 0, NULL }, 1205b95800eeSThierry Reding { "crc", tegra_dc_show_crc, 0, NULL }, 1206b95800eeSThierry Reding { "stats", tegra_dc_show_stats, 0, NULL }, 1207b95800eeSThierry Reding }; 1208b95800eeSThierry Reding 1209b95800eeSThierry Reding static int tegra_dc_late_register(struct drm_crtc *crtc) 1210b95800eeSThierry Reding { 1211b95800eeSThierry Reding unsigned int i, count = ARRAY_SIZE(debugfs_files); 1212b95800eeSThierry Reding struct drm_minor *minor = crtc->dev->primary; 1213b95800eeSThierry Reding struct dentry *root = crtc->debugfs_entry; 1214b95800eeSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1215b95800eeSThierry Reding int err; 1216b95800eeSThierry Reding 1217b95800eeSThierry Reding dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), 1218b95800eeSThierry Reding GFP_KERNEL); 1219b95800eeSThierry Reding if (!dc->debugfs_files) 1220b95800eeSThierry Reding return -ENOMEM; 1221b95800eeSThierry Reding 1222b95800eeSThierry Reding for (i = 0; i < count; i++) 1223b95800eeSThierry Reding dc->debugfs_files[i].data = dc; 1224b95800eeSThierry Reding 1225b95800eeSThierry Reding err = drm_debugfs_create_files(dc->debugfs_files, count, root, minor); 1226b95800eeSThierry Reding if (err < 0) 1227b95800eeSThierry Reding goto free; 1228b95800eeSThierry Reding 1229b95800eeSThierry Reding return 0; 1230b95800eeSThierry Reding 1231b95800eeSThierry Reding free: 1232b95800eeSThierry Reding kfree(dc->debugfs_files); 1233b95800eeSThierry Reding dc->debugfs_files = NULL; 1234b95800eeSThierry Reding 1235b95800eeSThierry Reding return err; 1236b95800eeSThierry Reding } 1237b95800eeSThierry Reding 1238b95800eeSThierry Reding static void tegra_dc_early_unregister(struct drm_crtc *crtc) 1239b95800eeSThierry Reding { 1240b95800eeSThierry Reding unsigned int count = ARRAY_SIZE(debugfs_files); 1241b95800eeSThierry Reding struct drm_minor *minor = crtc->dev->primary; 1242b95800eeSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1243b95800eeSThierry Reding 1244b95800eeSThierry Reding drm_debugfs_remove_files(dc->debugfs_files, count, minor); 1245b95800eeSThierry Reding kfree(dc->debugfs_files); 1246b95800eeSThierry Reding dc->debugfs_files = NULL; 1247b95800eeSThierry Reding } 1248b95800eeSThierry Reding 1249c49c81e2SThierry Reding static u32 tegra_dc_get_vblank_counter(struct drm_crtc *crtc) 1250c49c81e2SThierry Reding { 1251c49c81e2SThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1252c49c81e2SThierry Reding 125347307954SThierry Reding /* XXX vblank syncpoints don't work with nvdisplay yet */ 125447307954SThierry Reding if (dc->syncpt && !dc->soc->has_nvdisplay) 1255c49c81e2SThierry Reding return host1x_syncpt_read(dc->syncpt); 1256c49c81e2SThierry Reding 1257c49c81e2SThierry Reding /* fallback to software emulated VBLANK counter */ 1258c49c81e2SThierry Reding return drm_crtc_vblank_count(&dc->base); 1259c49c81e2SThierry Reding } 1260c49c81e2SThierry Reding 1261c49c81e2SThierry Reding static int tegra_dc_enable_vblank(struct drm_crtc *crtc) 1262c49c81e2SThierry Reding { 1263c49c81e2SThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1264c49c81e2SThierry Reding unsigned long value, flags; 1265c49c81e2SThierry Reding 1266c49c81e2SThierry Reding spin_lock_irqsave(&dc->lock, flags); 1267c49c81e2SThierry Reding 1268c49c81e2SThierry Reding value = tegra_dc_readl(dc, DC_CMD_INT_MASK); 1269c49c81e2SThierry Reding value |= VBLANK_INT; 1270c49c81e2SThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 1271c49c81e2SThierry Reding 1272c49c81e2SThierry Reding spin_unlock_irqrestore(&dc->lock, flags); 1273c49c81e2SThierry Reding 1274c49c81e2SThierry Reding return 0; 1275c49c81e2SThierry Reding } 1276c49c81e2SThierry Reding 1277c49c81e2SThierry Reding static void tegra_dc_disable_vblank(struct drm_crtc *crtc) 1278c49c81e2SThierry Reding { 1279c49c81e2SThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1280c49c81e2SThierry Reding unsigned long value, flags; 1281c49c81e2SThierry Reding 1282c49c81e2SThierry Reding spin_lock_irqsave(&dc->lock, flags); 1283c49c81e2SThierry Reding 1284c49c81e2SThierry Reding value = tegra_dc_readl(dc, DC_CMD_INT_MASK); 1285c49c81e2SThierry Reding value &= ~VBLANK_INT; 1286c49c81e2SThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 1287c49c81e2SThierry Reding 1288c49c81e2SThierry Reding spin_unlock_irqrestore(&dc->lock, flags); 1289c49c81e2SThierry Reding } 1290c49c81e2SThierry Reding 1291dee8268fSThierry Reding static const struct drm_crtc_funcs tegra_crtc_funcs = { 12921503ca47SThierry Reding .page_flip = drm_atomic_helper_page_flip, 129374f48791SThierry Reding .set_config = drm_atomic_helper_set_config, 1294f002abc1SThierry Reding .destroy = tegra_dc_destroy, 1295ca915b10SThierry Reding .reset = tegra_crtc_reset, 1296ca915b10SThierry Reding .atomic_duplicate_state = tegra_crtc_atomic_duplicate_state, 1297ca915b10SThierry Reding .atomic_destroy_state = tegra_crtc_atomic_destroy_state, 1298b95800eeSThierry Reding .late_register = tegra_dc_late_register, 1299b95800eeSThierry Reding .early_unregister = tegra_dc_early_unregister, 130010437d9bSShawn Guo .get_vblank_counter = tegra_dc_get_vblank_counter, 130110437d9bSShawn Guo .enable_vblank = tegra_dc_enable_vblank, 130210437d9bSShawn Guo .disable_vblank = tegra_dc_disable_vblank, 1303dee8268fSThierry Reding }; 1304dee8268fSThierry Reding 1305dee8268fSThierry Reding static int tegra_dc_set_timings(struct tegra_dc *dc, 1306dee8268fSThierry Reding struct drm_display_mode *mode) 1307dee8268fSThierry Reding { 13080444c0ffSThierry Reding unsigned int h_ref_to_sync = 1; 13090444c0ffSThierry Reding unsigned int v_ref_to_sync = 1; 1310dee8268fSThierry Reding unsigned long value; 1311dee8268fSThierry Reding 131247307954SThierry Reding if (!dc->soc->has_nvdisplay) { 1313dee8268fSThierry Reding tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); 1314dee8268fSThierry Reding 1315dee8268fSThierry Reding value = (v_ref_to_sync << 16) | h_ref_to_sync; 1316dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC); 131747307954SThierry Reding } 1318dee8268fSThierry Reding 1319dee8268fSThierry Reding value = ((mode->vsync_end - mode->vsync_start) << 16) | 1320dee8268fSThierry Reding ((mode->hsync_end - mode->hsync_start) << 0); 1321dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH); 1322dee8268fSThierry Reding 1323dee8268fSThierry Reding value = ((mode->vtotal - mode->vsync_end) << 16) | 1324dee8268fSThierry Reding ((mode->htotal - mode->hsync_end) << 0); 1325dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH); 1326dee8268fSThierry Reding 1327dee8268fSThierry Reding value = ((mode->vsync_start - mode->vdisplay) << 16) | 1328dee8268fSThierry Reding ((mode->hsync_start - mode->hdisplay) << 0); 1329dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH); 1330dee8268fSThierry Reding 1331dee8268fSThierry Reding value = (mode->vdisplay << 16) | mode->hdisplay; 1332dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_ACTIVE); 1333dee8268fSThierry Reding 1334dee8268fSThierry Reding return 0; 1335dee8268fSThierry Reding } 1336dee8268fSThierry Reding 13379d910b60SThierry Reding /** 13389d910b60SThierry Reding * tegra_dc_state_setup_clock - check clock settings and store them in atomic 13399d910b60SThierry Reding * state 13409d910b60SThierry Reding * @dc: display controller 13419d910b60SThierry Reding * @crtc_state: CRTC atomic state 13429d910b60SThierry Reding * @clk: parent clock for display controller 13439d910b60SThierry Reding * @pclk: pixel clock 13449d910b60SThierry Reding * @div: shift clock divider 13459d910b60SThierry Reding * 13469d910b60SThierry Reding * Returns: 13479d910b60SThierry Reding * 0 on success or a negative error-code on failure. 13489d910b60SThierry Reding */ 1349ca915b10SThierry Reding int tegra_dc_state_setup_clock(struct tegra_dc *dc, 1350ca915b10SThierry Reding struct drm_crtc_state *crtc_state, 1351ca915b10SThierry Reding struct clk *clk, unsigned long pclk, 1352ca915b10SThierry Reding unsigned int div) 1353ca915b10SThierry Reding { 1354ca915b10SThierry Reding struct tegra_dc_state *state = to_dc_state(crtc_state); 1355ca915b10SThierry Reding 1356d2982748SThierry Reding if (!clk_has_parent(dc->clk, clk)) 1357d2982748SThierry Reding return -EINVAL; 1358d2982748SThierry Reding 1359ca915b10SThierry Reding state->clk = clk; 1360ca915b10SThierry Reding state->pclk = pclk; 1361ca915b10SThierry Reding state->div = div; 1362ca915b10SThierry Reding 1363ca915b10SThierry Reding return 0; 1364ca915b10SThierry Reding } 1365ca915b10SThierry Reding 136676d59ed0SThierry Reding static void tegra_dc_commit_state(struct tegra_dc *dc, 136776d59ed0SThierry Reding struct tegra_dc_state *state) 136876d59ed0SThierry Reding { 136976d59ed0SThierry Reding u32 value; 137076d59ed0SThierry Reding int err; 137176d59ed0SThierry Reding 137276d59ed0SThierry Reding err = clk_set_parent(dc->clk, state->clk); 137376d59ed0SThierry Reding if (err < 0) 137476d59ed0SThierry Reding dev_err(dc->dev, "failed to set parent clock: %d\n", err); 137576d59ed0SThierry Reding 137676d59ed0SThierry Reding /* 137776d59ed0SThierry Reding * Outputs may not want to change the parent clock rate. This is only 137876d59ed0SThierry Reding * relevant to Tegra20 where only a single display PLL is available. 137976d59ed0SThierry Reding * Since that PLL would typically be used for HDMI, an internal LVDS 138076d59ed0SThierry Reding * panel would need to be driven by some other clock such as PLL_P 138176d59ed0SThierry Reding * which is shared with other peripherals. Changing the clock rate 138276d59ed0SThierry Reding * should therefore be avoided. 138376d59ed0SThierry Reding */ 138476d59ed0SThierry Reding if (state->pclk > 0) { 138576d59ed0SThierry Reding err = clk_set_rate(state->clk, state->pclk); 138676d59ed0SThierry Reding if (err < 0) 138776d59ed0SThierry Reding dev_err(dc->dev, 138876d59ed0SThierry Reding "failed to set clock rate to %lu Hz\n", 138976d59ed0SThierry Reding state->pclk); 139076d59ed0SThierry Reding } 139176d59ed0SThierry Reding 139276d59ed0SThierry Reding DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), 139376d59ed0SThierry Reding state->div); 139476d59ed0SThierry Reding DRM_DEBUG_KMS("pclk: %lu\n", state->pclk); 139576d59ed0SThierry Reding 139647307954SThierry Reding if (!dc->soc->has_nvdisplay) { 139776d59ed0SThierry Reding value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1; 139876d59ed0SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); 139947307954SThierry Reding } 140039e08affSThierry Reding 140139e08affSThierry Reding err = clk_set_rate(dc->clk, state->pclk); 140239e08affSThierry Reding if (err < 0) 140339e08affSThierry Reding dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n", 140439e08affSThierry Reding dc->clk, state->pclk, err); 140576d59ed0SThierry Reding } 140676d59ed0SThierry Reding 1407003fc848SThierry Reding static void tegra_dc_stop(struct tegra_dc *dc) 1408003fc848SThierry Reding { 1409003fc848SThierry Reding u32 value; 1410003fc848SThierry Reding 1411003fc848SThierry Reding /* stop the display controller */ 1412003fc848SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); 1413003fc848SThierry Reding value &= ~DISP_CTRL_MODE_MASK; 1414003fc848SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); 1415003fc848SThierry Reding 1416003fc848SThierry Reding tegra_dc_commit(dc); 1417003fc848SThierry Reding } 1418003fc848SThierry Reding 1419003fc848SThierry Reding static bool tegra_dc_idle(struct tegra_dc *dc) 1420003fc848SThierry Reding { 1421003fc848SThierry Reding u32 value; 1422003fc848SThierry Reding 1423003fc848SThierry Reding value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND); 1424003fc848SThierry Reding 1425003fc848SThierry Reding return (value & DISP_CTRL_MODE_MASK) == 0; 1426003fc848SThierry Reding } 1427003fc848SThierry Reding 1428003fc848SThierry Reding static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout) 1429003fc848SThierry Reding { 1430003fc848SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 1431003fc848SThierry Reding 1432003fc848SThierry Reding while (time_before(jiffies, timeout)) { 1433003fc848SThierry Reding if (tegra_dc_idle(dc)) 1434003fc848SThierry Reding return 0; 1435003fc848SThierry Reding 1436003fc848SThierry Reding usleep_range(1000, 2000); 1437003fc848SThierry Reding } 1438003fc848SThierry Reding 1439003fc848SThierry Reding dev_dbg(dc->dev, "timeout waiting for DC to become idle\n"); 1440003fc848SThierry Reding return -ETIMEDOUT; 1441003fc848SThierry Reding } 1442003fc848SThierry Reding 144364581714SLaurent Pinchart static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, 144464581714SLaurent Pinchart struct drm_crtc_state *old_state) 1445003fc848SThierry Reding { 1446003fc848SThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1447003fc848SThierry Reding u32 value; 1448003fc848SThierry Reding 1449003fc848SThierry Reding if (!tegra_dc_idle(dc)) { 1450003fc848SThierry Reding tegra_dc_stop(dc); 1451003fc848SThierry Reding 1452003fc848SThierry Reding /* 1453003fc848SThierry Reding * Ignore the return value, there isn't anything useful to do 1454003fc848SThierry Reding * in case this fails. 1455003fc848SThierry Reding */ 1456003fc848SThierry Reding tegra_dc_wait_idle(dc, 100); 1457003fc848SThierry Reding } 1458003fc848SThierry Reding 1459003fc848SThierry Reding /* 1460003fc848SThierry Reding * This should really be part of the RGB encoder driver, but clearing 1461003fc848SThierry Reding * these bits has the side-effect of stopping the display controller. 1462003fc848SThierry Reding * When that happens no VBLANK interrupts will be raised. At the same 1463003fc848SThierry Reding * time the encoder is disabled before the display controller, so the 1464003fc848SThierry Reding * above code is always going to timeout waiting for the controller 1465003fc848SThierry Reding * to go idle. 1466003fc848SThierry Reding * 1467003fc848SThierry Reding * Given the close coupling between the RGB encoder and the display 1468003fc848SThierry Reding * controller doing it here is still kind of okay. None of the other 1469003fc848SThierry Reding * encoder drivers require these bits to be cleared. 1470003fc848SThierry Reding * 1471003fc848SThierry Reding * XXX: Perhaps given that the display controller is switched off at 1472003fc848SThierry Reding * this point anyway maybe clearing these bits isn't even useful for 1473003fc848SThierry Reding * the RGB encoder? 1474003fc848SThierry Reding */ 1475003fc848SThierry Reding if (dc->rgb) { 1476003fc848SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 1477003fc848SThierry Reding value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 1478003fc848SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); 1479003fc848SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 1480003fc848SThierry Reding } 1481003fc848SThierry Reding 1482003fc848SThierry Reding tegra_dc_stats_reset(&dc->stats); 1483003fc848SThierry Reding drm_crtc_vblank_off(crtc); 148433a8eb8dSThierry Reding 14859d99ab6eSThierry Reding spin_lock_irq(&crtc->dev->event_lock); 14869d99ab6eSThierry Reding 14879d99ab6eSThierry Reding if (crtc->state->event) { 14889d99ab6eSThierry Reding drm_crtc_send_vblank_event(crtc, crtc->state->event); 14899d99ab6eSThierry Reding crtc->state->event = NULL; 14909d99ab6eSThierry Reding } 14919d99ab6eSThierry Reding 14929d99ab6eSThierry Reding spin_unlock_irq(&crtc->dev->event_lock); 14939d99ab6eSThierry Reding 149433a8eb8dSThierry Reding pm_runtime_put_sync(dc->dev); 1495003fc848SThierry Reding } 1496003fc848SThierry Reding 14970b20a0f8SLaurent Pinchart static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, 14980b20a0f8SLaurent Pinchart struct drm_crtc_state *old_state) 1499dee8268fSThierry Reding { 15004aa3df71SThierry Reding struct drm_display_mode *mode = &crtc->state->adjusted_mode; 150176d59ed0SThierry Reding struct tegra_dc_state *state = to_dc_state(crtc->state); 1502dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 1503dbb3f2f7SThierry Reding u32 value; 1504dee8268fSThierry Reding 150533a8eb8dSThierry Reding pm_runtime_get_sync(dc->dev); 150633a8eb8dSThierry Reding 150733a8eb8dSThierry Reding /* initialize display controller */ 150833a8eb8dSThierry Reding if (dc->syncpt) { 150947307954SThierry Reding u32 syncpt = host1x_syncpt_id(dc->syncpt), enable; 151047307954SThierry Reding 151147307954SThierry Reding if (dc->soc->has_nvdisplay) 151247307954SThierry Reding enable = 1 << 31; 151347307954SThierry Reding else 151447307954SThierry Reding enable = 1 << 8; 151533a8eb8dSThierry Reding 151633a8eb8dSThierry Reding value = SYNCPT_CNTRL_NO_STALL; 151733a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); 151833a8eb8dSThierry Reding 151947307954SThierry Reding value = enable | syncpt; 152033a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC); 152133a8eb8dSThierry Reding } 152233a8eb8dSThierry Reding 152347307954SThierry Reding if (dc->soc->has_nvdisplay) { 152447307954SThierry Reding value = DSC_TO_UF_INT | DSC_BBUF_UF_INT | DSC_RBUF_UF_INT | 152547307954SThierry Reding DSC_OBUF_UF_INT; 152647307954SThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); 152747307954SThierry Reding 152847307954SThierry Reding value = DSC_TO_UF_INT | DSC_BBUF_UF_INT | DSC_RBUF_UF_INT | 152947307954SThierry Reding DSC_OBUF_UF_INT | SD3_BUCKET_WALK_DONE_INT | 153047307954SThierry Reding HEAD_UF_INT | MSF_INT | REG_TMOUT_INT | 153147307954SThierry Reding REGION_CRC_INT | V_PULSE2_INT | V_PULSE3_INT | 153247307954SThierry Reding VBLANK_INT | FRAME_END_INT; 153347307954SThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); 153447307954SThierry Reding 153547307954SThierry Reding value = SD3_BUCKET_WALK_DONE_INT | HEAD_UF_INT | VBLANK_INT | 153647307954SThierry Reding FRAME_END_INT; 153747307954SThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); 153847307954SThierry Reding 153947307954SThierry Reding value = HEAD_UF_INT | REG_TMOUT_INT | FRAME_END_INT; 154047307954SThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 154147307954SThierry Reding 154247307954SThierry Reding tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); 154347307954SThierry Reding } else { 154433a8eb8dSThierry Reding value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 154533a8eb8dSThierry Reding WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; 154633a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); 154733a8eb8dSThierry Reding 154833a8eb8dSThierry Reding value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 154933a8eb8dSThierry Reding WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; 155033a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); 155133a8eb8dSThierry Reding 155233a8eb8dSThierry Reding /* initialize timer */ 155333a8eb8dSThierry Reding value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | 155433a8eb8dSThierry Reding WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); 155533a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); 155633a8eb8dSThierry Reding 155733a8eb8dSThierry Reding value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | 155833a8eb8dSThierry Reding WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); 155933a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); 156033a8eb8dSThierry Reding 156133a8eb8dSThierry Reding value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 156233a8eb8dSThierry Reding WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; 156333a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); 156433a8eb8dSThierry Reding 156533a8eb8dSThierry Reding value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 156633a8eb8dSThierry Reding WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; 156733a8eb8dSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 156847307954SThierry Reding } 156933a8eb8dSThierry Reding 15707116e9a8SThierry Reding if (dc->soc->supports_background_color) 15717116e9a8SThierry Reding tegra_dc_writel(dc, 0, DC_DISP_BLEND_BACKGROUND_COLOR); 15727116e9a8SThierry Reding else 157333a8eb8dSThierry Reding tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR); 157433a8eb8dSThierry Reding 157533a8eb8dSThierry Reding /* apply PLL and pixel clock changes */ 157676d59ed0SThierry Reding tegra_dc_commit_state(dc, state); 157776d59ed0SThierry Reding 1578dee8268fSThierry Reding /* program display mode */ 1579dee8268fSThierry Reding tegra_dc_set_timings(dc, mode); 1580dee8268fSThierry Reding 15818620fc62SThierry Reding /* interlacing isn't supported yet, so disable it */ 15828620fc62SThierry Reding if (dc->soc->supports_interlacing) { 15838620fc62SThierry Reding value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL); 15848620fc62SThierry Reding value &= ~INTERLACE_ENABLE; 15858620fc62SThierry Reding tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL); 15868620fc62SThierry Reding } 1587666cb873SThierry Reding 1588666cb873SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); 1589666cb873SThierry Reding value &= ~DISP_CTRL_MODE_MASK; 1590666cb873SThierry Reding value |= DISP_CTRL_MODE_C_DISPLAY; 1591666cb873SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); 1592666cb873SThierry Reding 159347307954SThierry Reding if (!dc->soc->has_nvdisplay) { 1594666cb873SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 1595666cb873SThierry Reding value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 1596666cb873SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; 1597666cb873SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 159847307954SThierry Reding } 159947307954SThierry Reding 160047307954SThierry Reding /* enable underflow reporting and display red for missing pixels */ 160147307954SThierry Reding if (dc->soc->has_nvdisplay) { 160247307954SThierry Reding value = UNDERFLOW_MODE_RED | UNDERFLOW_REPORT_ENABLE; 160347307954SThierry Reding tegra_dc_writel(dc, value, DC_COM_RG_UNDERFLOW); 160447307954SThierry Reding } 1605666cb873SThierry Reding 1606666cb873SThierry Reding tegra_dc_commit(dc); 1607dee8268fSThierry Reding 16088ff64c17SThierry Reding drm_crtc_vblank_on(crtc); 1609dee8268fSThierry Reding } 1610dee8268fSThierry Reding 16114aa3df71SThierry Reding static int tegra_crtc_atomic_check(struct drm_crtc *crtc, 16124aa3df71SThierry Reding struct drm_crtc_state *state) 16134aa3df71SThierry Reding { 1614c4755fb9SThierry Reding struct tegra_atomic_state *s = to_tegra_atomic_state(state->state); 1615c4755fb9SThierry Reding struct tegra_dc_state *tegra = to_dc_state(state); 1616c4755fb9SThierry Reding 1617c4755fb9SThierry Reding /* 1618c4755fb9SThierry Reding * The display hub display clock needs to be fed by the display clock 1619c4755fb9SThierry Reding * with the highest frequency to ensure proper functioning of all the 1620c4755fb9SThierry Reding * displays. 1621c4755fb9SThierry Reding * 1622c4755fb9SThierry Reding * Note that this isn't used before Tegra186, but it doesn't hurt and 1623c4755fb9SThierry Reding * conditionalizing it would make the code less clean. 1624c4755fb9SThierry Reding */ 1625c4755fb9SThierry Reding if (state->active) { 1626c4755fb9SThierry Reding if (!s->clk_disp || tegra->pclk > s->rate) { 1627c4755fb9SThierry Reding s->dc = to_tegra_dc(crtc); 1628c4755fb9SThierry Reding s->clk_disp = s->dc->clk; 1629c4755fb9SThierry Reding s->rate = tegra->pclk; 1630c4755fb9SThierry Reding } 1631c4755fb9SThierry Reding } 1632c4755fb9SThierry Reding 16334aa3df71SThierry Reding return 0; 16344aa3df71SThierry Reding } 16354aa3df71SThierry Reding 1636613d2b27SMaarten Lankhorst static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, 1637613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 16384aa3df71SThierry Reding { 16399d99ab6eSThierry Reding unsigned long flags; 16401503ca47SThierry Reding 16411503ca47SThierry Reding if (crtc->state->event) { 16429d99ab6eSThierry Reding spin_lock_irqsave(&crtc->dev->event_lock, flags); 16431503ca47SThierry Reding 16449d99ab6eSThierry Reding if (drm_crtc_vblank_get(crtc) != 0) 16459d99ab6eSThierry Reding drm_crtc_send_vblank_event(crtc, crtc->state->event); 16469d99ab6eSThierry Reding else 16479d99ab6eSThierry Reding drm_crtc_arm_vblank_event(crtc, crtc->state->event); 16481503ca47SThierry Reding 16499d99ab6eSThierry Reding spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 16509d99ab6eSThierry Reding 16511503ca47SThierry Reding crtc->state->event = NULL; 16521503ca47SThierry Reding } 16534aa3df71SThierry Reding } 16544aa3df71SThierry Reding 1655613d2b27SMaarten Lankhorst static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, 1656613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 16574aa3df71SThierry Reding { 165847802b09SThierry Reding struct tegra_dc_state *state = to_dc_state(crtc->state); 165947802b09SThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 166047307954SThierry Reding u32 value; 166147802b09SThierry Reding 166247307954SThierry Reding value = state->planes << 8 | GENERAL_UPDATE; 166347307954SThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 166447307954SThierry Reding value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); 166547307954SThierry Reding 166647307954SThierry Reding value = state->planes | GENERAL_ACT_REQ; 166747307954SThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 166847307954SThierry Reding value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); 16694aa3df71SThierry Reding } 16704aa3df71SThierry Reding 1671dee8268fSThierry Reding static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { 16724aa3df71SThierry Reding .atomic_check = tegra_crtc_atomic_check, 16734aa3df71SThierry Reding .atomic_begin = tegra_crtc_atomic_begin, 16744aa3df71SThierry Reding .atomic_flush = tegra_crtc_atomic_flush, 16750b20a0f8SLaurent Pinchart .atomic_enable = tegra_crtc_atomic_enable, 167664581714SLaurent Pinchart .atomic_disable = tegra_crtc_atomic_disable, 1677dee8268fSThierry Reding }; 1678dee8268fSThierry Reding 1679dee8268fSThierry Reding static irqreturn_t tegra_dc_irq(int irq, void *data) 1680dee8268fSThierry Reding { 1681dee8268fSThierry Reding struct tegra_dc *dc = data; 1682dee8268fSThierry Reding unsigned long status; 1683dee8268fSThierry Reding 1684dee8268fSThierry Reding status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); 1685dee8268fSThierry Reding tegra_dc_writel(dc, status, DC_CMD_INT_STATUS); 1686dee8268fSThierry Reding 1687dee8268fSThierry Reding if (status & FRAME_END_INT) { 1688dee8268fSThierry Reding /* 1689dee8268fSThierry Reding dev_dbg(dc->dev, "%s(): frame end\n", __func__); 1690dee8268fSThierry Reding */ 1691791ddb1eSThierry Reding dc->stats.frames++; 1692dee8268fSThierry Reding } 1693dee8268fSThierry Reding 1694dee8268fSThierry Reding if (status & VBLANK_INT) { 1695dee8268fSThierry Reding /* 1696dee8268fSThierry Reding dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); 1697dee8268fSThierry Reding */ 1698ed7dae58SThierry Reding drm_crtc_handle_vblank(&dc->base); 1699791ddb1eSThierry Reding dc->stats.vblank++; 1700dee8268fSThierry Reding } 1701dee8268fSThierry Reding 1702dee8268fSThierry Reding if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) { 1703dee8268fSThierry Reding /* 1704dee8268fSThierry Reding dev_dbg(dc->dev, "%s(): underflow\n", __func__); 1705dee8268fSThierry Reding */ 1706791ddb1eSThierry Reding dc->stats.underflow++; 1707791ddb1eSThierry Reding } 1708791ddb1eSThierry Reding 1709791ddb1eSThierry Reding if (status & (WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT)) { 1710791ddb1eSThierry Reding /* 1711791ddb1eSThierry Reding dev_dbg(dc->dev, "%s(): overflow\n", __func__); 1712791ddb1eSThierry Reding */ 1713791ddb1eSThierry Reding dc->stats.overflow++; 1714dee8268fSThierry Reding } 1715dee8268fSThierry Reding 171647307954SThierry Reding if (status & HEAD_UF_INT) { 171747307954SThierry Reding dev_dbg_ratelimited(dc->dev, "%s(): head underflow\n", __func__); 171847307954SThierry Reding dc->stats.underflow++; 171947307954SThierry Reding } 172047307954SThierry Reding 1721dee8268fSThierry Reding return IRQ_HANDLED; 1722dee8268fSThierry Reding } 1723dee8268fSThierry Reding 1724dee8268fSThierry Reding static int tegra_dc_init(struct host1x_client *client) 1725dee8268fSThierry Reding { 17269910f5c4SThierry Reding struct drm_device *drm = dev_get_drvdata(client->parent); 17272bcdcbfaSThierry Reding unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; 1728dee8268fSThierry Reding struct tegra_dc *dc = host1x_client_to_dc(client); 1729d1f3e1e0SThierry Reding struct tegra_drm *tegra = drm->dev_private; 1730c7679306SThierry Reding struct drm_plane *primary = NULL; 1731c7679306SThierry Reding struct drm_plane *cursor = NULL; 1732dee8268fSThierry Reding int err; 1733dee8268fSThierry Reding 1734617dd7ccSThierry Reding dc->syncpt = host1x_syncpt_request(client, flags); 17352bcdcbfaSThierry Reding if (!dc->syncpt) 17362bcdcbfaSThierry Reding dev_warn(dc->dev, "failed to allocate syncpoint\n"); 17372bcdcbfaSThierry Reding 1738df06b759SThierry Reding if (tegra->domain) { 1739df06b759SThierry Reding err = iommu_attach_device(tegra->domain, dc->dev); 1740df06b759SThierry Reding if (err < 0) { 1741df06b759SThierry Reding dev_err(dc->dev, "failed to attach to domain: %d\n", 1742df06b759SThierry Reding err); 1743df06b759SThierry Reding return err; 1744df06b759SThierry Reding } 1745df06b759SThierry Reding 1746df06b759SThierry Reding dc->domain = tegra->domain; 1747df06b759SThierry Reding } 1748df06b759SThierry Reding 174947307954SThierry Reding if (dc->soc->wgrps) 175047307954SThierry Reding primary = tegra_dc_add_shared_planes(drm, dc); 175147307954SThierry Reding else 175247307954SThierry Reding primary = tegra_dc_add_planes(drm, dc); 175347307954SThierry Reding 1754c7679306SThierry Reding if (IS_ERR(primary)) { 1755c7679306SThierry Reding err = PTR_ERR(primary); 1756c7679306SThierry Reding goto cleanup; 1757c7679306SThierry Reding } 1758c7679306SThierry Reding 1759c7679306SThierry Reding if (dc->soc->supports_cursor) { 1760c7679306SThierry Reding cursor = tegra_dc_cursor_plane_create(drm, dc); 1761c7679306SThierry Reding if (IS_ERR(cursor)) { 1762c7679306SThierry Reding err = PTR_ERR(cursor); 1763c7679306SThierry Reding goto cleanup; 1764c7679306SThierry Reding } 1765c7679306SThierry Reding } 1766c7679306SThierry Reding 1767c7679306SThierry Reding err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor, 1768f9882876SVille Syrjälä &tegra_crtc_funcs, NULL); 1769c7679306SThierry Reding if (err < 0) 1770c7679306SThierry Reding goto cleanup; 1771c7679306SThierry Reding 1772dee8268fSThierry Reding drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); 1773dee8268fSThierry Reding 1774d1f3e1e0SThierry Reding /* 1775d1f3e1e0SThierry Reding * Keep track of the minimum pitch alignment across all display 1776d1f3e1e0SThierry Reding * controllers. 1777d1f3e1e0SThierry Reding */ 1778d1f3e1e0SThierry Reding if (dc->soc->pitch_align > tegra->pitch_align) 1779d1f3e1e0SThierry Reding tegra->pitch_align = dc->soc->pitch_align; 1780d1f3e1e0SThierry Reding 17819910f5c4SThierry Reding err = tegra_dc_rgb_init(drm, dc); 1782dee8268fSThierry Reding if (err < 0 && err != -ENODEV) { 1783dee8268fSThierry Reding dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); 1784c7679306SThierry Reding goto cleanup; 1785dee8268fSThierry Reding } 1786dee8268fSThierry Reding 1787dee8268fSThierry Reding err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0, 1788dee8268fSThierry Reding dev_name(dc->dev), dc); 1789dee8268fSThierry Reding if (err < 0) { 1790dee8268fSThierry Reding dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, 1791dee8268fSThierry Reding err); 1792c7679306SThierry Reding goto cleanup; 1793dee8268fSThierry Reding } 1794dee8268fSThierry Reding 1795dee8268fSThierry Reding return 0; 1796c7679306SThierry Reding 1797c7679306SThierry Reding cleanup: 179847307954SThierry Reding if (!IS_ERR_OR_NULL(cursor)) 1799c7679306SThierry Reding drm_plane_cleanup(cursor); 1800c7679306SThierry Reding 180147307954SThierry Reding if (!IS_ERR(primary)) 1802c7679306SThierry Reding drm_plane_cleanup(primary); 1803c7679306SThierry Reding 1804c7679306SThierry Reding if (tegra->domain) { 1805c7679306SThierry Reding iommu_detach_device(tegra->domain, dc->dev); 1806c7679306SThierry Reding dc->domain = NULL; 1807c7679306SThierry Reding } 1808c7679306SThierry Reding 1809c7679306SThierry Reding return err; 1810dee8268fSThierry Reding } 1811dee8268fSThierry Reding 1812dee8268fSThierry Reding static int tegra_dc_exit(struct host1x_client *client) 1813dee8268fSThierry Reding { 1814dee8268fSThierry Reding struct tegra_dc *dc = host1x_client_to_dc(client); 1815dee8268fSThierry Reding int err; 1816dee8268fSThierry Reding 1817dee8268fSThierry Reding devm_free_irq(dc->dev, dc->irq, dc); 1818dee8268fSThierry Reding 1819dee8268fSThierry Reding err = tegra_dc_rgb_exit(dc); 1820dee8268fSThierry Reding if (err) { 1821dee8268fSThierry Reding dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err); 1822dee8268fSThierry Reding return err; 1823dee8268fSThierry Reding } 1824dee8268fSThierry Reding 1825df06b759SThierry Reding if (dc->domain) { 1826df06b759SThierry Reding iommu_detach_device(dc->domain, dc->dev); 1827df06b759SThierry Reding dc->domain = NULL; 1828df06b759SThierry Reding } 1829df06b759SThierry Reding 18302bcdcbfaSThierry Reding host1x_syncpt_free(dc->syncpt); 18312bcdcbfaSThierry Reding 1832dee8268fSThierry Reding return 0; 1833dee8268fSThierry Reding } 1834dee8268fSThierry Reding 1835dee8268fSThierry Reding static const struct host1x_client_ops dc_client_ops = { 1836dee8268fSThierry Reding .init = tegra_dc_init, 1837dee8268fSThierry Reding .exit = tegra_dc_exit, 1838dee8268fSThierry Reding }; 1839dee8268fSThierry Reding 18408620fc62SThierry Reding static const struct tegra_dc_soc_info tegra20_dc_soc_info = { 18417116e9a8SThierry Reding .supports_background_color = false, 18428620fc62SThierry Reding .supports_interlacing = false, 1843e687651bSThierry Reding .supports_cursor = false, 1844c134f019SThierry Reding .supports_block_linear = false, 1845d1f3e1e0SThierry Reding .pitch_align = 8, 18469c012700SThierry Reding .has_powergate = false, 18476ac1571bSDmitry Osipenko .broken_reset = true, 184847307954SThierry Reding .has_nvdisplay = false, 1849511c7023SThierry Reding .num_primary_formats = ARRAY_SIZE(tegra20_primary_formats), 1850511c7023SThierry Reding .primary_formats = tegra20_primary_formats, 1851511c7023SThierry Reding .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), 1852511c7023SThierry Reding .overlay_formats = tegra20_overlay_formats, 18538620fc62SThierry Reding }; 18548620fc62SThierry Reding 18558620fc62SThierry Reding static const struct tegra_dc_soc_info tegra30_dc_soc_info = { 18567116e9a8SThierry Reding .supports_background_color = false, 18578620fc62SThierry Reding .supports_interlacing = false, 1858e687651bSThierry Reding .supports_cursor = false, 1859c134f019SThierry Reding .supports_block_linear = false, 1860d1f3e1e0SThierry Reding .pitch_align = 8, 18619c012700SThierry Reding .has_powergate = false, 18626ac1571bSDmitry Osipenko .broken_reset = false, 186347307954SThierry Reding .has_nvdisplay = false, 1864511c7023SThierry Reding .num_primary_formats = ARRAY_SIZE(tegra20_primary_formats), 1865511c7023SThierry Reding .primary_formats = tegra20_primary_formats, 1866511c7023SThierry Reding .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), 1867511c7023SThierry Reding .overlay_formats = tegra20_overlay_formats, 1868d1f3e1e0SThierry Reding }; 1869d1f3e1e0SThierry Reding 1870d1f3e1e0SThierry Reding static const struct tegra_dc_soc_info tegra114_dc_soc_info = { 18717116e9a8SThierry Reding .supports_background_color = false, 1872d1f3e1e0SThierry Reding .supports_interlacing = false, 1873d1f3e1e0SThierry Reding .supports_cursor = false, 1874d1f3e1e0SThierry Reding .supports_block_linear = false, 1875d1f3e1e0SThierry Reding .pitch_align = 64, 18769c012700SThierry Reding .has_powergate = true, 18776ac1571bSDmitry Osipenko .broken_reset = false, 187847307954SThierry Reding .has_nvdisplay = false, 1879511c7023SThierry Reding .num_primary_formats = ARRAY_SIZE(tegra114_primary_formats), 1880511c7023SThierry Reding .primary_formats = tegra114_primary_formats, 1881511c7023SThierry Reding .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), 1882511c7023SThierry Reding .overlay_formats = tegra114_overlay_formats, 18838620fc62SThierry Reding }; 18848620fc62SThierry Reding 18858620fc62SThierry Reding static const struct tegra_dc_soc_info tegra124_dc_soc_info = { 18867116e9a8SThierry Reding .supports_background_color = true, 18878620fc62SThierry Reding .supports_interlacing = true, 1888e687651bSThierry Reding .supports_cursor = true, 1889c134f019SThierry Reding .supports_block_linear = true, 1890d1f3e1e0SThierry Reding .pitch_align = 64, 18919c012700SThierry Reding .has_powergate = true, 18926ac1571bSDmitry Osipenko .broken_reset = false, 189347307954SThierry Reding .has_nvdisplay = false, 1894511c7023SThierry Reding .num_primary_formats = ARRAY_SIZE(tegra124_primary_formats), 1895511c7023SThierry Reding .primary_formats = tegra114_primary_formats, 1896511c7023SThierry Reding .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats), 1897511c7023SThierry Reding .overlay_formats = tegra114_overlay_formats, 18988620fc62SThierry Reding }; 18998620fc62SThierry Reding 19005b4f516fSThierry Reding static const struct tegra_dc_soc_info tegra210_dc_soc_info = { 19017116e9a8SThierry Reding .supports_background_color = true, 19025b4f516fSThierry Reding .supports_interlacing = true, 19035b4f516fSThierry Reding .supports_cursor = true, 19045b4f516fSThierry Reding .supports_block_linear = true, 19055b4f516fSThierry Reding .pitch_align = 64, 19065b4f516fSThierry Reding .has_powergate = true, 19076ac1571bSDmitry Osipenko .broken_reset = false, 190847307954SThierry Reding .has_nvdisplay = false, 1909511c7023SThierry Reding .num_primary_formats = ARRAY_SIZE(tegra114_primary_formats), 1910511c7023SThierry Reding .primary_formats = tegra114_primary_formats, 1911511c7023SThierry Reding .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), 1912511c7023SThierry Reding .overlay_formats = tegra114_overlay_formats, 191347307954SThierry Reding }; 191447307954SThierry Reding 191547307954SThierry Reding static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { 191647307954SThierry Reding { 191747307954SThierry Reding .index = 0, 191847307954SThierry Reding .dc = 0, 191947307954SThierry Reding .windows = (const unsigned int[]) { 0 }, 192047307954SThierry Reding .num_windows = 1, 192147307954SThierry Reding }, { 192247307954SThierry Reding .index = 1, 192347307954SThierry Reding .dc = 1, 192447307954SThierry Reding .windows = (const unsigned int[]) { 1 }, 192547307954SThierry Reding .num_windows = 1, 192647307954SThierry Reding }, { 192747307954SThierry Reding .index = 2, 192847307954SThierry Reding .dc = 1, 192947307954SThierry Reding .windows = (const unsigned int[]) { 2 }, 193047307954SThierry Reding .num_windows = 1, 193147307954SThierry Reding }, { 193247307954SThierry Reding .index = 3, 193347307954SThierry Reding .dc = 2, 193447307954SThierry Reding .windows = (const unsigned int[]) { 3 }, 193547307954SThierry Reding .num_windows = 1, 193647307954SThierry Reding }, { 193747307954SThierry Reding .index = 4, 193847307954SThierry Reding .dc = 2, 193947307954SThierry Reding .windows = (const unsigned int[]) { 4 }, 194047307954SThierry Reding .num_windows = 1, 194147307954SThierry Reding }, { 194247307954SThierry Reding .index = 5, 194347307954SThierry Reding .dc = 2, 194447307954SThierry Reding .windows = (const unsigned int[]) { 5 }, 194547307954SThierry Reding .num_windows = 1, 194647307954SThierry Reding }, 194747307954SThierry Reding }; 194847307954SThierry Reding 194947307954SThierry Reding static const struct tegra_dc_soc_info tegra186_dc_soc_info = { 195047307954SThierry Reding .supports_background_color = true, 195147307954SThierry Reding .supports_interlacing = true, 195247307954SThierry Reding .supports_cursor = true, 195347307954SThierry Reding .supports_block_linear = true, 195447307954SThierry Reding .pitch_align = 64, 195547307954SThierry Reding .has_powergate = false, 195647307954SThierry Reding .broken_reset = false, 195747307954SThierry Reding .has_nvdisplay = true, 195847307954SThierry Reding .wgrps = tegra186_dc_wgrps, 195947307954SThierry Reding .num_wgrps = ARRAY_SIZE(tegra186_dc_wgrps), 19605b4f516fSThierry Reding }; 19615b4f516fSThierry Reding 19628620fc62SThierry Reding static const struct of_device_id tegra_dc_of_match[] = { 19638620fc62SThierry Reding { 196447307954SThierry Reding .compatible = "nvidia,tegra186-dc", 196547307954SThierry Reding .data = &tegra186_dc_soc_info, 196647307954SThierry Reding }, { 19675b4f516fSThierry Reding .compatible = "nvidia,tegra210-dc", 19685b4f516fSThierry Reding .data = &tegra210_dc_soc_info, 19695b4f516fSThierry Reding }, { 19708620fc62SThierry Reding .compatible = "nvidia,tegra124-dc", 19718620fc62SThierry Reding .data = &tegra124_dc_soc_info, 19728620fc62SThierry Reding }, { 19739c012700SThierry Reding .compatible = "nvidia,tegra114-dc", 19749c012700SThierry Reding .data = &tegra114_dc_soc_info, 19759c012700SThierry Reding }, { 19768620fc62SThierry Reding .compatible = "nvidia,tegra30-dc", 19778620fc62SThierry Reding .data = &tegra30_dc_soc_info, 19788620fc62SThierry Reding }, { 19798620fc62SThierry Reding .compatible = "nvidia,tegra20-dc", 19808620fc62SThierry Reding .data = &tegra20_dc_soc_info, 19818620fc62SThierry Reding }, { 19828620fc62SThierry Reding /* sentinel */ 19838620fc62SThierry Reding } 19848620fc62SThierry Reding }; 1985ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_dc_of_match); 19868620fc62SThierry Reding 198713411dddSThierry Reding static int tegra_dc_parse_dt(struct tegra_dc *dc) 198813411dddSThierry Reding { 198913411dddSThierry Reding struct device_node *np; 199013411dddSThierry Reding u32 value = 0; 199113411dddSThierry Reding int err; 199213411dddSThierry Reding 199313411dddSThierry Reding err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value); 199413411dddSThierry Reding if (err < 0) { 199513411dddSThierry Reding dev_err(dc->dev, "missing \"nvidia,head\" property\n"); 199613411dddSThierry Reding 199713411dddSThierry Reding /* 199813411dddSThierry Reding * If the nvidia,head property isn't present, try to find the 199913411dddSThierry Reding * correct head number by looking up the position of this 200013411dddSThierry Reding * display controller's node within the device tree. Assuming 200113411dddSThierry Reding * that the nodes are ordered properly in the DTS file and 200213411dddSThierry Reding * that the translation into a flattened device tree blob 200313411dddSThierry Reding * preserves that ordering this will actually yield the right 200413411dddSThierry Reding * head number. 200513411dddSThierry Reding * 200613411dddSThierry Reding * If those assumptions don't hold, this will still work for 200713411dddSThierry Reding * cases where only a single display controller is used. 200813411dddSThierry Reding */ 200913411dddSThierry Reding for_each_matching_node(np, tegra_dc_of_match) { 2010cf6b1744SJulia Lawall if (np == dc->dev->of_node) { 2011cf6b1744SJulia Lawall of_node_put(np); 201213411dddSThierry Reding break; 2013cf6b1744SJulia Lawall } 201413411dddSThierry Reding 201513411dddSThierry Reding value++; 201613411dddSThierry Reding } 201713411dddSThierry Reding } 201813411dddSThierry Reding 201913411dddSThierry Reding dc->pipe = value; 202013411dddSThierry Reding 202113411dddSThierry Reding return 0; 202213411dddSThierry Reding } 202313411dddSThierry Reding 2024dee8268fSThierry Reding static int tegra_dc_probe(struct platform_device *pdev) 2025dee8268fSThierry Reding { 2026dee8268fSThierry Reding struct resource *regs; 2027dee8268fSThierry Reding struct tegra_dc *dc; 2028dee8268fSThierry Reding int err; 2029dee8268fSThierry Reding 2030dee8268fSThierry Reding dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); 2031dee8268fSThierry Reding if (!dc) 2032dee8268fSThierry Reding return -ENOMEM; 2033dee8268fSThierry Reding 2034b9ff7aeaSThierry Reding dc->soc = of_device_get_match_data(&pdev->dev); 20358620fc62SThierry Reding 2036dee8268fSThierry Reding spin_lock_init(&dc->lock); 2037dee8268fSThierry Reding INIT_LIST_HEAD(&dc->list); 2038dee8268fSThierry Reding dc->dev = &pdev->dev; 2039dee8268fSThierry Reding 204013411dddSThierry Reding err = tegra_dc_parse_dt(dc); 204113411dddSThierry Reding if (err < 0) 204213411dddSThierry Reding return err; 204313411dddSThierry Reding 2044dee8268fSThierry Reding dc->clk = devm_clk_get(&pdev->dev, NULL); 2045dee8268fSThierry Reding if (IS_ERR(dc->clk)) { 2046dee8268fSThierry Reding dev_err(&pdev->dev, "failed to get clock\n"); 2047dee8268fSThierry Reding return PTR_ERR(dc->clk); 2048dee8268fSThierry Reding } 2049dee8268fSThierry Reding 2050ca48080aSStephen Warren dc->rst = devm_reset_control_get(&pdev->dev, "dc"); 2051ca48080aSStephen Warren if (IS_ERR(dc->rst)) { 2052ca48080aSStephen Warren dev_err(&pdev->dev, "failed to get reset\n"); 2053ca48080aSStephen Warren return PTR_ERR(dc->rst); 2054ca48080aSStephen Warren } 2055ca48080aSStephen Warren 2056a2f2f740SThierry Reding /* assert reset and disable clock */ 2057a2f2f740SThierry Reding if (!dc->soc->broken_reset) { 2058a2f2f740SThierry Reding err = clk_prepare_enable(dc->clk); 2059a2f2f740SThierry Reding if (err < 0) 2060a2f2f740SThierry Reding return err; 2061a2f2f740SThierry Reding 2062a2f2f740SThierry Reding usleep_range(2000, 4000); 2063a2f2f740SThierry Reding 2064a2f2f740SThierry Reding err = reset_control_assert(dc->rst); 2065a2f2f740SThierry Reding if (err < 0) 2066a2f2f740SThierry Reding return err; 2067a2f2f740SThierry Reding 2068a2f2f740SThierry Reding usleep_range(2000, 4000); 2069a2f2f740SThierry Reding 2070a2f2f740SThierry Reding clk_disable_unprepare(dc->clk); 2071a2f2f740SThierry Reding } 207233a8eb8dSThierry Reding 20739c012700SThierry Reding if (dc->soc->has_powergate) { 20749c012700SThierry Reding if (dc->pipe == 0) 20759c012700SThierry Reding dc->powergate = TEGRA_POWERGATE_DIS; 20769c012700SThierry Reding else 20779c012700SThierry Reding dc->powergate = TEGRA_POWERGATE_DISB; 20789c012700SThierry Reding 207933a8eb8dSThierry Reding tegra_powergate_power_off(dc->powergate); 20809c012700SThierry Reding } 2081dee8268fSThierry Reding 2082dee8268fSThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2083dee8268fSThierry Reding dc->regs = devm_ioremap_resource(&pdev->dev, regs); 2084dee8268fSThierry Reding if (IS_ERR(dc->regs)) 2085dee8268fSThierry Reding return PTR_ERR(dc->regs); 2086dee8268fSThierry Reding 2087dee8268fSThierry Reding dc->irq = platform_get_irq(pdev, 0); 2088dee8268fSThierry Reding if (dc->irq < 0) { 2089dee8268fSThierry Reding dev_err(&pdev->dev, "failed to get IRQ\n"); 2090dee8268fSThierry Reding return -ENXIO; 2091dee8268fSThierry Reding } 2092dee8268fSThierry Reding 2093dee8268fSThierry Reding err = tegra_dc_rgb_probe(dc); 2094dee8268fSThierry Reding if (err < 0 && err != -ENODEV) { 2095dee8268fSThierry Reding dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); 2096dee8268fSThierry Reding return err; 2097dee8268fSThierry Reding } 2098dee8268fSThierry Reding 209933a8eb8dSThierry Reding platform_set_drvdata(pdev, dc); 210033a8eb8dSThierry Reding pm_runtime_enable(&pdev->dev); 210133a8eb8dSThierry Reding 210233a8eb8dSThierry Reding INIT_LIST_HEAD(&dc->client.list); 210333a8eb8dSThierry Reding dc->client.ops = &dc_client_ops; 210433a8eb8dSThierry Reding dc->client.dev = &pdev->dev; 210533a8eb8dSThierry Reding 2106dee8268fSThierry Reding err = host1x_client_register(&dc->client); 2107dee8268fSThierry Reding if (err < 0) { 2108dee8268fSThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 2109dee8268fSThierry Reding err); 2110dee8268fSThierry Reding return err; 2111dee8268fSThierry Reding } 2112dee8268fSThierry Reding 2113dee8268fSThierry Reding return 0; 2114dee8268fSThierry Reding } 2115dee8268fSThierry Reding 2116dee8268fSThierry Reding static int tegra_dc_remove(struct platform_device *pdev) 2117dee8268fSThierry Reding { 2118dee8268fSThierry Reding struct tegra_dc *dc = platform_get_drvdata(pdev); 2119dee8268fSThierry Reding int err; 2120dee8268fSThierry Reding 2121dee8268fSThierry Reding err = host1x_client_unregister(&dc->client); 2122dee8268fSThierry Reding if (err < 0) { 2123dee8268fSThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 2124dee8268fSThierry Reding err); 2125dee8268fSThierry Reding return err; 2126dee8268fSThierry Reding } 2127dee8268fSThierry Reding 212859d29c0eSThierry Reding err = tegra_dc_rgb_remove(dc); 212959d29c0eSThierry Reding if (err < 0) { 213059d29c0eSThierry Reding dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err); 213159d29c0eSThierry Reding return err; 213259d29c0eSThierry Reding } 213359d29c0eSThierry Reding 213433a8eb8dSThierry Reding pm_runtime_disable(&pdev->dev); 213533a8eb8dSThierry Reding 213633a8eb8dSThierry Reding return 0; 213733a8eb8dSThierry Reding } 213833a8eb8dSThierry Reding 213933a8eb8dSThierry Reding #ifdef CONFIG_PM 214033a8eb8dSThierry Reding static int tegra_dc_suspend(struct device *dev) 214133a8eb8dSThierry Reding { 214233a8eb8dSThierry Reding struct tegra_dc *dc = dev_get_drvdata(dev); 214333a8eb8dSThierry Reding int err; 214433a8eb8dSThierry Reding 21456ac1571bSDmitry Osipenko if (!dc->soc->broken_reset) { 214633a8eb8dSThierry Reding err = reset_control_assert(dc->rst); 214733a8eb8dSThierry Reding if (err < 0) { 214833a8eb8dSThierry Reding dev_err(dev, "failed to assert reset: %d\n", err); 214933a8eb8dSThierry Reding return err; 215033a8eb8dSThierry Reding } 21516ac1571bSDmitry Osipenko } 21529c012700SThierry Reding 21539c012700SThierry Reding if (dc->soc->has_powergate) 21549c012700SThierry Reding tegra_powergate_power_off(dc->powergate); 21559c012700SThierry Reding 2156dee8268fSThierry Reding clk_disable_unprepare(dc->clk); 2157dee8268fSThierry Reding 2158dee8268fSThierry Reding return 0; 2159dee8268fSThierry Reding } 2160dee8268fSThierry Reding 216133a8eb8dSThierry Reding static int tegra_dc_resume(struct device *dev) 216233a8eb8dSThierry Reding { 216333a8eb8dSThierry Reding struct tegra_dc *dc = dev_get_drvdata(dev); 216433a8eb8dSThierry Reding int err; 216533a8eb8dSThierry Reding 216633a8eb8dSThierry Reding if (dc->soc->has_powergate) { 216733a8eb8dSThierry Reding err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, 216833a8eb8dSThierry Reding dc->rst); 216933a8eb8dSThierry Reding if (err < 0) { 217033a8eb8dSThierry Reding dev_err(dev, "failed to power partition: %d\n", err); 217133a8eb8dSThierry Reding return err; 217233a8eb8dSThierry Reding } 217333a8eb8dSThierry Reding } else { 217433a8eb8dSThierry Reding err = clk_prepare_enable(dc->clk); 217533a8eb8dSThierry Reding if (err < 0) { 217633a8eb8dSThierry Reding dev_err(dev, "failed to enable clock: %d\n", err); 217733a8eb8dSThierry Reding return err; 217833a8eb8dSThierry Reding } 217933a8eb8dSThierry Reding 21806ac1571bSDmitry Osipenko if (!dc->soc->broken_reset) { 218133a8eb8dSThierry Reding err = reset_control_deassert(dc->rst); 218233a8eb8dSThierry Reding if (err < 0) { 21836ac1571bSDmitry Osipenko dev_err(dev, 21846ac1571bSDmitry Osipenko "failed to deassert reset: %d\n", err); 218533a8eb8dSThierry Reding return err; 218633a8eb8dSThierry Reding } 218733a8eb8dSThierry Reding } 21886ac1571bSDmitry Osipenko } 218933a8eb8dSThierry Reding 219033a8eb8dSThierry Reding return 0; 219133a8eb8dSThierry Reding } 219233a8eb8dSThierry Reding #endif 219333a8eb8dSThierry Reding 219433a8eb8dSThierry Reding static const struct dev_pm_ops tegra_dc_pm_ops = { 219533a8eb8dSThierry Reding SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL) 219633a8eb8dSThierry Reding }; 219733a8eb8dSThierry Reding 2198dee8268fSThierry Reding struct platform_driver tegra_dc_driver = { 2199dee8268fSThierry Reding .driver = { 2200dee8268fSThierry Reding .name = "tegra-dc", 2201dee8268fSThierry Reding .of_match_table = tegra_dc_of_match, 220233a8eb8dSThierry Reding .pm = &tegra_dc_pm_ops, 2203dee8268fSThierry Reding }, 2204dee8268fSThierry Reding .probe = tegra_dc_probe, 2205dee8268fSThierry Reding .remove = tegra_dc_remove, 2206dee8268fSThierry Reding }; 2207