summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-06-04 12:09:57 +0200
committerThierry Reding <treding@nvidia.com>2014-06-04 12:09:57 +0200
commitf68a21631ad5b769ffc9e510c1a38c386f3aad90 (patch)
tree22cde52bedc7f8eda9b2dfbdcbdc9dc2e6f752fd
parentc72d9a86783016a2ecc3f144d3c26e586df65117 (diff)
parentc3bfe8a8773d747b510cf59ef337a42fd19f8894 (diff)
Merge branch 'staging/drm/tegra' into staging/master
-rw-r--r--Documentation/DocBook/drm.tmpl36
-rw-r--r--drivers/gpu/drm/drm_ioctl.c24
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c10
-rw-r--r--drivers/gpu/drm/drm_pci.c80
-rw-r--r--drivers/gpu/drm/drm_platform.c15
-rw-r--r--drivers/gpu/drm/drm_stub.c48
-rw-r--r--drivers/gpu/drm/drm_usb.c20
-rw-r--r--drivers/gpu/drm/tegra/Makefile1
-rw-r--r--drivers/gpu/drm/tegra/bus.c64
-rw-r--r--drivers/gpu/drm/tegra/dc.c121
-rw-r--r--drivers/gpu/drm/tegra/dc.h30
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c31
-rw-r--r--drivers/gpu/drm/tegra/drm.c35
-rw-r--r--drivers/gpu/drm/tegra/drm.h7
-rw-r--r--drivers/gpu/drm/tegra/dsi.c6
-rw-r--r--drivers/gpu/drm/tegra/gr2d.c8
-rw-r--r--drivers/gpu/drm/tegra/gr3d.c8
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c6
-rw-r--r--drivers/gpu/drm/tegra/output.c88
-rw-r--r--drivers/gpu/drm/tegra/sor.c17
-rw-r--r--drivers/gpu/host1x/bus.c12
-rw-r--r--include/drm/drmP.h2
-rw-r--r--include/drm/drm_mipi_dsi.h2
23 files changed, 440 insertions, 231 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 00f1c25e53d..016b42545ac 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -142,6 +142,12 @@
to register it with the DRM subsystem.
</para>
<para>
+ Newer drivers that no longer require a <structname>drm_bus</structname>
+ structure can alternatively use the low-level device initialization and
+ registration functions such as <function>drm_dev_alloc()</function> and
+ <function>drm_dev_register()</function> directly.
+ </para>
+ <para>
The <structname>drm_driver</structname> structure contains static
information that describes the driver and features it supports, and
pointers to methods that the DRM core will call to implement the DRM API.
@@ -282,6 +288,36 @@ char *date;</synopsis>
</sect3>
</sect2>
<sect2>
+ <title>Device Registration</title>
+ <para>
+ A number of functions are provided to help with device registration.
+ The functions deal with PCI, USB and platform devices, respectively.
+ </para>
+!Edrivers/gpu/drm/drm_pci.c
+!Edrivers/gpu/drm/drm_usb.c
+!Edrivers/gpu/drm/drm_platform.c
+ <para>
+ New drivers that no longer rely on the services provided by the
+ <structname>drm_bus</structname> structure can call the low-level
+ device registration functions directly. The
+ <function>drm_dev_alloc()</function> function can be used to allocate
+ and initialize a new <structname>drm_device</structname> structure.
+ Drivers will typically want to perform some additional setup on this
+ structure, such as allocating driver-specific data and storing a
+ pointer to it in the DRM device's <structfield>dev_private</structfield>
+ field. Drivers should also set the device's unique name using the
+ <function>drm_dev_set_unique()</function> function. After it has been
+ set up a device can be registered with the DRM subsystem by calling
+ <function>drm_dev_register()</function>. This will cause the device to
+ be exposed to userspace and will call the driver's
+ <structfield>.load()</structfield> implementation. When a device is
+ removed, the DRM device can safely be unregistered and freed by calling
+ <function>drm_dev_unregister()</function> followed by a call to
+ <function>drm_dev_unref()</function>.
+ </para>
+!Edrivers/gpu/drm/drm_stub.c
+ </sect2>
+ <sect2>
<title>Driver Load</title>
<para>
The <methodname>load</methodname> method is the driver and device
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 38269d5aa33..69c61f392e6 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -131,13 +131,25 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
if (master->unique != NULL)
drm_unset_busid(dev, master);
- ret = dev->driver->bus->set_busid(dev, master);
- if (ret)
- goto err;
+ if (dev->driver->bus && dev->driver->bus->set_busid) {
+ ret = dev->driver->bus->set_busid(dev, master);
+ if (ret) {
+ drm_unset_busid(dev, master);
+ return ret;
+ }
+ } else {
+ if (WARN(dev->unique == NULL,
+ "No drm_bus.set_busid() implementation provided by "
+ "%ps. Use drm_dev_set_unique() to set the unique "
+ "name explicitly.", dev->driver))
+ return -EINVAL;
+
+ master->unique = kstrdup(dev->unique, GFP_KERNEL);
+ if (master->unique)
+ master->unique_len = strlen(dev->unique);
+ }
+
return 0;
-err:
- drm_unset_busid(dev, master);
- return ret;
}
/**
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 09821f46d76..e633df2f68d 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -282,6 +282,14 @@ static int mipi_dsi_drv_remove(struct device *dev)
return drv->remove(dsi);
}
+static void mipi_dsi_drv_shutdown(struct device *dev)
+{
+ struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+ drv->shutdown(dsi);
+}
+
/**
* mipi_dsi_driver_register - register a driver for DSI devices
* @drv: DSI driver structure
@@ -293,6 +301,8 @@ int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
drv->driver.probe = mipi_dsi_drv_probe;
if (drv->remove)
drv->driver.remove = mipi_dsi_drv_remove;
+ if (drv->shutdown)
+ drv->driver.shutdown = mipi_dsi_drv_shutdown;
return driver_register(&drv->driver);
}
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index d237de36a07..020cfd93485 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -1,17 +1,3 @@
-/* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */
-/**
- * \file drm_pci.c
- * \brief Functions and ioctls to manage PCI memory
- *
- * \warning These interfaces aren't stable yet.
- *
- * \todo Implement the remaining ioctl's for the PCI pools.
- * \todo The wrappers here are so thin that they would be better off inlined..
- *
- * \author José Fonseca <jrfonseca@tungstengraphics.com>
- * \author Leif Delgass <ldelgass@retinalburn.net>
- */
-
/*
* Copyright 2003 José Fonseca.
* Copyright 2003 Leif Delgass.
@@ -42,12 +28,14 @@
#include <linux/export.h>
#include <drm/drmP.h>
-/**********************************************************************/
-/** \name PCI memory */
-/*@{*/
-
/**
- * \brief Allocate a PCI consistent memory block, for DMA.
+ * drm_pci_alloc - Allocate a PCI consistent memory block, for DMA.
+ * @dev: DRM device
+ * @size: size of block to allocate
+ * @align: alignment of block
+ *
+ * Return: A handle to the allocated memory block on success or NULL on
+ * failure.
*/
drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
{
@@ -88,8 +76,8 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali
EXPORT_SYMBOL(drm_pci_alloc);
-/**
- * \brief Free a PCI consistent memory block without freeing its descriptor.
+/*
+ * Free a PCI consistent memory block without freeing its descriptor.
*
* This function is for internal use in the Linux-specific DRM core code.
*/
@@ -111,7 +99,9 @@ void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
}
/**
- * \brief Free a PCI consistent memory block
+ * drm_pci_free - Free a PCI consistent memory block
+ * @dev: DRM device
+ * @dmah: handle to memory block
*/
void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
{
@@ -226,17 +216,16 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
}
/**
- * Get interrupt from bus id.
- *
- * \param inode device inode.
- * \param file_priv DRM file private.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_irq_busid structure.
- * \return zero on success or a negative number on failure.
+ * drm_irq_by_busid - Get interrupt from bus ID
+ * @dev: DRM device
+ * @data: IOCTL parameter pointing to a drm_irq_busid structure
+ * @file_priv: DRM file private.
*
* Finds the PCI device with the specified bus id and gets its IRQ number.
* This IOCTL is deprecated, and will now return EINVAL for any busid not equal
* to that of the device that this DRM instance attached to.
+ *
+ * Return: 0 on success or a negative error code on failure.
*/
int drm_irq_by_busid(struct drm_device *dev, void *data,
struct drm_file *file_priv)
@@ -285,15 +274,16 @@ static struct drm_bus drm_pci_bus = {
};
/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
+ * drm_get_pci_dev - Register a PCI device with the DRM subsystem
+ * @pdev: PCI device
+ * @ent: entry from the PCI ID table that matches @pdev
+ * @driver: DRM device driver
*
* Attempt to gets inter module "drm" information. If we are first
* then register the character device and inter module information.
* Try and register, if we fail to register, backout previous work.
+ *
+ * Return: 0 on success or a negative error code on failure.
*/
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver)
@@ -346,15 +336,14 @@ err_free:
EXPORT_SYMBOL(drm_get_pci_dev);
/**
- * PCI device initialization. Called direct from modules at load time.
+ * drm_pci_init - Register matching PCI devices with the DRM subsystem
+ * @driver: DRM device driver
+ * @pdriver: PCI device driver
*
- * \return zero on success or a negative number on failure.
+ * Initializes a drm_device structures, registering the stubs and initializing
+ * the AGP device.
*
- * Initializes a drm_device structures,registering the
- * stubs and initializing the AGP device.
- *
- * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
- * after the initialization for driver customization.
+ * Return: 0 on success or a negative error code on failure.
*/
int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
{
@@ -458,7 +447,14 @@ int drm_pci_set_unique(struct drm_device *dev,
EXPORT_SYMBOL(drm_pci_init);
-/*@}*/
+/**
+ * drm_pci_exit - Unregister matching PCI devices from the DRM subsystem
+ * @driver: DRM device driver
+ * @pdriver: PCI device driver
+ *
+ * Unregisters one or more devices matched by a PCI driver from the DRM
+ * subsystem.
+ */
void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
{
struct drm_device *dev, *tmp;
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index 234e0bc1ae5..d5b76f148c1 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -106,17 +106,16 @@ static struct drm_bus drm_platform_bus = {
};
/**
- * Platform device initialization. Called direct from modules.
+ * drm_platform_init - Register a platform device with the DRM subsystem
+ * @driver: DRM device driver
+ * @platform_device: platform device to register
*
- * \return zero on success or a negative number on failure.
- *
- * Initializes a drm_device structures,registering the
- * stubs
+ * Registers the specified DRM device driver and platform device with the DRM
+ * subsystem, initializing a drm_device structure and calling the driver's
+ * .load() function.
*
- * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
- * after the initialization for driver customization.
+ * Return: 0 on success or a negative error code on failure.
*/
-
int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device)
{
DRM_DEBUG("\n");
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 3727ac8bc31..14d16464000 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -1,16 +1,11 @@
-/**
- * \file drm_stub.h
- * Stub support
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- */
-
/*
* Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
*
* Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
+ * Author Rickard E. (Rik) Faith <faith@valinux.com>
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
@@ -425,11 +420,15 @@ void drm_minor_release(struct drm_minor *minor)
}
/**
- * Called via drm_exit() at module unload time or when pci device is
- * unplugged.
+ * drm_put_dev - Unregister and release a DRM device
+ * @dev: DRM device
*
- * Cleans up all DRM device, calling drm_lastclose().
+ * Called at module unload time or when a PCI device is unplugged.
+ *
+ * Use of this function is discouraged. It will eventually go away completely.
+ * Please use drm_dev_unregister() and drm_dev_unref() explicitly instead.
*
+ * Cleans up all DRM device, calling drm_lastclose().
*/
void drm_put_dev(struct drm_device *dev)
{
@@ -536,7 +535,7 @@ static void drm_fs_inode_free(struct inode *inode)
}
/**
- * drm_dev_alloc - Allocate new drm device
+ * drm_dev_alloc - Allocate new DRM device
* @driver: DRM driver to allocate device for
* @parent: Parent device object
*
@@ -650,6 +649,7 @@ static void drm_dev_release(struct kref *ref)
drm_minor_free(dev, DRM_MINOR_CONTROL);
mutex_destroy(&dev->master_mutex);
+ kfree(dev->unique);
kfree(dev);
}
@@ -689,6 +689,7 @@ EXPORT_SYMBOL(drm_dev_unref);
/**
* drm_dev_register - Register DRM device
* @dev: Device to register
+ * @flags: Flags passed to the driver's .load() function
*
* Register the DRM device @dev with the system, advertise device to user-space
* and start normal device operation. @dev must be allocated via drm_dev_alloc()
@@ -777,3 +778,28 @@ void drm_dev_unregister(struct drm_device *dev)
drm_minor_unregister(dev, DRM_MINOR_CONTROL);
}
EXPORT_SYMBOL(drm_dev_unregister);
+
+/**
+ * drm_dev_set_unique - Set the unique name of a DRM device
+ * @dev: device of which to set the unique name
+ * @fmt: format string for unique name
+ *
+ * Sets the unique name of a DRM device using the specified format string and
+ * a variable list of arguments. Drivers can use this at driver probe time if
+ * the unique name of the devices they drive is static.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int drm_dev_set_unique(struct drm_device *dev, const char *fmt, ...)
+{
+ va_list ap;
+
+ kfree(dev->unique);
+
+ va_start(ap, fmt);
+ dev->unique = kvasprintf(GFP_KERNEL, fmt, ap);
+ va_end(ap);
+
+ return dev->unique ? 0 : -ENOMEM;
+}
+EXPORT_SYMBOL(drm_dev_set_unique);
diff --git a/drivers/gpu/drm/drm_usb.c b/drivers/gpu/drm/drm_usb.c
index c6c7c29ad46..f2fe94aab90 100644
--- a/drivers/gpu/drm/drm_usb.c
+++ b/drivers/gpu/drm/drm_usb.c
@@ -45,7 +45,17 @@ static int drm_usb_set_busid(struct drm_device *dev,
static struct drm_bus drm_usb_bus = {
.set_busid = drm_usb_set_busid,
};
-
+
+/**
+ * drm_usb_init - Register matching USB devices with the DRM subsystem
+ * @driver: DRM device driver
+ * @udriver: USB device driver
+ *
+ * Registers one or more devices matched by a USB driver with the DRM
+ * subsystem.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver)
{
int res;
@@ -58,6 +68,14 @@ int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver)
}
EXPORT_SYMBOL(drm_usb_init);
+/**
+ * drm_usb_exit - Unregister matching USB devices from the DRM subsystem
+ * @driver: DRM device driver
+ * @udriver: USB device driver
+ *
+ * Unregisters one or more devices matched by a USB driver from the DRM
+ * subsystem.
+ */
void drm_usb_exit(struct drm_driver *driver,
struct usb_driver *udriver)
{
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index d43f21bb459..2c66a8db9da 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -1,7 +1,6 @@
ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
tegra-drm-y := \
- bus.o \
drm.o \
gem.o \
fb.o \
diff --git a/drivers/gpu/drm/tegra/bus.c b/drivers/gpu/drm/tegra/bus.c
deleted file mode 100644
index b3a66d65cb5..00000000000
--- a/drivers/gpu/drm/tegra/bus.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2013 NVIDIA Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "drm.h"
-
-static int drm_host1x_set_busid(struct drm_device *dev,
- struct drm_master *master)
-{
- const char *device = dev_name(dev->dev);
- const char *bus = dev->dev->bus->name;
-
- master->unique_len = strlen(bus) + 1 + strlen(device);
- master->unique_size = master->unique_len;
-
- master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
- if (!master->unique)
- return -ENOMEM;
-
- snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device);
-
- return 0;
-}
-
-static struct drm_bus drm_host1x_bus = {
- .set_busid = drm_host1x_set_busid,
-};
-
-int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
-{
- struct drm_device *drm;
- int ret;
-
- driver->bus = &drm_host1x_bus;
-
- drm = drm_dev_alloc(driver, &device->dev);
- if (!drm)
- return -ENOMEM;
-
- ret = drm_dev_register(drm, 0);
- if (ret)
- goto err_free;
-
- DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name,
- driver->major, driver->minor, driver->patchlevel,
- driver->date, drm->primary->index);
-
- return 0;
-
-err_free:
- drm_dev_unref(drm);
- return ret;
-}
-
-void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device)
-{
- struct tegra_drm *tegra = dev_get_drvdata(&device->dev);
-
- drm_put_dev(tegra->drm);
-}
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 859e424e15e..ef40381f390 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -17,6 +17,7 @@
struct tegra_dc_soc_info {
bool supports_interlacing;
+ bool supports_cursor;
};
struct tegra_plane {
@@ -477,6 +478,109 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc)
spin_unlock_irqrestore(&dc->lock, flags);
}
+static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file,
+ uint32_t handle, uint32_t width,
+ uint32_t height, int32_t hot_x, int32_t hot_y)
+{
+ unsigned long value = CURSOR_CLIP_DISPLAY;
+ struct tegra_dc *dc = to_tegra_dc(crtc);
+ struct drm_gem_object *gem;
+ struct tegra_bo *bo = NULL;
+
+ if (!dc->soc->supports_cursor)
+ return -ENXIO;
+
+ if (width != height)
+ return -EINVAL;
+
+ switch (width) {
+ case 32:
+ value |= CURSOR_SIZE_32x32;
+ break;
+
+ case 64:
+ value |= CURSOR_SIZE_64x64;
+ break;
+
+ case 128:
+ value |= CURSOR_SIZE_128x128;
+
+ case 256:
+ value |= CURSOR_SIZE_256x256;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (handle) {
+ gem = drm_gem_object_lookup(crtc->dev, file, handle);
+ if (!gem)
+ return -ENOENT;
+
+ bo = to_tegra_bo(gem);
+ }
+
+ if (bo) {
+ unsigned long addr = (bo->paddr & 0xfffffc00) >> 10;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ unsigned long high = (bo->paddr & 0xfffffffc) >> 32;
+#endif
+
+ tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI);
+#endif
+
+ value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+ value |= CURSOR_ENABLE;
+ tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+ value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
+ value &= ~CURSOR_DST_BLEND_MASK;
+ value &= ~CURSOR_SRC_BLEND_MASK;
+ value |= CURSOR_MODE_NORMAL;
+ value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
+ value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
+ value |= CURSOR_ALPHA;
+ tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
+ } else {
+ value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+ value &= ~CURSOR_ENABLE;
+ tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+ }
+
+ tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ return 0;
+}
+
+static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct tegra_dc *dc = to_tegra_dc(crtc);
+ unsigned long value;
+
+ if (!dc->soc->supports_cursor)
+ return -ENXIO;
+
+ value = ((y & 0x3fff) << 16) | (x & 0x3fff);
+ tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
+
+ tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ /* XXX: only required on generations earlier than Tegra124? */
+ tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ return 0;
+}
+
static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
{
struct drm_device *drm = dc->base.dev;
@@ -553,6 +657,8 @@ static void tegra_dc_destroy(struct drm_crtc *crtc)
}
static const struct drm_crtc_funcs tegra_crtc_funcs = {
+ .cursor_set2 = tegra_dc_cursor_set2,
+ .cursor_move = tegra_dc_cursor_move,
.page_flip = tegra_dc_page_flip,
.set_config = drm_crtc_helper_set_config,
.destroy = tegra_dc_destroy,
@@ -999,6 +1105,8 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
DUMP_REG(DC_DISP_SD_BL_CONTROL);
DUMP_REG(DC_DISP_SD_HW_K_VALUES);
DUMP_REG(DC_DISP_SD_MAN_K_VALUES);
+ DUMP_REG(DC_DISP_CURSOR_START_ADDR_HI);
+ DUMP_REG(DC_DISP_BLEND_CURSOR_CONTROL);
DUMP_REG(DC_WIN_WIN_OPTIONS);
DUMP_REG(DC_WIN_BYTE_SWAP);
DUMP_REG(DC_WIN_BUFFER_CONTROL);
@@ -1104,26 +1212,26 @@ static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
static int tegra_dc_init(struct host1x_client *client)
{
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_dc *dc = host1x_client_to_dc(client);
int err;
- drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
+ drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs);
drm_mode_crtc_set_gamma_size(&dc->base, 256);
drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
- err = tegra_dc_rgb_init(tegra->drm, dc);
+ err = tegra_dc_rgb_init(drm, dc);
if (err < 0 && err != -ENODEV) {
dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
return err;
}
- err = tegra_dc_add_planes(tegra->drm, dc);
+ err = tegra_dc_add_planes(drm, dc);
if (err < 0)
return err;
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_dc_debugfs_init(dc, tegra->drm->primary);
+ err = tegra_dc_debugfs_init(dc, drm->primary);
if (err < 0)
dev_err(dc->dev, "debugfs setup failed: %d\n", err);
}
@@ -1168,14 +1276,17 @@ static const struct host1x_client_ops dc_client_ops = {
static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
.supports_interlacing = false,
+ .supports_cursor = false,
};
static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
.supports_interlacing = false,
+ .supports_cursor = false,
};
static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
.supports_interlacing = true,
+ .supports_cursor = true,
};
static const struct of_device_id tegra_dc_of_match[] = {
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 44e31aefe89..78c5feff95d 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -67,10 +67,12 @@
#define WIN_A_ACT_REQ (1 << 1)
#define WIN_B_ACT_REQ (1 << 2)
#define WIN_C_ACT_REQ (1 << 3)
+#define CURSOR_ACT_REQ (1 << 7)
#define GENERAL_UPDATE (1 << 8)
#define WIN_A_UPDATE (1 << 9)
#define WIN_B_UPDATE (1 << 10)
#define WIN_C_UPDATE (1 << 11)
+#define CURSOR_UPDATE (1 << 15)
#define NC_HOST_TRIG (1 << 24)
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x042
@@ -116,9 +118,10 @@
#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
#define DC_DISP_DISP_WIN_OPTIONS 0x402
-#define HDMI_ENABLE (1 << 30)
-#define DSI_ENABLE (1 << 29)
-#define SOR_ENABLE (1 << 25)
+#define HDMI_ENABLE (1 << 30)
+#define DSI_ENABLE (1 << 29)
+#define SOR_ENABLE (1 << 25)
+#define CURSOR_ENABLE (1 << 16)
#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24)
@@ -266,6 +269,14 @@
#define DC_DISP_CURSOR_BACKGROUND 0x43d
#define DC_DISP_CURSOR_START_ADDR 0x43e
+#define CURSOR_CLIP_DISPLAY (0 << 28)
+#define CURSOR_CLIP_WIN_A (1 << 28)
+#define CURSOR_CLIP_WIN_B (2 << 28)
+#define CURSOR_CLIP_WIN_C (3 << 28)
+#define CURSOR_SIZE_32x32 (0 << 24)
+#define CURSOR_SIZE_64x64 (1 << 24)
+#define CURSOR_SIZE_128x128 (2 << 24)
+#define CURSOR_SIZE_256x256 (3 << 24)
#define DC_DISP_CURSOR_START_ADDR_NS 0x43f
#define DC_DISP_CURSOR_POSITION 0x440
@@ -302,6 +313,19 @@
#define INTERLACE_START (1 << 1)
#define INTERLACE_ENABLE (1 << 0)
+#define DC_DISP_CURSOR_START_ADDR_HI 0x4ec
+#define DC_DISP_BLEND_CURSOR_CONTROL 0x4f1
+#define CURSOR_MODE_LEGACY (0 << 24)
+#define CURSOR_MODE_NORMAL (1 << 24)
+#define CURSOR_DST_BLEND_ZERO (0 << 16)
+#define CURSOR_DST_BLEND_K1 (1 << 16)
+#define CURSOR_DST_BLEND_NEG_K1_TIMES_SRC (2 << 16)
+#define CURSOR_DST_BLEND_MASK (3 << 16)
+#define CURSOR_SRC_BLEND_K1 (0 << 8)
+#define CURSOR_SRC_BLEND_K1_TIMES_SRC (1 << 8)
+#define CURSOR_SRC_BLEND_MASK (3 << 8)
+#define CURSOR_ALPHA 0xff
+
#define DC_WIN_CSC_YOF 0x611
#define DC_WIN_CSC_KYRGB 0x612
#define DC_WIN_CSC_KUR 0x613
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index 005c19bd92d..12a94fb35ca 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
@@ -41,6 +42,7 @@ struct tegra_dpaux {
struct regulator *vdd;
struct completion complete;
+ struct work_struct work;
struct list_head list;
};
@@ -49,6 +51,11 @@ static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux)
return container_of(aux, struct tegra_dpaux, aux);
}
+static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work)
+{
+ return container_of(work, struct tegra_dpaux, work);
+}
+
static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux,
unsigned long offset)
{
@@ -231,6 +238,14 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
return ret;
}
+static void tegra_dpaux_hotplug(struct work_struct *work)
+{
+ struct tegra_dpaux *dpaux = work_to_dpaux(work);
+
+ if (dpaux->output)
+ drm_helper_hpd_irq_event(dpaux->output->connector.dev);
+}
+
static irqreturn_t tegra_dpaux_irq(int irq, void *data)
{
struct tegra_dpaux *dpaux = data;
@@ -241,16 +256,8 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data)
value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX);
tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
- if (value & DPAUX_INTR_PLUG_EVENT) {
- if (dpaux->output) {
- drm_helper_hpd_irq_event(dpaux->output->connector.dev);
- }
- }
-
- if (value & DPAUX_INTR_UNPLUG_EVENT) {
- if (dpaux->output)
- drm_helper_hpd_irq_event(dpaux->output->connector.dev);
- }
+ if (value & (DPAUX_INTR_PLUG_EVENT | DPAUX_INTR_UNPLUG_EVENT))
+ schedule_work(&dpaux->work);
if (value & DPAUX_INTR_IRQ_EVENT) {
/* TODO: handle this */
@@ -273,6 +280,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
if (!dpaux)
return -ENOMEM;
+ INIT_WORK(&dpaux->work, tegra_dpaux_hotplug);
init_completion(&dpaux->complete);
INIT_LIST_HEAD(&dpaux->list);
dpaux->dev = &pdev->dev;
@@ -361,6 +369,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
list_del(&dpaux->list);
mutex_unlock(&dpaux_lock);
+ cancel_work_sync(&dpaux->work);
+
clk_disable_unprepare(dpaux->clk_parent);
reset_control_assert(dpaux->rst);
clk_disable_unprepare(dpaux->clk);
@@ -404,6 +414,7 @@ int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
unsigned long timeout;
int err;
+ output->connector.polled = DRM_CONNECTOR_POLL_HPD;
dpaux->output = output;
err = regulator_enable(dpaux->vdd);
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index d492c2f12ca..fd736efd14b 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -33,7 +33,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (!tegra)
return -ENOMEM;
- dev_set_drvdata(drm->dev, tegra);
mutex_init(&tegra->clients_lock);
INIT_LIST_HEAD(&tegra->clients);
drm->dev_private = tegra;
@@ -644,14 +643,40 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
return 0;
}
-static int host1x_drm_probe(struct host1x_device *device)
+static int host1x_drm_probe(struct host1x_device *dev)
{
- return drm_host1x_init(&tegra_drm_driver, device);
+ struct drm_driver *driver = &tegra_drm_driver;
+ struct drm_device *drm;
+ int err;
+
+ drm = drm_dev_alloc(driver, &dev->dev);
+ if (!drm)
+ return -ENOMEM;
+
+ drm_dev_set_unique(drm, dev_name(&dev->dev));
+ dev_set_drvdata(&dev->dev, drm);
+
+ err = drm_dev_register(drm, 0);
+ if (err < 0)
+ goto unref;
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name,
+ driver->major, driver->minor, driver->patchlevel,
+ driver->date, drm->primary->index);
+
+ return 0;
+
+unref:
+ drm_dev_unref(drm);
+ return err;
}
-static int host1x_drm_remove(struct host1x_device *device)
+static int host1x_drm_remove(struct host1x_device *dev)
{
- drm_host1x_exit(&tegra_drm_driver, device);
+ struct drm_device *drm = dev_get_drvdata(&dev->dev);
+
+ drm_dev_unregister(drm);
+ drm_dev_unref(drm);
return 0;
}
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index d100f706d81..11f4049cebe 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -196,8 +196,9 @@ struct tegra_output {
struct drm_panel *panel;
struct i2c_adapter *ddc;
const struct edid *edid;
+
+ struct gpio_desc *hpd_gpio;
unsigned int hpd_irq;
- int hpd_gpio;
struct drm_encoder encoder;
struct drm_connector connector;
@@ -249,10 +250,6 @@ static inline int tegra_output_check_mode(struct tegra_output *output,
return output ? -ENOSYS : -EINVAL;
}
-/* from bus.c */
-int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device);
-void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device);
-
/* from rgb.c */
int tegra_dc_rgb_probe(struct tegra_dc *dc);
int tegra_dc_rgb_remove(struct tegra_dc *dc);
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 3838575f71c..bd56f2affa7 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -715,7 +715,7 @@ static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
static int tegra_dsi_init(struct host1x_client *client)
{
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_dsi *dsi = host1x_client_to_dsi(client);
int err;
@@ -723,14 +723,14 @@ static int tegra_dsi_init(struct host1x_client *client)
dsi->output.dev = client->dev;
dsi->output.ops = &dsi_ops;
- err = tegra_output_init(tegra->drm, &dsi->output);
+ err = tegra_output_init(drm, &dsi->output);
if (err < 0) {
dev_err(client->dev, "output setup failed: %d\n", err);
return err;
}
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_dsi_debugfs_init(dsi, tegra->drm->primary);
+ err = tegra_dsi_debugfs_init(dsi, drm->primary);
if (err < 0)
dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
}
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c
index 2c7ca748edf..7c53941f2a9 100644
--- a/drivers/gpu/drm/tegra/gr2d.c
+++ b/drivers/gpu/drm/tegra/gr2d.c
@@ -28,7 +28,7 @@ static inline struct gr2d *to_gr2d(struct tegra_drm_client *client)
static int gr2d_init(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *dev = dev_get_drvdata(client->parent);
unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
struct gr2d *gr2d = to_gr2d(drm);
@@ -42,17 +42,17 @@ static int gr2d_init(struct host1x_client *client)
return -ENOMEM;
}
- return tegra_drm_register_client(tegra, drm);
+ return tegra_drm_register_client(dev->dev_private, drm);
}
static int gr2d_exit(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *dev = dev_get_drvdata(client->parent);
struct gr2d *gr2d = to_gr2d(drm);
int err;
- err = tegra_drm_unregister_client(tegra, drm);
+ err = tegra_drm_unregister_client(dev->dev_private, drm);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c
index 0cbb24b1ae0..30f5ba9bd6d 100644
--- a/drivers/gpu/drm/tegra/gr3d.c
+++ b/drivers/gpu/drm/tegra/gr3d.c
@@ -37,7 +37,7 @@ static inline struct gr3d *to_gr3d(struct tegra_drm_client *client)
static int gr3d_init(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *dev = dev_get_drvdata(client->parent);
unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
struct gr3d *gr3d = to_gr3d(drm);
@@ -51,17 +51,17 @@ static int gr3d_init(struct host1x_client *client)
return -ENOMEM;
}
- return tegra_drm_register_client(tegra, drm);
+ return tegra_drm_register_client(dev->dev_private, drm);
}
static int gr3d_exit(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *dev = dev_get_drvdata(client->parent);
struct gr3d *gr3d = to_gr3d(drm);
int err;
- err = tegra_drm_unregister_client(tegra, drm);
+ err = tegra_drm_unregister_client(dev->dev_private, drm);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index fec1a63d32c..ba067bb767e 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -1347,7 +1347,7 @@ static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
static int tegra_hdmi_init(struct host1x_client *client)
{
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
int err;
@@ -1355,14 +1355,14 @@ static int tegra_hdmi_init(struct host1x_client *client)
hdmi->output.dev = client->dev;
hdmi->output.ops = &hdmi_ops;
- err = tegra_output_init(tegra->drm, &hdmi->output);
+ err = tegra_output_init(drm, &hdmi->output);
if (err < 0) {
dev_err(client->dev, "output setup failed: %d\n", err);
return err;
}
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_hdmi_debugfs_init(hdmi, tegra->drm->primary);
+ err = tegra_hdmi_debugfs_init(hdmi, drm->primary);
if (err < 0)
dev_err(client->dev, "debugfs setup failed: %d\n", err);
}
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index a3e4f1eca6f..ea844382725 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -80,8 +80,8 @@ tegra_connector_detect(struct drm_connector *connector, bool force)
if (output->ops->detect)
return output->ops->detect(output);
- if (gpio_is_valid(output->hpd_gpio)) {
- if (gpio_get_value(output->hpd_gpio) == 0)
+ if (output->hpd_gpio) {
+ if (gpiod_get_value(output->hpd_gpio) == 0)
status = connector_status_disconnected;
else
status = connector_status_connected;
@@ -190,14 +190,48 @@ static irqreturn_t hpd_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static int tegra_output_hpd_setup(struct tegra_output *output)
+{
+ unsigned long flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT;
+ struct device *dev = output->dev;
+ int err;
+
+ err = gpiod_direction_input(output->hpd_gpio);
+ if (err < 0) {
+ dev_err(dev, "failed to setup hotplug detect GPIO: %d\n", err);
+ return err;
+ }
+
+ err = gpiod_to_irq(output->hpd_gpio);
+ if (err < 0) {
+ dev_err(dev, "failed to get hotplug detect IRQ: %d\n", err);
+ return err;
+ }
+
+ output->hpd_irq = err;
+
+ err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, flags,
+ "hpd", output);
+ if (err < 0) {
+ dev_err(dev, "failed to request IRQ#%u: %d\n", output->hpd_irq,
+ err);
+ return err;
+ }
+
+ output->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ return 0;
+}
+
int tegra_output_probe(struct tegra_output *output)
{
+ struct device *dev = output->dev;
struct device_node *ddc, *panel;
- enum of_gpio_flags flags;
int err, size;
if (!output->of_node)
- output->of_node = output->dev->of_node;
+ output->of_node = dev->of_node;
panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
if (panel) {
@@ -222,41 +256,15 @@ int tegra_output_probe(struct tegra_output *output)
of_node_put(ddc);
}
- output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
- "nvidia,hpd-gpio", 0,
- &flags);
- if (gpio_is_valid(output->hpd_gpio)) {
- unsigned long flags;
-
- err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN,
- "HDMI hotplug detect");
- if (err < 0) {
- dev_err(output->dev, "gpio_request_one(): %d\n", err);
+ output->hpd_gpio = devm_gpiod_get_optional(dev, "nvidia,hpd");
+ if (IS_ERR(output->hpd_gpio)) {
+ err = PTR_ERR(output->hpd_gpio);
+ dev_err(dev, "failed to get hotplug detect GPIO: %d\n", err);
+ return err;
+ } else if (output->hpd_gpio) {
+ err = tegra_output_hpd_setup(output);
+ if (err < 0)
return err;
- }
-
- err = gpio_to_irq(output->hpd_gpio);
- if (err < 0) {
- dev_err(output->dev, "gpio_to_irq(): %d\n", err);
- gpio_free(output->hpd_gpio);
- return err;
- }
-
- output->hpd_irq = err;
-
- flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT;
-
- err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq,
- flags, "hpd", output);
- if (err < 0) {
- dev_err(output->dev, "failed to request IRQ#%u: %d\n",
- output->hpd_irq, err);
- gpio_free(output->hpd_gpio);
- return err;
- }
-
- output->connector.polled = DRM_CONNECTOR_POLL_HPD;
}
return 0;
@@ -264,10 +272,8 @@ int tegra_output_probe(struct tegra_output *output)
int tegra_output_remove(struct tegra_output *output)
{
- if (gpio_is_valid(output->hpd_gpio)) {
+ if (output->hpd_gpio)
free_irq(output->hpd_irq, output);
- gpio_free(output->hpd_gpio);
- }
if (output->ddc)
put_device(&output->ddc->dev);
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 7d66f6e5391..93ae4fac8ac 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -1007,12 +1007,13 @@ static const struct file_operations tegra_sor_crc_fops = {
.release = tegra_sor_crc_release,
};
-static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct dentry *root)
+static int tegra_sor_debugfs_init(struct tegra_sor *sor,
+ struct drm_minor *minor)
{
struct dentry *entry;
int err = 0;
- sor->debugfs = debugfs_create_dir("sor", root);
+ sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
if (!sor->debugfs)
return -ENOMEM;
@@ -1021,7 +1022,7 @@ static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct dentry *root)
if (!entry) {
dev_err(sor->dev,
"cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
- root->d_name.name);
+ minor->debugfs_root->d_name.name);
err = -ENOMEM;
goto remove;
}
@@ -1036,7 +1037,7 @@ remove:
static int tegra_sor_debugfs_exit(struct tegra_sor *sor)
{
- debugfs_remove(sor->debugfs);
+ debugfs_remove_recursive(sor->debugfs);
sor->debugfs = NULL;
return 0;
@@ -1044,7 +1045,7 @@ static int tegra_sor_debugfs_exit(struct tegra_sor *sor)
static int tegra_sor_init(struct host1x_client *client)
{
- struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+ struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_sor *sor = host1x_client_to_sor(client);
int err;
@@ -1056,16 +1057,14 @@ static int tegra_sor_init(struct host1x_client *client)
sor->output.dev = sor->dev;
sor->output.ops = &sor_ops;
- err = tegra_output_init(tegra->drm, &sor->output);
+ err = tegra_output_init(drm, &sor->output);
if (err < 0) {
dev_err(sor->dev, "output setup failed: %d\n", err);
return err;
}
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- struct dentry *root = tegra->drm->primary->debugfs_root;
-
- err = tegra_sor_debugfs_init(sor, root);
+ err = tegra_sor_debugfs_init(sor, drm->primary);
if (err < 0)
dev_err(sor->dev, "debugfs setup failed: %d\n", err);
}
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index ccdd2e6da5e..aaf54859adb 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -216,8 +216,8 @@ int host1x_device_exit(struct host1x_device *device)
}
EXPORT_SYMBOL(host1x_device_exit);
-static int host1x_register_client(struct host1x *host1x,
- struct host1x_client *client)
+static int host1x_add_client(struct host1x *host1x,
+ struct host1x_client *client)
{
struct host1x_device *device;
struct host1x_subdev *subdev;
@@ -238,8 +238,8 @@ static int host1x_register_client(struct host1x *host1x,
return -ENODEV;
}
-static int host1x_unregister_client(struct host1x *host1x,
- struct host1x_client *client)
+static int host1x_del_client(struct host1x *host1x,
+ struct host1x_client *client)
{
struct host1x_device *device, *dt;
struct host1x_subdev *subdev;
@@ -503,7 +503,7 @@ int host1x_client_register(struct host1x_client *client)
mutex_lock(&devices_lock);
list_for_each_entry(host1x, &devices, list) {
- err = host1x_register_client(host1x, client);
+ err = host1x_add_client(host1x, client);
if (!err) {
mutex_unlock(&devices_lock);
return 0;
@@ -529,7 +529,7 @@ int host1x_client_unregister(struct host1x_client *client)
mutex_lock(&devices_lock);
list_for_each_entry(host1x, &devices, list) {
- err = host1x_unregister_client(host1x, client);
+ err = host1x_del_client(host1x, client);
if (!err) {
mutex_unlock(&devices_lock);
return 0;
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index d37e31dda33..904f93bc70f 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1061,6 +1061,7 @@ struct drm_device {
struct drm_minor *render; /**< Render node */
atomic_t unplugged; /**< Flag whether dev is dead */
struct inode *anon_inode; /**< inode for private address-space */
+ char *unique; /**< unique name of the device */
/*@} */
/** \name Locks */
@@ -1625,6 +1626,7 @@ void drm_dev_ref(struct drm_device *dev);
void drm_dev_unref(struct drm_device *dev);
int drm_dev_register(struct drm_device *dev, unsigned long flags);
void drm_dev_unregister(struct drm_device *dev);
+int drm_dev_set_unique(struct drm_device *dev, const char *fmt, ...);
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 7209df15a3c..944f33f8ba3 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -135,11 +135,13 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel,
* @driver: device driver model driver
* @probe: callback for device binding
* @remove: callback for device unbinding
+ * @shutdown: called at shutdown time to quiesce the device
*/
struct mipi_dsi_driver {
struct device_driver driver;
int(*probe)(struct mipi_dsi_device *dsi);
int(*remove)(struct mipi_dsi_device *dsi);
+ void (*shutdown)(struct mipi_dsi_device *dsi);
};
#define to_mipi_dsi_driver(d) container_of(d, struct mipi_dsi_driver, driver)