Merge tag 'drm/tegra/for-5.9-rc1' of ssh://git.freedesktop.org/git/tegra/linux into...
authorDave Airlie <airlied@redhat.com>
Thu, 23 Jul 2020 23:38:44 +0000 (09:38 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 23 Jul 2020 23:38:55 +0000 (09:38 +1000)
drm/tegra: Changes for v5.9-rc1

This set of patches contains a few preparatory patches to enable video
capture support from external camera modules. This is a dependency for
the V4L2 driver patches that will likely be merged in v5.9 or v5.10.

On top of that there are a couple of fixes across the board as well as
some improvements.

From a feature point of view this also adds support for horizontal
reflection and 180° rotation of planes.

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Thierry Reding <thierry.reding@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200717162011.1661788-1-thierry.reding@gmail.com
14 files changed:
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/gr2d.c
drivers/gpu/drm/tegra/gr2d.h
drivers/gpu/drm/tegra/gr3d.c
drivers/gpu/drm/tegra/plane.c
drivers/gpu/drm/tegra/plane.h
drivers/gpu/drm/tegra/sor.c
drivers/gpu/host1x/debug.c
drivers/gpu/host1x/hw/debug_hw.c
drivers/gpu/host1x/job.c
drivers/gpu/host1x/mipi.c
include/linux/host1x.h

index da8b998..9a0b324 100644 (file)
@@ -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->bottom_up)
-               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,7 +473,10 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
                value |= COLOR_EXPAND;
        }
 
-       if (window->bottom_up)
+       if (window->reflect_x)
+               value |= H_DIRECTION;
+
+       if (window->reflect_y)
                value |= V_DIRECTION;
 
        if (tegra_plane_use_horizontal_filtering(plane, window)) {
@@ -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,12 +648,26 @@ 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->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 +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.bottom_up = tegra_fb_is_bottom_up(fb) || state->bottom_up;
+       window.reflect_x = state->reflect_x;
+       window.reflect_y = state->reflect_y;
 
        /* copy from state */
        window.zpos = plane->state->normalized_zpos;
@@ -792,6 +816,8 @@ 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)
                dev_err(dc->dev, "failed to create rotation property: %d\n",
@@ -1080,6 +1106,8 @@ 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)
                dev_err(dc->dev, "failed to create rotation property: %d\n",
@@ -2555,10 +2583,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) {
index 3d8ddcc..051d03d 100644 (file)
@@ -136,7 +136,8 @@ struct tegra_dc_window {
        unsigned int stride[2];
        unsigned long base[3];
        unsigned int zpos;
-       bool bottom_up;
+       bool reflect_x;
+       bool reflect_y;
 
        struct tegra_bo_tiling tiling;
        u32 format;
index 38beab9..3820e8d 100644 (file)
@@ -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,
@@ -1618,7 +1623,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);
 
index 48363f7..1a0d3ba 100644 (file)
@@ -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,
index 2398486..9b7d66e 100644 (file)
@@ -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
index c0a528b..b0b8154 100644 (file)
@@ -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);
 
index 9ccfb56..4cd0461 100644 (file)
@@ -61,7 +61,8 @@ 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_x = state->reflect_x;
+       copy->reflect_y = state->reflect_y;
        copy->opaque = state->opaque;
 
        for (i = 0; i < 2; i++)
index a158a91..c691dd7 100644 (file)
@@ -46,7 +46,8 @@ struct tegra_plane_state {
        u32 format;
        u32 swap;
 
-       bool bottom_up;
+       bool reflect_x;
+       bool reflect_y;
 
        /* used for legacy blending support only */
        struct tegra_plane_legacy_blending_state blending[2];
index 7cbcf96..45b5258 100644 (file)
@@ -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));
index c039267..1b4997b 100644 (file)
@@ -16,6 +16,8 @@
 #include "debug.h"
 #include "channel.h"
 
+static DEFINE_MUTEX(debug_lock);
+
 unsigned int host1x_debug_trace_cmdbuf;
 
 static pid_t host1x_debug_force_timeout_pid;
@@ -52,12 +54,14 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
        struct output *o = data;
 
        mutex_lock(&ch->cdma.lock);
+       mutex_lock(&debug_lock);
 
        if (show_fifo)
                host1x_hw_show_channel_fifo(m, ch, o);
 
        host1x_hw_show_channel_cdma(m, ch, o);
 
+       mutex_unlock(&debug_lock);
        mutex_unlock(&ch->cdma.lock);
 
        return 0;
index 0212584..f31bcfa 100644 (file)
@@ -192,8 +192,14 @@ static void show_gather(struct output *o, phys_addr_t phys_addr,
 
 static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
 {
+       struct push_buffer *pb = &cdma->push_buffer;
        struct host1x_job *job;
 
+       host1x_debug_output(o, "PUSHBUF at %pad, %u words\n",
+                           &pb->dma, pb->size / 4);
+
+       show_gather(o, pb->dma, pb->size / 4, cdma, pb->dma, pb->mapped);
+
        list_for_each_entry(job, &cdma->sync_queue, list) {
                unsigned int i;
 
index a10643a..89b6c14 100644 (file)
@@ -27,10 +27,13 @@ struct host1x_job *host1x_job_alloc(struct host1x_channel *ch,
                                    u32 num_cmdbufs, u32 num_relocs)
 {
        struct host1x_job *job = NULL;
-       unsigned int num_unpins = num_cmdbufs + num_relocs;
+       unsigned int num_unpins = num_relocs;
        u64 total;
        void *mem;
 
+       if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
+               num_unpins += num_cmdbufs;
+
        /* Check that we're not going to overflow */
        total = sizeof(struct host1x_job) +
                (u64)num_relocs * sizeof(struct host1x_reloc) +
@@ -102,6 +105,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
 {
        struct host1x_client *client = job->client;
        struct device *dev = client->dev;
+       struct host1x_job_gather *g;
        struct iommu_domain *domain;
        unsigned int i;
        int err;
@@ -183,8 +187,14 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
                job->num_unpins++;
        }
 
+       /*
+        * We will copy gathers BO content later, so there is no need to
+        * hold and pin them.
+        */
+       if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
+               return 0;
+
        for (i = 0; i < job->num_gathers; i++) {
-               struct host1x_job_gather *g = &job->gathers[i];
                size_t gather_size = 0;
                struct scatterlist *sg;
                struct sg_table *sgt;
@@ -194,6 +204,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
                dma_addr_t *phys;
                unsigned int j;
 
+               g = &job->gathers[i];
                g->bo = host1x_bo_get(g->bo);
                if (!g->bo) {
                        err = -EINVAL;
@@ -213,10 +224,10 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
                sgt = host1x_bo_pin(host->dev, g->bo, phys);
                if (IS_ERR(sgt)) {
                        err = PTR_ERR(sgt);
-                       goto unpin;
+                       goto put;
                }
 
-               if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) {
+               if (host->domain) {
                        for_each_sg(sgt->sgl, sg, sgt->nents, j)
                                gather_size += sg->length;
                        gather_size = iova_align(&host->iova, gather_size);
@@ -226,7 +237,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
                                           host->iova_end >> shift, true);
                        if (!alloc) {
                                err = -ENOMEM;
-                               goto unpin;
+                               goto put;
                        }
 
                        err = iommu_map_sg(host->domain,
@@ -235,7 +246,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
                        if (err == 0) {
                                __free_iova(&host->iova, alloc);
                                err = -EINVAL;
-                               goto unpin;
+                               goto put;
                        }
 
                        job->unpins[job->num_unpins].size = gather_size;
@@ -245,7 +256,7 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
                                         DMA_TO_DEVICE);
                        if (!err) {
                                err = -ENOMEM;
-                               goto unpin;
+                               goto put;
                        }
 
                        job->unpins[job->num_unpins].dir = DMA_TO_DEVICE;
@@ -263,6 +274,8 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
 
        return 0;
 
+put:
+       host1x_bo_put(g->bo);
 unpin:
        host1x_job_unpin(job);
        return err;
index e00809d..e606464 100644 (file)
@@ -21,9 +21,9 @@
  */
 
 #include <linux/clk.h>
-#include <linux/delay.h>
 #include <linux/host1x.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -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;
@@ -293,22 +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)
 {
-       unsigned long timeout = jiffies + msecs_to_jiffies(250);
+       struct tegra_mipi *mipi = device->mipi;
+       void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2);
        u32 value;
+       int err;
 
-       while (time_before(jiffies, timeout)) {
-               value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
-               if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
-                   (value & MIPI_CAL_STATUS_DONE) != 0)
-                       return 0;
+       err = clk_enable(device->mipi->clk);
+       if (err < 0)
+               return err;
 
-               usleep_range(10, 50);
-       }
+       mutex_lock(&device->mipi->lock);
 
-       return -ETIMEDOUT;
+       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)
 {
@@ -374,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);
 
index a3a568b..20c885d 100644 (file)
@@ -328,10 +328,12 @@ 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);
 int tegra_mipi_calibrate(struct tegra_mipi_device *device);
+int tegra_mipi_wait(struct tegra_mipi_device *device);
 
 #endif