Commit 395be0f4 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm/tegra/for-5.9-rc1' of ssh://git.freedesktop.org/git/tegra/linux into drm-next

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: default avatarDave 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
parents 41206a07 4fba6d22
......@@ -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) {
......
......@@ -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;
......
......@@ -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);
......
......@@ -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,
......
......@@ -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
......
......@@ -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);
......
......@@ -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++)
......
......@@ -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];
......
......@@ -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));
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment