Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b677e43 authored by Dave Airlie's avatar Dave Airlie
Browse files

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

drm/tegra: Changes for v4.15-rc1

This contains a bit of cleanup and some minor fixes for the host1x and
Tegra DRM drivers. There's also some more preparatory work for Tegra186
support which I'm not quite ready to send upstream because the GPIO
driver needed for HDMI support has been stuck for months, and we can't
do much without it. Hopefully that driver will land in v4.15, which
would mean we could go ahead with Tegra186 display support in v4.16.

* tag 'drm/tegra/for-4.15-rc1' of git://anongit.freedesktop.org/tegra/linux: (21 commits)
  drm/tegra: hdmi: Add cec-notifier support
  drm/tegra: dc: Perform a complete reset sequence
  drm/tegra: dc: Make sure to set the module clock rate
  drm/tegra: dc: Simplify atomic plane helper functions
  drm/tegra: dc: Move some declarations to dc.h
  drm/tegra: vic: Use of_device_get_match_data()
  drm/tegra: sor: Use of_device_get_match_data()
  drm/tegra: hdmi: Use of_device_get_match_data()
  drm/tegra: dc: Use of_device_get_match_data()
  drm/tegra: Use u64_to_user_ptr helper
  gpu: host1x: Fix incorrect comment for channel_request
  gpu: host1x: Disassemble more instructions
  gpu: host1x: Improve debug disassembly formatting
  gpu: host1x: Enable gather filter
  gpu: host1x: Enable Tegra186 syncpoint protection
  gpu: host1x: Call of_dma_configure() after setting bus
  drm/tegra: Add Tegra186 support for VIC
  gpu: host1x: Add Tegra186 support
  dt-bindings: host1x: Add Tegra186 information
  gpu: host1x: syncpt: Request syncpoints per client
  ...
parents 3064abfa fb83be88
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3,6 +3,10 @@ NVIDIA Tegra host1x
Required properties:
- compatible: "nvidia,tegra<chip>-host1x"
- reg: Physical base address and length of the controller's registers.
  For pre-Tegra186, one entry describing the whole register area.
  For Tegra186, one entry for each entry in reg-names:
    "vm" - VM region assigned to Linux
    "hypervisor" - Hypervisor region (only if Linux acts as hypervisor)
- interrupts: The interrupt outputs from the controller.
- #address-cells: The number of cells used to represent physical base addresses
  in the host1x address space. Should be 1.
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ config DRM_TEGRA
	select DRM_PANEL
	select TEGRA_HOST1X
	select IOMMU_IOVA if IOMMU_SUPPORT
	select CEC_CORE if CEC_NOTIFIER
	help
	  Choose this option if you have an NVIDIA Tegra SoC.

+38 −46
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/iommu.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>

@@ -23,16 +24,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>

struct tegra_dc_soc_info {
	bool supports_border_color;
	bool supports_interlacing;
	bool supports_cursor;
	bool supports_block_linear;
	unsigned int pitch_align;
	bool has_powergate;
	bool broken_reset;
};

struct tegra_plane {
	struct drm_plane base;
	unsigned int index;
@@ -559,14 +550,21 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
	return 0;
}

static void tegra_dc_disable_window(struct tegra_dc *dc, int index)
static void tegra_plane_atomic_disable(struct drm_plane *plane,
				       struct drm_plane_state *old_state)
{
	struct tegra_dc *dc = to_tegra_dc(old_state->crtc);
	struct tegra_plane *p = to_tegra_plane(plane);
	unsigned long flags;
	u32 value;

	/* rien ne va plus */
	if (!old_state || !old_state->crtc)
		return;

	spin_lock_irqsave(&dc->lock, flags);

	value = WINDOW_A_SELECT << index;
	value = WINDOW_A_SELECT << p->index;
	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);

	value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
@@ -591,7 +589,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
		return;

	if (!plane->state->visible)
		return tegra_dc_disable_window(dc, p->index);
		return tegra_plane_atomic_disable(plane, old_state);

	memset(&window, 0, sizeof(window));
	window.src.x = plane->state->src.x1 >> 16;
@@ -627,25 +625,10 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
	tegra_dc_setup_window(dc, p->index, &window);
}

static void tegra_plane_atomic_disable(struct drm_plane *plane,
				       struct drm_plane_state *old_state)
{
	struct tegra_plane *p = to_tegra_plane(plane);
	struct tegra_dc *dc;

	/* rien ne va plus */
	if (!old_state || !old_state->crtc)
		return;

	dc = to_tegra_dc(old_state->crtc);

	tegra_dc_disable_window(dc, p->index);
}

static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
	.atomic_check = tegra_plane_atomic_check,
	.atomic_update = tegra_plane_atomic_update,
	.atomic_disable = tegra_plane_atomic_disable,
	.atomic_update = tegra_plane_atomic_update,
};

static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
@@ -685,7 +668,7 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
		return ERR_PTR(err);
	}

	drm_plane_helper_add(&plane->base, &tegra_primary_plane_helper_funcs);
	drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);

	return &plane->base;
}
@@ -880,12 +863,6 @@ static const uint32_t tegra_overlay_plane_formats[] = {
	DRM_FORMAT_YUV422,
};

static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = {
	.atomic_check = tegra_plane_atomic_check,
	.atomic_update = tegra_plane_atomic_update,
	.atomic_disable = tegra_plane_atomic_disable,
};

static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
						       struct tegra_dc *dc,
						       unsigned int index)
@@ -913,7 +890,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
		return ERR_PTR(err);
	}

	drm_plane_helper_add(&plane->base, &tegra_overlay_plane_helper_funcs);
	drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);

	return &plane->base;
}
@@ -1161,6 +1138,11 @@ static void tegra_dc_commit_state(struct tegra_dc *dc,

	value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1;
	tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);

	err = clk_set_rate(dc->clk, state->pclk);
	if (err < 0)
		dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n",
			dc->clk, state->pclk, err);
}

static void tegra_dc_stop(struct tegra_dc *dc)
@@ -1756,7 +1738,7 @@ static int tegra_dc_init(struct host1x_client *client)
	struct drm_plane *cursor = NULL;
	int err;

	dc->syncpt = host1x_syncpt_request(dc->dev, flags);
	dc->syncpt = host1x_syncpt_request(client, flags);
	if (!dc->syncpt)
		dev_warn(dc->dev, "failed to allocate syncpoint\n");

@@ -1985,7 +1967,6 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)

static int tegra_dc_probe(struct platform_device *pdev)
{
	const struct of_device_id *id;
	struct resource *regs;
	struct tegra_dc *dc;
	int err;
@@ -1994,14 +1975,11 @@ static int tegra_dc_probe(struct platform_device *pdev)
	if (!dc)
		return -ENOMEM;

	id = of_match_node(tegra_dc_of_match, pdev->dev.of_node);
	if (!id)
		return -ENODEV;
	dc->soc = of_device_get_match_data(&pdev->dev);

	spin_lock_init(&dc->lock);
	INIT_LIST_HEAD(&dc->list);
	dc->dev = &pdev->dev;
	dc->soc = id->data;

	err = tegra_dc_parse_dt(dc);
	if (err < 0)
@@ -2019,8 +1997,22 @@ static int tegra_dc_probe(struct platform_device *pdev)
		return PTR_ERR(dc->rst);
	}

	if (!dc->soc->broken_reset)
		reset_control_assert(dc->rst);
	/* assert reset and disable clock */
	if (!dc->soc->broken_reset) {
		err = clk_prepare_enable(dc->clk);
		if (err < 0)
			return err;

		usleep_range(2000, 4000);

		err = reset_control_assert(dc->rst);
		if (err < 0)
			return err;

		usleep_range(2000, 4000);

		clk_disable_unprepare(dc->clk);
	}

	if (dc->soc->has_powergate) {
		if (dc->pipe == 0)
+120 −0
Original line number Diff line number Diff line
@@ -10,6 +10,126 @@
#ifndef TEGRA_DC_H
#define TEGRA_DC_H 1

#include <linux/host1x.h>

#include <drm/drm_crtc.h>

#include "drm.h"

struct tegra_output;

struct tegra_dc_stats {
	unsigned long frames;
	unsigned long vblank;
	unsigned long underflow;
	unsigned long overflow;
};

struct tegra_dc_soc_info {
	bool supports_border_color;
	bool supports_interlacing;
	bool supports_cursor;
	bool supports_block_linear;
	unsigned int pitch_align;
	bool has_powergate;
	bool broken_reset;
};

struct tegra_dc {
	struct host1x_client client;
	struct host1x_syncpt *syncpt;
	struct device *dev;
	spinlock_t lock;

	struct drm_crtc base;
	unsigned int powergate;
	int pipe;

	struct clk *clk;
	struct reset_control *rst;
	void __iomem *regs;
	int irq;

	struct tegra_output *rgb;

	struct tegra_dc_stats stats;
	struct list_head list;

	struct drm_info_list *debugfs_files;
	struct drm_minor *minor;
	struct dentry *debugfs;

	/* page-flip handling */
	struct drm_pending_vblank_event *event;

	const struct tegra_dc_soc_info *soc;

	struct iommu_domain *domain;
};

static inline struct tegra_dc *
host1x_client_to_dc(struct host1x_client *client)
{
	return container_of(client, struct tegra_dc, client);
}

static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc)
{
	return crtc ? container_of(crtc, struct tegra_dc, base) : NULL;
}

static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value,
				   unsigned int offset)
{
	trace_dc_writel(dc->dev, offset, value);
	writel(value, dc->regs + (offset << 2));
}

static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned int offset)
{
	u32 value = readl(dc->regs + (offset << 2));

	trace_dc_readl(dc->dev, offset, value);

	return value;
}

struct tegra_dc_window {
	struct {
		unsigned int x;
		unsigned int y;
		unsigned int w;
		unsigned int h;
	} src;
	struct {
		unsigned int x;
		unsigned int y;
		unsigned int w;
		unsigned int h;
	} dst;
	unsigned int bits_per_pixel;
	unsigned int stride[2];
	unsigned long base[3];
	bool bottom_up;

	struct tegra_bo_tiling tiling;
	u32 format;
	u32 swap;
};

/* from dc.c */
void tegra_dc_commit(struct tegra_dc *dc);
int tegra_dc_state_setup_clock(struct tegra_dc *dc,
			       struct drm_crtc_state *crtc_state,
			       struct clk *clk, unsigned long pclk,
			       unsigned int div);

/* from rgb.c */
int tegra_dc_rgb_probe(struct tegra_dc *dc);
int tegra_dc_rgb_remove(struct tegra_dc *dc);
int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
int tegra_dc_rgb_exit(struct tegra_dc *dc);

#define DC_CMD_GENERAL_INCR_SYNCPT		0x000
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL	0x001
#define  SYNCPT_CNTRL_NO_STALL   (1 << 8)
+16 −14
Original line number Diff line number Diff line
@@ -386,12 +386,10 @@ int tegra_drm_submit(struct tegra_drm_context *context,
	unsigned int num_cmdbufs = args->num_cmdbufs;
	unsigned int num_relocs = args->num_relocs;
	unsigned int num_waitchks = args->num_waitchks;
	struct drm_tegra_cmdbuf __user *cmdbufs =
		(void __user *)(uintptr_t)args->cmdbufs;
	struct drm_tegra_reloc __user *relocs =
		(void __user *)(uintptr_t)args->relocs;
	struct drm_tegra_waitchk __user *waitchks =
		(void __user *)(uintptr_t)args->waitchks;
	struct drm_tegra_cmdbuf __user *user_cmdbufs;
	struct drm_tegra_reloc __user *user_relocs;
	struct drm_tegra_waitchk __user *user_waitchks;
	struct drm_tegra_syncpt __user *user_syncpt;
	struct drm_tegra_syncpt syncpt;
	struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
	struct drm_gem_object **refs;
@@ -400,6 +398,11 @@ int tegra_drm_submit(struct tegra_drm_context *context,
	unsigned int num_refs;
	int err;

	user_cmdbufs = u64_to_user_ptr(args->cmdbufs);
	user_relocs = u64_to_user_ptr(args->relocs);
	user_waitchks = u64_to_user_ptr(args->waitchks);
	user_syncpt = u64_to_user_ptr(args->syncpts);

	/* We don't yet support other than one syncpt_incr struct per submit */
	if (args->num_syncpts != 1)
		return -EINVAL;
@@ -440,7 +443,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
		struct tegra_bo *obj;
		u64 offset;

		if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) {
		if (copy_from_user(&cmdbuf, user_cmdbufs, sizeof(cmdbuf))) {
			err = -EFAULT;
			goto fail;
		}
@@ -476,7 +479,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,

		host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
		num_cmdbufs--;
		cmdbufs++;
		user_cmdbufs++;
	}

	/* copy and resolve relocations from submit */
@@ -485,7 +488,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
		struct tegra_bo *obj;

		err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
						  &relocs[num_relocs], drm,
						  &user_relocs[num_relocs], drm,
						  file);
		if (err < 0)
			goto fail;
@@ -519,9 +522,8 @@ int tegra_drm_submit(struct tegra_drm_context *context,
		struct host1x_waitchk *wait = &job->waitchk[num_waitchks];
		struct tegra_bo *obj;

		err = host1x_waitchk_copy_from_user(wait,
						    &waitchks[num_waitchks],
						    file);
		err = host1x_waitchk_copy_from_user(
			wait, &user_waitchks[num_waitchks], file);
		if (err < 0)
			goto fail;

@@ -539,8 +541,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
		}
	}

	if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts,
			   sizeof(syncpt))) {
	if (copy_from_user(&syncpt, user_syncpt, sizeof(syncpt))) {
		err = -EFAULT;
		goto fail;
	}
@@ -1317,6 +1318,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
	{ .compatible = "nvidia,tegra210-sor", },
	{ .compatible = "nvidia,tegra210-sor1", },
	{ .compatible = "nvidia,tegra210-vic", },
	{ .compatible = "nvidia,tegra186-vic", },
	{ /* sentinel */ }
};

Loading