3291 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2012 Avionic Design GmbH4 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.5 */6 7#include <linux/clk.h>8#include <linux/debugfs.h>9#include <linux/delay.h>10#include <linux/dma-mapping.h>11#include <linux/iommu.h>12#include <linux/interconnect.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/pm_domain.h>17#include <linux/pm_opp.h>18#include <linux/pm_runtime.h>19#include <linux/reset.h>20 21#include <soc/tegra/common.h>22#include <soc/tegra/pmc.h>23 24#include <drm/drm_atomic.h>25#include <drm/drm_atomic_helper.h>26#include <drm/drm_blend.h>27#include <drm/drm_debugfs.h>28#include <drm/drm_fourcc.h>29#include <drm/drm_framebuffer.h>30#include <drm/drm_vblank.h>31 32#include "dc.h"33#include "drm.h"34#include "gem.h"35#include "hub.h"36#include "plane.h"37 38static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,39 struct drm_crtc_state *state);40 41static void tegra_dc_stats_reset(struct tegra_dc_stats *stats)42{43 stats->frames = 0;44 stats->vblank = 0;45 stats->underflow = 0;46 stats->overflow = 0;47}48 49/* Reads the active copy of a register. */50static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset)51{52 u32 value;53 54 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);55 value = tegra_dc_readl(dc, offset);56 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);57 58 return value;59}60 61static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,62 unsigned int offset)63{64 if (offset >= 0x500 && offset <= 0x638) {65 offset = 0x000 + (offset - 0x500);66 return plane->offset + offset;67 }68 69 if (offset >= 0x700 && offset <= 0x719) {70 offset = 0x180 + (offset - 0x700);71 return plane->offset + offset;72 }73 74 if (offset >= 0x800 && offset <= 0x839) {75 offset = 0x1c0 + (offset - 0x800);76 return plane->offset + offset;77 }78 79 dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset);80 81 return plane->offset + offset;82}83 84static inline u32 tegra_plane_readl(struct tegra_plane *plane,85 unsigned int offset)86{87 return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));88}89 90static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value,91 unsigned int offset)92{93 tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));94}95 96bool tegra_dc_has_output(struct tegra_dc *dc, struct device *dev)97{98 struct device_node *np = dc->dev->of_node;99 struct of_phandle_iterator it;100 int err;101 102 of_for_each_phandle(&it, err, np, "nvidia,outputs", NULL, 0)103 if (it.node == dev->of_node)104 return true;105 106 return false;107}108 109/*110 * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the111 * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy.112 * Latching happens mmediately if the display controller is in STOP mode or113 * on the next frame boundary otherwise.114 *115 * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The116 * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits117 * are written. When the *_ACT_REQ bits are written, the ARM copy is latched118 * into the ACTIVE copy, either immediately if the display controller is in119 * STOP mode, or at the next frame boundary otherwise.120 */121void tegra_dc_commit(struct tegra_dc *dc)122{123 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);124 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);125}126 127static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v,128 unsigned int bpp)129{130 fixed20_12 outf = dfixed_init(out);131 fixed20_12 inf = dfixed_init(in);132 u32 dda_inc;133 int max;134 135 if (v)136 max = 15;137 else {138 switch (bpp) {139 case 2:140 max = 8;141 break;142 143 default:144 WARN_ON_ONCE(1);145 fallthrough;146 case 4:147 max = 4;148 break;149 }150 }151 152 outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1));153 inf.full -= dfixed_const(1);154 155 dda_inc = dfixed_div(inf, outf);156 dda_inc = min_t(u32, dda_inc, dfixed_const(max));157 158 return dda_inc;159}160 161static inline u32 compute_initial_dda(unsigned int in)162{163 fixed20_12 inf = dfixed_init(in);164 return dfixed_frac(inf);165}166 167static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)168{169 u32 background[3] = {170 BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,171 BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,172 BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,173 };174 u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) |175 BLEND_COLOR_KEY_NONE;176 u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);177 struct tegra_plane_state *state;178 u32 blending[2];179 unsigned int i;180 181 /* disable blending for non-overlapping case */182 tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);183 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);184 185 state = to_tegra_plane_state(plane->base.state);186 187 if (state->opaque) {188 /*189 * Since custom fix-weight blending isn't utilized and weight190 * of top window is set to max, we can enforce dependent191 * blending which in this case results in transparent bottom192 * window if top window is opaque and if top window enables193 * alpha blending, then bottom window is getting alpha value194 * of 1 minus the sum of alpha components of the overlapping195 * plane.196 */197 background[0] |= BLEND_CONTROL_DEPENDENT;198 background[1] |= BLEND_CONTROL_DEPENDENT;199 200 /*201 * The region where three windows overlap is the intersection202 * of the two regions where two windows overlap. It contributes203 * to the area if all of the windows on top of it have an alpha204 * component.205 */206 switch (state->base.normalized_zpos) {207 case 0:208 if (state->blending[0].alpha &&209 state->blending[1].alpha)210 background[2] |= BLEND_CONTROL_DEPENDENT;211 break;212 213 case 1:214 background[2] |= BLEND_CONTROL_DEPENDENT;215 break;216 }217 } else {218 /*219 * Enable alpha blending if pixel format has an alpha220 * component.221 */222 foreground |= BLEND_CONTROL_ALPHA;223 224 /*225 * If any of the windows on top of this window is opaque, it226 * will completely conceal this window within that area. If227 * top window has an alpha component, it is blended over the228 * bottom window.229 */230 for (i = 0; i < 2; i++) {231 if (state->blending[i].alpha &&232 state->blending[i].top)233 background[i] |= BLEND_CONTROL_DEPENDENT;234 }235 236 switch (state->base.normalized_zpos) {237 case 0:238 if (state->blending[0].alpha &&239 state->blending[1].alpha)240 background[2] |= BLEND_CONTROL_DEPENDENT;241 break;242 243 case 1:244 /*245 * When both middle and topmost windows have an alpha,246 * these windows a mixed together and then the result247 * is blended over the bottom window.248 */249 if (state->blending[0].alpha &&250 state->blending[0].top)251 background[2] |= BLEND_CONTROL_ALPHA;252 253 if (state->blending[1].alpha &&254 state->blending[1].top)255 background[2] |= BLEND_CONTROL_ALPHA;256 break;257 }258 }259 260 switch (state->base.normalized_zpos) {261 case 0:262 tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);263 tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);264 tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);265 break;266 267 case 1:268 /*269 * If window B / C is topmost, then X / Y registers are270 * matching the order of blending[...] state indices,271 * otherwise a swap is required.272 */273 if (!state->blending[0].top && state->blending[1].top) {274 blending[0] = foreground;275 blending[1] = background[1];276 } else {277 blending[0] = background[0];278 blending[1] = foreground;279 }280 281 tegra_plane_writel(plane, blending[0], DC_WIN_BLEND_2WIN_X);282 tegra_plane_writel(plane, blending[1], DC_WIN_BLEND_2WIN_Y);283 tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);284 break;285 286 case 2:287 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);288 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_Y);289 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_3WIN_XY);290 break;291 }292}293 294static void tegra_plane_setup_blending(struct tegra_plane *plane,295 const struct tegra_dc_window *window)296{297 u32 value;298 299 value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |300 BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |301 BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;302 tegra_plane_writel(plane, value, DC_WIN_BLEND_MATCH_SELECT);303 304 value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |305 BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |306 BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;307 tegra_plane_writel(plane, value, DC_WIN_BLEND_NOMATCH_SELECT);308 309 value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - window->zpos);310 tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL);311}312 313static bool314tegra_plane_use_horizontal_filtering(struct tegra_plane *plane,315 const struct tegra_dc_window *window)316{317 struct tegra_dc *dc = plane->dc;318 319 if (window->src.w == window->dst.w)320 return false;321 322 if (plane->index == 0 && dc->soc->has_win_a_without_filters)323 return false;324 325 return true;326}327 328static bool329tegra_plane_use_vertical_filtering(struct tegra_plane *plane,330 const struct tegra_dc_window *window)331{332 struct tegra_dc *dc = plane->dc;333 334 if (window->src.h == window->dst.h)335 return false;336 337 if (plane->index == 0 && dc->soc->has_win_a_without_filters)338 return false;339 340 if (plane->index == 2 && dc->soc->has_win_c_without_vert_filter)341 return false;342 343 return true;344}345 346static void tegra_dc_setup_window(struct tegra_plane *plane,347 const struct tegra_dc_window *window)348{349 unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;350 struct tegra_dc *dc = plane->dc;351 unsigned int planes;352 u32 value;353 bool yuv;354 355 /*356 * For YUV planar modes, the number of bytes per pixel takes into357 * account only the luma component and therefore is 1.358 */359 yuv = tegra_plane_format_is_yuv(window->format, &planes, NULL);360 if (!yuv)361 bpp = window->bits_per_pixel / 8;362 else363 bpp = (planes > 1) ? 1 : 2;364 365 tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH);366 tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP);367 368 value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x);369 tegra_plane_writel(plane, value, DC_WIN_POSITION);370 371 value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w);372 tegra_plane_writel(plane, value, DC_WIN_SIZE);373 374 h_offset = window->src.x * bpp;375 v_offset = window->src.y;376 h_size = window->src.w * bpp;377 v_size = window->src.h;378 379 if (window->reflect_x)380 h_offset += (window->src.w - 1) * bpp;381 382 if (window->reflect_y)383 v_offset += window->src.h - 1;384 385 value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size);386 tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE);387 388 /*389 * For DDA computations the number of bytes per pixel for YUV planar390 * modes needs to take into account all Y, U and V components.391 */392 if (yuv && planes > 1)393 bpp = 2;394 395 h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);396 v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp);397 398 value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda);399 tegra_plane_writel(plane, value, DC_WIN_DDA_INC);400 401 h_dda = compute_initial_dda(window->src.x);402 v_dda = compute_initial_dda(window->src.y);403 404 tegra_plane_writel(plane, h_dda, DC_WIN_H_INITIAL_DDA);405 tegra_plane_writel(plane, v_dda, DC_WIN_V_INITIAL_DDA);406 407 tegra_plane_writel(plane, 0, DC_WIN_UV_BUF_STRIDE);408 tegra_plane_writel(plane, 0, DC_WIN_BUF_STRIDE);409 410 tegra_plane_writel(plane, window->base[0], DC_WINBUF_START_ADDR);411 412 if (yuv && planes > 1) {413 tegra_plane_writel(plane, window->base[1], DC_WINBUF_START_ADDR_U);414 415 if (planes > 2)416 tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);417 418 value = window->stride[1] << 16 | window->stride[0];419 tegra_plane_writel(plane, value, DC_WIN_LINE_STRIDE);420 } else {421 tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE);422 }423 424 tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET);425 tegra_plane_writel(plane, v_offset, DC_WINBUF_ADDR_V_OFFSET);426 427 if (dc->soc->supports_block_linear) {428 unsigned long height = window->tiling.value;429 430 switch (window->tiling.mode) {431 case TEGRA_BO_TILING_MODE_PITCH:432 value = DC_WINBUF_SURFACE_KIND_PITCH;433 break;434 435 case TEGRA_BO_TILING_MODE_TILED:436 value = DC_WINBUF_SURFACE_KIND_TILED;437 break;438 439 case TEGRA_BO_TILING_MODE_BLOCK:440 value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |441 DC_WINBUF_SURFACE_KIND_BLOCK;442 break;443 }444 445 tegra_plane_writel(plane, value, DC_WINBUF_SURFACE_KIND);446 } else {447 switch (window->tiling.mode) {448 case TEGRA_BO_TILING_MODE_PITCH:449 value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |450 DC_WIN_BUFFER_ADDR_MODE_LINEAR;451 break;452 453 case TEGRA_BO_TILING_MODE_TILED:454 value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |455 DC_WIN_BUFFER_ADDR_MODE_TILE;456 break;457 458 case TEGRA_BO_TILING_MODE_BLOCK:459 /*460 * No need to handle this here because ->atomic_check461 * will already have filtered it out.462 */463 break;464 }465 466 tegra_plane_writel(plane, value, DC_WIN_BUFFER_ADDR_MODE);467 }468 469 value = WIN_ENABLE;470 471 if (yuv) {472 /* setup default colorspace conversion coefficients */473 tegra_plane_writel(plane, 0x00f0, DC_WIN_CSC_YOF);474 tegra_plane_writel(plane, 0x012a, DC_WIN_CSC_KYRGB);475 tegra_plane_writel(plane, 0x0000, DC_WIN_CSC_KUR);476 tegra_plane_writel(plane, 0x0198, DC_WIN_CSC_KVR);477 tegra_plane_writel(plane, 0x039b, DC_WIN_CSC_KUG);478 tegra_plane_writel(plane, 0x032f, DC_WIN_CSC_KVG);479 tegra_plane_writel(plane, 0x0204, DC_WIN_CSC_KUB);480 tegra_plane_writel(plane, 0x0000, DC_WIN_CSC_KVB);481 482 value |= CSC_ENABLE;483 } else if (window->bits_per_pixel < 24) {484 value |= COLOR_EXPAND;485 }486 487 if (window->reflect_x)488 value |= H_DIRECTION;489 490 if (window->reflect_y)491 value |= V_DIRECTION;492 493 if (tegra_plane_use_horizontal_filtering(plane, window)) {494 /*495 * Enable horizontal 6-tap filter and set filtering496 * coefficients to the default values defined in TRM.497 */498 tegra_plane_writel(plane, 0x00008000, DC_WIN_H_FILTER_P(0));499 tegra_plane_writel(plane, 0x3e087ce1, DC_WIN_H_FILTER_P(1));500 tegra_plane_writel(plane, 0x3b117ac1, DC_WIN_H_FILTER_P(2));501 tegra_plane_writel(plane, 0x591b73aa, DC_WIN_H_FILTER_P(3));502 tegra_plane_writel(plane, 0x57256d9a, DC_WIN_H_FILTER_P(4));503 tegra_plane_writel(plane, 0x552f668b, DC_WIN_H_FILTER_P(5));504 tegra_plane_writel(plane, 0x73385e8b, DC_WIN_H_FILTER_P(6));505 tegra_plane_writel(plane, 0x72435583, DC_WIN_H_FILTER_P(7));506 tegra_plane_writel(plane, 0x714c4c8b, DC_WIN_H_FILTER_P(8));507 tegra_plane_writel(plane, 0x70554393, DC_WIN_H_FILTER_P(9));508 tegra_plane_writel(plane, 0x715e389b, DC_WIN_H_FILTER_P(10));509 tegra_plane_writel(plane, 0x71662faa, DC_WIN_H_FILTER_P(11));510 tegra_plane_writel(plane, 0x536d25ba, DC_WIN_H_FILTER_P(12));511 tegra_plane_writel(plane, 0x55731bca, DC_WIN_H_FILTER_P(13));512 tegra_plane_writel(plane, 0x387a11d9, DC_WIN_H_FILTER_P(14));513 tegra_plane_writel(plane, 0x3c7c08f1, DC_WIN_H_FILTER_P(15));514 515 value |= H_FILTER;516 }517 518 if (tegra_plane_use_vertical_filtering(plane, window)) {519 unsigned int i, k;520 521 /*522 * Enable vertical 2-tap filter and set filtering523 * coefficients to the default values defined in TRM.524 */525 for (i = 0, k = 128; i < 16; i++, k -= 8)526 tegra_plane_writel(plane, k, DC_WIN_V_FILTER_P(i));527 528 value |= V_FILTER;529 }530 531 tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS);532 533 if (dc->soc->has_legacy_blending)534 tegra_plane_setup_blending_legacy(plane);535 else536 tegra_plane_setup_blending(plane, window);537}538 539static const u32 tegra20_primary_formats[] = {540 DRM_FORMAT_ARGB4444,541 DRM_FORMAT_ARGB1555,542 DRM_FORMAT_RGB565,543 DRM_FORMAT_RGBA5551,544 DRM_FORMAT_ABGR8888,545 DRM_FORMAT_ARGB8888,546 /* non-native formats */547 DRM_FORMAT_XRGB1555,548 DRM_FORMAT_RGBX5551,549 DRM_FORMAT_XBGR8888,550 DRM_FORMAT_XRGB8888,551};552 553static const u64 tegra20_modifiers[] = {554 DRM_FORMAT_MOD_LINEAR,555 DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED,556 DRM_FORMAT_MOD_INVALID557};558 559static const u32 tegra114_primary_formats[] = {560 DRM_FORMAT_ARGB4444,561 DRM_FORMAT_ARGB1555,562 DRM_FORMAT_RGB565,563 DRM_FORMAT_RGBA5551,564 DRM_FORMAT_ABGR8888,565 DRM_FORMAT_ARGB8888,566 /* new on Tegra114 */567 DRM_FORMAT_ABGR4444,568 DRM_FORMAT_ABGR1555,569 DRM_FORMAT_BGRA5551,570 DRM_FORMAT_XRGB1555,571 DRM_FORMAT_RGBX5551,572 DRM_FORMAT_XBGR1555,573 DRM_FORMAT_BGRX5551,574 DRM_FORMAT_BGR565,575 DRM_FORMAT_BGRA8888,576 DRM_FORMAT_RGBA8888,577 DRM_FORMAT_XRGB8888,578 DRM_FORMAT_XBGR8888,579};580 581static const u32 tegra124_primary_formats[] = {582 DRM_FORMAT_ARGB4444,583 DRM_FORMAT_ARGB1555,584 DRM_FORMAT_RGB565,585 DRM_FORMAT_RGBA5551,586 DRM_FORMAT_ABGR8888,587 DRM_FORMAT_ARGB8888,588 /* new on Tegra114 */589 DRM_FORMAT_ABGR4444,590 DRM_FORMAT_ABGR1555,591 DRM_FORMAT_BGRA5551,592 DRM_FORMAT_XRGB1555,593 DRM_FORMAT_RGBX5551,594 DRM_FORMAT_XBGR1555,595 DRM_FORMAT_BGRX5551,596 DRM_FORMAT_BGR565,597 DRM_FORMAT_BGRA8888,598 DRM_FORMAT_RGBA8888,599 DRM_FORMAT_XRGB8888,600 DRM_FORMAT_XBGR8888,601 /* new on Tegra124 */602 DRM_FORMAT_RGBX8888,603 DRM_FORMAT_BGRX8888,604};605 606static const u64 tegra124_modifiers[] = {607 DRM_FORMAT_MOD_LINEAR,608 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),609 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),610 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),611 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),612 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),613 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),614 DRM_FORMAT_MOD_INVALID615};616 617static int tegra_plane_atomic_check(struct drm_plane *plane,618 struct drm_atomic_state *state)619{620 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,621 plane);622 struct tegra_plane_state *plane_state = to_tegra_plane_state(new_plane_state);623 unsigned int supported_rotation = DRM_MODE_ROTATE_0 |624 DRM_MODE_REFLECT_X |625 DRM_MODE_REFLECT_Y;626 unsigned int rotation = new_plane_state->rotation;627 struct tegra_bo_tiling *tiling = &plane_state->tiling;628 struct tegra_plane *tegra = to_tegra_plane(plane);629 struct tegra_dc *dc = to_tegra_dc(new_plane_state->crtc);630 int err;631 632 plane_state->peak_memory_bandwidth = 0;633 plane_state->avg_memory_bandwidth = 0;634 635 /* no need for further checks if the plane is being disabled */636 if (!new_plane_state->crtc) {637 plane_state->total_peak_memory_bandwidth = 0;638 return 0;639 }640 641 err = tegra_plane_format(new_plane_state->fb->format->format,642 &plane_state->format,643 &plane_state->swap);644 if (err < 0)645 return err;646 647 /*648 * Tegra20 and Tegra30 are special cases here because they support649 * only variants of specific formats with an alpha component, but not650 * the corresponding opaque formats. However, the opaque formats can651 * be emulated by disabling alpha blending for the plane.652 */653 if (dc->soc->has_legacy_blending) {654 err = tegra_plane_setup_legacy_state(tegra, plane_state);655 if (err < 0)656 return err;657 }658 659 err = tegra_fb_get_tiling(new_plane_state->fb, tiling);660 if (err < 0)661 return err;662 663 if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&664 !dc->soc->supports_block_linear) {665 DRM_ERROR("hardware doesn't support block linear mode\n");666 return -EINVAL;667 }668 669 /*670 * Older userspace used custom BO flag in order to specify the Y671 * reflection, while modern userspace uses the generic DRM rotation672 * property in order to achieve the same result. The legacy BO flag673 * duplicates the DRM rotation property when both are set.674 */675 if (tegra_fb_is_bottom_up(new_plane_state->fb))676 rotation |= DRM_MODE_REFLECT_Y;677 678 rotation = drm_rotation_simplify(rotation, supported_rotation);679 680 if (rotation & DRM_MODE_REFLECT_X)681 plane_state->reflect_x = true;682 else683 plane_state->reflect_x = false;684 685 if (rotation & DRM_MODE_REFLECT_Y)686 plane_state->reflect_y = true;687 else688 plane_state->reflect_y = false;689 690 /*691 * Tegra doesn't support different strides for U and V planes so we692 * error out if the user tries to display a framebuffer with such a693 * configuration.694 */695 if (new_plane_state->fb->format->num_planes > 2) {696 if (new_plane_state->fb->pitches[2] != new_plane_state->fb->pitches[1]) {697 DRM_ERROR("unsupported UV-plane configuration\n");698 return -EINVAL;699 }700 }701 702 err = tegra_plane_state_add(tegra, new_plane_state);703 if (err < 0)704 return err;705 706 return 0;707}708 709static void tegra_plane_atomic_disable(struct drm_plane *plane,710 struct drm_atomic_state *state)711{712 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,713 plane);714 struct tegra_plane *p = to_tegra_plane(plane);715 u32 value;716 717 /* rien ne va plus */718 if (!old_state || !old_state->crtc)719 return;720 721 value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS);722 value &= ~WIN_ENABLE;723 tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);724}725 726static void tegra_plane_atomic_update(struct drm_plane *plane,727 struct drm_atomic_state *state)728{729 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,730 plane);731 struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state);732 struct drm_framebuffer *fb = new_state->fb;733 struct tegra_plane *p = to_tegra_plane(plane);734 struct tegra_dc_window window;735 unsigned int i;736 737 /* rien ne va plus */738 if (!new_state->crtc || !new_state->fb)739 return;740 741 if (!new_state->visible)742 return tegra_plane_atomic_disable(plane, state);743 744 memset(&window, 0, sizeof(window));745 window.src.x = new_state->src.x1 >> 16;746 window.src.y = new_state->src.y1 >> 16;747 window.src.w = drm_rect_width(&new_state->src) >> 16;748 window.src.h = drm_rect_height(&new_state->src) >> 16;749 window.dst.x = new_state->dst.x1;750 window.dst.y = new_state->dst.y1;751 window.dst.w = drm_rect_width(&new_state->dst);752 window.dst.h = drm_rect_height(&new_state->dst);753 window.bits_per_pixel = fb->format->cpp[0] * 8;754 window.reflect_x = tegra_plane_state->reflect_x;755 window.reflect_y = tegra_plane_state->reflect_y;756 757 /* copy from state */758 window.zpos = new_state->normalized_zpos;759 window.tiling = tegra_plane_state->tiling;760 window.format = tegra_plane_state->format;761 window.swap = tegra_plane_state->swap;762 763 for (i = 0; i < fb->format->num_planes; i++) {764 window.base[i] = tegra_plane_state->iova[i] + fb->offsets[i];765 766 /*767 * Tegra uses a shared stride for UV planes. Framebuffers are768 * already checked for this in the tegra_plane_atomic_check()769 * function, so it's safe to ignore the V-plane pitch here.770 */771 if (i < 2)772 window.stride[i] = fb->pitches[i];773 }774 775 tegra_dc_setup_window(p, &window);776}777 778static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {779 .prepare_fb = tegra_plane_prepare_fb,780 .cleanup_fb = tegra_plane_cleanup_fb,781 .atomic_check = tegra_plane_atomic_check,782 .atomic_disable = tegra_plane_atomic_disable,783 .atomic_update = tegra_plane_atomic_update,784};785 786static unsigned long tegra_plane_get_possible_crtcs(struct drm_device *drm)787{788 /*789 * Ideally this would use drm_crtc_mask(), but that would require the790 * CRTC to already be in the mode_config's list of CRTCs. However, it791 * will only be added to that list in the drm_crtc_init_with_planes()792 * (in tegra_dc_init()), which in turn requires registration of these793 * planes. So we have ourselves a nice little chicken and egg problem794 * here.795 *796 * We work around this by manually creating the mask from the number797 * of CRTCs that have been registered, and should therefore always be798 * the same as drm_crtc_index() after registration.799 */800 return 1 << drm->mode_config.num_crtc;801}802 803static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,804 struct tegra_dc *dc)805{806 unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm);807 enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY;808 struct tegra_plane *plane;809 unsigned int num_formats;810 const u64 *modifiers;811 const u32 *formats;812 int err;813 814 plane = kzalloc(sizeof(*plane), GFP_KERNEL);815 if (!plane)816 return ERR_PTR(-ENOMEM);817 818 /* Always use window A as primary window */819 plane->offset = 0xa00;820 plane->index = 0;821 plane->dc = dc;822 823 num_formats = dc->soc->num_primary_formats;824 formats = dc->soc->primary_formats;825 modifiers = dc->soc->modifiers;826 827 err = tegra_plane_interconnect_init(plane);828 if (err) {829 kfree(plane);830 return ERR_PTR(err);831 }832 833 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,834 &tegra_plane_funcs, formats,835 num_formats, modifiers, type, NULL);836 if (err < 0) {837 kfree(plane);838 return ERR_PTR(err);839 }840 841 drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);842 drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255);843 844 err = drm_plane_create_rotation_property(&plane->base,845 DRM_MODE_ROTATE_0,846 DRM_MODE_ROTATE_0 |847 DRM_MODE_ROTATE_180 |848 DRM_MODE_REFLECT_X |849 DRM_MODE_REFLECT_Y);850 if (err < 0)851 dev_err(dc->dev, "failed to create rotation property: %d\n",852 err);853 854 return &plane->base;855}856 857static const u32 tegra_legacy_cursor_plane_formats[] = {858 DRM_FORMAT_RGBA8888,859};860 861static const u32 tegra_cursor_plane_formats[] = {862 DRM_FORMAT_ARGB8888,863};864 865static int tegra_cursor_atomic_check(struct drm_plane *plane,866 struct drm_atomic_state *state)867{868 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,869 plane);870 struct tegra_plane_state *plane_state = to_tegra_plane_state(new_plane_state);871 struct tegra_plane *tegra = to_tegra_plane(plane);872 int err;873 874 plane_state->peak_memory_bandwidth = 0;875 plane_state->avg_memory_bandwidth = 0;876 877 /* no need for further checks if the plane is being disabled */878 if (!new_plane_state->crtc) {879 plane_state->total_peak_memory_bandwidth = 0;880 return 0;881 }882 883 /* scaling not supported for cursor */884 if ((new_plane_state->src_w >> 16 != new_plane_state->crtc_w) ||885 (new_plane_state->src_h >> 16 != new_plane_state->crtc_h))886 return -EINVAL;887 888 /* only square cursors supported */889 if (new_plane_state->src_w != new_plane_state->src_h)890 return -EINVAL;891 892 if (new_plane_state->crtc_w != 32 && new_plane_state->crtc_w != 64 &&893 new_plane_state->crtc_w != 128 && new_plane_state->crtc_w != 256)894 return -EINVAL;895 896 err = tegra_plane_state_add(tegra, new_plane_state);897 if (err < 0)898 return err;899 900 return 0;901}902 903static void __tegra_cursor_atomic_update(struct drm_plane *plane,904 struct drm_plane_state *new_state)905{906 struct tegra_plane_state *tegra_plane_state = to_tegra_plane_state(new_state);907 struct tegra_dc *dc = to_tegra_dc(new_state->crtc);908 struct tegra_drm *tegra = plane->dev->dev_private;909#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT910 u64 dma_mask = *dc->dev->dma_mask;911#endif912 unsigned int x, y;913 u32 value = 0;914 915 /* rien ne va plus */916 if (!new_state->crtc || !new_state->fb)917 return;918 919 /*920 * Legacy display supports hardware clipping of the cursor, but921 * nvdisplay relies on software to clip the cursor to the screen.922 */923 if (!dc->soc->has_nvdisplay)924 value |= CURSOR_CLIP_DISPLAY;925 926 switch (new_state->crtc_w) {927 case 32:928 value |= CURSOR_SIZE_32x32;929 break;930 931 case 64:932 value |= CURSOR_SIZE_64x64;933 break;934 935 case 128:936 value |= CURSOR_SIZE_128x128;937 break;938 939 case 256:940 value |= CURSOR_SIZE_256x256;941 break;942 943 default:944 WARN(1, "cursor size %ux%u not supported\n",945 new_state->crtc_w, new_state->crtc_h);946 return;947 }948 949 value |= (tegra_plane_state->iova[0] >> 10) & 0x3fffff;950 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);951 952#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT953 value = (tegra_plane_state->iova[0] >> 32) & (dma_mask >> 32);954 tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);955#endif956 957 /* enable cursor and set blend mode */958 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);959 value |= CURSOR_ENABLE;960 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);961 962 value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);963 value &= ~CURSOR_DST_BLEND_MASK;964 value &= ~CURSOR_SRC_BLEND_MASK;965 966 if (dc->soc->has_nvdisplay)967 value &= ~CURSOR_COMPOSITION_MODE_XOR;968 else969 value |= CURSOR_MODE_NORMAL;970 971 value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;972 value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;973 value |= CURSOR_ALPHA;974 tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);975 976 /* nvdisplay relies on software for clipping */977 if (dc->soc->has_nvdisplay) {978 struct drm_rect src;979 980 x = new_state->dst.x1;981 y = new_state->dst.y1;982 983 drm_rect_fp_to_int(&src, &new_state->src);984 985 value = (src.y1 & tegra->vmask) << 16 | (src.x1 & tegra->hmask);986 tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR);987 988 value = (drm_rect_height(&src) & tegra->vmask) << 16 |989 (drm_rect_width(&src) & tegra->hmask);990 tegra_dc_writel(dc, value, DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR);991 } else {992 x = new_state->crtc_x;993 y = new_state->crtc_y;994 }995 996 /* position the cursor */997 value = ((y & tegra->vmask) << 16) | (x & tegra->hmask);998 tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);999}1000 1001static void tegra_cursor_atomic_update(struct drm_plane *plane,1002 struct drm_atomic_state *state)1003{1004 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);1005 1006 __tegra_cursor_atomic_update(plane, new_state);1007}1008 1009static void tegra_cursor_atomic_disable(struct drm_plane *plane,1010 struct drm_atomic_state *state)1011{1012 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,1013 plane);1014 struct tegra_dc *dc;1015 u32 value;1016 1017 /* rien ne va plus */1018 if (!old_state || !old_state->crtc)1019 return;1020 1021 dc = to_tegra_dc(old_state->crtc);1022 1023 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);1024 value &= ~CURSOR_ENABLE;1025 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);1026}1027 1028static int tegra_cursor_atomic_async_check(struct drm_plane *plane, struct drm_atomic_state *state)1029{1030 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);1031 struct drm_crtc_state *crtc_state;1032 int min_scale, max_scale;1033 int err;1034 1035 crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc);1036 if (WARN_ON(!crtc_state))1037 return -EINVAL;1038 1039 if (!crtc_state->active)1040 return -EINVAL;1041 1042 if (plane->state->crtc != new_state->crtc ||1043 plane->state->src_w != new_state->src_w ||1044 plane->state->src_h != new_state->src_h ||1045 plane->state->crtc_w != new_state->crtc_w ||1046 plane->state->crtc_h != new_state->crtc_h ||1047 plane->state->fb != new_state->fb ||1048 plane->state->fb == NULL)1049 return -EINVAL;1050 1051 min_scale = (1 << 16) / 8;1052 max_scale = (8 << 16) / 1;1053 1054 err = drm_atomic_helper_check_plane_state(new_state, crtc_state, min_scale, max_scale,1055 true, true);1056 if (err < 0)1057 return err;1058 1059 if (new_state->visible != plane->state->visible)1060 return -EINVAL;1061 1062 return 0;1063}1064 1065static void tegra_cursor_atomic_async_update(struct drm_plane *plane,1066 struct drm_atomic_state *state)1067{1068 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);1069 struct tegra_dc *dc = to_tegra_dc(new_state->crtc);1070 1071 plane->state->src_x = new_state->src_x;1072 plane->state->src_y = new_state->src_y;1073 plane->state->crtc_x = new_state->crtc_x;1074 plane->state->crtc_y = new_state->crtc_y;1075 1076 if (new_state->visible) {1077 struct tegra_plane *p = to_tegra_plane(plane);1078 u32 value;1079 1080 __tegra_cursor_atomic_update(plane, new_state);1081 1082 value = (WIN_A_ACT_REQ << p->index) << 8 | GENERAL_UPDATE;1083 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);1084 (void)tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);1085 1086 value = (WIN_A_ACT_REQ << p->index) | GENERAL_ACT_REQ;1087 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);1088 (void)tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);1089 }1090}1091 1092static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {1093 .prepare_fb = tegra_plane_prepare_fb,1094 .cleanup_fb = tegra_plane_cleanup_fb,1095 .atomic_check = tegra_cursor_atomic_check,1096 .atomic_update = tegra_cursor_atomic_update,1097 .atomic_disable = tegra_cursor_atomic_disable,1098 .atomic_async_check = tegra_cursor_atomic_async_check,1099 .atomic_async_update = tegra_cursor_atomic_async_update,1100};1101 1102static const uint64_t linear_modifiers[] = {1103 DRM_FORMAT_MOD_LINEAR,1104 DRM_FORMAT_MOD_INVALID1105};1106 1107static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,1108 struct tegra_dc *dc)1109{1110 unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm);1111 struct tegra_plane *plane;1112 unsigned int num_formats;1113 const u32 *formats;1114 int err;1115 1116 plane = kzalloc(sizeof(*plane), GFP_KERNEL);1117 if (!plane)1118 return ERR_PTR(-ENOMEM);1119 1120 /*1121 * This index is kind of fake. The cursor isn't a regular plane, but1122 * its update and activation request bits in DC_CMD_STATE_CONTROL do1123 * use the same programming. Setting this fake index here allows the1124 * code in tegra_add_plane_state() to do the right thing without the1125 * need to special-casing the cursor plane.1126 */1127 plane->index = 6;1128 plane->dc = dc;1129 1130 if (!dc->soc->has_nvdisplay) {1131 num_formats = ARRAY_SIZE(tegra_legacy_cursor_plane_formats);1132 formats = tegra_legacy_cursor_plane_formats;1133 1134 err = tegra_plane_interconnect_init(plane);1135 if (err) {1136 kfree(plane);1137 return ERR_PTR(err);1138 }1139 } else {1140 num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);1141 formats = tegra_cursor_plane_formats;1142 }1143 1144 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,1145 &tegra_plane_funcs, formats,1146 num_formats, linear_modifiers,1147 DRM_PLANE_TYPE_CURSOR, NULL);1148 if (err < 0) {1149 kfree(plane);1150 return ERR_PTR(err);1151 }1152 1153 drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs);1154 drm_plane_create_zpos_immutable_property(&plane->base, 255);1155 1156 return &plane->base;1157}1158 1159static const u32 tegra20_overlay_formats[] = {1160 DRM_FORMAT_ARGB4444,1161 DRM_FORMAT_ARGB1555,1162 DRM_FORMAT_RGB565,1163 DRM_FORMAT_RGBA5551,1164 DRM_FORMAT_ABGR8888,1165 DRM_FORMAT_ARGB8888,1166 /* non-native formats */1167 DRM_FORMAT_XRGB1555,1168 DRM_FORMAT_RGBX5551,1169 DRM_FORMAT_XBGR8888,1170 DRM_FORMAT_XRGB8888,1171 /* planar formats */1172 DRM_FORMAT_UYVY,1173 DRM_FORMAT_YUYV,1174 DRM_FORMAT_YUV420,1175 DRM_FORMAT_YUV422,1176};1177 1178static const u32 tegra114_overlay_formats[] = {1179 DRM_FORMAT_ARGB4444,1180 DRM_FORMAT_ARGB1555,1181 DRM_FORMAT_RGB565,1182 DRM_FORMAT_RGBA5551,1183 DRM_FORMAT_ABGR8888,1184 DRM_FORMAT_ARGB8888,1185 /* new on Tegra114 */1186 DRM_FORMAT_ABGR4444,1187 DRM_FORMAT_ABGR1555,1188 DRM_FORMAT_BGRA5551,1189 DRM_FORMAT_XRGB1555,1190 DRM_FORMAT_RGBX5551,1191 DRM_FORMAT_XBGR1555,1192 DRM_FORMAT_BGRX5551,1193 DRM_FORMAT_BGR565,1194 DRM_FORMAT_BGRA8888,1195 DRM_FORMAT_RGBA8888,1196 DRM_FORMAT_XRGB8888,1197 DRM_FORMAT_XBGR8888,1198 /* planar formats */1199 DRM_FORMAT_UYVY,1200 DRM_FORMAT_YUYV,1201 DRM_FORMAT_YUV420,1202 DRM_FORMAT_YUV422,1203 /* semi-planar formats */1204 DRM_FORMAT_NV12,1205 DRM_FORMAT_NV21,1206 DRM_FORMAT_NV16,1207 DRM_FORMAT_NV61,1208 DRM_FORMAT_NV24,1209 DRM_FORMAT_NV42,1210};1211 1212static const u32 tegra124_overlay_formats[] = {1213 DRM_FORMAT_ARGB4444,1214 DRM_FORMAT_ARGB1555,1215 DRM_FORMAT_RGB565,1216 DRM_FORMAT_RGBA5551,1217 DRM_FORMAT_ABGR8888,1218 DRM_FORMAT_ARGB8888,1219 /* new on Tegra114 */1220 DRM_FORMAT_ABGR4444,1221 DRM_FORMAT_ABGR1555,1222 DRM_FORMAT_BGRA5551,1223 DRM_FORMAT_XRGB1555,1224 DRM_FORMAT_RGBX5551,1225 DRM_FORMAT_XBGR1555,1226 DRM_FORMAT_BGRX5551,1227 DRM_FORMAT_BGR565,1228 DRM_FORMAT_BGRA8888,1229 DRM_FORMAT_RGBA8888,1230 DRM_FORMAT_XRGB8888,1231 DRM_FORMAT_XBGR8888,1232 /* new on Tegra124 */1233 DRM_FORMAT_RGBX8888,1234 DRM_FORMAT_BGRX8888,1235 /* planar formats */1236 DRM_FORMAT_UYVY,1237 DRM_FORMAT_YUYV,1238 DRM_FORMAT_YVYU,1239 DRM_FORMAT_VYUY,1240 DRM_FORMAT_YUV420, /* YU12 */1241 DRM_FORMAT_YUV422, /* YU16 */1242 DRM_FORMAT_YUV444, /* YU24 */1243 /* semi-planar formats */1244 DRM_FORMAT_NV12,1245 DRM_FORMAT_NV21,1246 DRM_FORMAT_NV16,1247 DRM_FORMAT_NV61,1248 DRM_FORMAT_NV24,1249 DRM_FORMAT_NV42,1250};1251 1252static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,1253 struct tegra_dc *dc,1254 unsigned int index,1255 bool cursor)1256{1257 unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm);1258 struct tegra_plane *plane;1259 unsigned int num_formats;1260 enum drm_plane_type type;1261 const u32 *formats;1262 int err;1263 1264 plane = kzalloc(sizeof(*plane), GFP_KERNEL);1265 if (!plane)1266 return ERR_PTR(-ENOMEM);1267 1268 plane->offset = 0xa00 + 0x200 * index;1269 plane->index = index;1270 plane->dc = dc;1271 1272 num_formats = dc->soc->num_overlay_formats;1273 formats = dc->soc->overlay_formats;1274 1275 err = tegra_plane_interconnect_init(plane);1276 if (err) {1277 kfree(plane);1278 return ERR_PTR(err);1279 }1280 1281 if (!cursor)1282 type = DRM_PLANE_TYPE_OVERLAY;1283 else1284 type = DRM_PLANE_TYPE_CURSOR;1285 1286 err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,1287 &tegra_plane_funcs, formats,1288 num_formats, linear_modifiers,1289 type, NULL);1290 if (err < 0) {1291 kfree(plane);1292 return ERR_PTR(err);1293 }1294 1295 drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);1296 drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255);1297 1298 err = drm_plane_create_rotation_property(&plane->base,1299 DRM_MODE_ROTATE_0,1300 DRM_MODE_ROTATE_0 |1301 DRM_MODE_ROTATE_180 |1302 DRM_MODE_REFLECT_X |1303 DRM_MODE_REFLECT_Y);1304 if (err < 0)1305 dev_err(dc->dev, "failed to create rotation property: %d\n",1306 err);1307 1308 return &plane->base;1309}1310 1311static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,1312 struct tegra_dc *dc)1313{1314 struct drm_plane *plane, *primary = NULL;1315 unsigned int i, j;1316 1317 for (i = 0; i < dc->soc->num_wgrps; i++) {1318 const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i];1319 1320 if (wgrp->dc == dc->pipe) {1321 for (j = 0; j < wgrp->num_windows; j++) {1322 unsigned int index = wgrp->windows[j];1323 1324 plane = tegra_shared_plane_create(drm, dc,1325 wgrp->index,1326 index);1327 if (IS_ERR(plane))1328 return plane;1329 1330 /*1331 * Choose the first shared plane owned by this1332 * head as the primary plane.1333 */1334 if (!primary) {1335 plane->type = DRM_PLANE_TYPE_PRIMARY;1336 primary = plane;1337 }1338 }1339 }1340 }1341 1342 return primary;1343}1344 1345static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,1346 struct tegra_dc *dc)1347{1348 struct drm_plane *planes[2], *primary;1349 unsigned int planes_num;1350 unsigned int i;1351 int err;1352 1353 primary = tegra_primary_plane_create(drm, dc);1354 if (IS_ERR(primary))1355 return primary;1356 1357 if (dc->soc->supports_cursor)1358 planes_num = 2;1359 else1360 planes_num = 1;1361 1362 for (i = 0; i < planes_num; i++) {1363 planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i,1364 false);1365 if (IS_ERR(planes[i])) {1366 err = PTR_ERR(planes[i]);1367 1368 while (i--)1369 planes[i]->funcs->destroy(planes[i]);1370 1371 primary->funcs->destroy(primary);1372 return ERR_PTR(err);1373 }1374 }1375 1376 return primary;1377}1378 1379static void tegra_dc_destroy(struct drm_crtc *crtc)1380{1381 drm_crtc_cleanup(crtc);1382}1383 1384static void tegra_crtc_reset(struct drm_crtc *crtc)1385{1386 struct tegra_dc_state *state = kzalloc(sizeof(*state), GFP_KERNEL);1387 1388 if (crtc->state)1389 tegra_crtc_atomic_destroy_state(crtc, crtc->state);1390 1391 __drm_atomic_helper_crtc_reset(crtc, &state->base);1392}1393 1394static struct drm_crtc_state *1395tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)1396{1397 struct tegra_dc_state *state = to_dc_state(crtc->state);1398 struct tegra_dc_state *copy;1399 1400 copy = kmalloc(sizeof(*copy), GFP_KERNEL);1401 if (!copy)1402 return NULL;1403 1404 __drm_atomic_helper_crtc_duplicate_state(crtc, ©->base);1405 copy->clk = state->clk;1406 copy->pclk = state->pclk;1407 copy->div = state->div;1408 copy->planes = state->planes;1409 1410 return ©->base;1411}1412 1413static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,1414 struct drm_crtc_state *state)1415{1416 __drm_atomic_helper_crtc_destroy_state(state);1417 kfree(state);1418}1419 1420#define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name }1421 1422static const struct debugfs_reg32 tegra_dc_regs[] = {1423 DEBUGFS_REG32(DC_CMD_GENERAL_INCR_SYNCPT),1424 DEBUGFS_REG32(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL),1425 DEBUGFS_REG32(DC_CMD_GENERAL_INCR_SYNCPT_ERROR),1426 DEBUGFS_REG32(DC_CMD_WIN_A_INCR_SYNCPT),1427 DEBUGFS_REG32(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL),1428 DEBUGFS_REG32(DC_CMD_WIN_A_INCR_SYNCPT_ERROR),1429 DEBUGFS_REG32(DC_CMD_WIN_B_INCR_SYNCPT),1430 DEBUGFS_REG32(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL),1431 DEBUGFS_REG32(DC_CMD_WIN_B_INCR_SYNCPT_ERROR),1432 DEBUGFS_REG32(DC_CMD_WIN_C_INCR_SYNCPT),1433 DEBUGFS_REG32(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL),1434 DEBUGFS_REG32(DC_CMD_WIN_C_INCR_SYNCPT_ERROR),1435 DEBUGFS_REG32(DC_CMD_CONT_SYNCPT_VSYNC),1436 DEBUGFS_REG32(DC_CMD_DISPLAY_COMMAND_OPTION0),1437 DEBUGFS_REG32(DC_CMD_DISPLAY_COMMAND),1438 DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE),1439 DEBUGFS_REG32(DC_CMD_DISPLAY_POWER_CONTROL),1440 DEBUGFS_REG32(DC_CMD_INT_STATUS),1441 DEBUGFS_REG32(DC_CMD_INT_MASK),1442 DEBUGFS_REG32(DC_CMD_INT_ENABLE),1443 DEBUGFS_REG32(DC_CMD_INT_TYPE),1444 DEBUGFS_REG32(DC_CMD_INT_POLARITY),1445 DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE1),1446 DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE2),1447 DEBUGFS_REG32(DC_CMD_SIGNAL_RAISE3),1448 DEBUGFS_REG32(DC_CMD_STATE_ACCESS),1449 DEBUGFS_REG32(DC_CMD_STATE_CONTROL),1450 DEBUGFS_REG32(DC_CMD_DISPLAY_WINDOW_HEADER),1451 DEBUGFS_REG32(DC_CMD_REG_ACT_CONTROL),1452 DEBUGFS_REG32(DC_COM_CRC_CONTROL),1453 DEBUGFS_REG32(DC_COM_CRC_CHECKSUM),1454 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(0)),1455 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(1)),1456 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(2)),1457 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_ENABLE(3)),1458 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(0)),1459 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(1)),1460 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(2)),1461 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_POLARITY(3)),1462 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(0)),1463 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(1)),1464 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(2)),1465 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_DATA(3)),1466 DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(0)),1467 DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(1)),1468 DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(2)),1469 DEBUGFS_REG32(DC_COM_PIN_INPUT_ENABLE(3)),1470 DEBUGFS_REG32(DC_COM_PIN_INPUT_DATA(0)),1471 DEBUGFS_REG32(DC_COM_PIN_INPUT_DATA(1)),1472 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(0)),1473 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(1)),1474 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(2)),1475 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(3)),1476 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(4)),1477 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(5)),1478 DEBUGFS_REG32(DC_COM_PIN_OUTPUT_SELECT(6)),1479 DEBUGFS_REG32(DC_COM_PIN_MISC_CONTROL),1480 DEBUGFS_REG32(DC_COM_PIN_PM0_CONTROL),1481 DEBUGFS_REG32(DC_COM_PIN_PM0_DUTY_CYCLE),1482 DEBUGFS_REG32(DC_COM_PIN_PM1_CONTROL),1483 DEBUGFS_REG32(DC_COM_PIN_PM1_DUTY_CYCLE),1484 DEBUGFS_REG32(DC_COM_SPI_CONTROL),1485 DEBUGFS_REG32(DC_COM_SPI_START_BYTE),1486 DEBUGFS_REG32(DC_COM_HSPI_WRITE_DATA_AB),1487 DEBUGFS_REG32(DC_COM_HSPI_WRITE_DATA_CD),1488 DEBUGFS_REG32(DC_COM_HSPI_CS_DC),1489 DEBUGFS_REG32(DC_COM_SCRATCH_REGISTER_A),1490 DEBUGFS_REG32(DC_COM_SCRATCH_REGISTER_B),1491 DEBUGFS_REG32(DC_COM_GPIO_CTRL),1492 DEBUGFS_REG32(DC_COM_GPIO_DEBOUNCE_COUNTER),1493 DEBUGFS_REG32(DC_COM_CRC_CHECKSUM_LATCHED),1494 DEBUGFS_REG32(DC_DISP_DISP_SIGNAL_OPTIONS0),1495 DEBUGFS_REG32(DC_DISP_DISP_SIGNAL_OPTIONS1),1496 DEBUGFS_REG32(DC_DISP_DISP_WIN_OPTIONS),1497 DEBUGFS_REG32(DC_DISP_DISP_MEM_HIGH_PRIORITY),1498 DEBUGFS_REG32(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER),1499 DEBUGFS_REG32(DC_DISP_DISP_TIMING_OPTIONS),1500 DEBUGFS_REG32(DC_DISP_REF_TO_SYNC),1501 DEBUGFS_REG32(DC_DISP_SYNC_WIDTH),1502 DEBUGFS_REG32(DC_DISP_BACK_PORCH),1503 DEBUGFS_REG32(DC_DISP_ACTIVE),1504 DEBUGFS_REG32(DC_DISP_FRONT_PORCH),1505 DEBUGFS_REG32(DC_DISP_H_PULSE0_CONTROL),1506 DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_A),1507 DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_B),1508 DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_C),1509 DEBUGFS_REG32(DC_DISP_H_PULSE0_POSITION_D),1510 DEBUGFS_REG32(DC_DISP_H_PULSE1_CONTROL),1511 DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_A),1512 DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_B),1513 DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_C),1514 DEBUGFS_REG32(DC_DISP_H_PULSE1_POSITION_D),1515 DEBUGFS_REG32(DC_DISP_H_PULSE2_CONTROL),1516 DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_A),1517 DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_B),1518 DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_C),1519 DEBUGFS_REG32(DC_DISP_H_PULSE2_POSITION_D),1520 DEBUGFS_REG32(DC_DISP_V_PULSE0_CONTROL),1521 DEBUGFS_REG32(DC_DISP_V_PULSE0_POSITION_A),1522 DEBUGFS_REG32(DC_DISP_V_PULSE0_POSITION_B),1523 DEBUGFS_REG32(DC_DISP_V_PULSE0_POSITION_C),1524 DEBUGFS_REG32(DC_DISP_V_PULSE1_CONTROL),1525 DEBUGFS_REG32(DC_DISP_V_PULSE1_POSITION_A),1526 DEBUGFS_REG32(DC_DISP_V_PULSE1_POSITION_B),1527 DEBUGFS_REG32(DC_DISP_V_PULSE1_POSITION_C),1528 DEBUGFS_REG32(DC_DISP_V_PULSE2_CONTROL),1529 DEBUGFS_REG32(DC_DISP_V_PULSE2_POSITION_A),1530 DEBUGFS_REG32(DC_DISP_V_PULSE3_CONTROL),1531 DEBUGFS_REG32(DC_DISP_V_PULSE3_POSITION_A),1532 DEBUGFS_REG32(DC_DISP_M0_CONTROL),1533 DEBUGFS_REG32(DC_DISP_M1_CONTROL),1534 DEBUGFS_REG32(DC_DISP_DI_CONTROL),1535 DEBUGFS_REG32(DC_DISP_PP_CONTROL),1536 DEBUGFS_REG32(DC_DISP_PP_SELECT_A),1537 DEBUGFS_REG32(DC_DISP_PP_SELECT_B),1538 DEBUGFS_REG32(DC_DISP_PP_SELECT_C),1539 DEBUGFS_REG32(DC_DISP_PP_SELECT_D),1540 DEBUGFS_REG32(DC_DISP_DISP_CLOCK_CONTROL),1541 DEBUGFS_REG32(DC_DISP_DISP_INTERFACE_CONTROL),1542 DEBUGFS_REG32(DC_DISP_DISP_COLOR_CONTROL),1543 DEBUGFS_REG32(DC_DISP_SHIFT_CLOCK_OPTIONS),1544 DEBUGFS_REG32(DC_DISP_DATA_ENABLE_OPTIONS),1545 DEBUGFS_REG32(DC_DISP_SERIAL_INTERFACE_OPTIONS),1546 DEBUGFS_REG32(DC_DISP_LCD_SPI_OPTIONS),1547 DEBUGFS_REG32(DC_DISP_BORDER_COLOR),1548 DEBUGFS_REG32(DC_DISP_COLOR_KEY0_LOWER),1549 DEBUGFS_REG32(DC_DISP_COLOR_KEY0_UPPER),1550 DEBUGFS_REG32(DC_DISP_COLOR_KEY1_LOWER),1551 DEBUGFS_REG32(DC_DISP_COLOR_KEY1_UPPER),1552 DEBUGFS_REG32(DC_DISP_CURSOR_FOREGROUND),1553 DEBUGFS_REG32(DC_DISP_CURSOR_BACKGROUND),1554 DEBUGFS_REG32(DC_DISP_CURSOR_START_ADDR),1555 DEBUGFS_REG32(DC_DISP_CURSOR_START_ADDR_NS),1556 DEBUGFS_REG32(DC_DISP_CURSOR_POSITION),1557 DEBUGFS_REG32(DC_DISP_CURSOR_POSITION_NS),1558 DEBUGFS_REG32(DC_DISP_INIT_SEQ_CONTROL),1559 DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_A),1560 DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_B),1561 DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_C),1562 DEBUGFS_REG32(DC_DISP_SPI_INIT_SEQ_DATA_D),1563 DEBUGFS_REG32(DC_DISP_DC_MCCIF_FIFOCTRL),1564 DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY0A_HYST),1565 DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY0B_HYST),1566 DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY1A_HYST),1567 DEBUGFS_REG32(DC_DISP_MCCIF_DISPLAY1B_HYST),1568 DEBUGFS_REG32(DC_DISP_DAC_CRT_CTRL),1569 DEBUGFS_REG32(DC_DISP_DISP_MISC_CONTROL),1570 DEBUGFS_REG32(DC_DISP_SD_CONTROL),1571 DEBUGFS_REG32(DC_DISP_SD_CSC_COEFF),1572 DEBUGFS_REG32(DC_DISP_SD_LUT(0)),1573 DEBUGFS_REG32(DC_DISP_SD_LUT(1)),1574 DEBUGFS_REG32(DC_DISP_SD_LUT(2)),1575 DEBUGFS_REG32(DC_DISP_SD_LUT(3)),1576 DEBUGFS_REG32(DC_DISP_SD_LUT(4)),1577 DEBUGFS_REG32(DC_DISP_SD_LUT(5)),1578 DEBUGFS_REG32(DC_DISP_SD_LUT(6)),1579 DEBUGFS_REG32(DC_DISP_SD_LUT(7)),1580 DEBUGFS_REG32(DC_DISP_SD_LUT(8)),1581 DEBUGFS_REG32(DC_DISP_SD_FLICKER_CONTROL),1582 DEBUGFS_REG32(DC_DISP_DC_PIXEL_COUNT),1583 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(0)),1584 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(1)),1585 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(2)),1586 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(3)),1587 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(4)),1588 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(5)),1589 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(6)),1590 DEBUGFS_REG32(DC_DISP_SD_HISTOGRAM(7)),1591 DEBUGFS_REG32(DC_DISP_SD_BL_TF(0)),1592 DEBUGFS_REG32(DC_DISP_SD_BL_TF(1)),1593 DEBUGFS_REG32(DC_DISP_SD_BL_TF(2)),1594 DEBUGFS_REG32(DC_DISP_SD_BL_TF(3)),1595 DEBUGFS_REG32(DC_DISP_SD_BL_CONTROL),1596 DEBUGFS_REG32(DC_DISP_SD_HW_K_VALUES),1597 DEBUGFS_REG32(DC_DISP_SD_MAN_K_VALUES),1598 DEBUGFS_REG32(DC_DISP_CURSOR_START_ADDR_HI),1599 DEBUGFS_REG32(DC_DISP_BLEND_CURSOR_CONTROL),1600 DEBUGFS_REG32(DC_WIN_WIN_OPTIONS),1601 DEBUGFS_REG32(DC_WIN_BYTE_SWAP),1602 DEBUGFS_REG32(DC_WIN_BUFFER_CONTROL),1603 DEBUGFS_REG32(DC_WIN_COLOR_DEPTH),1604 DEBUGFS_REG32(DC_WIN_POSITION),1605 DEBUGFS_REG32(DC_WIN_SIZE),1606 DEBUGFS_REG32(DC_WIN_PRESCALED_SIZE),1607 DEBUGFS_REG32(DC_WIN_H_INITIAL_DDA),1608 DEBUGFS_REG32(DC_WIN_V_INITIAL_DDA),1609 DEBUGFS_REG32(DC_WIN_DDA_INC),1610 DEBUGFS_REG32(DC_WIN_LINE_STRIDE),1611 DEBUGFS_REG32(DC_WIN_BUF_STRIDE),1612 DEBUGFS_REG32(DC_WIN_UV_BUF_STRIDE),1613 DEBUGFS_REG32(DC_WIN_BUFFER_ADDR_MODE),1614 DEBUGFS_REG32(DC_WIN_DV_CONTROL),1615 DEBUGFS_REG32(DC_WIN_BLEND_NOKEY),1616 DEBUGFS_REG32(DC_WIN_BLEND_1WIN),1617 DEBUGFS_REG32(DC_WIN_BLEND_2WIN_X),1618 DEBUGFS_REG32(DC_WIN_BLEND_2WIN_Y),1619 DEBUGFS_REG32(DC_WIN_BLEND_3WIN_XY),1620 DEBUGFS_REG32(DC_WIN_HP_FETCH_CONTROL),1621 DEBUGFS_REG32(DC_WINBUF_START_ADDR),1622 DEBUGFS_REG32(DC_WINBUF_START_ADDR_NS),1623 DEBUGFS_REG32(DC_WINBUF_START_ADDR_U),1624 DEBUGFS_REG32(DC_WINBUF_START_ADDR_U_NS),1625 DEBUGFS_REG32(DC_WINBUF_START_ADDR_V),1626 DEBUGFS_REG32(DC_WINBUF_START_ADDR_V_NS),1627 DEBUGFS_REG32(DC_WINBUF_ADDR_H_OFFSET),1628 DEBUGFS_REG32(DC_WINBUF_ADDR_H_OFFSET_NS),1629 DEBUGFS_REG32(DC_WINBUF_ADDR_V_OFFSET),1630 DEBUGFS_REG32(DC_WINBUF_ADDR_V_OFFSET_NS),1631 DEBUGFS_REG32(DC_WINBUF_UFLOW_STATUS),1632 DEBUGFS_REG32(DC_WINBUF_AD_UFLOW_STATUS),1633 DEBUGFS_REG32(DC_WINBUF_BD_UFLOW_STATUS),1634 DEBUGFS_REG32(DC_WINBUF_CD_UFLOW_STATUS),1635};1636 1637static int tegra_dc_show_regs(struct seq_file *s, void *data)1638{1639 struct drm_info_node *node = s->private;1640 struct tegra_dc *dc = node->info_ent->data;1641 unsigned int i;1642 int err = 0;1643 1644 drm_modeset_lock(&dc->base.mutex, NULL);1645 1646 if (!dc->base.state->active) {1647 err = -EBUSY;1648 goto unlock;1649 }1650 1651 for (i = 0; i < ARRAY_SIZE(tegra_dc_regs); i++) {1652 unsigned int offset = tegra_dc_regs[i].offset;1653 1654 seq_printf(s, "%-40s %#05x %08x\n", tegra_dc_regs[i].name,1655 offset, tegra_dc_readl(dc, offset));1656 }1657 1658unlock:1659 drm_modeset_unlock(&dc->base.mutex);1660 return err;1661}1662 1663static int tegra_dc_show_crc(struct seq_file *s, void *data)1664{1665 struct drm_info_node *node = s->private;1666 struct tegra_dc *dc = node->info_ent->data;1667 int err = 0;1668 u32 value;1669 1670 drm_modeset_lock(&dc->base.mutex, NULL);1671 1672 if (!dc->base.state->active) {1673 err = -EBUSY;1674 goto unlock;1675 }1676 1677 value = DC_COM_CRC_CONTROL_ACTIVE_DATA | DC_COM_CRC_CONTROL_ENABLE;1678 tegra_dc_writel(dc, value, DC_COM_CRC_CONTROL);1679 tegra_dc_commit(dc);1680 1681 drm_crtc_wait_one_vblank(&dc->base);1682 drm_crtc_wait_one_vblank(&dc->base);1683 1684 value = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM);1685 seq_printf(s, "%08x\n", value);1686 1687 tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL);1688 1689unlock:1690 drm_modeset_unlock(&dc->base.mutex);1691 return err;1692}1693 1694static int tegra_dc_show_stats(struct seq_file *s, void *data)1695{1696 struct drm_info_node *node = s->private;1697 struct tegra_dc *dc = node->info_ent->data;1698 1699 seq_printf(s, "frames: %lu\n", dc->stats.frames);1700 seq_printf(s, "vblank: %lu\n", dc->stats.vblank);1701 seq_printf(s, "underflow: %lu\n", dc->stats.underflow);1702 seq_printf(s, "overflow: %lu\n", dc->stats.overflow);1703 1704 seq_printf(s, "frames total: %lu\n", dc->stats.frames_total);1705 seq_printf(s, "vblank total: %lu\n", dc->stats.vblank_total);1706 seq_printf(s, "underflow total: %lu\n", dc->stats.underflow_total);1707 seq_printf(s, "overflow total: %lu\n", dc->stats.overflow_total);1708 1709 return 0;1710}1711 1712static struct drm_info_list debugfs_files[] = {1713 { "regs", tegra_dc_show_regs, 0, NULL },1714 { "crc", tegra_dc_show_crc, 0, NULL },1715 { "stats", tegra_dc_show_stats, 0, NULL },1716};1717 1718static int tegra_dc_late_register(struct drm_crtc *crtc)1719{1720 unsigned int i, count = ARRAY_SIZE(debugfs_files);1721 struct drm_minor *minor = crtc->dev->primary;1722 struct dentry *root;1723 struct tegra_dc *dc = to_tegra_dc(crtc);1724 1725#ifdef CONFIG_DEBUG_FS1726 root = crtc->debugfs_entry;1727#else1728 root = NULL;1729#endif1730 1731 dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),1732 GFP_KERNEL);1733 if (!dc->debugfs_files)1734 return -ENOMEM;1735 1736 for (i = 0; i < count; i++)1737 dc->debugfs_files[i].data = dc;1738 1739 drm_debugfs_create_files(dc->debugfs_files, count, root, minor);1740 1741 return 0;1742}1743 1744static void tegra_dc_early_unregister(struct drm_crtc *crtc)1745{1746 unsigned int count = ARRAY_SIZE(debugfs_files);1747 struct drm_minor *minor = crtc->dev->primary;1748 struct tegra_dc *dc = to_tegra_dc(crtc);1749 struct dentry *root;1750 1751#ifdef CONFIG_DEBUG_FS1752 root = crtc->debugfs_entry;1753#else1754 root = NULL;1755#endif1756 1757 drm_debugfs_remove_files(dc->debugfs_files, count, root, minor);1758 kfree(dc->debugfs_files);1759 dc->debugfs_files = NULL;1760}1761 1762static u32 tegra_dc_get_vblank_counter(struct drm_crtc *crtc)1763{1764 struct tegra_dc *dc = to_tegra_dc(crtc);1765 1766 /* XXX vblank syncpoints don't work with nvdisplay yet */1767 if (dc->syncpt && !dc->soc->has_nvdisplay)1768 return host1x_syncpt_read(dc->syncpt);1769 1770 /* fallback to software emulated VBLANK counter */1771 return (u32)drm_crtc_vblank_count(&dc->base);1772}1773 1774static int tegra_dc_enable_vblank(struct drm_crtc *crtc)1775{1776 struct tegra_dc *dc = to_tegra_dc(crtc);1777 u32 value;1778 1779 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);1780 value |= VBLANK_INT;1781 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);1782 1783 return 0;1784}1785 1786static void tegra_dc_disable_vblank(struct drm_crtc *crtc)1787{1788 struct tegra_dc *dc = to_tegra_dc(crtc);1789 u32 value;1790 1791 value = tegra_dc_readl(dc, DC_CMD_INT_MASK);1792 value &= ~VBLANK_INT;1793 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);1794}1795 1796static const struct drm_crtc_funcs tegra_crtc_funcs = {1797 .page_flip = drm_atomic_helper_page_flip,1798 .set_config = drm_atomic_helper_set_config,1799 .destroy = tegra_dc_destroy,1800 .reset = tegra_crtc_reset,1801 .atomic_duplicate_state = tegra_crtc_atomic_duplicate_state,1802 .atomic_destroy_state = tegra_crtc_atomic_destroy_state,1803 .late_register = tegra_dc_late_register,1804 .early_unregister = tegra_dc_early_unregister,1805 .get_vblank_counter = tegra_dc_get_vblank_counter,1806 .enable_vblank = tegra_dc_enable_vblank,1807 .disable_vblank = tegra_dc_disable_vblank,1808};1809 1810static int tegra_dc_set_timings(struct tegra_dc *dc,1811 struct drm_display_mode *mode)1812{1813 unsigned int h_ref_to_sync = 1;1814 unsigned int v_ref_to_sync = 1;1815 unsigned long value;1816 1817 if (!dc->soc->has_nvdisplay) {1818 tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);1819 1820 value = (v_ref_to_sync << 16) | h_ref_to_sync;1821 tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC);1822 }1823 1824 value = ((mode->vsync_end - mode->vsync_start) << 16) |1825 ((mode->hsync_end - mode->hsync_start) << 0);1826 tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH);1827 1828 value = ((mode->vtotal - mode->vsync_end) << 16) |1829 ((mode->htotal - mode->hsync_end) << 0);1830 tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH);1831 1832 value = ((mode->vsync_start - mode->vdisplay) << 16) |1833 ((mode->hsync_start - mode->hdisplay) << 0);1834 tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH);1835 1836 value = (mode->vdisplay << 16) | mode->hdisplay;1837 tegra_dc_writel(dc, value, DC_DISP_ACTIVE);1838 1839 return 0;1840}1841 1842/**1843 * tegra_dc_state_setup_clock - check clock settings and store them in atomic1844 * state1845 * @dc: display controller1846 * @crtc_state: CRTC atomic state1847 * @clk: parent clock for display controller1848 * @pclk: pixel clock1849 * @div: shift clock divider1850 *1851 * Returns:1852 * 0 on success or a negative error-code on failure.1853 */1854int tegra_dc_state_setup_clock(struct tegra_dc *dc,1855 struct drm_crtc_state *crtc_state,1856 struct clk *clk, unsigned long pclk,1857 unsigned int div)1858{1859 struct tegra_dc_state *state = to_dc_state(crtc_state);1860 1861 if (!clk_has_parent(dc->clk, clk))1862 return -EINVAL;1863 1864 state->clk = clk;1865 state->pclk = pclk;1866 state->div = div;1867 1868 return 0;1869}1870 1871static void tegra_dc_update_voltage_state(struct tegra_dc *dc,1872 struct tegra_dc_state *state)1873{1874 unsigned long rate, pstate;1875 struct dev_pm_opp *opp;1876 int err;1877 1878 if (!dc->has_opp_table)1879 return;1880 1881 /* calculate actual pixel clock rate which depends on internal divider */1882 rate = DIV_ROUND_UP(clk_get_rate(dc->clk) * 2, state->div + 2);1883 1884 /* find suitable OPP for the rate */1885 opp = dev_pm_opp_find_freq_ceil(dc->dev, &rate);1886 1887 /*1888 * Very high resolution modes may results in a clock rate that is1889 * above the characterized maximum. In this case it's okay to fall1890 * back to the characterized maximum.1891 */1892 if (opp == ERR_PTR(-ERANGE))1893 opp = dev_pm_opp_find_freq_floor(dc->dev, &rate);1894 1895 if (IS_ERR(opp)) {1896 dev_err(dc->dev, "failed to find OPP for %luHz: %pe\n",1897 rate, opp);1898 return;1899 }1900 1901 pstate = dev_pm_opp_get_required_pstate(opp, 0);1902 dev_pm_opp_put(opp);1903 1904 /*1905 * The minimum core voltage depends on the pixel clock rate (which1906 * depends on internal clock divider of the CRTC) and not on the1907 * rate of the display controller clock. This is why we're not using1908 * dev_pm_opp_set_rate() API and instead controlling the power domain1909 * directly.1910 */1911 err = dev_pm_genpd_set_performance_state(dc->dev, pstate);1912 if (err)1913 dev_err(dc->dev, "failed to set power domain state to %lu: %d\n",1914 pstate, err);1915}1916 1917static void tegra_dc_set_clock_rate(struct tegra_dc *dc,1918 struct tegra_dc_state *state)1919{1920 int err;1921 1922 err = clk_set_parent(dc->clk, state->clk);1923 if (err < 0)1924 dev_err(dc->dev, "failed to set parent clock: %d\n", err);1925 1926 /*1927 * Outputs may not want to change the parent clock rate. This is only1928 * relevant to Tegra20 where only a single display PLL is available.1929 * Since that PLL would typically be used for HDMI, an internal LVDS1930 * panel would need to be driven by some other clock such as PLL_P1931 * which is shared with other peripherals. Changing the clock rate1932 * should therefore be avoided.1933 */1934 if (state->pclk > 0) {1935 err = clk_set_rate(state->clk, state->pclk);1936 if (err < 0)1937 dev_err(dc->dev,1938 "failed to set clock rate to %lu Hz\n",1939 state->pclk);1940 1941 err = clk_set_rate(dc->clk, state->pclk);1942 if (err < 0)1943 dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n",1944 dc->clk, state->pclk, err);1945 }1946 1947 DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk),1948 state->div);1949 DRM_DEBUG_KMS("pclk: %lu\n", state->pclk);1950 1951 tegra_dc_update_voltage_state(dc, state);1952}1953 1954static void tegra_dc_stop(struct tegra_dc *dc)1955{1956 u32 value;1957 1958 /* stop the display controller */1959 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);1960 value &= ~DISP_CTRL_MODE_MASK;1961 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);1962 1963 tegra_dc_commit(dc);1964}1965 1966static bool tegra_dc_idle(struct tegra_dc *dc)1967{1968 u32 value;1969 1970 value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);1971 1972 return (value & DISP_CTRL_MODE_MASK) == 0;1973}1974 1975static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)1976{1977 timeout = jiffies + msecs_to_jiffies(timeout);1978 1979 while (time_before(jiffies, timeout)) {1980 if (tegra_dc_idle(dc))1981 return 0;1982 1983 usleep_range(1000, 2000);1984 }1985 1986 dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");1987 return -ETIMEDOUT;1988}1989 1990static void1991tegra_crtc_update_memory_bandwidth(struct drm_crtc *crtc,1992 struct drm_atomic_state *state,1993 bool prepare_bandwidth_transition)1994{1995 const struct tegra_plane_state *old_tegra_state, *new_tegra_state;1996 u32 i, new_avg_bw, old_avg_bw, new_peak_bw, old_peak_bw;1997 const struct drm_plane_state *old_plane_state;1998 const struct drm_crtc_state *old_crtc_state;1999 struct tegra_dc_window window, old_window;2000 struct tegra_dc *dc = to_tegra_dc(crtc);2001 struct tegra_plane *tegra;2002 struct drm_plane *plane;2003 2004 if (dc->soc->has_nvdisplay)2005 return;2006 2007 old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);2008 2009 if (!crtc->state->active) {2010 if (!old_crtc_state->active)2011 return;2012 2013 /*2014 * When CRTC is disabled on DPMS, the state of attached planes2015 * is kept unchanged. Hence we need to enforce removal of the2016 * bandwidths from the ICC paths.2017 */2018 drm_atomic_crtc_for_each_plane(plane, crtc) {2019 tegra = to_tegra_plane(plane);2020 2021 icc_set_bw(tegra->icc_mem, 0, 0);2022 icc_set_bw(tegra->icc_mem_vfilter, 0, 0);2023 }2024 2025 return;2026 }2027 2028 for_each_old_plane_in_state(old_crtc_state->state, plane,2029 old_plane_state, i) {2030 old_tegra_state = to_const_tegra_plane_state(old_plane_state);2031 new_tegra_state = to_const_tegra_plane_state(plane->state);2032 tegra = to_tegra_plane(plane);2033 2034 /*2035 * We're iterating over the global atomic state and it contains2036 * planes from another CRTC, hence we need to filter out the2037 * planes unrelated to this CRTC.2038 */2039 if (tegra->dc != dc)2040 continue;2041 2042 new_avg_bw = new_tegra_state->avg_memory_bandwidth;2043 old_avg_bw = old_tegra_state->avg_memory_bandwidth;2044 2045 new_peak_bw = new_tegra_state->total_peak_memory_bandwidth;2046 old_peak_bw = old_tegra_state->total_peak_memory_bandwidth;2047 2048 /*2049 * See the comment related to !crtc->state->active above,2050 * which explains why bandwidths need to be updated when2051 * CRTC is turning ON.2052 */2053 if (new_avg_bw == old_avg_bw && new_peak_bw == old_peak_bw &&2054 old_crtc_state->active)2055 continue;2056 2057 window.src.h = drm_rect_height(&plane->state->src) >> 16;2058 window.dst.h = drm_rect_height(&plane->state->dst);2059 2060 old_window.src.h = drm_rect_height(&old_plane_state->src) >> 16;2061 old_window.dst.h = drm_rect_height(&old_plane_state->dst);2062 2063 /*2064 * During the preparation phase (atomic_begin), the memory2065 * freq should go high before the DC changes are committed2066 * if bandwidth requirement goes up, otherwise memory freq2067 * should to stay high if BW requirement goes down. The2068 * opposite applies to the completion phase (post_commit).2069 */2070 if (prepare_bandwidth_transition) {2071 new_avg_bw = max(old_avg_bw, new_avg_bw);2072 new_peak_bw = max(old_peak_bw, new_peak_bw);2073 2074 if (tegra_plane_use_vertical_filtering(tegra, &old_window))2075 window = old_window;2076 }2077 2078 icc_set_bw(tegra->icc_mem, new_avg_bw, new_peak_bw);2079 2080 if (tegra_plane_use_vertical_filtering(tegra, &window))2081 icc_set_bw(tegra->icc_mem_vfilter, new_avg_bw, new_peak_bw);2082 else2083 icc_set_bw(tegra->icc_mem_vfilter, 0, 0);2084 }2085}2086 2087static void tegra_crtc_atomic_disable(struct drm_crtc *crtc,2088 struct drm_atomic_state *state)2089{2090 struct tegra_dc *dc = to_tegra_dc(crtc);2091 u32 value;2092 int err;2093 2094 if (!tegra_dc_idle(dc)) {2095 tegra_dc_stop(dc);2096 2097 /*2098 * Ignore the return value, there isn't anything useful to do2099 * in case this fails.2100 */2101 tegra_dc_wait_idle(dc, 100);2102 }2103 2104 /*2105 * This should really be part of the RGB encoder driver, but clearing2106 * these bits has the side-effect of stopping the display controller.2107 * When that happens no VBLANK interrupts will be raised. At the same2108 * time the encoder is disabled before the display controller, so the2109 * above code is always going to timeout waiting for the controller2110 * to go idle.2111 *2112 * Given the close coupling between the RGB encoder and the display2113 * controller doing it here is still kind of okay. None of the other2114 * encoder drivers require these bits to be cleared.2115 *2116 * XXX: Perhaps given that the display controller is switched off at2117 * this point anyway maybe clearing these bits isn't even useful for2118 * the RGB encoder?2119 */2120 if (dc->rgb) {2121 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);2122 value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |2123 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);2124 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);2125 }2126 2127 tegra_dc_stats_reset(&dc->stats);2128 drm_crtc_vblank_off(crtc);2129 2130 spin_lock_irq(&crtc->dev->event_lock);2131 2132 if (crtc->state->event) {2133 drm_crtc_send_vblank_event(crtc, crtc->state->event);2134 crtc->state->event = NULL;2135 }2136 2137 spin_unlock_irq(&crtc->dev->event_lock);2138 2139 err = host1x_client_suspend(&dc->client);2140 if (err < 0)2141 dev_err(dc->dev, "failed to suspend: %d\n", err);2142 2143 if (dc->has_opp_table) {2144 err = dev_pm_genpd_set_performance_state(dc->dev, 0);2145 if (err)2146 dev_err(dc->dev,2147 "failed to clear power domain state: %d\n", err);2148 }2149}2150 2151static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,2152 struct drm_atomic_state *state)2153{2154 struct drm_display_mode *mode = &crtc->state->adjusted_mode;2155 struct tegra_dc_state *crtc_state = to_dc_state(crtc->state);2156 struct tegra_dc *dc = to_tegra_dc(crtc);2157 u32 value;2158 int err;2159 2160 /* apply PLL changes */2161 tegra_dc_set_clock_rate(dc, crtc_state);2162 2163 err = host1x_client_resume(&dc->client);2164 if (err < 0) {2165 dev_err(dc->dev, "failed to resume: %d\n", err);2166 return;2167 }2168 2169 /* initialize display controller */2170 if (dc->syncpt) {2171 u32 syncpt = host1x_syncpt_id(dc->syncpt), enable;2172 2173 if (dc->soc->has_nvdisplay)2174 enable = 1 << 31;2175 else2176 enable = 1 << 8;2177 2178 value = SYNCPT_CNTRL_NO_STALL;2179 tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);2180 2181 value = enable | syncpt;2182 tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);2183 }2184 2185 if (dc->soc->has_nvdisplay) {2186 value = DSC_TO_UF_INT | DSC_BBUF_UF_INT | DSC_RBUF_UF_INT |2187 DSC_OBUF_UF_INT;2188 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);2189 2190 value = DSC_TO_UF_INT | DSC_BBUF_UF_INT | DSC_RBUF_UF_INT |2191 DSC_OBUF_UF_INT | SD3_BUCKET_WALK_DONE_INT |2192 HEAD_UF_INT | MSF_INT | REG_TMOUT_INT |2193 REGION_CRC_INT | V_PULSE2_INT | V_PULSE3_INT |2194 VBLANK_INT | FRAME_END_INT;2195 tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);2196 2197 value = SD3_BUCKET_WALK_DONE_INT | HEAD_UF_INT | VBLANK_INT |2198 FRAME_END_INT;2199 tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);2200 2201 value = HEAD_UF_INT | REG_TMOUT_INT | FRAME_END_INT;2202 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);2203 2204 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);2205 } else {2206 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |2207 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;2208 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);2209 2210 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |2211 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;2212 tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);2213 2214 /* initialize timer */2215 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |2216 WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);2217 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);2218 2219 value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |2220 WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);2221 tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);2222 2223 value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |2224 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;2225 tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);2226 2227 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |2228 WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;2229 tegra_dc_writel(dc, value, DC_CMD_INT_MASK);2230 }2231 2232 if (dc->soc->supports_background_color)2233 tegra_dc_writel(dc, 0, DC_DISP_BLEND_BACKGROUND_COLOR);2234 else2235 tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);2236 2237 /* apply pixel clock changes */2238 if (!dc->soc->has_nvdisplay) {2239 value = SHIFT_CLK_DIVIDER(crtc_state->div) | PIXEL_CLK_DIVIDER_PCD1;2240 tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);2241 }2242 2243 /* program display mode */2244 tegra_dc_set_timings(dc, mode);2245 2246 /* interlacing isn't supported yet, so disable it */2247 if (dc->soc->supports_interlacing) {2248 value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);2249 value &= ~INTERLACE_ENABLE;2250 tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);2251 }2252 2253 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);2254 value &= ~DISP_CTRL_MODE_MASK;2255 value |= DISP_CTRL_MODE_C_DISPLAY;2256 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);2257 2258 if (!dc->soc->has_nvdisplay) {2259 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);2260 value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |2261 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;2262 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);2263 }2264 2265 /* enable underflow reporting and display red for missing pixels */2266 if (dc->soc->has_nvdisplay) {2267 value = UNDERFLOW_MODE_RED | UNDERFLOW_REPORT_ENABLE;2268 tegra_dc_writel(dc, value, DC_COM_RG_UNDERFLOW);2269 }2270 2271 if (dc->rgb) {2272 /* XXX: parameterize? */2273 value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;2274 tegra_dc_writel(dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);2275 }2276 2277 tegra_dc_commit(dc);2278 2279 drm_crtc_vblank_on(crtc);2280}2281 2282static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,2283 struct drm_atomic_state *state)2284{2285 unsigned long flags;2286 2287 tegra_crtc_update_memory_bandwidth(crtc, state, true);2288 2289 if (crtc->state->event) {2290 spin_lock_irqsave(&crtc->dev->event_lock, flags);2291 2292 if (drm_crtc_vblank_get(crtc) != 0)2293 drm_crtc_send_vblank_event(crtc, crtc->state->event);2294 else2295 drm_crtc_arm_vblank_event(crtc, crtc->state->event);2296 2297 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);2298 2299 crtc->state->event = NULL;2300 }2301}2302 2303static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,2304 struct drm_atomic_state *state)2305{2306 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,2307 crtc);2308 struct tegra_dc_state *dc_state = to_dc_state(crtc_state);2309 struct tegra_dc *dc = to_tegra_dc(crtc);2310 u32 value;2311 2312 value = dc_state->planes << 8 | GENERAL_UPDATE;2313 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);2314 value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);2315 2316 value = dc_state->planes | GENERAL_ACT_REQ;2317 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);2318 value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);2319}2320 2321static bool tegra_plane_is_cursor(const struct drm_plane_state *state)2322{2323 const struct tegra_dc_soc_info *soc = to_tegra_dc(state->crtc)->soc;2324 const struct drm_format_info *fmt = state->fb->format;2325 unsigned int src_w = drm_rect_width(&state->src) >> 16;2326 unsigned int dst_w = drm_rect_width(&state->dst);2327 2328 if (state->plane->type != DRM_PLANE_TYPE_CURSOR)2329 return false;2330 2331 if (soc->supports_cursor)2332 return true;2333 2334 if (src_w != dst_w || fmt->num_planes != 1 || src_w * fmt->cpp[0] > 256)2335 return false;2336 2337 return true;2338}2339 2340static unsigned long2341tegra_plane_overlap_mask(struct drm_crtc_state *state,2342 const struct drm_plane_state *plane_state)2343{2344 const struct drm_plane_state *other_state;2345 const struct tegra_plane *tegra;2346 unsigned long overlap_mask = 0;2347 struct drm_plane *plane;2348 struct drm_rect rect;2349 2350 if (!plane_state->visible || !plane_state->fb)2351 return 0;2352 2353 /*2354 * Data-prefetch FIFO will easily help to overcome temporal memory2355 * pressure if other plane overlaps with the cursor plane.2356 */2357 if (tegra_plane_is_cursor(plane_state))2358 return 0;2359 2360 drm_atomic_crtc_state_for_each_plane_state(plane, other_state, state) {2361 rect = plane_state->dst;2362 2363 tegra = to_tegra_plane(other_state->plane);2364 2365 if (!other_state->visible || !other_state->fb)2366 continue;2367 2368 /*2369 * Ignore cursor plane overlaps because it's not practical to2370 * assume that it contributes to the bandwidth in overlapping2371 * area if window width is small.2372 */2373 if (tegra_plane_is_cursor(other_state))2374 continue;2375 2376 if (drm_rect_intersect(&rect, &other_state->dst))2377 overlap_mask |= BIT(tegra->index);2378 }2379 2380 return overlap_mask;2381}2382 2383static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc,2384 struct drm_atomic_state *state)2385{2386 ulong overlap_mask[TEGRA_DC_LEGACY_PLANES_NUM] = {}, mask;2387 u32 plane_peak_bw[TEGRA_DC_LEGACY_PLANES_NUM] = {};2388 bool all_planes_overlap_simultaneously = true;2389 const struct tegra_plane_state *tegra_state;2390 const struct drm_plane_state *plane_state;2391 struct tegra_dc *dc = to_tegra_dc(crtc);2392 struct drm_crtc_state *new_state;2393 struct tegra_plane *tegra;2394 struct drm_plane *plane;2395 2396 /*2397 * The nv-display uses shared planes. The algorithm below assumes2398 * maximum 3 planes per-CRTC, this assumption isn't applicable to2399 * the nv-display. Note that T124 support has additional windows,2400 * but currently they aren't supported by the driver.2401 */2402 if (dc->soc->has_nvdisplay)2403 return 0;2404 2405 new_state = drm_atomic_get_new_crtc_state(state, crtc);2406 2407 /*2408 * For overlapping planes pixel's data is fetched for each plane at2409 * the same time, hence bandwidths are accumulated in this case.2410 * This needs to be taken into account for calculating total bandwidth2411 * consumed by all planes.2412 *2413 * Here we get the overlapping state of each plane, which is a2414 * bitmask of plane indices telling with what planes there is an2415 * overlap. Note that bitmask[plane] includes BIT(plane) in order2416 * to make further code nicer and simpler.2417 */2418 drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, new_state) {2419 tegra_state = to_const_tegra_plane_state(plane_state);2420 tegra = to_tegra_plane(plane);2421 2422 if (WARN_ON_ONCE(tegra->index >= TEGRA_DC_LEGACY_PLANES_NUM))2423 return -EINVAL;2424 2425 plane_peak_bw[tegra->index] = tegra_state->peak_memory_bandwidth;2426 mask = tegra_plane_overlap_mask(new_state, plane_state);2427 overlap_mask[tegra->index] = mask;2428 2429 if (hweight_long(mask) != 3)2430 all_planes_overlap_simultaneously = false;2431 }2432 2433 /*2434 * Then we calculate maximum bandwidth of each plane state.2435 * The bandwidth includes the plane BW + BW of the "simultaneously"2436 * overlapping planes, where "simultaneously" means areas where DC2437 * fetches from the planes simultaneously during of scan-out process.2438 *2439 * For example, if plane A overlaps with planes B and C, but B and C2440 * don't overlap, then the peak bandwidth will be either in area where2441 * A-and-B or A-and-C planes overlap.2442 *2443 * The plane_peak_bw[] contains peak memory bandwidth values of2444 * each plane, this information is needed by interconnect provider2445 * in order to set up latency allowance based on the peak BW, see2446 * tegra_crtc_update_memory_bandwidth().2447 */2448 drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, new_state) {2449 u32 i, old_peak_bw, new_peak_bw, overlap_bw = 0;2450 2451 /*2452 * Note that plane's atomic check doesn't touch the2453 * total_peak_memory_bandwidth of enabled plane, hence the2454 * current state contains the old bandwidth state from the2455 * previous CRTC commit.2456 */2457 tegra_state = to_const_tegra_plane_state(plane_state);2458 tegra = to_tegra_plane(plane);2459 2460 for_each_set_bit(i, &overlap_mask[tegra->index], 3) {2461 if (i == tegra->index)2462 continue;2463 2464 if (all_planes_overlap_simultaneously)2465 overlap_bw += plane_peak_bw[i];2466 else2467 overlap_bw = max(overlap_bw, plane_peak_bw[i]);2468 }2469 2470 new_peak_bw = plane_peak_bw[tegra->index] + overlap_bw;2471 old_peak_bw = tegra_state->total_peak_memory_bandwidth;2472 2473 /*2474 * If plane's peak bandwidth changed (for example plane isn't2475 * overlapped anymore) and plane isn't in the atomic state,2476 * then add plane to the state in order to have the bandwidth2477 * updated.2478 */2479 if (old_peak_bw != new_peak_bw) {2480 struct tegra_plane_state *new_tegra_state;2481 struct drm_plane_state *new_plane_state;2482 2483 new_plane_state = drm_atomic_get_plane_state(state, plane);2484 if (IS_ERR(new_plane_state))2485 return PTR_ERR(new_plane_state);2486 2487 new_tegra_state = to_tegra_plane_state(new_plane_state);2488 new_tegra_state->total_peak_memory_bandwidth = new_peak_bw;2489 }2490 }2491 2492 return 0;2493}2494 2495static int tegra_crtc_atomic_check(struct drm_crtc *crtc,2496 struct drm_atomic_state *state)2497{2498 int err;2499 2500 err = tegra_crtc_calculate_memory_bandwidth(crtc, state);2501 if (err)2502 return err;2503 2504 return 0;2505}2506 2507void tegra_crtc_atomic_post_commit(struct drm_crtc *crtc,2508 struct drm_atomic_state *state)2509{2510 /*2511 * Display bandwidth is allowed to go down only once hardware state2512 * is known to be armed, i.e. state was committed and VBLANK event2513 * received.2514 */2515 tegra_crtc_update_memory_bandwidth(crtc, state, false);2516}2517 2518static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {2519 .atomic_check = tegra_crtc_atomic_check,2520 .atomic_begin = tegra_crtc_atomic_begin,2521 .atomic_flush = tegra_crtc_atomic_flush,2522 .atomic_enable = tegra_crtc_atomic_enable,2523 .atomic_disable = tegra_crtc_atomic_disable,2524};2525 2526static irqreturn_t tegra_dc_irq(int irq, void *data)2527{2528 struct tegra_dc *dc = data;2529 unsigned long status;2530 2531 status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);2532 tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);2533 2534 if (status & FRAME_END_INT) {2535 /*2536 dev_dbg(dc->dev, "%s(): frame end\n", __func__);2537 */2538 dc->stats.frames_total++;2539 dc->stats.frames++;2540 }2541 2542 if (status & VBLANK_INT) {2543 /*2544 dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);2545 */2546 drm_crtc_handle_vblank(&dc->base);2547 dc->stats.vblank_total++;2548 dc->stats.vblank++;2549 }2550 2551 if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) {2552 /*2553 dev_dbg(dc->dev, "%s(): underflow\n", __func__);2554 */2555 dc->stats.underflow_total++;2556 dc->stats.underflow++;2557 }2558 2559 if (status & (WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT)) {2560 /*2561 dev_dbg(dc->dev, "%s(): overflow\n", __func__);2562 */2563 dc->stats.overflow_total++;2564 dc->stats.overflow++;2565 }2566 2567 if (status & HEAD_UF_INT) {2568 dev_dbg_ratelimited(dc->dev, "%s(): head underflow\n", __func__);2569 dc->stats.underflow_total++;2570 dc->stats.underflow++;2571 }2572 2573 return IRQ_HANDLED;2574}2575 2576static bool tegra_dc_has_window_groups(struct tegra_dc *dc)2577{2578 unsigned int i;2579 2580 if (!dc->soc->wgrps)2581 return true;2582 2583 for (i = 0; i < dc->soc->num_wgrps; i++) {2584 const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i];2585 2586 if (wgrp->dc == dc->pipe && wgrp->num_windows > 0)2587 return true;2588 }2589 2590 return false;2591}2592 2593static int tegra_dc_early_init(struct host1x_client *client)2594{2595 struct drm_device *drm = dev_get_drvdata(client->host);2596 struct tegra_drm *tegra = drm->dev_private;2597 2598 tegra->num_crtcs++;2599 2600 return 0;2601}2602 2603static int tegra_dc_init(struct host1x_client *client)2604{2605 struct drm_device *drm = dev_get_drvdata(client->host);2606 unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;2607 struct tegra_dc *dc = host1x_client_to_dc(client);2608 struct tegra_drm *tegra = drm->dev_private;2609 struct drm_plane *primary = NULL;2610 struct drm_plane *cursor = NULL;2611 int err;2612 2613 /*2614 * DC has been reset by now, so VBLANK syncpoint can be released2615 * for general use.2616 */2617 host1x_syncpt_release_vblank_reservation(client, 26 + dc->pipe);2618 2619 /*2620 * XXX do not register DCs with no window groups because we cannot2621 * assign a primary plane to them, which in turn will cause KMS to2622 * crash.2623 */2624 if (!tegra_dc_has_window_groups(dc))2625 return 0;2626 2627 /*2628 * Set the display hub as the host1x client parent for the display2629 * controller. This is needed for the runtime reference counting that2630 * ensures the display hub is always powered when any of the display2631 * controllers are.2632 */2633 if (dc->soc->has_nvdisplay)2634 client->parent = &tegra->hub->client;2635 2636 dc->syncpt = host1x_syncpt_request(client, flags);2637 if (!dc->syncpt)2638 dev_warn(dc->dev, "failed to allocate syncpoint\n");2639 2640 err = host1x_client_iommu_attach(client);2641 if (err < 0 && err != -ENODEV) {2642 dev_err(client->dev, "failed to attach to domain: %d\n", err);2643 return err;2644 }2645 2646 if (dc->soc->wgrps)2647 primary = tegra_dc_add_shared_planes(drm, dc);2648 else2649 primary = tegra_dc_add_planes(drm, dc);2650 2651 if (IS_ERR(primary)) {2652 err = PTR_ERR(primary);2653 goto cleanup;2654 }2655 2656 if (dc->soc->supports_cursor) {2657 cursor = tegra_dc_cursor_plane_create(drm, dc);2658 if (IS_ERR(cursor)) {2659 err = PTR_ERR(cursor);2660 goto cleanup;2661 }2662 } else {2663 /* dedicate one overlay to mouse cursor */2664 cursor = tegra_dc_overlay_plane_create(drm, dc, 2, true);2665 if (IS_ERR(cursor)) {2666 err = PTR_ERR(cursor);2667 goto cleanup;2668 }2669 }2670 2671 err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,2672 &tegra_crtc_funcs, NULL);2673 if (err < 0)2674 goto cleanup;2675 2676 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);2677 2678 /*2679 * Keep track of the minimum pitch alignment across all display2680 * controllers.2681 */2682 if (dc->soc->pitch_align > tegra->pitch_align)2683 tegra->pitch_align = dc->soc->pitch_align;2684 2685 /* track maximum resolution */2686 if (dc->soc->has_nvdisplay)2687 drm->mode_config.max_width = drm->mode_config.max_height = 16384;2688 else2689 drm->mode_config.max_width = drm->mode_config.max_height = 4096;2690 2691 err = tegra_dc_rgb_init(drm, dc);2692 if (err < 0 && err != -ENODEV) {2693 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);2694 goto cleanup;2695 }2696 2697 err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0,2698 dev_name(dc->dev), dc);2699 if (err < 0) {2700 dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq,2701 err);2702 goto cleanup;2703 }2704 2705 /*2706 * Inherit the DMA parameters (such as maximum segment size) from the2707 * parent host1x device.2708 */2709 client->dev->dma_parms = client->host->dma_parms;2710 2711 return 0;2712 2713cleanup:2714 if (!IS_ERR_OR_NULL(cursor))2715 drm_plane_cleanup(cursor);2716 2717 if (!IS_ERR(primary))2718 drm_plane_cleanup(primary);2719 2720 host1x_client_iommu_detach(client);2721 host1x_syncpt_put(dc->syncpt);2722 2723 return err;2724}2725 2726static int tegra_dc_exit(struct host1x_client *client)2727{2728 struct tegra_dc *dc = host1x_client_to_dc(client);2729 int err;2730 2731 if (!tegra_dc_has_window_groups(dc))2732 return 0;2733 2734 /* avoid a dangling pointer just in case this disappears */2735 client->dev->dma_parms = NULL;2736 2737 devm_free_irq(dc->dev, dc->irq, dc);2738 2739 err = tegra_dc_rgb_exit(dc);2740 if (err) {2741 dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err);2742 return err;2743 }2744 2745 host1x_client_iommu_detach(client);2746 host1x_syncpt_put(dc->syncpt);2747 2748 return 0;2749}2750 2751static int tegra_dc_late_exit(struct host1x_client *client)2752{2753 struct drm_device *drm = dev_get_drvdata(client->host);2754 struct tegra_drm *tegra = drm->dev_private;2755 2756 tegra->num_crtcs--;2757 2758 return 0;2759}2760 2761static int tegra_dc_runtime_suspend(struct host1x_client *client)2762{2763 struct tegra_dc *dc = host1x_client_to_dc(client);2764 struct device *dev = client->dev;2765 int err;2766 2767 err = reset_control_assert(dc->rst);2768 if (err < 0) {2769 dev_err(dev, "failed to assert reset: %d\n", err);2770 return err;2771 }2772 2773 if (dc->soc->has_powergate)2774 tegra_powergate_power_off(dc->powergate);2775 2776 clk_disable_unprepare(dc->clk);2777 pm_runtime_put_sync(dev);2778 2779 return 0;2780}2781 2782static int tegra_dc_runtime_resume(struct host1x_client *client)2783{2784 struct tegra_dc *dc = host1x_client_to_dc(client);2785 struct device *dev = client->dev;2786 int err;2787 2788 err = pm_runtime_resume_and_get(dev);2789 if (err < 0) {2790 dev_err(dev, "failed to get runtime PM: %d\n", err);2791 return err;2792 }2793 2794 if (dc->soc->has_powergate) {2795 err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,2796 dc->rst);2797 if (err < 0) {2798 dev_err(dev, "failed to power partition: %d\n", err);2799 goto put_rpm;2800 }2801 } else {2802 err = clk_prepare_enable(dc->clk);2803 if (err < 0) {2804 dev_err(dev, "failed to enable clock: %d\n", err);2805 goto put_rpm;2806 }2807 2808 err = reset_control_deassert(dc->rst);2809 if (err < 0) {2810 dev_err(dev, "failed to deassert reset: %d\n", err);2811 goto disable_clk;2812 }2813 }2814 2815 return 0;2816 2817disable_clk:2818 clk_disable_unprepare(dc->clk);2819put_rpm:2820 pm_runtime_put_sync(dev);2821 return err;2822}2823 2824static const struct host1x_client_ops dc_client_ops = {2825 .early_init = tegra_dc_early_init,2826 .init = tegra_dc_init,2827 .exit = tegra_dc_exit,2828 .late_exit = tegra_dc_late_exit,2829 .suspend = tegra_dc_runtime_suspend,2830 .resume = tegra_dc_runtime_resume,2831};2832 2833static const struct tegra_dc_soc_info tegra20_dc_soc_info = {2834 .supports_background_color = false,2835 .supports_interlacing = false,2836 .supports_cursor = false,2837 .supports_block_linear = false,2838 .supports_sector_layout = false,2839 .has_legacy_blending = true,2840 .pitch_align = 8,2841 .has_powergate = false,2842 .coupled_pm = true,2843 .has_nvdisplay = false,2844 .num_primary_formats = ARRAY_SIZE(tegra20_primary_formats),2845 .primary_formats = tegra20_primary_formats,2846 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),2847 .overlay_formats = tegra20_overlay_formats,2848 .modifiers = tegra20_modifiers,2849 .has_win_a_without_filters = true,2850 .has_win_b_vfilter_mem_client = true,2851 .has_win_c_without_vert_filter = true,2852 .plane_tiled_memory_bandwidth_x2 = false,2853 .has_pll_d2_out0 = false,2854};2855 2856static const struct tegra_dc_soc_info tegra30_dc_soc_info = {2857 .supports_background_color = false,2858 .supports_interlacing = false,2859 .supports_cursor = false,2860 .supports_block_linear = false,2861 .supports_sector_layout = false,2862 .has_legacy_blending = true,2863 .pitch_align = 8,2864 .has_powergate = false,2865 .coupled_pm = false,2866 .has_nvdisplay = false,2867 .num_primary_formats = ARRAY_SIZE(tegra20_primary_formats),2868 .primary_formats = tegra20_primary_formats,2869 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),2870 .overlay_formats = tegra20_overlay_formats,2871 .modifiers = tegra20_modifiers,2872 .has_win_a_without_filters = false,2873 .has_win_b_vfilter_mem_client = true,2874 .has_win_c_without_vert_filter = false,2875 .plane_tiled_memory_bandwidth_x2 = true,2876 .has_pll_d2_out0 = true,2877};2878 2879static const struct tegra_dc_soc_info tegra114_dc_soc_info = {2880 .supports_background_color = false,2881 .supports_interlacing = false,2882 .supports_cursor = false,2883 .supports_block_linear = false,2884 .supports_sector_layout = false,2885 .has_legacy_blending = true,2886 .pitch_align = 64,2887 .has_powergate = true,2888 .coupled_pm = false,2889 .has_nvdisplay = false,2890 .num_primary_formats = ARRAY_SIZE(tegra114_primary_formats),2891 .primary_formats = tegra114_primary_formats,2892 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),2893 .overlay_formats = tegra114_overlay_formats,2894 .modifiers = tegra20_modifiers,2895 .has_win_a_without_filters = false,2896 .has_win_b_vfilter_mem_client = false,2897 .has_win_c_without_vert_filter = false,2898 .plane_tiled_memory_bandwidth_x2 = true,2899 .has_pll_d2_out0 = true,2900};2901 2902static const struct tegra_dc_soc_info tegra124_dc_soc_info = {2903 .supports_background_color = true,2904 .supports_interlacing = true,2905 .supports_cursor = true,2906 .supports_block_linear = true,2907 .supports_sector_layout = false,2908 .has_legacy_blending = false,2909 .pitch_align = 64,2910 .has_powergate = true,2911 .coupled_pm = false,2912 .has_nvdisplay = false,2913 .num_primary_formats = ARRAY_SIZE(tegra124_primary_formats),2914 .primary_formats = tegra124_primary_formats,2915 .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats),2916 .overlay_formats = tegra124_overlay_formats,2917 .modifiers = tegra124_modifiers,2918 .has_win_a_without_filters = false,2919 .has_win_b_vfilter_mem_client = false,2920 .has_win_c_without_vert_filter = false,2921 .plane_tiled_memory_bandwidth_x2 = false,2922 .has_pll_d2_out0 = true,2923};2924 2925static const struct tegra_dc_soc_info tegra210_dc_soc_info = {2926 .supports_background_color = true,2927 .supports_interlacing = true,2928 .supports_cursor = true,2929 .supports_block_linear = true,2930 .supports_sector_layout = false,2931 .has_legacy_blending = false,2932 .pitch_align = 64,2933 .has_powergate = true,2934 .coupled_pm = false,2935 .has_nvdisplay = false,2936 .num_primary_formats = ARRAY_SIZE(tegra114_primary_formats),2937 .primary_formats = tegra114_primary_formats,2938 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),2939 .overlay_formats = tegra114_overlay_formats,2940 .modifiers = tegra124_modifiers,2941 .has_win_a_without_filters = false,2942 .has_win_b_vfilter_mem_client = false,2943 .has_win_c_without_vert_filter = false,2944 .plane_tiled_memory_bandwidth_x2 = false,2945 .has_pll_d2_out0 = true,2946};2947 2948static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = {2949 {2950 .index = 0,2951 .dc = 0,2952 .windows = (const unsigned int[]) { 0 },2953 .num_windows = 1,2954 }, {2955 .index = 1,2956 .dc = 1,2957 .windows = (const unsigned int[]) { 1 },2958 .num_windows = 1,2959 }, {2960 .index = 2,2961 .dc = 1,2962 .windows = (const unsigned int[]) { 2 },2963 .num_windows = 1,2964 }, {2965 .index = 3,2966 .dc = 2,2967 .windows = (const unsigned int[]) { 3 },2968 .num_windows = 1,2969 }, {2970 .index = 4,2971 .dc = 2,2972 .windows = (const unsigned int[]) { 4 },2973 .num_windows = 1,2974 }, {2975 .index = 5,2976 .dc = 2,2977 .windows = (const unsigned int[]) { 5 },2978 .num_windows = 1,2979 },2980};2981 2982static const struct tegra_dc_soc_info tegra186_dc_soc_info = {2983 .supports_background_color = true,2984 .supports_interlacing = true,2985 .supports_cursor = true,2986 .supports_block_linear = true,2987 .supports_sector_layout = false,2988 .has_legacy_blending = false,2989 .pitch_align = 64,2990 .has_powergate = false,2991 .coupled_pm = false,2992 .has_nvdisplay = true,2993 .wgrps = tegra186_dc_wgrps,2994 .num_wgrps = ARRAY_SIZE(tegra186_dc_wgrps),2995 .plane_tiled_memory_bandwidth_x2 = false,2996 .has_pll_d2_out0 = false,2997};2998 2999static const struct tegra_windowgroup_soc tegra194_dc_wgrps[] = {3000 {3001 .index = 0,3002 .dc = 0,3003 .windows = (const unsigned int[]) { 0 },3004 .num_windows = 1,3005 }, {3006 .index = 1,3007 .dc = 1,3008 .windows = (const unsigned int[]) { 1 },3009 .num_windows = 1,3010 }, {3011 .index = 2,3012 .dc = 1,3013 .windows = (const unsigned int[]) { 2 },3014 .num_windows = 1,3015 }, {3016 .index = 3,3017 .dc = 2,3018 .windows = (const unsigned int[]) { 3 },3019 .num_windows = 1,3020 }, {3021 .index = 4,3022 .dc = 2,3023 .windows = (const unsigned int[]) { 4 },3024 .num_windows = 1,3025 }, {3026 .index = 5,3027 .dc = 2,3028 .windows = (const unsigned int[]) { 5 },3029 .num_windows = 1,3030 },3031};3032 3033static const struct tegra_dc_soc_info tegra194_dc_soc_info = {3034 .supports_background_color = true,3035 .supports_interlacing = true,3036 .supports_cursor = true,3037 .supports_block_linear = true,3038 .supports_sector_layout = true,3039 .has_legacy_blending = false,3040 .pitch_align = 64,3041 .has_powergate = false,3042 .coupled_pm = false,3043 .has_nvdisplay = true,3044 .wgrps = tegra194_dc_wgrps,3045 .num_wgrps = ARRAY_SIZE(tegra194_dc_wgrps),3046 .plane_tiled_memory_bandwidth_x2 = false,3047 .has_pll_d2_out0 = false,3048};3049 3050static const struct of_device_id tegra_dc_of_match[] = {3051 {3052 .compatible = "nvidia,tegra194-dc",3053 .data = &tegra194_dc_soc_info,3054 }, {3055 .compatible = "nvidia,tegra186-dc",3056 .data = &tegra186_dc_soc_info,3057 }, {3058 .compatible = "nvidia,tegra210-dc",3059 .data = &tegra210_dc_soc_info,3060 }, {3061 .compatible = "nvidia,tegra124-dc",3062 .data = &tegra124_dc_soc_info,3063 }, {3064 .compatible = "nvidia,tegra114-dc",3065 .data = &tegra114_dc_soc_info,3066 }, {3067 .compatible = "nvidia,tegra30-dc",3068 .data = &tegra30_dc_soc_info,3069 }, {3070 .compatible = "nvidia,tegra20-dc",3071 .data = &tegra20_dc_soc_info,3072 }, {3073 /* sentinel */3074 }3075};3076MODULE_DEVICE_TABLE(of, tegra_dc_of_match);3077 3078static int tegra_dc_parse_dt(struct tegra_dc *dc)3079{3080 struct device_node *np;3081 u32 value = 0;3082 int err;3083 3084 err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value);3085 if (err < 0) {3086 dev_err(dc->dev, "missing \"nvidia,head\" property\n");3087 3088 /*3089 * If the nvidia,head property isn't present, try to find the3090 * correct head number by looking up the position of this3091 * display controller's node within the device tree. Assuming3092 * that the nodes are ordered properly in the DTS file and3093 * that the translation into a flattened device tree blob3094 * preserves that ordering this will actually yield the right3095 * head number.3096 *3097 * If those assumptions don't hold, this will still work for3098 * cases where only a single display controller is used.3099 */3100 for_each_matching_node(np, tegra_dc_of_match) {3101 if (np == dc->dev->of_node) {3102 of_node_put(np);3103 break;3104 }3105 3106 value++;3107 }3108 }3109 3110 dc->pipe = value;3111 3112 return 0;3113}3114 3115static int tegra_dc_match_by_pipe(struct device *dev, const void *data)3116{3117 struct tegra_dc *dc = dev_get_drvdata(dev);3118 unsigned int pipe = (unsigned long)(void *)data;3119 3120 return dc->pipe == pipe;3121}3122 3123static int tegra_dc_couple(struct tegra_dc *dc)3124{3125 /*3126 * On Tegra20, DC1 requires DC0 to be taken out of reset in order to3127 * be enabled, otherwise CPU hangs on writing to CMD_DISPLAY_COMMAND /3128 * POWER_CONTROL registers during CRTC enabling.3129 */3130 if (dc->soc->coupled_pm && dc->pipe == 1) {3131 struct device *companion;3132 struct tegra_dc *parent;3133 3134 companion = driver_find_device(dc->dev->driver, NULL, (const void *)0,3135 tegra_dc_match_by_pipe);3136 if (!companion)3137 return -EPROBE_DEFER;3138 3139 parent = dev_get_drvdata(companion);3140 dc->client.parent = &parent->client;3141 3142 dev_dbg(dc->dev, "coupled to %s\n", dev_name(companion));3143 }3144 3145 return 0;3146}3147 3148static int tegra_dc_init_opp_table(struct tegra_dc *dc)3149{3150 struct tegra_core_opp_params opp_params = {};3151 int err;3152 3153 err = devm_tegra_core_dev_init_opp_table(dc->dev, &opp_params);3154 if (err && err != -ENODEV)3155 return err;3156 3157 if (err)3158 dc->has_opp_table = false;3159 else3160 dc->has_opp_table = true;3161 3162 return 0;3163}3164 3165static int tegra_dc_probe(struct platform_device *pdev)3166{3167 u64 dma_mask = dma_get_mask(pdev->dev.parent);3168 struct tegra_dc *dc;3169 int err;3170 3171 err = dma_coerce_mask_and_coherent(&pdev->dev, dma_mask);3172 if (err < 0) {3173 dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);3174 return err;3175 }3176 3177 dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL);3178 if (!dc)3179 return -ENOMEM;3180 3181 dc->soc = of_device_get_match_data(&pdev->dev);3182 3183 INIT_LIST_HEAD(&dc->list);3184 dc->dev = &pdev->dev;3185 3186 err = tegra_dc_parse_dt(dc);3187 if (err < 0)3188 return err;3189 3190 err = tegra_dc_couple(dc);3191 if (err < 0)3192 return err;3193 3194 dc->clk = devm_clk_get(&pdev->dev, NULL);3195 if (IS_ERR(dc->clk)) {3196 dev_err(&pdev->dev, "failed to get clock\n");3197 return PTR_ERR(dc->clk);3198 }3199 3200 dc->rst = devm_reset_control_get(&pdev->dev, "dc");3201 if (IS_ERR(dc->rst)) {3202 dev_err(&pdev->dev, "failed to get reset\n");3203 return PTR_ERR(dc->rst);3204 }3205 3206 /* assert reset and disable clock */3207 err = clk_prepare_enable(dc->clk);3208 if (err < 0)3209 return err;3210 3211 usleep_range(2000, 4000);3212 3213 err = reset_control_assert(dc->rst);3214 if (err < 0) {3215 clk_disable_unprepare(dc->clk);3216 return err;3217 }3218 3219 usleep_range(2000, 4000);3220 3221 clk_disable_unprepare(dc->clk);3222 3223 if (dc->soc->has_powergate) {3224 if (dc->pipe == 0)3225 dc->powergate = TEGRA_POWERGATE_DIS;3226 else3227 dc->powergate = TEGRA_POWERGATE_DISB;3228 3229 tegra_powergate_power_off(dc->powergate);3230 }3231 3232 err = tegra_dc_init_opp_table(dc);3233 if (err < 0)3234 return err;3235 3236 dc->regs = devm_platform_ioremap_resource(pdev, 0);3237 if (IS_ERR(dc->regs))3238 return PTR_ERR(dc->regs);3239 3240 dc->irq = platform_get_irq(pdev, 0);3241 if (dc->irq < 0)3242 return -ENXIO;3243 3244 err = tegra_dc_rgb_probe(dc);3245 if (err < 0 && err != -ENODEV)3246 return dev_err_probe(&pdev->dev, err,3247 "failed to probe RGB output\n");3248 3249 platform_set_drvdata(pdev, dc);3250 pm_runtime_enable(&pdev->dev);3251 3252 INIT_LIST_HEAD(&dc->client.list);3253 dc->client.ops = &dc_client_ops;3254 dc->client.dev = &pdev->dev;3255 3256 err = host1x_client_register(&dc->client);3257 if (err < 0) {3258 dev_err(&pdev->dev, "failed to register host1x client: %d\n",3259 err);3260 goto disable_pm;3261 }3262 3263 return 0;3264 3265disable_pm:3266 pm_runtime_disable(&pdev->dev);3267 tegra_dc_rgb_remove(dc);3268 3269 return err;3270}3271 3272static void tegra_dc_remove(struct platform_device *pdev)3273{3274 struct tegra_dc *dc = platform_get_drvdata(pdev);3275 3276 host1x_client_unregister(&dc->client);3277 3278 tegra_dc_rgb_remove(dc);3279 3280 pm_runtime_disable(&pdev->dev);3281}3282 3283struct platform_driver tegra_dc_driver = {3284 .driver = {3285 .name = "tegra-dc",3286 .of_match_table = tegra_dc_of_match,3287 },3288 .probe = tegra_dc_probe,3289 .remove_new = tegra_dc_remove,3290};3291