// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. */ #include <linux/clk.h>#include <linux/debugfs.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/iommu.h>#include <linux/interconnect.h>#include <linux/module.h>#include <linux/of.h>#include <linux/platform_device.h>#include <linux/pm_domain.h>#include <linux/pm_opp.h>#include <linux/pm_runtime.h>#include <linux/reset.h> #include <soc/tegra/common.h>#include <soc/tegra/pmc.h> #include <drm/drm_atomic.h>#include <drm/drm_atomic_helper.h>#include <drm/drm_blend.h>#include <drm/drm_debugfs.h>#include <drm/drm_fourcc.h>#include <drm/drm_framebuffer.h>#include <drm/drm_print.h>#include <drm/drm_vblank.h> #include "dc.h"#include "drm.h"#include "gem.h"#include "hub.h"#include "plane.h" static const u16 default_srgb_lut[] = { 0x6000, 0x60CE, 0x619D, 0x626C, 0x632D, 0x63D4, 0x6469, 0x64F0, 0x656B, 0x65DF, 0x664A, 0x66B0, 0x6711, 0x676D, 0x67C4, 0x6819, 0x686A, 0x68B8, 0x6904, 0x694D, 0x6994, 0x69D8, 0x6A1B, 0x6A5D, 0x6A9C, 0x6ADA, 0x6B17, 0x6B52, 0x6B8C, 0x6BC5, 0x6BFD, 0x6C33, 0x6C69, 0x6C9E, 0x6CD1, 0x6D04, 0x6D36, 0x6D67, 0x6D98, 0x6DC7, 0x6DF6, 0x6E25, 0x6E52, 0x6E7F, 0x6EAC, 0x6ED7, 0x6F03, 0x6F2D, 0x6F58, 0x6F81, 0x6FAA, 0x6FD3, 0x6FFB, 0x7023, 0x704B, 0x7071, 0x7098, 0x70BE, 0x70E4, 0x7109, 0x712E, 0x7153, 0x7177, 0x719B, 0x71BF, 0x71E2, 0x7205, 0x7227, 0x724A, 0x726C, 0x728E, 0x72AF, 0x72D0, 0x72F1, 0x7312, 0x7333, 0x7353, 0x7373, 0x7392, 0x73B2, 0x73D1, 0x73F0, 0x740F, 0x742D, 0x744C, 0x746A, 0x7488, 0x74A6, 0x74C3, 0x74E0, 0x74FE, 0x751B, 0x7537, 0x7554, 0x7570, 0x758D, 0x75A9, 0x75C4, 0x75E0, 0x75FC, 0x7617, 0x7632, 0x764D, 0x7668, 0x7683, 0x769E, 0x76B8, 0x76D3, 0x76ED, 0x7707, 0x7721, 0x773B, 0x7754, 0x776E, 0x7787, 0x77A0, 0x77B9, 0x77D2, 0x77EB, 0x7804, 0x781D, 0x7835, 0x784E, 0x7866, 0x787E, 0x7896, 0x78AE, 0x78C6, 0x78DD, 0x78F5, 0x790D, 0x7924, 0x793B, 0x7952, 0x796A, 0x7981, 0x7997, 0x79AE, 0x79C5, 0x79DB, 0x79F2, 0x7A08, 0x7A1F, 0x7A35, 0x7A4B, 0x7A61, 0x7A77, 0x7A8D, 0x7AA3, 0x7AB8, 0x7ACE, 0x7AE3, 0x7AF9, 0x7B0E, 0x7B24, 0x7B39, 0x7B4E, 0x7B63, 0x7B78, 0x7B8D, 0x7BA2, 0x7BB6, 0x7BCB, 0x7BE0, 0x7BF4, 0x7C08, 0x7C1D, 0x7C31, 0x7C45, 0x7C59, 0x7C6E, 0x7C82, 0x7C96, 0x7CA9, 0x7CBD, 0x7CD1, 0x7CE5, 0x7CF8, 0x7D0C, 0x7D1F, 0x7D33, 0x7D46, 0x7D59, 0x7D6D, 0x7D80, 0x7D93, 0x7DA6, 0x7DB9, 0x7DCC, 0x7DDF, 0x7DF2, 0x7E04, 0x7E17, 0x7E2A, 0x7E3C, 0x7E4F, 0x7E61, 0x7E74, 0x7E86, 0x7E98, 0x7EAB, 0x7EBD, 0x7ECF, 0x7EE1, 0x7EF3, 0x7F05, 0x7F17, 0x7F29, 0x7F3B, 0x7F4D, 0x7F5E, 0x7F70, 0x7F82, 0x7F93, 0x7FA5, 0x7FB6, 0x7FC8, 0x7FD9, 0x7FEB, 0x7FFC, 0x800D, 0x801E, 0x8030, 0x8041, 0x8052, 0x8063, 0x8074, 0x8085, 0x8096, 0x80A7, 0x80B7, 0x80C8, 0x80D9, 0x80EA, 0x80FA, 0x810B, 0x811C, 0x812C, 0x813D, 0x814D, 0x815D, 0x816E, 0x817E, 0x818E, 0x819F, 0x81AF, 0x81BF, 0x81CF, 0x81DF, 0x81EF, 0x81FF, 0x820F, 0x821F, 0x822F, 0x823F, 0x824F, 0x825F, 0x826F, 0x827E, 0x828E, 0x829E, 0x82AD, 0x82BD, 0x82CC, 0x82DC, 0x82EB, 0x82FB, 0x830A, 0x831A, 0x8329, 0x8338, 0x8348, 0x8357, 0x8366, 0x8375, 0x8385, 0x8394, 0x83A3, 0x83B2, 0x83C1, 0x83D0, 0x83DF, 0x83EE, 0x83FD, 0x840C, 0x841A, 0x8429, 0x8438, 0x8447, 0x8455, 0x8464, 0x8473, 0x8481, 0x8490, 0x849F, 0x84AD, 0x84BC, 0x84CA, 0x84D9, 0x84E7, 0x84F5, 0x8504, 0x8512, 0x8521, 0x852F, 0x853D, 0x854B, 0x855A, 0x8568, 0x8576, 0x8584, 0x8592, 0x85A0, 0x85AE, 0x85BC, 0x85CA, 0x85D8, 0x85E6, 0x85F4, 0x8602, 0x8610, 0x861E, 0x862C, 0x8639, 0x8647, 0x8655, 0x8663, 0x8670, 0x867E, 0x868C, 0x8699, 0x86A7, 0x86B5, 0x86C2, 0x86D0, 0x86DD, 0x86EB, 0x86F8, 0x8705, 0x8713, 0x8720, 0x872E, 0x873B, 0x8748, 0x8756, 0x8763, 0x8770, 0x877D, 0x878B, 0x8798, 0x87A5, 0x87B2, 0x87BF, 0x87CC, 0x87D9, 0x87E6, 0x87F3, 0x8801, 0x880E, 0x881A, 0x8827, 0x8834, 0x8841, 0x884E, 0x885B, 0x8868, 0x8875, 0x8882, 0x888E, 0x889B, 0x88A8, 0x88B5, 0x88C1, 0x88CE, 0x88DB, 0x88E7, 0x88F4, 0x8900, 0x890D, 0x891A, 0x8926, 0x8933, 0x893F, 0x894C, 0x8958, 0x8965, 0x8971, 0x897D, 0x898A, 0x8996, 0x89A3, 0x89AF, 0x89BB, 0x89C8, 0x89D4, 0x89E0, 0x89EC, 0x89F9, 0x8A05, 0x8A11, 0x8A1D, 0x8A29, 0x8A36, 0x8A42, 0x8A4E, 0x8A5A, 0x8A66, 0x8A72, 0x8A7E, 0x8A8A, 0x8A96, 0x8AA2, 0x8AAE, 0x8ABA, 0x8AC6, 0x8AD2, 0x8ADE, 0x8AEA, 0x8AF5, 0x8B01, 0x8B0D, 0x8B19, 0x8B25, 0x8B31, 0x8B3C, 0x8B48, 0x8B54, 0x8B60, 0x8B6B, 0x8B77, 0x8B83, 0x8B8E, 0x8B9A, 0x8BA6, 0x8BB1, 0x8BBD, 0x8BC8, 0x8BD4, 0x8BDF, 0x8BEB, 0x8BF6, 0x8C02, 0x8C0D, 0x8C19, 0x8C24, 0x8C30, 0x8C3B, 0x8C47, 0x8C52, 0x8C5D, 0x8C69, 0x8C74, 0x8C80, 0x8C8B, 0x8C96, 0x8CA1, 0x8CAD, 0x8CB8, 0x8CC3, 0x8CCF, 0x8CDA, 0x8CE5, 0x8CF0, 0x8CFB, 0x8D06, 0x8D12, 0x8D1D, 0x8D28, 0x8D33, 0x8D3E, 0x8D49, 0x8D54, 0x8D5F, 0x8D6A, 0x8D75, 0x8D80, 0x8D8B, 0x8D96, 0x8DA1, 0x8DAC, 0x8DB7, 0x8DC2, 0x8DCD, 0x8DD8, 0x8DE3, 0x8DEE, 0x8DF9, 0x8E04, 0x8E0E, 0x8E19, 0x8E24, 0x8E2F, 0x8E3A, 0x8E44, 0x8E4F, 0x8E5A, 0x8E65, 0x8E6F, 0x8E7A, 0x8E85, 0x8E90, 0x8E9A, 0x8EA5, 0x8EB0, 0x8EBA, 0x8EC5, 0x8ECF, 0x8EDA, 0x8EE5, 0x8EEF, 0x8EFA, 0x8F04, 0x8F0F, 0x8F19, 0x8F24, 0x8F2E, 0x8F39, 0x8F43, 0x8F4E, 0x8F58, 0x8F63, 0x8F6D, 0x8F78, 0x8F82, 0x8F8C, 0x8F97, 0x8FA1, 0x8FAC, 0x8FB6, 0x8FC0, 0x8FCB, 0x8FD5, 0x8FDF, 0x8FEA, 0x8FF4, 0x8FFE, 0x9008, 0x9013, 0x901D, 0x9027, 0x9031, 0x903C, 0x9046, 0x9050, 0x905A, 0x9064, 0x906E, 0x9079, 0x9083, 0x908D, 0x9097, 0x90A1, 0x90AB, 0x90B5, 0x90BF, 0x90C9, 0x90D3, 0x90DD, 0x90E7, 0x90F1, 0x90FB, 0x9105, 0x910F, 0x9119, 0x9123, 0x912D, 0x9137, 0x9141, 0x914B, 0x9155, 0x915F, 0x9169, 0x9173, 0x917D, 0x9186, 0x9190, 0x919A, 0x91A4, 0x91AE, 0x91B8, 0x91C1, 0x91CB, 0x91D5, 0x91DF, 0x91E9, 0x91F2, 0x91FC, 0x9206, 0x9210, 0x9219, 0x9223, 0x922D, 0x9236, 0x9240, 0x924A, 0x9253, 0x925D, 0x9267, 0x9270, 0x927A, 0x9283, 0x928D, 0x9297, 0x92A0, 0x92AA, 0x92B3, 0x92BD, 0x92C6, 0x92D0, 0x92DA, 0x92E3, 0x92ED, 0x92F6, 0x9300, 0x9309, 0x9313, 0x931C, 0x9325, 0x932F, 0x9338, 0x9342, 0x934B, 0x9355, 0x935E, 0x9367, 0x9371, 0x937A, 0x9384, 0x938D, 0x9396, 0x93A0, 0x93A9, 0x93B2, 0x93BC, 0x93C5, 0x93CE, 0x93D7, 0x93E1, 0x93EA, 0x93F3, 0x93FC, 0x9406, 0x940F, 0x9418, 0x9421, 0x942B, 0x9434, 0x943D, 0x9446, 0x944F, 0x9459, 0x9462, 0x946B, 0x9474, 0x947D, 0x9486, 0x948F, 0x9499, 0x94A2, 0x94AB, 0x94B4, 0x94BD, 0x94C6, 0x94CF, 0x94D8, 0x94E1, 0x94EA, 0x94F3, 0x94FC, 0x9505, 0x950E, 0x9517, 0x9520, 0x9529, 0x9532, 0x953B, 0x9544, 0x954D, 0x9556, 0x955F, 0x9568, 0x9571, 0x957A, 0x9583, 0x958C, 0x9595, 0x959D, 0x95A6, 0x95AF, 0x95B8, 0x95C1, 0x95CA, 0x95D3, 0x95DB, 0x95E4, 0x95ED, 0x95F6, 0x95FF, 0x9608, 0x9610, 0x9619, 0x9622, 0x962B, 0x9633, 0x963C, 0x9645, 0x964E, 0x9656, 0x965F, 0x9668, 0x9671, 0x9679, 0x9682, 0x968B, 0x9693, 0x969C, 0x96A5, 0x96AD, 0x96B6, 0x96BF, 0x96C7, 0x96D0, 0x96D9, 0x96E1, 0x96EA, 0x96F2, 0x96FB, 0x9704, 0x970C, 0x9715, 0x971D, 0x9726, 0x972E, 0x9737, 0x9740, 0x9748, 0x9751, 0x9759, 0x9762, 0x976A, 0x9773, 0x977B, 0x9784, 0x978C, 0x9795, 0x979D, 0x97A6, 0x97AE, 0x97B6, 0x97BF, 0x97C7, 0x97D0, 0x97D8, 0x97E1, 0x97E9, 0x97F1, 0x97FA, 0x9802, 0x980B, 0x9813, 0x981B, 0x9824, 0x982C, 0x9834, 0x983D, 0x9845, 0x984D, 0x9856, 0x985E, 0x9866, 0x986F, 0x9877, 0x987F, 0x9888, 0x9890, 0x9898, 0x98A0, 0x98A9, 0x98B1, 0x98B9, 0x98C1, 0x98CA, 0x98D2, 0x98DA, 0x98E2, 0x98EB, 0x98F3, 0x98FB, 0x9903, 0x990B, 0x9914, 0x991C, 0x9924, 0x992C, 0x9934, 0x993C, 0x9945, 0x994D, 0x9955, 0x995D, 0x9965, 0x996D, 0x9975, 0x997D, 0x9986, 0x998E, 0x9996, 0x999E, 0x99A6, 0x99AE, 0x99B6, 0x99BE, 0x99C6, 0x99CE, 0x99D6, 0x99DE, 0x99E6, 0x99EE, 0x99F6, 0x99FE, 0x9A06, 0x9A0E, 0x9A16, 0x9A1E, 0x9A26, 0x9A2E, 0x9A36, 0x9A3E, 0x9A46, 0x9A4E, 0x9A56, 0x9A5E, 0x9A66, 0x9A6E, 0x9A76, 0x9A7E, 0x9A86, 0x9A8E, 0x9A96, 0x9A9D, 0x9AA5, 0x9AAD, 0x9AB5, 0x9ABD, 0x9AC5, 0x9ACD, 0x9AD5, 0x9ADC, 0x9AE4, 0x9AEC, 0x9AF4, 0x9AFC, 0x9B04, 0x9B0C, 0x9B13, 0x9B1B, 0x9B23, 0x9B2B, 0x9B33, 0x9B3A, 0x9B42, 0x9B4A, 0x9B52, 0x9B59, 0x9B61, 0x9B69, 0x9B71, 0x9B79, 0x9B80, 0x9B88, 0x9B90, 0x9B97, 0x9B9F, 0x9BA7, 0x9BAF, 0x9BB6, 0x9BBE, 0x9BC6, 0x9BCD, 0x9BD5, 0x9BDD, 0x9BE5, 0x9BEC, 0x9BF4, 0x9BFC, 0x9C03, 0x9C0B, 0x9C12, 0x9C1A, 0x9C22, 0x9C29, 0x9C31, 0x9C39, 0x9C40, 0x9C48, 0x9C50, 0x9C57, 0x9C5F, 0x9C66, 0x9C6E, 0x9C75, 0x9C7D, 0x9C85, 0x9C8C, 0x9C94, 0x9C9B, 0x9CA3, 0x9CAA, 0x9CB2, 0x9CBA, 0x9CC1, 0x9CC9, 0x9CD0, 0x9CD8, 0x9CDF, 0x9CE7, 0x9CEE, 0x9CF6, 0x9CFD, 0x9D05, 0x9D0C, 0x9D14, 0x9D1B, 0x9D23, 0x9D2A, 0x9D32, 0x9D39, 0x9D40, 0x9D48, 0x9D4F, 0x9D57, 0x9D5E, 0x9D66, 0x9D6D, 0x9D75, 0x9D7C, 0x9D83, 0x9D8B, 0x9D92, 0x9D9A, 0x9DA1, 0x9DA8, 0x9DB0, 0x9DB7, 0x9DBE, 0x9DC6, 0x9DCD, 0x9DD5, 0x9DDC, 0x9DE3, 0x9DEB, 0x9DF2, 0x9DF9, 0x9E01, 0x9E08, 0x9E0F, 0x9E17, 0x9E1E, 0x9E25, 0x9E2D, 0x9E34, 0x9E3B, 0x9E43, 0x9E4A, 0x9E51, 0x9E58, 0x9E60, 0x9E67, 0x9E6E, 0x9E75, 0x9E7D, 0x9E84, 0x9E8B, 0x9E92, 0x9E9A, 0x9EA1, 0x9EA8, 0x9EAF, 0x9EB7, 0x9EBE, 0x9EC5, 0x9ECC, 0x9ED4, 0x9EDB, 0x9EE2, 0x9EE9, 0x9EF0, 0x9EF7, 0x9EFF, 0x9F06, 0x9F0D, 0x9F14, 0x9F1B, 0x9F23, 0x9F2A, 0x9F31, 0x9F38, 0x9F3F, 0x9F46, 0x9F4D, 0x9F55, 0x9F5C, 0x9F63, 0x9F6A, 0x9F71, 0x9F78, 0x9F7F, 0x9F86, 0x9F8D, 0x9F95, 0x9F9C, 0x9FA3, 0x9FAA, 0x9FB1, 0x9FB8, 0x9FBF, 0x9FC6, 0x9FCD, 0x9FD4, 0x9FDB, 0x9FE2, 0x9FE9, 0x9FF0, 0x9FF7, 0x9FFF,}; static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); static void tegra_dc_stats_reset(struct tegra_dc_stats *stats){ stats->frames = 0; stats->vblank = 0; stats->underflow = 0; stats->overflow = 0;} /* Reads the active copy of a register. */static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset){ u32 value; tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); value = tegra_dc_readl(dc, offset); tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); return value;} static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, unsigned int offset){ if (offset >= 0x500 && offset <= 0x638) { offset = 0x000 + (offset - 0x500); return plane->offset + offset; } if (offset >= 0x700 && offset <= 0x719) { offset = 0x180 + (offset - 0x700); return plane->offset + offset; } if (offset >= 0x800 && offset <= 0x839) { offset = 0x1c0 + (offset - 0x800); return plane->offset + offset; } dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset); return plane->offset + offset;} static inline u32 tegra_plane_readl(struct tegra_plane *plane, unsigned int offset){ return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset));} static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value, unsigned int offset){ tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset));} bool tegra_dc_has_output(struct tegra_dc *dc, struct device *dev){ struct device_node *np = dc->dev->of_node; struct of_phandle_iterator it; int err; of_for_each_phandle(&it, err, np, "nvidia,outputs", NULL, 0) if (it.node == dev->of_node) { of_node_put(it.node); return true; } return false;} /* * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy. * Latching happens mmediately if the display controller is in STOP mode or * on the next frame boundary otherwise. * * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits * are written. When the *_ACT_REQ bits are written, the ARM copy is latched * into the ACTIVE copy, either immediately if the display controller is in * STOP mode, or at the next frame boundary otherwise. */void tegra_dc_commit(struct tegra_dc *dc){ tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);} static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, unsigned int bpp){ fixed20_12 outf = dfixed_init(out); fixed20_12 inf = dfixed_init(in); u32 dda_inc; int max; if (v) max = 15; else { switch (bpp) { case 2: max = 8; break; default: WARN_ON_ONCE(1); fallthrough; case 4: max = 4; break; } } outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); inf.full -= dfixed_const(1); dda_inc = dfixed_div(inf, outf); dda_inc = min_t(u32, dda_inc, dfixed_const(max)); return dda_inc;} static inline u32 compute_initial_dda(unsigned int in){ fixed20_12 inf = dfixed_init(in); return dfixed_frac(inf);} static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane){ u32 background[3] = { BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE, BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE, BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE, }; u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) | BLEND_COLOR_KEY_NONE; u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255); struct tegra_plane_state *state; u32 blending[2]; unsigned int i; /* disable blending for non-overlapping case */ tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY); tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN); state = to_tegra_plane_state(plane->base.state); if (state->opaque) { /* * Since custom fix-weight blending isn't utilized and weight * of top window is set to max, we can enforce dependent * blending which in this case results in transparent bottom * window if top window is opaque and if top window enables * alpha blending, then bottom window is getting alpha value * of 1 minus the sum of alpha components of the overlapping * plane. */ background[0] |= BLEND_CONTROL_DEPENDENT; background[1] |= BLEND_CONTROL_DEPENDENT; /* * The region where three windows overlap is the intersection * of the two regions where two windows overlap. It contributes * to the area if all of the windows on top of it have an alpha * component. */ switch (state->base.normalized_zpos) { case 0: if (state->blending[0].alpha && state->blending[1].alpha) background[2] |= BLEND_CONTROL_DEPENDENT; break; case 1: background[2] |= BLEND_CONTROL_DEPENDENT; break; } } else { /* * Enable alpha blending if pixel format has an alpha * component. */ foreground |= BLEND_CONTROL_ALPHA; /* * If any of the windows on top of this window is opaque, it * will completely conceal this window within that area. If * top window has an alpha component, it is blended over the * bottom window. */ for (i = 0; i < 2; i++) { if (state->blending[i].alpha && state->blending[i].top) background[i] |= BLEND_CONTROL_DEPENDENT; } switch (state->base.normalized_zpos) { case 0: if (state->blending[0].alpha && state->blending[1].alpha) background[2] |= BLEND_CONTROL_DEPENDENT; break; case 1: /* * When both middle and topmost windows have an alpha, * these windows a mixed together and then the result * is blended over the bottom window. */ if (state->blending[0].alpha && state->blending[0].top) background[2] |= BLEND_CONTROL_ALPHA; if (state->blending[1].alpha && state->blending[1].top) background[2] |= BLEND_CONTROL_ALPHA; break; } } switch (state->base.normalized_zpos) { case 0: tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X); tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y); tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY); break; case 1: /* * If window B / C is topmost, then X / Y registers are * matching the order of blending[...] state indices, * otherwise a swap is required. */ if (!state->blending[0].top && state->blending[1].top) { blending[0] = foreground; blending[1] = background[1]; } else { blending[0] = background[0]; blending[1] = foreground; } tegra_plane_writel(plane, blending[0], DC_WIN_BLEND_2WIN_X); tegra_plane_writel(plane, blending[1], DC_WIN_BLEND_2WIN_Y); tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY); break; case 2: tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X); tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_Y); tegra_plane_writel(plane, foreground, DC_WIN_BLEND_3WIN_XY); break; }} static void tegra_plane_setup_blending(struct tegra_plane *plane, const struct tegra_dc_window *window){ u32 value; value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 | BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC | BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC; tegra_plane_writel(plane, value, DC_WIN_BLEND_MATCH_SELECT); value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 | BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC | BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC; tegra_plane_writel(plane, value, DC_WIN_BLEND_NOMATCH_SELECT); value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - window->zpos); tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL);} static booltegra_plane_use_horizontal_filtering(struct tegra_plane *plane, const struct tegra_dc_window *window){ struct tegra_dc *dc = plane->dc; if (window->src.w == window->dst.w) return false; if (plane->index == 0 && dc->soc->has_win_a_without_filters) return false; return true;} static booltegra_plane_use_vertical_filtering(struct tegra_plane *plane, const struct tegra_dc_window *window){ struct tegra_dc *dc = plane->dc; if (window->src.h == window->dst.h) return false; if (plane->index == 0 && dc->soc->has_win_a_without_filters) return false; if (plane->index == 2 && dc->soc->has_win_c_without_vert_filter) return false; return true;} static void tegra_dc_setup_window(struct tegra_plane *plane, const struct tegra_dc_window *window){ unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; struct tegra_dc *dc = plane->dc; unsigned int planes; u32 value; bool yuv; /* * For YUV planar modes, the number of bytes per pixel takes into * account only the luma component and therefore is 1. */ yuv = tegra_plane_format_is_yuv(window->format, &planes, NULL); if (!yuv) bpp = window->bits_per_pixel / 8; else bpp = (planes > 1) ? 1 : 2; tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH); tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP); value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); tegra_plane_writel(plane, value, DC_WIN_POSITION); value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); tegra_plane_writel(plane, value, DC_WIN_SIZE); h_offset = window->src.x * bpp; v_offset = window->src.y; h_size = window->src.w * bpp; v_size = window->src.h; if (window->reflect_x) h_offset += (window->src.w - 1) * bpp; if (window->reflect_y) v_offset += window->src.h - 1; value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE); /* * For DDA computations the number of bytes per pixel for YUV planar * modes needs to take into account all Y, U and V components. */ if (yuv && planes > 1) bpp = 2; h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); tegra_plane_writel(plane, value, DC_WIN_DDA_INC); Lines 1–500 of 3430. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. */ #include <linux/clk.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/iommu.h> #include <linux/interconnect.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/reset.h> #include <soc/tegra/common.h> #include <soc/tegra/pmc.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_debugfs.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_print.h> #include <drm/drm_vblank.h> #include "dc.h" #include "drm.h" #include "gem.h" #include "hub.h" #include "plane.h" static const u16 default_srgb_lut[] = { 0x6000, 0x60CE, 0x619D, 0x626C, 0x632D, 0x63D4, 0x6469, 0x64F0, 0x656B, 0x65DF, 0x664A, 0x66B0, 0x6711, 0x676D, 0x67C4, 0x6819, 0x686A, 0x68B8, 0x6904, 0x694D, 0x6994, 0x69D8, 0x6A1B, 0x6A5D, 0x6A9C, 0x6ADA, 0x6B17, 0x6B52, 0x6B8C, 0x6BC5, 0x6BFD, 0x6C33, 0x6C69, 0x6C9E, 0x6CD1, 0x6D04, 0x6D36, 0x6D67, 0x6D98, 0x6DC7, 0x6DF6, 0x6E25, 0x6E52, 0x6E7F, 0x6EAC, 0x6ED7, 0x6F03, 0x6F2D, 0x6F58, 0x6F81, 0x6FAA, 0x6FD3, 0x6FFB, 0x7023, 0x704B, 0x7071, 0x7098, 0x70BE, 0x70E4, 0x7109, 0x712E, 0x7153, 0x7177, 0x719B, 0x71BF, 0x71E2, 0x7205, 0x7227, 0x724A, 0x726C, 0x728E, 0x72AF, 0x72D0, 0x72F1, 0x7312, 0x7333, 0x7353, 0x7373, 0x7392, 0x73B2, 0x73D1, 0x73F0, 0x740F, 0x742D, 0x744C, 0x746A, 0x7488, 0x74A6, 0x74C3, 0x74E0, 0x74FE, 0x751B, 0x7537, 0x7554, 0x7570, 0x758D, 0x75A9, 0x75C4, 0x75E0, 0x75FC, 0x7617, 0x7632, 0x764D, 0x7668, 0x7683, 0x769E, 0x76B8, 0x76D3, 0x76ED, 0x7707, 0x7721, 0x773B, 0x7754, 0x776E, 0x7787, 0x77A0, 0x77B9, 0x77D2, 0x77EB, 0x7804, 0x781D, 0x7835, 0x784E, 0x7866, 0x787E, 0x7896, 0x78AE, 0x78C6, 0x78DD, 0x78F5, 0x790D, 0x7924, 0x793B, 0x7952, 0x796A, 0x7981, 0x7997, 0x79AE, 0x79C5, 0x79DB, 0x79F2, 0x7A08, 0x7A1F, 0x7A35, 0x7A4B, 0x7A61, 0x7A77, 0x7A8D, 0x7AA3, 0x7AB8, 0x7ACE, 0x7AE3, 0x7AF9, 0x7B0E, 0x7B24, 0x7B39, 0x7B4E, 0x7B63, 0x7B78, 0x7B8D, 0x7BA2, 0x7BB6, 0x7BCB, 0x7BE0, 0x7BF4, 0x7C08, 0x7C1D, 0x7C31, 0x7C45, 0x7C59, 0x7C6E, 0x7C82, 0x7C96, 0x7CA9, 0x7CBD, 0x7CD1, 0x7CE5, 0x7CF8, 0x7D0C, 0x7D1F, 0x7D33, 0x7D46, 0x7D59, 0x7D6D, 0x7D80, 0x7D93, 0x7DA6, 0x7DB9, 0x7DCC, 0x7DDF, 0x7DF2, 0x7E04, 0x7E17, 0x7E2A, 0x7E3C, 0x7E4F, 0x7E61, 0x7E74, 0x7E86, 0x7E98, 0x7EAB, 0x7EBD, 0x7ECF, 0x7EE1, 0x7EF3, 0x7F05, 0x7F17, 0x7F29, 0x7F3B, 0x7F4D, 0x7F5E, 0x7F70, 0x7F82, 0x7F93, 0x7FA5, 0x7FB6, 0x7FC8, 0x7FD9, 0x7FEB, 0x7FFC, 0x800D, 0x801E, 0x8030, 0x8041, 0x8052, 0x8063, 0x8074, 0x8085, 0x8096, 0x80A7, 0x80B7, 0x80C8, 0x80D9, 0x80EA, 0x80FA, 0x810B, 0x811C, 0x812C, 0x813D, 0x814D, 0x815D, 0x816E, 0x817E, 0x818E, 0x819F, 0x81AF, 0x81BF, 0x81CF, 0x81DF, 0x81EF, 0x81FF, 0x820F, 0x821F, 0x822F, 0x823F, 0x824F, 0x825F, 0x826F, 0x827E, 0x828E, 0x829E, 0x82AD, 0x82BD, 0x82CC, 0x82DC, 0x82EB, 0x82FB, 0x830A, 0x831A, 0x8329, 0x8338, 0x8348, 0x8357, 0x8366, 0x8375, 0x8385, 0x8394, 0x83A3, 0x83B2, 0x83C1, 0x83D0, 0x83DF, 0x83EE, 0x83FD, 0x840C, 0x841A, 0x8429, 0x8438, 0x8447, 0x8455, 0x8464, 0x8473, 0x8481, 0x8490, 0x849F, 0x84AD, 0x84BC, 0x84CA, 0x84D9, 0x84E7, 0x84F5, 0x8504, 0x8512, 0x8521, 0x852F, 0x853D, 0x854B, 0x855A, 0x8568, 0x8576, 0x8584, 0x8592, 0x85A0, 0x85AE, 0x85BC, 0x85CA, 0x85D8, 0x85E6, 0x85F4, 0x8602, 0x8610, 0x861E, 0x862C, 0x8639, 0x8647, 0x8655, 0x8663, 0x8670, 0x867E, 0x868C, 0x8699, 0x86A7, 0x86B5, 0x86C2, 0x86D0, 0x86DD, 0x86EB, 0x86F8, 0x8705, 0x8713, 0x8720, 0x872E, 0x873B, 0x8748, 0x8756, 0x8763, 0x8770, 0x877D, 0x878B, 0x8798, 0x87A5, 0x87B2, 0x87BF, 0x87CC, 0x87D9, 0x87E6, 0x87F3, 0x8801, 0x880E, 0x881A, 0x8827, 0x8834, 0x8841, 0x884E, 0x885B, 0x8868, 0x8875, 0x8882, 0x888E, 0x889B, 0x88A8, 0x88B5, 0x88C1, 0x88CE, 0x88DB, 0x88E7, 0x88F4, 0x8900, 0x890D, 0x891A, 0x8926, 0x8933, 0x893F, 0x894C, 0x8958, 0x8965, 0x8971, 0x897D, 0x898A, 0x8996, 0x89A3, 0x89AF, 0x89BB, 0x89C8, 0x89D4, 0x89E0, 0x89EC, 0x89F9, 0x8A05, 0x8A11, 0x8A1D, 0x8A29, 0x8A36, 0x8A42, 0x8A4E, 0x8A5A, 0x8A66, 0x8A72, 0x8A7E, 0x8A8A, 0x8A96, 0x8AA2, 0x8AAE, 0x8ABA, 0x8AC6, 0x8AD2, 0x8ADE, 0x8AEA, 0x8AF5, 0x8B01, 0x8B0D, 0x8B19, 0x8B25, 0x8B31, 0x8B3C, 0x8B48, 0x8B54, 0x8B60, 0x8B6B, 0x8B77, 0x8B83, 0x8B8E, 0x8B9A, 0x8BA6, 0x8BB1, 0x8BBD, 0x8BC8, 0x8BD4, 0x8BDF, 0x8BEB, 0x8BF6, 0x8C02, 0x8C0D, 0x8C19, 0x8C24, 0x8C30, 0x8C3B, 0x8C47, 0x8C52, 0x8C5D, 0x8C69, 0x8C74, 0x8C80, 0x8C8B, 0x8C96, 0x8CA1, 0x8CAD, 0x8CB8, 0x8CC3, 0x8CCF, 0x8CDA, 0x8CE5, 0x8CF0, 0x8CFB, 0x8D06, 0x8D12, 0x8D1D, 0x8D28, 0x8D33, 0x8D3E, 0x8D49, 0x8D54, 0x8D5F, 0x8D6A, 0x8D75, 0x8D80, 0x8D8B, 0x8D96, 0x8DA1, 0x8DAC, 0x8DB7, 0x8DC2, 0x8DCD, 0x8DD8, 0x8DE3, 0x8DEE, 0x8DF9, 0x8E04, 0x8E0E, 0x8E19, 0x8E24, 0x8E2F, 0x8E3A, 0x8E44, 0x8E4F, 0x8E5A, 0x8E65, 0x8E6F, 0x8E7A, 0x8E85, 0x8E90, 0x8E9A, 0x8EA5, 0x8EB0, 0x8EBA, 0x8EC5, 0x8ECF, 0x8EDA, 0x8EE5, 0x8EEF, 0x8EFA, 0x8F04, 0x8F0F, 0x8F19, 0x8F24, 0x8F2E, 0x8F39, 0x8F43, 0x8F4E, 0x8F58, 0x8F63, 0x8F6D, 0x8F78, 0x8F82, 0x8F8C, 0x8F97, 0x8FA1, 0x8FAC, 0x8FB6, 0x8FC0, 0x8FCB, 0x8FD5, 0x8FDF, 0x8FEA, 0x8FF4, 0x8FFE, 0x9008, 0x9013, 0x901D, 0x9027, 0x9031, 0x903C, 0x9046, 0x9050, 0x905A, 0x9064, 0x906E, 0x9079, 0x9083, 0x908D, 0x9097, 0x90A1, 0x90AB, 0x90B5, 0x90BF, 0x90C9, 0x90D3, 0x90DD, 0x90E7, 0x90F1, 0x90FB, 0x9105, 0x910F, 0x9119, 0x9123, 0x912D, 0x9137, 0x9141, 0x914B, 0x9155, 0x915F, 0x9169, 0x9173, 0x917D, 0x9186, 0x9190, 0x919A, 0x91A4, 0x91AE, 0x91B8, 0x91C1, 0x91CB, 0x91D5, 0x91DF, 0x91E9, 0x91F2, 0x91FC, 0x9206, 0x9210, 0x9219, 0x9223, 0x922D, 0x9236, 0x9240, 0x924A, 0x9253, 0x925D, 0x9267, 0x9270, 0x927A, 0x9283, 0x928D, 0x9297, 0x92A0, 0x92AA, 0x92B3, 0x92BD, 0x92C6, 0x92D0, 0x92DA, 0x92E3, 0x92ED, 0x92F6, 0x9300, 0x9309, 0x9313, 0x931C, 0x9325, 0x932F, 0x9338, 0x9342, 0x934B, 0x9355, 0x935E, 0x9367, 0x9371, 0x937A, 0x9384, 0x938D, 0x9396, 0x93A0, 0x93A9, 0x93B2, 0x93BC, 0x93C5, 0x93CE, 0x93D7, 0x93E1, 0x93EA, 0x93F3, 0x93FC, 0x9406, 0x940F, 0x9418, 0x9421, 0x942B, 0x9434, 0x943D, 0x9446, 0x944F, 0x9459, 0x9462, 0x946B, 0x9474, 0x947D, 0x9486, 0x948F, 0x9499, 0x94A2, 0x94AB, 0x94B4, 0x94BD, 0x94C6, 0x94CF, 0x94D8, 0x94E1, 0x94EA, 0x94F3, 0x94FC, 0x9505, 0x950E, 0x9517, 0x9520, 0x9529, 0x9532, 0x953B, 0x9544, 0x954D, 0x9556, 0x955F, 0x9568, 0x9571, 0x957A, 0x9583, 0x958C, 0x9595, 0x959D, 0x95A6, 0x95AF, 0x95B8, 0x95C1, 0x95CA, 0x95D3, 0x95DB, 0x95E4, 0x95ED, 0x95F6, 0x95FF, 0x9608, 0x9610, 0x9619, 0x9622, 0x962B, 0x9633, 0x963C, 0x9645, 0x964E, 0x9656, 0x965F, 0x9668, 0x9671, 0x9679, 0x9682, 0x968B, 0x9693, 0x969C, 0x96A5, 0x96AD, 0x96B6, 0x96BF, 0x96C7, 0x96D0, 0x96D9, 0x96E1, 0x96EA, 0x96F2, 0x96FB, 0x9704, 0x970C, 0x9715, 0x971D, 0x9726, 0x972E, 0x9737, 0x9740, 0x9748, 0x9751, 0x9759, 0x9762, 0x976A, 0x9773, 0x977B, 0x9784, 0x978C, 0x9795, 0x979D, 0x97A6, 0x97AE, 0x97B6, 0x97BF, 0x97C7, 0x97D0, 0x97D8, 0x97E1, 0x97E9, 0x97F1, 0x97FA, 0x9802, 0x980B, 0x9813, 0x981B, 0x9824, 0x982C, 0x9834, 0x983D, 0x9845, 0x984D, 0x9856, 0x985E, 0x9866, 0x986F, 0x9877, 0x987F, 0x9888, 0x9890, 0x9898, 0x98A0, 0x98A9, 0x98B1, 0x98B9, 0x98C1, 0x98CA, 0x98D2, 0x98DA, 0x98E2, 0x98EB, 0x98F3, 0x98FB, 0x9903, 0x990B, 0x9914, 0x991C, 0x9924, 0x992C, 0x9934, 0x993C, 0x9945, 0x994D, 0x9955, 0x995D, 0x9965, 0x996D, 0x9975, 0x997D, 0x9986, 0x998E, 0x9996, 0x999E, 0x99A6, 0x99AE, 0x99B6, 0x99BE, 0x99C6, 0x99CE, 0x99D6, 0x99DE, 0x99E6, 0x99EE, 0x99F6, 0x99FE, 0x9A06, 0x9A0E, 0x9A16, 0x9A1E, 0x9A26, 0x9A2E, 0x9A36, 0x9A3E, 0x9A46, 0x9A4E, 0x9A56, 0x9A5E, 0x9A66, 0x9A6E, 0x9A76, 0x9A7E, 0x9A86, 0x9A8E, 0x9A96, 0x9A9D, 0x9AA5, 0x9AAD, 0x9AB5, 0x9ABD, 0x9AC5, 0x9ACD, 0x9AD5, 0x9ADC, 0x9AE4, 0x9AEC, 0x9AF4, 0x9AFC, 0x9B04, 0x9B0C, 0x9B13, 0x9B1B, 0x9B23, 0x9B2B, 0x9B33, 0x9B3A, 0x9B42, 0x9B4A, 0x9B52, 0x9B59, 0x9B61, 0x9B69, 0x9B71, 0x9B79, 0x9B80, 0x9B88, 0x9B90, 0x9B97, 0x9B9F, 0x9BA7, 0x9BAF, 0x9BB6, 0x9BBE, 0x9BC6, 0x9BCD, 0x9BD5, 0x9BDD, 0x9BE5, 0x9BEC, 0x9BF4, 0x9BFC, 0x9C03, 0x9C0B, 0x9C12, 0x9C1A, 0x9C22, 0x9C29, 0x9C31, 0x9C39, 0x9C40, 0x9C48, 0x9C50, 0x9C57, 0x9C5F, 0x9C66, 0x9C6E, 0x9C75, 0x9C7D, 0x9C85, 0x9C8C, 0x9C94, 0x9C9B, 0x9CA3, 0x9CAA, 0x9CB2, 0x9CBA, 0x9CC1, 0x9CC9, 0x9CD0, 0x9CD8, 0x9CDF, 0x9CE7, 0x9CEE, 0x9CF6, 0x9CFD, 0x9D05, 0x9D0C, 0x9D14, 0x9D1B, 0x9D23, 0x9D2A, 0x9D32, 0x9D39, 0x9D40, 0x9D48, 0x9D4F, 0x9D57, 0x9D5E, 0x9D66, 0x9D6D, 0x9D75, 0x9D7C, 0x9D83, 0x9D8B, 0x9D92, 0x9D9A, 0x9DA1, 0x9DA8, 0x9DB0, 0x9DB7, 0x9DBE, 0x9DC6, 0x9DCD, 0x9DD5, 0x9DDC, 0x9DE3, 0x9DEB, 0x9DF2, 0x9DF9, 0x9E01, 0x9E08, 0x9E0F, 0x9E17, 0x9E1E, 0x9E25, 0x9E2D, 0x9E34, 0x9E3B, 0x9E43, 0x9E4A, 0x9E51, 0x9E58, 0x9E60, 0x9E67, 0x9E6E, 0x9E75, 0x9E7D, 0x9E84, 0x9E8B, 0x9E92, 0x9E9A, 0x9EA1, 0x9EA8, 0x9EAF, 0x9EB7, 0x9EBE, 0x9EC5, 0x9ECC, 0x9ED4, 0x9EDB, 0x9EE2, 0x9EE9, 0x9EF0, 0x9EF7, 0x9EFF, 0x9F06, 0x9F0D, 0x9F14, 0x9F1B, 0x9F23, 0x9F2A, 0x9F31, 0x9F38, 0x9F3F, 0x9F46, 0x9F4D, 0x9F55, 0x9F5C, 0x9F63, 0x9F6A, 0x9F71, 0x9F78, 0x9F7F, 0x9F86, 0x9F8D, 0x9F95, 0x9F9C, 0x9FA3, 0x9FAA, 0x9FB1, 0x9FB8, 0x9FBF, 0x9FC6, 0x9FCD, 0x9FD4, 0x9FDB, 0x9FE2, 0x9FE9, 0x9FF0, 0x9FF7, 0x9FFF, }; static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); static void tegra_dc_stats_reset(struct tegra_dc_stats *stats) { stats->frames = 0; stats->vblank = 0; stats->underflow = 0; stats->overflow = 0; } /* Reads the active copy of a register. */ static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset) { u32 value; tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); value = tegra_dc_readl(dc, offset); tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); return value; } static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, unsigned int offset) { if (offset >= 0x500 && offset <= 0x638) { offset = 0x000 + (offset - 0x500); return plane->offset + offset; } if (offset >= 0x700 && offset <= 0x719) { offset = 0x180 + (offset - 0x700); return plane->offset + offset; } if (offset >= 0x800 && offset <= 0x839) { offset = 0x1c0 + (offset - 0x800); return plane->offset + offset; } dev_WARN(plane->dc->dev, "invalid offset: %x\n", offset); return plane->offset + offset; } static inline u32 tegra_plane_readl(struct tegra_plane *plane, unsigned int offset) { return tegra_dc_readl(plane->dc, tegra_plane_offset(plane, offset)); } static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value, unsigned int offset) { tegra_dc_writel(plane->dc, value, tegra_plane_offset(plane, offset)); } bool tegra_dc_has_output(struct tegra_dc *dc, struct device *dev) { struct device_node *np = dc->dev->of_node; struct of_phandle_iterator it; int err; of_for_each_phandle(&it, err, np, "nvidia,outputs", NULL, 0) if (it.node == dev->of_node) { of_node_put(it.node); return true; } return false; } /* * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy. * Latching happens mmediately if the display controller is in STOP mode or * on the next frame boundary otherwise. * * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits * are written. When the *_ACT_REQ bits are written, the ARM copy is latched * into the ACTIVE copy, either immediately if the display controller is in * STOP mode, or at the next frame boundary otherwise. */ void tegra_dc_commit(struct tegra_dc *dc) { tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); } static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, unsigned int bpp) { fixed20_12 outf = dfixed_init(out); fixed20_12 inf = dfixed_init(in); u32 dda_inc; int max; if (v) max = 15; else { switch (bpp) { case 2: max = 8; break; default: WARN_ON_ONCE(1); fallthrough; case 4: max = 4; break; } } outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); inf.full -= dfixed_const(1); dda_inc = dfixed_div(inf, outf); dda_inc = min_t(u32, dda_inc, dfixed_const(max)); return dda_inc; } static inline u32 compute_initial_dda(unsigned int in) { fixed20_12 inf = dfixed_init(in); return dfixed_frac(inf); } static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane) { u32 background[3] = { BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE, BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE, BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE, }; u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) | BLEND_COLOR_KEY_NONE; u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255); struct tegra_plane_state *state; u32 blending[2]; unsigned int i; /* disable blending for non-overlapping case */ tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY); tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN); state = to_tegra_plane_state(plane->base.state); if (state->opaque) { /* * Since custom fix-weight blending isn't utilized and weight * of top window is set to max, we can enforce dependent * blending which in this case results in transparent bottom * window if top window is opaque and if top window enables * alpha blending, then bottom window is getting alpha value * of 1 minus the sum of alpha components of the overlapping * plane. */ background[0] |= BLEND_CONTROL_DEPENDENT; background[1] |= BLEND_CONTROL_DEPENDENT; /* * The region where three windows overlap is the intersection * of the two regions where two windows overlap. It contributes * to the area if all of the windows on top of it have an alpha * component. */ switch (state->base.normalized_zpos) { case 0: if (state->blending[0].alpha && state->blending[1].alpha) background[2] |= BLEND_CONTROL_DEPENDENT; break; case 1: background[2] |= BLEND_CONTROL_DEPENDENT; break; } } else { /* * Enable alpha blending if pixel format has an alpha * component. */ foreground |= BLEND_CONTROL_ALPHA; /* * If any of the windows on top of this window is opaque, it * will completely conceal this window within that area. If * top window has an alpha component, it is blended over the * bottom window. */ for (i = 0; i < 2; i++) { if (state->blending[i].alpha && state->blending[i].top) background[i] |= BLEND_CONTROL_DEPENDENT; } switch (state->base.normalized_zpos) { case 0: if (state->blending[0].alpha && state->blending[1].alpha) background[2] |= BLEND_CONTROL_DEPENDENT; break; case 1: /* * When both middle and topmost windows have an alpha, * these windows a mixed together and then the result * is blended over the bottom window. */ if (state->blending[0].alpha && state->blending[0].top) background[2] |= BLEND_CONTROL_ALPHA; if (state->blending[1].alpha && state->blending[1].top) background[2] |= BLEND_CONTROL_ALPHA; break; } } switch (state->base.normalized_zpos) { case 0: tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X); tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y); tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY); break; case 1: /* * If window B / C is topmost, then X / Y registers are * matching the order of blending[...] state indices, * otherwise a swap is required. */ if (!state->blending[0].top && state->blending[1].top) { blending[0] = foreground; blending[1] = background[1]; } else { blending[0] = background[0]; blending[1] = foreground; } tegra_plane_writel(plane, blending[0], DC_WIN_BLEND_2WIN_X); tegra_plane_writel(plane, blending[1], DC_WIN_BLEND_2WIN_Y); tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY); break; case 2: tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X); tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_Y); tegra_plane_writel(plane, foreground, DC_WIN_BLEND_3WIN_XY); break; } } static void tegra_plane_setup_blending(struct tegra_plane *plane, const struct tegra_dc_window *window) { u32 value; value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 | BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC | BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC; tegra_plane_writel(plane, value, DC_WIN_BLEND_MATCH_SELECT); value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 | BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC | BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC; tegra_plane_writel(plane, value, DC_WIN_BLEND_NOMATCH_SELECT); value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - window->zpos); tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL); } static bool tegra_plane_use_horizontal_filtering(struct tegra_plane *plane, const struct tegra_dc_window *window) { struct tegra_dc *dc = plane->dc; if (window->src.w == window->dst.w) return false; if (plane->index == 0 && dc->soc->has_win_a_without_filters) return false; return true; } static bool tegra_plane_use_vertical_filtering(struct tegra_plane *plane, const struct tegra_dc_window *window) { struct tegra_dc *dc = plane->dc; if (window->src.h == window->dst.h) return false; if (plane->index == 0 && dc->soc->has_win_a_without_filters) return false; if (plane->index == 2 && dc->soc->has_win_c_without_vert_filter) return false; return true; } static void tegra_dc_setup_window(struct tegra_plane *plane, const struct tegra_dc_window *window) { unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; struct tegra_dc *dc = plane->dc; unsigned int planes; u32 value; bool yuv; /* * For YUV planar modes, the number of bytes per pixel takes into * account only the luma component and therefore is 1. */ yuv = tegra_plane_format_is_yuv(window->format, &planes, NULL); if (!yuv) bpp = window->bits_per_pixel / 8; else bpp = (planes > 1) ? 1 : 2; tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH); tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP); value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); tegra_plane_writel(plane, value, DC_WIN_POSITION); value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); tegra_plane_writel(plane, value, DC_WIN_SIZE); h_offset = window->src.x * bpp; v_offset = window->src.y; h_size = window->src.w * bpp; v_size = window->src.h; if (window->reflect_x) h_offset += (window->src.w - 1) * bpp; if (window->reflect_y) v_offset += window->src.h - 1; value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); tegra_plane_writel(plane, value, DC_WIN_PRESCALED_SIZE); /* * For DDA computations the number of bytes per pixel for YUV planar * modes needs to take into account all Y, U and V components. */ if (yuv && planes > 1) bpp = 2; h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); tegra_plane_writel(plane, value, DC_WIN_DDA_INC);