From ef4e417eb3ec7fe657928f10ac1d2154d8a5fb38 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 19 May 2020 02:03:01 -0700 Subject: drm/tegra: hub: Do not enable orphaned window group Though the unconditional enable/disable code is not a final solution, we don't want to run into a NULL pointer situation when window group doesn't link to its DC parent if the DC is disabled in Device Tree. So this patch simply adds a check to make sure that window group has a valid parent before running into tegra_windowgroup_enable/disable. Signed-off-by: Nicolin Chen Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/hub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 8183e617bf6b..a2ef8f218d4e 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -149,7 +149,9 @@ int tegra_display_hub_prepare(struct tegra_display_hub *hub) for (i = 0; i < hub->soc->num_wgrps; i++) { struct tegra_windowgroup *wgrp = &hub->wgrps[i]; - tegra_windowgroup_enable(wgrp); + /* Skip orphaned window group whose parent DC is disabled */ + if (wgrp->parent) + tegra_windowgroup_enable(wgrp); } return 0; @@ -166,7 +168,9 @@ void tegra_display_hub_cleanup(struct tegra_display_hub *hub) for (i = 0; i < hub->soc->num_wgrps; i++) { struct tegra_windowgroup *wgrp = &hub->wgrps[i]; - tegra_windowgroup_disable(wgrp); + /* Skip orphaned window group whose parent DC is disabled */ + if (wgrp->parent) + tegra_windowgroup_disable(wgrp); } } -- cgit v1.2.3 From a101e3dad8a90a840ccb45e492cd2ef7c01199ea Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 12 Jun 2020 17:01:00 +0200 Subject: drm/tegra: hub: Register child devices In order to remove the dependency on the simple-bus compatible string, which causes the OF driver core to register all child devices, make the display-hub driver explicitly register the display controller children. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/hub.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index a2ef8f218d4e..22a03f7ffdc1 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -948,6 +948,15 @@ static int tegra_display_hub_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register host1x client: %d\n", err); + err = devm_of_platform_populate(&pdev->dev); + if (err < 0) + goto unregister; + + return err; + +unregister: + host1x_client_unregister(&hub->client); + pm_runtime_disable(&pdev->dev); return err; } -- cgit v1.2.3 From fce3a51d9b31312aa12ecb72ffabfc4c7b40bdc6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Jun 2020 13:30:59 +0200 Subject: drm/tegra: Add zpos property for cursor planes As of commit 4dc55525b095 ("drm: plane: Verify that no or all planes have a zpos property") a warning is emitted if there's a mix of planes with and without a zpos property. On Tegra, cursor planes are always composited on top of all other planes, which is why they never had a zpos property attached to them. However, since the composition order is fixed, this is trivial to remedy by simply attaching an immutable zpos property to them. v3: do not hardcode zpos for overlay planes used as cursor (Dmitry) v2: hardcode cursor plane zpos to 255 instead of 0 (Ville) Reported-by: Jonathan Hunter Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 83f31c6e891c..04d6848d19fc 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -957,6 +957,7 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm, } drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs); + drm_plane_create_zpos_immutable_property(&plane->base, 255); return &plane->base; } -- cgit v1.2.3 From 767598d447aa46411289c5808b0e45e20a1823b4 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 14 Jul 2020 21:20:51 -0700 Subject: gpu: host1x: mipi: Update tegra_mipi_request() to be node based Tegra CSI driver need a separate MIPI device for each channel as calibration of corresponding MIPI pads for each channel should happen independently. So, this patch updates tegra_mipi_request() API to add a device_node pointer argument to allow creating mipi device for specific device node rather than a device. Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 2 +- drivers/gpu/host1x/mipi.c | 4 ++-- include/linux/host1x.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 38beab9ab4f8..3c09e290632c 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1618,7 +1618,7 @@ static int tegra_dsi_probe(struct platform_device *pdev) if (IS_ERR(dsi->regs)) return PTR_ERR(dsi->regs); - dsi->mipi = tegra_mipi_request(&pdev->dev); + dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node); if (IS_ERR(dsi->mipi)) return PTR_ERR(dsi->mipi); diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c index e00809d996a2..762d349ad00f 100644 --- a/drivers/gpu/host1x/mipi.c +++ b/drivers/gpu/host1x/mipi.c @@ -206,9 +206,9 @@ static int tegra_mipi_power_down(struct tegra_mipi *mipi) return 0; } -struct tegra_mipi_device *tegra_mipi_request(struct device *device) +struct tegra_mipi_device *tegra_mipi_request(struct device *device, + struct device_node *np) { - struct device_node *np = device->of_node; struct tegra_mipi_device *dev; struct of_phandle_args args; int err; diff --git a/include/linux/host1x.h b/include/linux/host1x.h index a3a568bf9686..9e678412778c 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -328,7 +328,8 @@ int host1x_client_resume(struct host1x_client *client); struct tegra_mipi_device; -struct tegra_mipi_device *tegra_mipi_request(struct device *device); +struct tegra_mipi_device *tegra_mipi_request(struct device *device, + struct device_node *np); void tegra_mipi_free(struct tegra_mipi_device *device); int tegra_mipi_enable(struct tegra_mipi_device *device); int tegra_mipi_disable(struct tegra_mipi_device *device); -- cgit v1.2.3 From b3f1b760710f2acfc04abefc09358c26a75e7e89 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 14 Jul 2020 21:20:53 -0700 Subject: gpu: host1x: mipi: Split tegra_mipi_calibrate() and tegra_mipi_wait() SW can trigger MIPI pads calibration any time after power on but calibration results will be latched and applied to the pads by MIPI CAL unit only when the link is in LP-11 state and then status register will be updated. For CSI, trigger of pads calibration happen during CSI stream enable where CSI receiver is kept ready prior to sensor or CSI transmitter stream start. So, pads may not be in LP-11 at this time and waiting for the calibration to be done immediate after calibration start will result in timeout. This patch splits tegra_mipi_calibrate() and tegra_mipi_wait() so triggering for calibration and waiting for it to complete can happen at different stages. Signed-off-by: Sowjanya Komatineni Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dsi.c | 7 ++++++- drivers/gpu/host1x/mipi.c | 17 +++++++++++++---- include/linux/host1x.h | 1 + 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 3c09e290632c..3820e8dff14b 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -670,6 +670,7 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi) static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) { u32 value; + int err; /* * XXX Is this still needed? The module reset is deasserted right @@ -693,7 +694,11 @@ static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3); - return tegra_mipi_calibrate(dsi->mipi); + err = tegra_mipi_calibrate(dsi->mipi); + if (err < 0) + return err; + + return tegra_mipi_wait(dsi->mipi); } static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c index 259e70c47a38..e606464aa43c 100644 --- a/drivers/gpu/host1x/mipi.c +++ b/drivers/gpu/host1x/mipi.c @@ -293,18 +293,29 @@ int tegra_mipi_disable(struct tegra_mipi_device *dev) } EXPORT_SYMBOL(tegra_mipi_disable); -static int tegra_mipi_wait(struct tegra_mipi *mipi) +int tegra_mipi_wait(struct tegra_mipi_device *device) { + struct tegra_mipi *mipi = device->mipi; void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2); u32 value; int err; + err = clk_enable(device->mipi->clk); + if (err < 0) + return err; + + mutex_lock(&device->mipi->lock); + err = readl_relaxed_poll_timeout(status_reg, value, !(value & MIPI_CAL_STATUS_ACTIVE) && (value & MIPI_CAL_STATUS_DONE), 50, 250000); + mutex_unlock(&device->mipi->lock); + clk_disable(device->mipi->clk); + return err; } +EXPORT_SYMBOL(tegra_mipi_wait); int tegra_mipi_calibrate(struct tegra_mipi_device *device) { @@ -370,12 +381,10 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device) value |= MIPI_CAL_CTRL_START; tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL); - err = tegra_mipi_wait(device->mipi); - mutex_unlock(&device->mipi->lock); clk_disable(device->mipi->clk); - return err; + return 0; } EXPORT_SYMBOL(tegra_mipi_calibrate); diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 9e678412778c..20c885d0bddc 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -334,5 +334,6 @@ void tegra_mipi_free(struct tegra_mipi_device *device); int tegra_mipi_enable(struct tegra_mipi_device *device); int tegra_mipi_disable(struct tegra_mipi_device *device); int tegra_mipi_calibrate(struct tegra_mipi_device *device); +int tegra_mipi_wait(struct tegra_mipi_device *device); #endif -- cgit v1.2.3 From 5fba01a0d3488a15c4082bc18aea5375bd8fb97f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 26 Jun 2020 10:26:32 +0200 Subject: drm/tegra: sor: Use correct power supply names for HDMI The hardware documentation uses AVDD_IO_HDMI_DP and VDD_HDMI_DP_PLL to denote the two power supplies that drive the HDMI/DP outputs of the SOR. Use these names instead of the arbitrary AVDD_IO and VDD_PLL names that were used previously to avoid confusion. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/sor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 7cbcf9617f5e..45b5258c77a2 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -2946,7 +2946,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor) { int err; - sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io"); + sor->avdd_io_supply = devm_regulator_get(sor->dev, "avdd-io-hdmi-dp"); if (IS_ERR(sor->avdd_io_supply)) { dev_err(sor->dev, "cannot get AVDD I/O supply: %ld\n", PTR_ERR(sor->avdd_io_supply)); @@ -2960,7 +2960,7 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor) return err; } - sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-pll"); + sor->vdd_pll_supply = devm_regulator_get(sor->dev, "vdd-hdmi-dp-pll"); if (IS_ERR(sor->vdd_pll_supply)) { dev_err(sor->dev, "cannot get VDD PLL supply: %ld\n", PTR_ERR(sor->vdd_pll_supply)); -- cgit v1.2.3 From 2c2a291d01efdcf336796557de1f651b2581e08d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 29 Jun 2020 06:18:37 +0300 Subject: drm/tegra: gr3d: Assert reset before power-gating Tegra TRM documentation states that hardware should be in a default state when power partition is turned off, i.e. reset should be asserted. This patch adds the missing reset assertions. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/gr3d.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index c0a528be0369..b0b8154e8104 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -381,10 +381,12 @@ static int gr3d_remove(struct platform_device *pdev) } if (gr3d->clk_secondary) { + reset_control_assert(gr3d->rst_secondary); tegra_powergate_power_off(TEGRA_POWERGATE_3D1); clk_disable_unprepare(gr3d->clk_secondary); } + reset_control_assert(gr3d->rst); tegra_powergate_power_off(TEGRA_POWERGATE_3D); clk_disable_unprepare(gr3d->clk); -- cgit v1.2.3 From 5c9b969f699979981b1a2008cef76b56cf906f3e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 29 Jun 2020 06:18:38 +0300 Subject: drm/tegra: gr2d: Add tiled PATBASE address register There are two PATBASE address registers, one for linear layout and other for tiled. The driver's address registers list misses the tiled PATBASE register. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/gr2d.c | 1 + drivers/gpu/drm/tegra/gr2d.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 48363f744bb9..1a0d3ba6e525 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -177,6 +177,7 @@ static const u32 gr2d_addr_regs[] = { GR2D_DSTC_BASE_ADDR, GR2D_SRCA_BASE_ADDR, GR2D_SRCB_BASE_ADDR, + GR2D_PATBASE_ADDR, GR2D_SRC_BASE_ADDR_SB, GR2D_DSTA_BASE_ADDR_SB, GR2D_DSTB_BASE_ADDR_SB, diff --git a/drivers/gpu/drm/tegra/gr2d.h b/drivers/gpu/drm/tegra/gr2d.h index 2398486f0699..9b7d66e15b9f 100644 --- a/drivers/gpu/drm/tegra/gr2d.h +++ b/drivers/gpu/drm/tegra/gr2d.h @@ -14,6 +14,7 @@ #define GR2D_DSTC_BASE_ADDR 0x2d #define GR2D_SRCA_BASE_ADDR 0x31 #define GR2D_SRCB_BASE_ADDR 0x32 +#define GR2D_PATBASE_ADDR 0x47 #define GR2D_SRC_BASE_ADDR_SB 0x48 #define GR2D_DSTA_BASE_ADDR_SB 0x49 #define GR2D_DSTB_BASE_ADDR_SB 0x4a -- cgit v1.2.3 From 5f1df70f59257d6988712b4f8de51737fc1abd87 Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Thu, 16 Apr 2020 22:43:17 +0800 Subject: drm/tegra: dc: Omit superfluous error message in tegra_dc_probe() In the function tegra_dc_probe(), when get irq failed, the function platform_get_irq() logs an error message, so remove redundant message here. Signed-off-by: Tang Bin Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 04d6848d19fc..dc835ae94f44 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -2556,10 +2556,8 @@ static int tegra_dc_probe(struct platform_device *pdev) return PTR_ERR(dc->regs); dc->irq = platform_get_irq(pdev, 0); - if (dc->irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ\n"); + if (dc->irq < 0) return -ENXIO; - } err = tegra_dc_rgb_probe(dc); if (err < 0 && err != -ENODEV) { -- cgit v1.2.3 From e9e476f7f7eaaf12058290f83cccbcb076596b2f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 18 Jun 2020 02:40:38 +0300 Subject: drm/tegra: plane: Rename bottom_up to reflect_y This makes the naming consistent with the DRM core. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 10 +++++----- drivers/gpu/drm/tegra/dc.h | 2 +- drivers/gpu/drm/tegra/plane.c | 2 +- drivers/gpu/drm/tegra/plane.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index dc835ae94f44..27b1b82cdad7 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -404,7 +404,7 @@ static void tegra_dc_setup_window(struct tegra_plane *plane, tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE); } - if (window->bottom_up) + if (window->reflect_y) v_offset += window->src.h - 1; tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET); @@ -470,7 +470,7 @@ static void tegra_dc_setup_window(struct tegra_plane *plane, value |= COLOR_EXPAND; } - if (window->bottom_up) + if (window->reflect_y) value |= V_DIRECTION; if (tegra_plane_use_horizontal_filtering(plane, window)) { @@ -642,9 +642,9 @@ static int tegra_plane_atomic_check(struct drm_plane *plane, rotation = drm_rotation_simplify(state->rotation, rotation); if (rotation & DRM_MODE_REFLECT_Y) - plane_state->bottom_up = true; + plane_state->reflect_y = true; else - plane_state->bottom_up = false; + plane_state->reflect_y = false; /* * Tegra doesn't support different strides for U and V planes so we @@ -706,7 +706,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane, window.dst.w = drm_rect_width(&plane->state->dst); window.dst.h = drm_rect_height(&plane->state->dst); window.bits_per_pixel = fb->format->cpp[0] * 8; - window.bottom_up = tegra_fb_is_bottom_up(fb) || state->bottom_up; + window.reflect_y = tegra_fb_is_bottom_up(fb) || state->reflect_y; /* copy from state */ window.zpos = plane->state->normalized_zpos; diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 3d8ddccd758f..98e1b625168e 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -136,7 +136,7 @@ struct tegra_dc_window { unsigned int stride[2]; unsigned long base[3]; unsigned int zpos; - bool bottom_up; + bool reflect_y; struct tegra_bo_tiling tiling; u32 format; diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 9ccfb56e9b01..e05ef6013a97 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -61,7 +61,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane) copy->tiling = state->tiling; copy->format = state->format; copy->swap = state->swap; - copy->bottom_up = state->bottom_up; + copy->reflect_y = state->reflect_y; copy->opaque = state->opaque; for (i = 0; i < 2; i++) diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h index a158a915109a..8047fc916d8c 100644 --- a/drivers/gpu/drm/tegra/plane.h +++ b/drivers/gpu/drm/tegra/plane.h @@ -46,7 +46,7 @@ struct tegra_plane_state { u32 format; u32 swap; - bool bottom_up; + bool reflect_y; /* used for legacy blending support only */ struct tegra_plane_legacy_blending_state blending[2]; -- cgit v1.2.3 From cd740777d29d7053e0172c7e0105789428425941 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 18 Jun 2020 02:40:39 +0300 Subject: drm/tegra: plane: Support horizontal reflection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support horizontal reflection mode which will allow to support 180° rotation mode when combined with the vertical reflection. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 38 ++++++++++++++++++++++++++++++++------ drivers/gpu/drm/tegra/dc.h | 1 + drivers/gpu/drm/tegra/plane.c | 1 + drivers/gpu/drm/tegra/plane.h | 1 + 4 files changed, 35 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 27b1b82cdad7..03c75db2ed39 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -368,6 +368,12 @@ static void tegra_dc_setup_window(struct tegra_plane *plane, 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); @@ -404,9 +410,6 @@ static void tegra_dc_setup_window(struct tegra_plane *plane, tegra_plane_writel(plane, window->stride[0], DC_WIN_LINE_STRIDE); } - if (window->reflect_y) - v_offset += window->src.h - 1; - tegra_plane_writel(plane, h_offset, DC_WINBUF_ADDR_H_OFFSET); tegra_plane_writel(plane, v_offset, DC_WINBUF_ADDR_V_OFFSET); @@ -470,6 +473,9 @@ static void tegra_dc_setup_window(struct tegra_plane *plane, value |= COLOR_EXPAND; } + if (window->reflect_x) + value |= H_DIRECTION; + if (window->reflect_y) value |= V_DIRECTION; @@ -601,7 +607,10 @@ static int tegra_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct tegra_plane_state *plane_state = to_tegra_plane_state(state); - unsigned int rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y; + unsigned int supported_rotation = DRM_MODE_ROTATE_0 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y; + unsigned int rotation = state->rotation; struct tegra_bo_tiling *tiling = &plane_state->tiling; struct tegra_plane *tegra = to_tegra_plane(plane); struct tegra_dc *dc = to_tegra_dc(state->crtc); @@ -639,7 +648,21 @@ static int tegra_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - rotation = drm_rotation_simplify(state->rotation, rotation); + /* + * Older userspace used custom BO flag in order to specify the Y + * reflection, while modern userspace uses the generic DRM rotation + * property in order to achieve the same result. The legacy BO flag + * duplicates the DRM rotation property when both are set. + */ + if (tegra_fb_is_bottom_up(state->fb)) + rotation |= DRM_MODE_REFLECT_Y; + + rotation = drm_rotation_simplify(rotation, supported_rotation); + + if (rotation & DRM_MODE_REFLECT_X) + plane_state->reflect_x = true; + else + plane_state->reflect_x = false; if (rotation & DRM_MODE_REFLECT_Y) plane_state->reflect_y = true; @@ -706,7 +729,8 @@ static void tegra_plane_atomic_update(struct drm_plane *plane, window.dst.w = drm_rect_width(&plane->state->dst); window.dst.h = drm_rect_height(&plane->state->dst); window.bits_per_pixel = fb->format->cpp[0] * 8; - window.reflect_y = tegra_fb_is_bottom_up(fb) || state->reflect_y; + window.reflect_x = state->reflect_x; + window.reflect_y = state->reflect_y; /* copy from state */ window.zpos = plane->state->normalized_zpos; @@ -792,6 +816,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, err = drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); if (err < 0) dev_err(dc->dev, "failed to create rotation property: %d\n", @@ -1080,6 +1105,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, err = drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); if (err < 0) dev_err(dc->dev, "failed to create rotation property: %d\n", diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 98e1b625168e..051d03dcb9b0 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -136,6 +136,7 @@ struct tegra_dc_window { unsigned int stride[2]; unsigned long base[3]; unsigned int zpos; + bool reflect_x; bool reflect_y; struct tegra_bo_tiling tiling; diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index e05ef6013a97..4cd0461cc508 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -61,6 +61,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane) copy->tiling = state->tiling; copy->format = state->format; copy->swap = state->swap; + copy->reflect_x = state->reflect_x; copy->reflect_y = state->reflect_y; copy->opaque = state->opaque; diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h index 8047fc916d8c..c691dd79b27b 100644 --- a/drivers/gpu/drm/tegra/plane.h +++ b/drivers/gpu/drm/tegra/plane.h @@ -46,6 +46,7 @@ struct tegra_plane_state { u32 format; u32 swap; + bool reflect_x; bool reflect_y; /* used for legacy blending support only */ -- cgit v1.2.3 From 4fba6d22ca9ad28b8871d763b35a4da2e1ca272e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 18 Jun 2020 02:40:40 +0300 Subject: drm/tegra: plane: Support 180° rotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combining horizontal and vertical reflections gives us 180 degrees of rotation. Both reflection modes are already supported, and thus, we just need to mark the 180 rotation mode as supported. The 180 rotation mode is needed for devices like Nexus 7 tablet, which have display panel mounted upside-down. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/tegra') diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 03c75db2ed39..a9159cb456c8 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -816,6 +816,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, err = drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_180 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); if (err < 0) @@ -1105,6 +1106,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, err = drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_180 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); if (err < 0) -- cgit v1.2.3