summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma-buf/dma-buf.c44
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h3
-rw-r--r--drivers/gpu/drm/arc/arcpgu_drv.c8
-rw-r--r--drivers/gpu/drm/arm/Kconfig16
-rw-r--r--drivers/gpu/drm/arm/Makefile2
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c216
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c512
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h54
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c691
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h241
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c298
-rw-r--r--drivers/gpu/drm/arm/malidp_regs.h172
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c1
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c1
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c15
-rw-r--r--drivers/gpu/drm/bridge/Kconfig8
-rw-r--r--drivers/gpu/drm/bridge/Makefile1
-rw-r--r--drivers/gpu/drm/bridge/sii902x.c467
-rw-r--r--drivers/gpu/drm/drm_auth.c285
-rw-r--r--drivers/gpu/drm/drm_bufs.c8
-rw-r--r--drivers/gpu/drm/drm_crtc.c164
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c3
-rw-r--r--drivers/gpu/drm/drm_crtc_internal.h88
-rw-r--r--drivers/gpu/drm/drm_debugfs.c3
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c56
-rw-r--r--drivers/gpu/drm/drm_drv.c239
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c2
-rw-r--r--drivers/gpu/drm/drm_fops.c125
-rw-r--r--drivers/gpu/drm/drm_info.c117
-rw-r--r--drivers/gpu/drm/drm_internal.h21
-rw-r--r--drivers/gpu/drm/drm_ioctl.c124
-rw-r--r--drivers/gpu/drm/drm_irq.c4
-rw-r--r--drivers/gpu/drm/drm_legacy.h8
-rw-r--r--drivers/gpu/drm/drm_lock.c240
-rw-r--r--drivers/gpu/drm/drm_pci.c51
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c28
-rw-r--r--drivers/gpu/drm/drm_platform.c18
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c1
-rw-r--r--drivers/gpu/drm/drm_vm.c54
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c1
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c13
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c9
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h3
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c4
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c15
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c22
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c4
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h17
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c2
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c2
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c2
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c13
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c26
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c2
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c1
-rw-r--r--drivers/gpu/drm/mediatek/Kconfig1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c9
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_plane.c1
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c7
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c21
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c1
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_drv.c1
-rw-r--r--drivers/gpu/drm/sis/sis_mm.c2
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c20
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.h3
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c12
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c32
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c138
-rw-r--r--drivers/gpu/drm/sti/sti_drv.h1
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c25
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c32
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c26
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c40
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c32
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c5
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.h2
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c24
-rw-r--r--drivers/gpu/drm/sti/sti_plane.h7
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c36
-rw-r--r--drivers/gpu/drm/sti/sti_vid.c5
-rw-r--r--drivers/gpu/drm/sti/sti_vid.h2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c38
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c13
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c2
-rw-r--r--drivers/gpu/drm/via/via_mm.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drm_bus.c10
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.c1
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h1
100 files changed, 3951 insertions, 1157 deletions
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 6355ab3..20ce068 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -824,7 +824,7 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
EXPORT_SYMBOL_GPL(dma_buf_vunmap);
#ifdef CONFIG_DEBUG_FS
-static int dma_buf_describe(struct seq_file *s)
+static int dma_buf_debug_show(struct seq_file *s, void *unused)
{
int ret;
struct dma_buf *buf_obj;
@@ -879,17 +879,9 @@ static int dma_buf_describe(struct seq_file *s)
return 0;
}
-static int dma_buf_show(struct seq_file *s, void *unused)
-{
- void (*func)(struct seq_file *) = s->private;
-
- func(s);
- return 0;
-}
-
static int dma_buf_debug_open(struct inode *inode, struct file *file)
{
- return single_open(file, dma_buf_show, inode->i_private);
+ return single_open(file, dma_buf_debug_show, NULL);
}
static const struct file_operations dma_buf_debug_fops = {
@@ -903,20 +895,23 @@ static struct dentry *dma_buf_debugfs_dir;
static int dma_buf_init_debugfs(void)
{
+ struct dentry *d;
int err = 0;
- dma_buf_debugfs_dir = debugfs_create_dir("dma_buf", NULL);
-
- if (IS_ERR(dma_buf_debugfs_dir)) {
- err = PTR_ERR(dma_buf_debugfs_dir);
- dma_buf_debugfs_dir = NULL;
- return err;
- }
+ d = debugfs_create_dir("dma_buf", NULL);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
- err = dma_buf_debugfs_create_file("bufinfo", dma_buf_describe);
+ dma_buf_debugfs_dir = d;
- if (err)
+ d = debugfs_create_file("bufinfo", S_IRUGO, dma_buf_debugfs_dir,
+ NULL, &dma_buf_debug_fops);
+ if (IS_ERR(d)) {
pr_debug("dma_buf: debugfs: failed to create node bufinfo\n");
+ debugfs_remove_recursive(dma_buf_debugfs_dir);
+ dma_buf_debugfs_dir = NULL;
+ err = PTR_ERR(d);
+ }
return err;
}
@@ -926,17 +921,6 @@ static void dma_buf_uninit_debugfs(void)
if (dma_buf_debugfs_dir)
debugfs_remove_recursive(dma_buf_debugfs_dir);
}
-
-int dma_buf_debugfs_create_file(const char *name,
- int (*write)(struct seq_file *))
-{
- struct dentry *d;
-
- d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir,
- write, &dma_buf_debug_fops);
-
- return PTR_ERR_OR_ZERO(d);
-}
#else
static inline int dma_buf_init_debugfs(void)
{
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
index ec4036a..a625b91 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
@@ -187,12 +187,12 @@ int init_pipelines(struct device_queue_manager *dqm,
unsigned int get_first_pipe(struct device_queue_manager *dqm);
unsigned int get_pipes_num(struct device_queue_manager *dqm);
-extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
+static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
{
return (pdd->lds_base >> 16) & 0xFF;
}
-extern inline unsigned int
+static inline unsigned int
get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
{
return (pdd->lds_base >> 60) & 0x0E;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index d0d5f4b..80113c3 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -617,10 +617,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd);
int kfd_init_apertures(struct kfd_process *process);
/* Queue Context Management */
-inline uint32_t lower_32(uint64_t x);
-inline uint32_t upper_32(uint64_t x);
struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd);
-inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m);
int init_queue(struct queue **q, struct queue_properties properties);
void uninit_queue(struct queue *q);
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c
index 381c5fc..ccbdadb 100644
--- a/drivers/gpu/drm/arc/arcpgu_drv.c
+++ b/drivers/gpu/drm/arc/arcpgu_drv.c
@@ -211,15 +211,8 @@ static int arcpgu_probe(struct platform_device *pdev)
if (ret)
goto err_unload;
- ret = drm_connector_register_all(drm);
- if (ret)
- goto err_unregister;
-
return 0;
-err_unregister:
- drm_dev_unregister(drm);
-
err_unload:
arcpgu_unload(drm);
@@ -233,7 +226,6 @@ static int arcpgu_remove(struct platform_device *pdev)
{
struct drm_device *drm = platform_get_drvdata(pdev);
- drm_connector_unregister_all(drm);
drm_dev_unregister(drm);
arcpgu_unload(drm);
drm_dev_unref(drm);
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index eaed454..1b29065 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -25,3 +25,19 @@ config DRM_HDLCD_SHOW_UNDERRUN
Enable this option to show in red colour the pixels that the
HDLCD device did not fetch from framebuffer due to underrun
conditions.
+
+config DRM_MALI_DISPLAY
+ tristate "ARM Mali Display Processor"
+ depends on DRM && OF && (ARM || ARM64)
+ depends on COMMON_CLK
+ select DRM_ARM
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
+ select VIDEOMODE_HELPERS
+ help
+ Choose this option if you want to compile the ARM Mali Display
+ Processor driver. It supports the DP500, DP550 and DP650 variants
+ of the hardware.
+
+ If compiled as a module it will be called mali-dp.
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
index 89dcb7b..bb8b158 100644
--- a/drivers/gpu/drm/arm/Makefile
+++ b/drivers/gpu/drm/arm/Makefile
@@ -1,2 +1,4 @@
hdlcd-y := hdlcd_drv.o hdlcd_crtc.o
obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
+mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
+obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
new file mode 100644
index 0000000..08e6a71
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -0,0 +1,216 @@
+/*
+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP500/DP550/DP650 driver (crtc operations)
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/clk.h>
+#include <video/videomode.h>
+
+#include "malidp_drv.h"
+#include "malidp_hw.h"
+
+static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ /*
+ * check that the hardware can drive the required clock rate,
+ * but skip the check if the clock is meant to be disabled (req_rate = 0)
+ */
+ long rate, req_rate = mode->crtc_clock * 1000;
+
+ if (req_rate) {
+ rate = clk_round_rate(hwdev->mclk, req_rate);
+ if (rate < req_rate) {
+ DRM_DEBUG_DRIVER("mclk clock unable to reach %d kHz\n",
+ mode->crtc_clock);
+ return false;
+ }
+
+ rate = clk_round_rate(hwdev->pxlclk, req_rate);
+ if (rate != req_rate) {
+ DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n",
+ req_rate);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void malidp_crtc_enable(struct drm_crtc *crtc)
+{
+ struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
+ struct malidp_hw_device *hwdev = malidp->dev;
+ struct videomode vm;
+
+ drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm);
+
+ clk_prepare_enable(hwdev->pxlclk);
+
+ /* mclk needs to be set to the same or higher rate than pxlclk */
+ clk_set_rate(hwdev->mclk, crtc->state->adjusted_mode.crtc_clock * 1000);
+ clk_set_rate(hwdev->pxlclk, crtc->state->adjusted_mode.crtc_clock * 1000);
+
+ hwdev->modeset(hwdev, &vm);
+ hwdev->leave_config_mode(hwdev);
+ drm_crtc_vblank_on(crtc);
+}
+
+static void malidp_crtc_disable(struct drm_crtc *crtc)
+{
+ struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ drm_crtc_vblank_off(crtc);
+ hwdev->enter_config_mode(hwdev);
+ clk_disable_unprepare(hwdev->pxlclk);
+}
+
+static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
+ struct malidp_hw_device *hwdev = malidp->dev;
+ struct drm_plane *plane;
+ const struct drm_plane_state *pstate;
+ u32 rot_mem_free, rot_mem_usable;
+ int rotated_planes = 0;
+
+ /*
+ * check if there is enough rotation memory available for planes
+ * that need 90° and 270° rotation. Each plane has set its required
+ * memory size in the ->plane_check() callback, here we only make
+ * sure that the sums are less that the total usable memory.
+ *
+ * The rotation memory allocation algorithm (for each plane):
+ * a. If no more rotated planes exist, all remaining rotate
+ * memory in the bank is available for use by the plane.
+ * b. If other rotated planes exist, and plane's layer ID is
+ * DE_VIDEO1, it can use all the memory from first bank if
+ * secondary rotation memory bank is available, otherwise it can
+ * use up to half the bank's memory.
+ * c. If other rotated planes exist, and plane's layer ID is not
+ * DE_VIDEO1, it can use half of the available memory
+ *
+ * Note: this algorithm assumes that the order in which the planes are
+ * checked always has DE_VIDEO1 plane first in the list if it is
+ * rotated. Because that is how we create the planes in the first
+ * place, under current DRM version things work, but if ever the order
+ * in which drm_atomic_crtc_state_for_each_plane() iterates over planes
+ * changes, we need to pre-sort the planes before validation.
+ */
+
+ /* first count the number of rotated planes */
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+ if (pstate->rotation & MALIDP_ROTATED_MASK)
+ rotated_planes++;
+ }
+
+ rot_mem_free = hwdev->rotation_memory[0];
+ /*
+ * if we have more than 1 plane using rotation memory, use the second
+ * block of rotation memory as well
+ */
+ if (rotated_planes > 1)
+ rot_mem_free += hwdev->rotation_memory[1];
+
+ /* now validate the rotation memory requirements */
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
+ struct malidp_plane *mp = to_malidp_plane(plane);
+ struct malidp_plane_state *ms = to_malidp_plane_state(pstate);
+
+ if (pstate->rotation & MALIDP_ROTATED_MASK) {
+ /* process current plane */
+ rotated_planes--;
+
+ if (!rotated_planes) {
+ /* no more rotated planes, we can use what's left */
+ rot_mem_usable = rot_mem_free;
+ } else {
+ if ((mp->layer->id != DE_VIDEO1) ||
+ (hwdev->rotation_memory[1] == 0))
+ rot_mem_usable = rot_mem_free / 2;
+ else
+ rot_mem_usable = hwdev->rotation_memory[0];
+ }
+
+ rot_mem_free -= rot_mem_usable;
+
+ if (ms->rotmem_size > rot_mem_usable)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
+ .mode_fixup = malidp_crtc_mode_fixup,
+ .enable = malidp_crtc_enable,
+ .disable = malidp_crtc_disable,
+ .atomic_check = malidp_crtc_atomic_check,
+};
+
+static const struct drm_crtc_funcs malidp_crtc_funcs = {
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+int malidp_crtc_init(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct drm_plane *primary = NULL, *plane;
+ int ret;
+
+ ret = malidp_de_planes_init(drm);
+ if (ret < 0) {
+ DRM_ERROR("Failed to initialise planes\n");
+ return ret;
+ }
+
+ drm_for_each_plane(plane, drm) {
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+ primary = plane;
+ break;
+ }
+ }
+
+ if (!primary) {
+ DRM_ERROR("no primary plane found\n");
+ ret = -EINVAL;
+ goto crtc_cleanup_planes;
+ }
+
+ ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL,
+ &malidp_crtc_funcs, NULL);
+
+ if (!ret) {
+ drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs);
+ return 0;
+ }
+
+crtc_cleanup_planes:
+ malidp_de_planes_destroy(drm);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
new file mode 100644
index 0000000..e5b44e9
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -0,0 +1,512 @@
+/*
+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP500/DP550/DP650 KMS/DRM driver
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+
+#include "malidp_drv.h"
+#include "malidp_regs.h"
+#include "malidp_hw.h"
+
+#define MALIDP_CONF_VALID_TIMEOUT 250
+
+/*
+ * set the "config valid" bit and wait until the hardware acts on it
+ */
+static int malidp_set_and_wait_config_valid(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+ int ret;
+
+ hwdev->set_config_valid(hwdev);
+ /* don't wait for config_valid flag if we are in config mode */
+ if (hwdev->in_config_mode(hwdev))
+ return 0;
+
+ ret = wait_event_interruptible_timeout(malidp->wq,
+ atomic_read(&malidp->config_valid) == 1,
+ msecs_to_jiffies(MALIDP_CONF_VALID_TIMEOUT));
+
+ return (ret > 0) ? 0 : -ETIMEDOUT;
+}
+
+static void malidp_output_poll_changed(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+
+ drm_fbdev_cma_hotplug_event(malidp->fbdev);
+}
+
+static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
+{
+ struct drm_pending_vblank_event *event;
+ struct drm_device *drm = state->dev;
+ struct malidp_drm *malidp = drm->dev_private;
+ int ret = malidp_set_and_wait_config_valid(drm);
+
+ if (ret)
+ DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n");
+
+ event = malidp->crtc.state->event;
+ if (event) {
+ malidp->crtc.state->event = NULL;
+
+ spin_lock_irq(&drm->event_lock);
+ if (drm_crtc_vblank_get(&malidp->crtc) == 0)
+ drm_crtc_arm_vblank_event(&malidp->crtc, event);
+ else
+ drm_crtc_send_vblank_event(&malidp->crtc, event);
+ spin_unlock_irq(&drm->event_lock);
+ }
+ drm_atomic_helper_commit_hw_done(state);
+}
+
+static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct drm_device *drm = state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(drm, state);
+ drm_atomic_helper_commit_modeset_enables(drm, state);
+ drm_atomic_helper_commit_planes(drm, state, true);
+
+ malidp_atomic_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(drm, state);
+
+ drm_atomic_helper_cleanup_planes(drm, state);
+}
+
+static struct drm_mode_config_helper_funcs malidp_mode_config_helpers = {
+ .atomic_commit_tail = malidp_atomic_commit_tail,
+};
+
+static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = malidp_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static int malidp_enable_vblank(struct drm_device *drm, unsigned int crtc)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
+ hwdev->map.de_irq_map.vsync_irq);
+ return 0;
+}
+
+static void malidp_disable_vblank(struct drm_device *drm, unsigned int pipe)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
+ hwdev->map.de_irq_map.vsync_irq);
+}
+
+static int malidp_init(struct drm_device *drm)
+{
+ int ret;
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ drm_mode_config_init(drm);
+
+ drm->mode_config.min_width = hwdev->min_line_size;
+ drm->mode_config.min_height = hwdev->min_line_size;
+ drm->mode_config.max_width = hwdev->max_line_size;
+ drm->mode_config.max_height = hwdev->max_line_size;
+ drm->mode_config.funcs = &malidp_mode_config_funcs;
+ drm->mode_config.helper_private = &malidp_mode_config_helpers;
+
+ ret = malidp_crtc_init(drm);
+ if (ret) {
+ drm_mode_config_cleanup(drm);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int malidp_irq_init(struct platform_device *pdev)
+{
+ int irq_de, irq_se, ret = 0;
+ struct drm_device *drm = dev_get_drvdata(&pdev->dev);
+
+ /* fetch the interrupts from DT */
+ irq_de = platform_get_irq_byname(pdev, "DE");
+ if (irq_de < 0) {
+ DRM_ERROR("no 'DE' IRQ specified!\n");
+ return irq_de;
+ }
+ irq_se = platform_get_irq_byname(pdev, "SE");
+ if (irq_se < 0) {
+ DRM_ERROR("no 'SE' IRQ specified!\n");
+ return irq_se;
+ }
+
+ ret = malidp_de_irq_init(drm, irq_de);
+ if (ret)
+ return ret;
+
+ ret = malidp_se_irq_init(drm, irq_se);
+ if (ret) {
+ malidp_de_irq_fini(drm);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void malidp_lastclose(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+
+ drm_fbdev_cma_restore_mode(malidp->fbdev);
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = noop_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver malidp_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
+ DRIVER_PRIME,
+ .lastclose = malidp_lastclose,
+ .get_vblank_counter = drm_vblank_no_hw_counter,
+ .enable_vblank = malidp_enable_vblank,
+ .disable_vblank = malidp_disable_vblank,
+ .gem_free_object_unlocked = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = drm_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_dumb_destroy,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .fops = &fops,
+ .name = "mali-dp",
+ .desc = "ARM Mali Display Processor driver",
+ .date = "20160106",
+ .major = 1,
+ .minor = 0,
+};
+
+static const struct of_device_id malidp_drm_of_match[] = {
+ {
+ .compatible = "arm,mali-dp500",
+ .data = &malidp_device[MALIDP_500]
+ },
+ {
+ .compatible = "arm,mali-dp550",
+ .data = &malidp_device[MALIDP_550]
+ },
+ {
+ .compatible = "arm,mali-dp650",
+ .data = &malidp_device[MALIDP_650]
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, malidp_drm_of_match);
+
+#define MAX_OUTPUT_CHANNELS 3
+
+static int malidp_bind(struct device *dev)
+{
+ struct resource *res;
+ struct drm_device *drm;
+ struct malidp_drm *malidp;
+ struct malidp_hw_device *hwdev;
+ struct platform_device *pdev = to_platform_device(dev);
+ /* number of lines for the R, G and B output */
+ u8 output_width[MAX_OUTPUT_CHANNELS];
+ int ret = 0, i;
+ u32 version, out_depth = 0;
+
+ malidp = devm_kzalloc(dev, sizeof(*malidp), GFP_KERNEL);
+ if (!malidp)
+ return -ENOMEM;
+
+ hwdev = devm_kzalloc(dev, sizeof(*hwdev), GFP_KERNEL);
+ if (!hwdev)
+ return -ENOMEM;
+
+ /*
+ * copy the associated data from malidp_drm_of_match to avoid
+ * having to keep a reference to the OF node after binding
+ */
+ memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev));
+ malidp->dev = hwdev;
+
+ INIT_LIST_HEAD(&malidp->event_list);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hwdev->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hwdev->regs)) {
+ DRM_ERROR("Failed to map control registers area\n");
+ return PTR_ERR(hwdev->regs);
+ }
+
+ hwdev->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(hwdev->pclk))
+ return PTR_ERR(hwdev->pclk);
+
+ hwdev->aclk = devm_clk_get(dev, "aclk");
+ if (IS_ERR(hwdev->aclk))
+ return PTR_ERR(hwdev->aclk);
+
+ hwdev->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(hwdev->mclk))
+ return PTR_ERR(hwdev->mclk);
+
+ hwdev->pxlclk = devm_clk_get(dev, "pxlclk");
+ if (IS_ERR(hwdev->pxlclk))
+ return PTR_ERR(hwdev->pxlclk);
+
+ /* Get the optional framebuffer memory resource */
+ ret = of_reserved_mem_device_init(dev);
+ if (ret && ret != -ENODEV)
+ return ret;
+
+ drm = drm_dev_alloc(&malidp_driver, dev);
+ if (!drm) {
+ ret = -ENOMEM;
+ goto alloc_fail;
+ }
+
+ /* Enable APB clock in order to get access to the registers */
+ clk_prepare_enable(hwdev->pclk);
+ /*
+ * Enable AXI clock and main clock so that prefetch can start once
+ * the registers are set
+ */
+ clk_prepare_enable(hwdev->aclk);
+ clk_prepare_enable(hwdev->mclk);
+
+ ret = hwdev->query_hw(hwdev);
+ if (ret) {
+ DRM_ERROR("Invalid HW configuration\n");
+ goto query_hw_fail;
+ }
+
+ version = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_DE_CORE_ID);
+ DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16,
+ (version >> 12) & 0xf, (version >> 8) & 0xf);
+
+ /* set the number of lines used for output of RGB data */
+ ret = of_property_read_u8_array(dev->of_node,
+ "arm,malidp-output-port-lines",
+ output_width, MAX_OUTPUT_CHANNELS);
+ if (ret)
+ goto query_hw_fail;
+
+ for (i = 0; i < MAX_OUTPUT_CHANNELS; i++)
+ out_depth = (out_depth << 8) | (output_width[i] & 0xf);
+ malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base);
+
+ drm->dev_private = malidp;
+ dev_set_drvdata(dev, drm);
+ atomic_set(&malidp->config_valid, 0);
+ init_waitqueue_head(&malidp->wq);
+
+ ret = malidp_init(drm);
+ if (ret < 0)
+ goto init_fail;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ goto register_fail;
+
+ /* Set the CRTC's port so that the encoder component can find it */
+ malidp->crtc.port = of_graph_get_next_endpoint(dev->of_node, NULL);
+
+ ret = component_bind_all(dev, drm);
+ of_node_put(malidp->crtc.port);
+
+ if (ret) {
+ DRM_ERROR("Failed to bind all components\n");
+ goto bind_fail;
+ }
+
+ ret = malidp_irq_init(pdev);
+ if (ret < 0)
+ goto irq_init_fail;
+
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (ret < 0) {
+ DRM_ERROR("failed to initialise vblank\n");
+ goto vblank_fail;
+ }
+
+ drm_mode_config_reset(drm);
+
+ malidp->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
+ drm->mode_config.num_connector);
+
+ if (IS_ERR(malidp->fbdev)) {
+ ret = PTR_ERR(malidp->fbdev);
+ malidp->fbdev = NULL;
+ goto fbdev_fail;
+ }
+
+ drm_kms_helper_poll_init(drm);
+ return 0;
+
+fbdev_fail:
+ drm_vblank_cleanup(drm);
+vblank_fail:
+ malidp_se_irq_fini(drm);
+ malidp_de_irq_fini(drm);
+irq_init_fail:
+ component_unbind_all(dev, drm);
+bind_fail:
+ drm_dev_unregister(drm);
+register_fail:
+ malidp_de_planes_destroy(drm);
+ drm_mode_config_cleanup(drm);
+init_fail:
+ drm->dev_private = NULL;
+ dev_set_drvdata(dev, NULL);
+query_hw_fail:
+ clk_disable_unprepare(hwdev->mclk);
+ clk_disable_unprepare(hwdev->aclk);
+ clk_disable_unprepare(hwdev->pclk);
+ drm_dev_unref(drm);
+alloc_fail:
+ of_reserved_mem_device_release(dev);
+
+ return ret;
+}
+
+static void malidp_unbind(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ if (malidp->fbdev) {
+ drm_fbdev_cma_fini(malidp->fbdev);
+ malidp->fbdev = NULL;
+ }
+ drm_kms_helper_poll_fini(drm);
+ malidp_se_irq_fini(drm);
+ malidp_de_irq_fini(drm);
+ drm_vblank_cleanup(drm);
+ component_unbind_all(dev, drm);
+ drm_dev_unregister(drm);
+ malidp_de_planes_destroy(drm);
+ drm_mode_config_cleanup(drm);
+ drm->dev_private = NULL;
+ dev_set_drvdata(dev, NULL);
+ clk_disable_unprepare(hwdev->mclk);
+ clk_disable_unprepare(hwdev->aclk);
+ clk_disable_unprepare(hwdev->pclk);
+ drm_dev_unref(drm);
+ of_reserved_mem_device_release(dev);
+}
+
+static const struct component_master_ops malidp_master_ops = {
+ .bind = malidp_bind,
+ .unbind = malidp_unbind,
+};
+
+static int malidp_compare_dev(struct device *dev, void *data)
+{
+ struct device_node *np = data;
+
+ return dev->of_node == np;
+}
+
+static int malidp_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *port, *ep;
+ struct component_match *match = NULL;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ /* there is only one output port inside each device, find it */
+ ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
+ if (!ep)
+ return -ENODEV;
+
+ if (!of_device_is_available(ep)) {
+ of_node_put(ep);
+ return -ENODEV;
+ }
+
+ /* add the remote encoder port as component */
+ port = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (!port || !of_device_is_available(port)) {
+ of_node_put(port);
+ return -EAGAIN;
+ }
+
+ component_match_add(&pdev->dev, &match, malidp_compare_dev, port);
+ return component_master_add_with_match(&pdev->dev, &malidp_master_ops,
+ match);
+}
+
+static int malidp_platform_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &malidp_master_ops);
+ return 0;
+}
+
+static struct platform_driver malidp_platform_driver = {
+ .probe = malidp_platform_probe,
+ .remove = malidp_platform_remove,
+ .driver = {
+ .name = "mali-dp",
+ .of_match_table = malidp_drm_of_match,
+ },
+};
+
+module_platform_driver(malidp_platform_driver);
+
+MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>");
+MODULE_DESCRIPTION("ARM Mali DP DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
new file mode 100644
index 0000000..95558fd
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -0,0 +1,54 @@
+/*
+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP500/DP550/DP650 KMS/DRM driver structures
+ */
+
+#ifndef __MALIDP_DRV_H__
+#define __MALIDP_DRV_H__
+
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include "malidp_hw.h"
+
+struct malidp_drm {
+ struct malidp_hw_device *dev;
+ struct drm_fbdev_cma *fbdev;
+ struct list_head event_list;
+ struct drm_crtc crtc;
+ wait_queue_head_t wq;
+ atomic_t config_valid;
+};
+
+#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc)
+
+struct malidp_plane {
+ struct drm_plane base;
+ struct malidp_hw_device *hwdev;
+ const struct malidp_layer *layer;
+};
+
+struct malidp_plane_state {
+ struct drm_plane_state base;
+
+ /* size of the required rotation memory if plane is rotated */
+ u32 rotmem_size;
+};
+
+#define to_malidp_plane(x) container_of(x, struct malidp_plane, base)
+#define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base)
+
+int malidp_de_planes_init(struct drm_device *drm);
+void malidp_de_planes_destroy(struct drm_device *drm);
+int malidp_crtc_init(struct drm_device *drm);
+
+/* often used combination of rotational bits */
+#define MALIDP_ROTATED_MASK (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))
+
+#endif /* __MALIDP_DRV_H__ */
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
new file mode 100644
index 0000000..a6132f1
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -0,0 +1,691 @@
+/*
+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
+ * the difference between various versions of the hardware is being dealt with
+ * in an attempt to provide to the rest of the driver code a unified view
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <drm/drmP.h>
+#include <video/videomode.h>
+#include <video/display_timing.h>
+
+#include "malidp_drv.h"
+#include "malidp_hw.h"
+
+static const struct malidp_input_format malidp500_de_formats[] = {
+ /* fourcc, layers supporting the format, internal id */
+ { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 },
+ { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 },
+ { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 },
+ { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 },
+ { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 4 },
+ { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 5 },
+ { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 },
+ { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 },
+ { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 },
+ { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 },
+ { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
+ { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
+ { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
+ { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
+ { DRM_FORMAT_NV12, DE_VIDEO1, 14 },
+ { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
+};
+
+#define MALIDP_ID(__group, __format) \
+ ((((__group) & 0x7) << 3) | ((__format) & 0x7))
+
+#define MALIDP_COMMON_FORMATS \
+ /* fourcc, layers supporting the format, internal id */ \
+ { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
+ { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
+ { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
+ { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
+ { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
+ { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
+ { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
+ { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
+ { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
+ { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
+ { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
+ { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
+ { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
+ { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
+ { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
+ { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
+ { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
+ { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
+ { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \
+ { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \
+ { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
+ { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
+
+static const struct malidp_input_format malidp550_de_formats[] = {
+ MALIDP_COMMON_FORMATS,
+};
+
+static const struct malidp_layer malidp500_layers[] = {
+ { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE },
+ { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE },
+ { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE },
+};
+
+static const struct malidp_layer malidp550_layers[] = {
+ { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE },
+ { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE },
+ { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE },
+ { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE },
+};
+
+#define MALIDP_DE_DEFAULT_PREFETCH_START 5
+
+static int malidp500_query_hw(struct malidp_hw_device *hwdev)
+{
+ u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
+ /* bit 4 of the CONFIG_ID register holds the line size multiplier */
+ u8 ln_size_mult = conf & 0x10 ? 2 : 1;
+
+ hwdev->min_line_size = 2;
+ hwdev->max_line_size = SZ_2K * ln_size_mult;
+ hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
+ hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
+
+ return 0;
+}
+
+static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
+{
+ u32 status, count = 100;
+
+ malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
+ while (count) {
+ status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
+ break;
+ /*
+ * entering config mode can take as long as the rendering
+ * of a full frame, hence the long sleep here
+ */
+ usleep_range(1000, 10000);
+ count--;
+ }
+ WARN(count == 0, "timeout while entering config mode");
+}
+
+static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
+{
+ u32 status, count = 100;
+
+ malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
+ while (count) {
+ status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
+ break;
+ usleep_range(100, 1000);
+ count--;
+ }
+ WARN(count == 0, "timeout while leaving config mode");
+}
+
+static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
+{
+ u32 status;
+
+ status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
+ return true;
+
+ return false;
+}
+
+static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
+{
+ malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
+}
+
+static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
+{
+ u32 val = 0;
+
+ malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
+ if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ val |= MALIDP500_HSYNCPOL;
+ if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ val |= MALIDP500_VSYNCPOL;
+ val |= MALIDP_DE_DEFAULT_PREFETCH_START;
+ malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
+
+ /*
+ * Mali-DP500 encodes the background color like this:
+ * - red @ MALIDP500_BGND_COLOR[12:0]
+ * - green @ MALIDP500_BGND_COLOR[27:16]
+ * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0]
+ */
+ val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
+ (MALIDP_BGND_COLOR_R & 0xfff);
+ malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
+ malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
+
+ val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
+ MALIDP_DE_H_BACKPORCH(mode->hback_porch);
+ malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
+
+ val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
+ MALIDP_DE_V_BACKPORCH(mode->vback_porch);
+ malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
+
+ val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
+ MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
+ malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
+
+ val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
+ malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
+
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED)
+ malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
+ else
+ malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
+}
+
+static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
+{
+ unsigned int depth;
+ int bpp;
+
+ /* RGB888 or BGR888 can't be rotated */
+ if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
+ return -EINVAL;
+
+ /*
+ * Each layer needs enough rotation memory to fit 8 lines
+ * worth of pixel data. Required size is then:
+ * size = rotated_width * (bpp / 8) * 8;
+ */
+ drm_fb_get_bpp_depth(fmt, &depth, &bpp);
+
+ return w * bpp;
+}
+
+static int malidp550_query_hw(struct malidp_hw_device *hwdev)
+{
+ u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
+ u8 ln_size = (conf >> 4) & 0x3, rsize;
+
+ hwdev->min_line_size = 2;
+
+ switch (ln_size) {
+ case 0:
+ hwdev->max_line_size = SZ_2K;
+ /* two banks of 64KB for rotation memory */
+ rsize = 64;
+ break;
+ case 1:
+ hwdev->max_line_size = SZ_4K;
+ /* two banks of 128KB for rotation memory */
+ rsize = 128;
+ break;
+ case 2:
+ hwdev->max_line_size = 1280;
+ /* two banks of 40KB for rotation memory */
+ rsize = 40;
+ break;
+ case 3:
+ /* reserved value */
+ hwdev->max_line_size = 0;
+ return -EINVAL;
+ }
+
+ hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
+ return 0;
+}
+
+static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
+{
+ u32 status, count = 100;
+
+ malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
+ while (count) {
+ status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
+ break;
+ /*
+ * entering config mode can take as long as the rendering
+ * of a full frame, hence the long sleep here
+ */
+ usleep_range(1000, 10000);
+ count--;
+ }
+ WARN(count == 0, "timeout while entering config mode");
+}
+
+static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
+{
+ u32 status, count = 100;
+
+ malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
+ while (count) {
+ status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
+ break;
+ usleep_range(100, 1000);
+ count--;
+ }
+ WARN(count == 0, "timeout while leaving config mode");
+}
+
+static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
+{
+ u32 status;
+
+ status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
+ return true;
+
+ return false;
+}
+
+static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
+{
+ malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
+}
+
+static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
+{
+ u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
+
+ malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
+ /*
+ * Mali-DP550 and Mali-DP650 encode the background color like this:
+ * - red @ MALIDP550_DE_BGND_COLOR[23:16]
+ * - green @ MALIDP550_DE_BGND_COLOR[15:8]
+ * - blue @ MALIDP550_DE_BGND_COLOR[7:0]
+ *
+ * We need to truncate the least significant 4 bits from the default
+ * MALIDP_BGND_COLOR_x values
+ */
+ val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
+ (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
+ ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
+ malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
+
+ val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
+ MALIDP_DE_H_BACKPORCH(mode->hback_porch);
+ malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
+
+ val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
+ MALIDP_DE_V_BACKPORCH(mode->vback_porch);
+ malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
+
+ val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
+ MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
+ if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ val |= MALIDP550_HSYNCPOL;
+ if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ val |= MALIDP550_VSYNCPOL;
+ malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
+
+ val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
+ malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
+
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED)
+ malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
+ else
+ malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
+}
+
+static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
+{
+ u32 bytes_per_col;
+
+ /* raw RGB888 or BGR888 can't be rotated */
+ if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
+ return -EINVAL;
+
+ switch (fmt) {
+ /* 8 lines at 4 bytes per pixel */
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_BGRA1010102:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ /* 16 lines at 2 bytes per pixel */
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_YUYV:
+ bytes_per_col = 32;
+ break;
+ /* 16 lines at 1.5 bytes per pixel */
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_YUV420:
+ bytes_per_col = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return w * bytes_per_col;
+}
+
+static int malidp650_query_hw(struct malidp_hw_device *hwdev)
+{
+ u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
+ u8 ln_size = (conf >> 4) & 0x3, rsize;
+
+ hwdev->min_line_size = 4;
+
+ switch (ln_size) {
+ case 0:
+ case 2:
+ /* reserved values */
+ hwdev->max_line_size = 0;
+ return -EINVAL;
+ case 1:
+ hwdev->max_line_size = SZ_4K;
+ /* two banks of 128KB for rotation memory */
+ rsize = 128;
+ break;
+ case 3:
+ hwdev->max_line_size = 2560;
+ /* two banks of 80KB for rotation memory */
+ rsize = 80;
+ }
+
+ hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
+ return 0;
+}
+
+const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
+ [MALIDP_500] = {
+ .map = {
+ .se_base = MALIDP500_SE_BASE,
+ .dc_base = MALIDP500_DC_BASE,
+ .out_depth_base = MALIDP500_OUTPUT_DEPTH,
+ .features = 0, /* no CLEARIRQ register */
+ .n_layers = ARRAY_SIZE(malidp500_layers),
+ .layers = malidp500_layers,
+ .de_irq_map = {
+ .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
+ MALIDP500_DE_IRQ_AXI_ERR |
+ MALIDP500_DE_IRQ_VSYNC |
+ MALIDP500_DE_IRQ_GLOBAL,
+ .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
+ },
+ .se_irq_map = {
+ .irq_mask = MALIDP500_SE_IRQ_CONF_MODE,
+ .vsync_irq = 0,
+ },
+ .dc_irq_map = {
+ .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
+ .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
+ },
+ .input_formats = malidp500_de_formats,
+ .n_input_formats = ARRAY_SIZE(malidp500_de_formats),
+ },
+ .query_hw = malidp500_query_hw,
+ .enter_config_mode = malidp500_enter_config_mode,
+ .leave_config_mode = malidp500_leave_config_mode,
+ .in_config_mode = malidp500_in_config_mode,
+ .set_config_valid = malidp500_set_config_valid,
+ .modeset = malidp500_modeset,
+ .rotmem_required = malidp500_rotmem_required,
+ },
+ [MALIDP_550] = {
+ .map = {
+ .se_base = MALIDP550_SE_BASE,
+ .dc_base = MALIDP550_DC_BASE,
+ .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
+ .features = MALIDP_REGMAP_HAS_CLEARIRQ,
+ .n_layers = ARRAY_SIZE(malidp550_layers),
+ .layers = malidp550_layers,
+ .de_irq_map = {
+ .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
+ MALIDP550_DE_IRQ_VSYNC,
+ .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
+ },
+ .se_irq_map = {
+ .irq_mask = MALIDP550_SE_IRQ_EOW |
+ MALIDP550_SE_IRQ_AXI_ERR,
+ },
+ .dc_irq_map = {
+ .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
+ .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
+ },
+ .input_formats = malidp550_de_formats,
+ .n_input_formats = ARRAY_SIZE(malidp550_de_formats),
+ },
+ .query_hw = malidp550_query_hw,
+ .enter_config_mode = malidp550_enter_config_mode,
+ .leave_config_mode = malidp550_leave_config_mode,
+ .in_config_mode = malidp550_in_config_mode,
+ .set_config_valid = malidp550_set_config_valid,
+ .modeset = malidp550_modeset,
+ .rotmem_required = malidp550_rotmem_required,
+ },
+ [MALIDP_650] = {
+ .map = {
+ .se_base = MALIDP550_SE_BASE,
+ .dc_base = MALIDP550_DC_BASE,
+ .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
+ .features = MALIDP_REGMAP_HAS_CLEARIRQ,
+ .n_layers = ARRAY_SIZE(malidp550_layers),
+ .layers = malidp550_layers,
+ .de_irq_map = {
+ .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
+ MALIDP650_DE_IRQ_DRIFT |
+ MALIDP550_DE_IRQ_VSYNC,
+ .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
+ },
+ .se_irq_map = {
+ .irq_mask = MALIDP550_SE_IRQ_EOW |
+ MALIDP550_SE_IRQ_AXI_ERR,
+ },
+ .dc_irq_map = {
+ .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
+ .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
+ },
+ .input_formats = malidp550_de_formats,
+ .n_input_formats = ARRAY_SIZE(malidp550_de_formats),
+ },
+ .query_hw = malidp650_query_hw,
+ .enter_config_mode = malidp550_enter_config_mode,
+ .leave_config_mode = malidp550_leave_config_mode,
+ .in_config_mode = malidp550_in_config_mode,
+ .set_config_valid = malidp550_set_config_valid,
+ .modeset = malidp550_modeset,
+ .rotmem_required = malidp550_rotmem_required,
+ },
+};
+
+u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
+ u8 layer_id, u32 format)
+{
+ unsigned int i;
+
+ for (i = 0; i < map->n_input_formats; i++) {
+ if (((map->input_formats[i].layer & layer_id) == layer_id) &&
+ (map->input_formats[i].format == format))
+ return map->input_formats[i].id;
+ }
+
+ return MALIDP_INVALID_FORMAT_ID;
+}
+
+static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
+{
+ u32 base = malidp_get_block_base(hwdev, block);
+
+ if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
+ malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
+ else
+ malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
+}
+
+static irqreturn_t malidp_de_irq(int irq, void *arg)
+{
+ struct drm_device *drm = arg;
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev;
+ const struct malidp_irq_map *de;
+ u32 status, mask, dc_status;
+ irqreturn_t ret = IRQ_NONE;
+
+ if (!drm->dev_private)
+ return IRQ_HANDLED;
+
+ hwdev = malidp->dev;
+ de = &hwdev->map.de_irq_map;
+
+ /* first handle the config valid IRQ */
+ dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
+ if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
+ /* we have a page flip event */
+ atomic_set(&malidp->config_valid, 1);
+ malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
+ if (!(status & de->irq_mask))
+ return ret;
+
+ mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
+ status &= mask;
+ if (status & de->vsync_irq)
+ drm_crtc_handle_vblank(&malidp->crtc);
+
+ malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
+
+ return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
+}
+
+static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
+{
+ struct drm_device *drm = arg;
+ struct malidp_drm *malidp = drm->dev_private;
+
+ wake_up(&malidp->wq);
+
+ return IRQ_HANDLED;
+}
+
+int malidp_de_irq_init(struct drm_device *drm, int irq)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+ int ret;
+
+ /* ensure interrupts are disabled */
+ malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
+ malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
+ malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
+ malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
+
+ ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
+ malidp_de_irq_thread_handler,
+ IRQF_SHARED, "malidp-de", drm);
+ if (ret < 0) {
+ DRM_ERROR("failed to install DE IRQ handler\n");
+ return ret;
+ }
+
+ /* first enable the DC block IRQs */
+ malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
+ hwdev->map.dc_irq_map.irq_mask);
+
+ /* now enable the DE block IRQs */
+ malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
+ hwdev->map.de_irq_map.irq_mask);
+
+ return 0;
+}
+
+void malidp_de_irq_fini(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
+ hwdev->map.de_irq_map.irq_mask);
+ malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
+ hwdev->map.dc_irq_map.irq_mask);
+}
+
+static irqreturn_t malidp_se_irq(int irq, void *arg)
+{
+ struct drm_device *drm = arg;
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+ u32 status, mask;
+
+ status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
+ if (!(status & hwdev->map.se_irq_map.irq_mask))
+ return IRQ_NONE;
+
+ mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
+ status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
+ status &= mask;
+ /* ToDo: status decoding and firing up of VSYNC and page flip events */
+
+ malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
+{
+ return IRQ_HANDLED;
+}
+
+int malidp_se_irq_init(struct drm_device *drm, int irq)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+ int ret;
+
+ /* ensure interrupts are disabled */
+ malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
+ malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
+
+ ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
+ malidp_se_irq_thread_handler,
+ IRQF_SHARED, "malidp-se", drm);
+ if (ret < 0) {
+ DRM_ERROR("failed to install SE IRQ handler\n");
+ return ret;
+ }
+
+ malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
+ hwdev->map.se_irq_map.irq_mask);
+
+ return 0;
+}
+
+void malidp_se_irq_fini(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ struct malidp_hw_device *hwdev = malidp->dev;
+
+ malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
+ hwdev->map.se_irq_map.irq_mask);
+}
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
new file mode 100644
index 0000000..141743e
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -0,0 +1,241 @@
+/*
+ *
+ * (C) COPYRIGHT 2013-2016 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP hardware manipulation routines.
+ */
+
+#ifndef __MALIDP_HW_H__
+#define __MALIDP_HW_H__
+
+#include <linux/bitops.h>
+#include "malidp_regs.h"
+
+struct videomode;
+struct clk;
+
+/* Mali DP IP blocks */
+enum {
+ MALIDP_DE_BLOCK = 0,
+ MALIDP_SE_BLOCK,
+ MALIDP_DC_BLOCK
+};
+
+/* Mali DP layer IDs */
+enum {
+ DE_VIDEO1 = BIT(0),
+ DE_GRAPHICS1 = BIT(1),
+ DE_GRAPHICS2 = BIT(2), /* used only in DP500 */
+ DE_VIDEO2 = BIT(3),
+ DE_SMART = BIT(4),
+};
+
+struct malidp_input_format {
+ u32 format; /* DRM fourcc */
+ u8 layer; /* bitmask of layers supporting it */
+ u8 id; /* used internally */
+};
+
+#define MALIDP_INVALID_FORMAT_ID 0xff
+
+/*
+ * hide the differences between register maps
+ * by using a common structure to hold the
+ * base register offsets
+ */
+
+struct malidp_irq_map {
+ u32 irq_mask; /* mask of IRQs that can be enabled in the block */
+ u32 vsync_irq; /* IRQ bit used for signaling during VSYNC */
+};
+
+struct malidp_layer {
+ u16 id; /* layer ID */
+ u16 base; /* address offset for the register bank */
+ u16 ptr; /* address offset for the pointer register */
+};
+
+/* regmap features */
+#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
+
+struct malidp_hw_regmap {
+ /* address offset of the DE register bank */
+ /* is always 0x0000 */
+ /* address offset of the SE registers bank */
+ const u16 se_base;
+ /* address offset of the DC registers bank */
+ const u16 dc_base;
+
+ /* address offset for the output depth register */
+ const u16 out_depth_base;
+
+ /* bitmap with register map features */
+ const u8 features;
+
+ /* list of supported layers */
+ const u8 n_layers;
+ const struct malidp_layer *layers;
+
+ const struct malidp_irq_map de_irq_map;
+ const struct malidp_irq_map se_irq_map;
+ const struct malidp_irq_map dc_irq_map;
+
+ /* list of supported input formats for each layer */
+ const struct malidp_input_format *input_formats;
+ const u8 n_input_formats;
+};
+
+struct malidp_hw_device {
+ const struct malidp_hw_regmap map;
+ void __iomem *regs;
+
+ /* APB clock */
+ struct clk *pclk;
+ /* AXI clock */
+ struct clk *aclk;
+ /* main clock for display core */
+ struct clk *mclk;
+ /* pixel clock for display core */
+ struct clk *pxlclk;
+
+ /*
+ * Validate the driver instance against the hardware bits
+ */
+ int (*query_hw)(struct malidp_hw_device *hwdev);
+
+ /*
+ * Set the hardware into config mode, ready to accept mode changes
+ */
+ void (*enter_config_mode)(struct malidp_hw_device *hwdev);
+
+ /*
+ * Tell hardware to exit configuration mode
+ */
+ void (*leave_config_mode)(struct malidp_hw_device *hwdev);
+
+ /*
+ * Query if hardware is in configuration mode
+ */
+ bool (*in_config_mode)(struct malidp_hw_device *hwdev);
+
+ /*
+ * Set configuration valid flag for hardware parameters that can
+ * be changed outside the configuration mode. Hardware will use
+ * the new settings when config valid is set after the end of the
+ * current buffer scanout
+ */
+ void (*set_config_valid)(struct malidp_hw_device *hwdev);
+
+ /*
+ * Set a new mode in hardware. Requires the hardware to be in
+ * configuration mode before this function is called.
+ */
+ void (*modeset)(struct malidp_hw_device *hwdev, struct videomode *m);
+
+ /*
+ * Calculate the required rotation memory given the active area
+ * and the buffer format.
+ */
+ int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt);
+
+ u8 features;
+
+ u8 min_line_size;
+ u16 max_line_size;
+
+ /* size of memory used for rotating layers, up to two banks available */
+ u32 rotation_memory[2];
+};
+
+/* Supported variants of the hardware */
+enum {
+ MALIDP_500 = 0,
+ MALIDP_550,
+ MALIDP_650,
+ /* keep the next entry last */
+ MALIDP_MAX_DEVICES
+};
+
+extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES];
+
+static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)
+{
+ return readl(hwdev->regs + reg);
+}
+
+static inline void malidp_hw_write(struct malidp_hw_device *hwdev,
+ u32 value, u32 reg)
+{
+ writel(value, hwdev->regs + reg);
+}
+
+static inline void malidp_hw_setbits(struct malidp_hw_device *hwdev,
+ u32 mask, u32 reg)
+{
+ u32 data = malidp_hw_read(hwdev, reg);
+
+ data |= mask;
+ malidp_hw_write(hwdev, data, reg);
+}
+
+static inline void malidp_hw_clearbits(struct malidp_hw_device *hwdev,
+ u32 mask, u32 reg)
+{
+ u32 data = malidp_hw_read(hwdev, reg);
+
+ data &= ~mask;
+ malidp_hw_write(hwdev, data, reg);
+}
+
+static inline u32 malidp_get_block_base(struct malidp_hw_device *hwdev,
+ u8 block)
+{
+ switch (block) {
+ case MALIDP_SE_BLOCK:
+ return hwdev->map.se_base;
+ case MALIDP_DC_BLOCK:
+ return hwdev->map.dc_base;
+ }
+
+ return 0;
+}
+
+static inline void malidp_hw_disable_irq(struct malidp_hw_device *hwdev,
+ u8 block, u32 irq)
+{
+ u32 base = malidp_get_block_base(hwdev, block);
+
+ malidp_hw_clearbits(hwdev, irq, base + MALIDP_REG_MASKIRQ);
+}
+
+static inline void malidp_hw_enable_irq(struct malidp_hw_device *hwdev,
+ u8 block, u32 irq)
+{
+ u32 base = malidp_get_block_base(hwdev, block);
+
+ malidp_hw_setbits(hwdev, irq, base + MALIDP_REG_MASKIRQ);
+}
+
+int malidp_de_irq_init(struct drm_device *drm, int irq);
+void malidp_de_irq_fini(struct drm_device *drm);
+int malidp_se_irq_init(struct drm_device *drm, int irq);
+void malidp_se_irq_fini(struct drm_device *drm);
+
+u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
+ u8 layer_id, u32 format);
+
+/*
+ * background color components are defined as 12bits values,
+ * they will be shifted right when stored on hardware that
+ * supports only 8bits per channel
+ */
+#define MALIDP_BGND_COLOR_R 0x000
+#define MALIDP_BGND_COLOR_G 0x000
+#define MALIDP_BGND_COLOR_B 0x000
+
+#endif /* __MALIDP_HW_H__ */
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
new file mode 100644
index 0000000..725098d
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -0,0 +1,298 @@
+/*
+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP plane manipulation routines.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "malidp_hw.h"
+#include "malidp_drv.h"
+
+/* Layer specific register offsets */
+#define MALIDP_LAYER_FORMAT 0x000
+#define MALIDP_LAYER_CONTROL 0x004
+#define LAYER_ENABLE (1 << 0)
+#define LAYER_ROT_OFFSET 8
+#define LAYER_H_FLIP (1 << 10)
+#define LAYER_V_FLIP (1 << 11)
+#define LAYER_ROT_MASK (0xf << 8)
+#define MALIDP_LAYER_SIZE 0x00c
+#define LAYER_H_VAL(x) (((x) & 0x1fff) << 0)
+#define LAYER_V_VAL(x) (((x) & 0x1fff) << 16)
+#define MALIDP_LAYER_COMP_SIZE 0x010
+#define MALIDP_LAYER_OFFSET 0x014
+#define MALIDP_LAYER_STRIDE 0x018
+
+static void malidp_de_plane_destroy(struct drm_plane *plane)
+{
+ struct malidp_plane *mp = to_malidp_plane(plane);
+
+ if (mp->base.fb)
+ drm_framebuffer_unreference(mp->base.fb);
+
+ drm_plane_helper_disable(plane);
+ drm_plane_cleanup(plane);
+ devm_kfree(plane->dev->dev, mp);
+}
+
+struct drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
+{
+ struct malidp_plane_state *state, *m_state;
+
+ if (!plane->state)
+ return NULL;
+
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state) {
+ m_state = to_malidp_plane_state(plane->state);
+ __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+ state->rotmem_size = m_state->rotmem_size;
+ }
+
+ return &state->base;
+}
+
+void malidp_destroy_plane_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct malidp_plane_state *m_state = to_malidp_plane_state(state);
+
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(m_state);
+}
+
+static const struct drm_plane_funcs malidp_de_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = malidp_de_plane_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = malidp_duplicate_plane_state,
+ .atomic_destroy_state = malidp_destroy_plane_state,
+};
+
+static int malidp_de_plane_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct malidp_plane *mp = to_malidp_plane(plane);
+ struct malidp_plane_state *ms = to_malidp_plane_state(state);
+ u8 format_id;
+ u32 src_w, src_h;
+
+ if (!state->crtc || !state->fb)
+ return 0;
+
+ format_id = malidp_hw_get_format_id(&mp->hwdev->map, mp->layer->id,
+ state->fb->pixel_format);
+ if (format_id == MALIDP_INVALID_FORMAT_ID)
+ return -EINVAL;
+
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+
+ if ((state->crtc_w > mp->hwdev->max_line_size) ||
+ (state->crtc_h > mp->hwdev->max_line_size) ||
+ (state->crtc_w < mp->hwdev->min_line_size) ||
+ (state->crtc_h < mp->hwdev->min_line_size) ||
+ (state->crtc_w != src_w) || (state->crtc_h != src_h))
+ return -EINVAL;
+
+ /* packed RGB888 / BGR888 can't be rotated or flipped */
+ if (state->rotation != BIT(DRM_ROTATE_0) &&
+ (state->fb->pixel_format == DRM_FORMAT_RGB888 ||
+ state->fb->pixel_format == DRM_FORMAT_BGR888))
+ return -EINVAL;
+
+ ms->rotmem_size = 0;
+ if (state->rotation & MALIDP_ROTATED_MASK) {
+ int val;
+
+ val = mp->hwdev->rotmem_required(mp->hwdev, state->crtc_h,
+ state->crtc_w,
+ state->fb->pixel_format);
+ if (val < 0)
+ return val;
+
+ ms->rotmem_size = val;
+ }
+
+ return 0;
+}
+
+static void malidp_de_plane_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_gem_cma_object *obj;
+ struct malidp_plane *mp;
+ const struct malidp_hw_regmap *map;
+ u8 format_id;
+ u16 ptr;
+ u32 format, src_w, src_h, dest_w, dest_h, val = 0;
+ int num_planes, i;
+
+ mp = to_malidp_plane(plane);
+
+ map = &mp->hwdev->map;
+ format = plane->state->fb->pixel_format;
+ format_id = malidp_hw_get_format_id(map, mp->layer->id, format);
+ num_planes = drm_format_num_planes(format);
+
+ /* convert src values from Q16 fixed point to integer */
+ src_w = plane->state->src_w >> 16;
+ src_h = plane->state->src_h >> 16;
+ if (plane->state->rotation & MALIDP_ROTATED_MASK) {
+ dest_w = plane->state->crtc_h;
+ dest_h = plane->state->crtc_w;
+ } else {
+ dest_w = plane->state->crtc_w;
+ dest_h = plane->state->crtc_h;
+ }
+
+ malidp_hw_write(mp->hwdev, format_id, mp->layer->base);
+
+ for (i = 0; i < num_planes; i++) {
+ /* calculate the offset for the layer's plane registers */
+ ptr = mp->layer->ptr + (i << 4);
+
+ obj = drm_fb_cma_get_gem_obj(plane->state->fb, i);
+ malidp_hw_write(mp->hwdev, lower_32_bits(obj->paddr), ptr);
+ malidp_hw_write(mp->hwdev, upper_32_bits(obj->paddr), ptr + 4);
+ malidp_hw_write(mp->hwdev, plane->state->fb->pitches[i],
+ mp->layer->base + MALIDP_LAYER_STRIDE);
+ }
+
+ malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
+ mp->layer->base + MALIDP_LAYER_SIZE);
+
+ malidp_hw_write(mp->hwdev, LAYER_H_VAL(dest_w) | LAYER_V_VAL(dest_h),
+ mp->layer->base + MALIDP_LAYER_COMP_SIZE);
+
+ malidp_hw_write(mp->hwdev, LAYER_H_VAL(plane->state->crtc_x) |
+ LAYER_V_VAL(plane->state->crtc_y),
+ mp->layer->base + MALIDP_LAYER_OFFSET);
+
+ /* first clear the rotation bits in the register */
+ malidp_hw_clearbits(mp->hwdev, LAYER_ROT_MASK,
+ mp->layer->base + MALIDP_LAYER_CONTROL);
+
+ /* setup the rotation and axis flip bits */
+ if (plane->state->rotation & DRM_ROTATE_MASK)
+ val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET;
+ if (plane->state->rotation & BIT(DRM_REFLECT_X))
+ val |= LAYER_V_FLIP;
+ if (plane->state->rotation & BIT(DRM_REFLECT_Y))
+ val |= LAYER_H_FLIP;
+
+ /* set the 'enable layer' bit */
+ val |= LAYER_ENABLE;
+
+ malidp_hw_setbits(mp->hwdev, val,
+ mp->layer->base + MALIDP_LAYER_CONTROL);
+}
+
+static void malidp_de_plane_disable(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct malidp_plane *mp = to_malidp_plane(plane);
+
+ malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE,
+ mp->layer->base + MALIDP_LAYER_CONTROL);
+}
+
+static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = {
+ .atomic_check = malidp_de_plane_check,
+ .atomic_update = malidp_de_plane_update,
+ .atomic_disable = malidp_de_plane_disable,
+};
+
+int malidp_de_planes_init(struct drm_device *drm)
+{
+ struct malidp_drm *malidp = drm->dev_private;
+ const struct malidp_hw_regmap *map = &malidp->dev->map;
+ struct malidp_plane *plane = NULL;
+ enum drm_plane_type plane_type;
+ unsigned long crtcs = 1 << drm->mode_config.num_crtc;
+ u32 *formats;
+ int ret, i, j, n;
+
+ formats = kcalloc(map->n_input_formats, sizeof(*formats), GFP_KERNEL);
+ if (!formats) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ for (i = 0; i < map->n_layers; i++) {
+ u8 id = map->layers[i].id;
+
+ plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+ if (!plane) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* build the list of DRM supported formats based on the map */
+ for (n = 0, j = 0; j < map->n_input_formats; j++) {
+ if ((map->input_formats[j].layer & id) == id)
+ formats[n++] = map->input_formats[j].format;
+ }
+
+ plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
+ DRM_PLANE_TYPE_OVERLAY;
+ ret = drm_universal_plane_init(drm, &plane->base, crtcs,
+ &malidp_de_plane_funcs, formats,
+ n, plane_type, NULL);
+ if (ret < 0)
+ goto cleanup;
+
+ if (!drm->mode_config.rotation_property) {
+ unsigned long flags = BIT(DRM_ROTATE_0) |
+ BIT(DRM_ROTATE_90) |
+ BIT(DRM_ROTATE_180) |
+ BIT(DRM_ROTATE_270) |
+ BIT(DRM_REFLECT_X) |
+ BIT(DRM_REFLECT_Y);
+ drm->mode_config.rotation_property =
+ drm_mode_create_rotation_property(drm, flags);
+ }
+ /* SMART layer can't be rotated */
+ if (drm->mode_config.rotation_property && (id != DE_SMART))
+ drm_object_attach_property(&plane->base.base,
+ drm->mode_config.rotation_property,
+ BIT(DRM_ROTATE_0));
+
+ drm_plane_helper_add(&plane->base,
+ &malidp_de_plane_helper_funcs);
+ plane->hwdev = malidp->dev;
+ plane->layer = &map->layers[i];
+ }
+
+ kfree(formats);
+
+ return 0;
+
+cleanup:
+ malidp_de_planes_destroy(drm);
+ kfree(formats);
+
+ return ret;
+}
+
+void malidp_de_planes_destroy(struct drm_device *drm)
+{
+ struct drm_plane *p, *pt;
+
+ list_for_each_entry_safe(p, pt, &drm->mode_config.plane_list, head) {
+ drm_plane_cleanup(p);
+ kfree(p);
+ }
+}
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
new file mode 100644
index 0000000..73fecb3
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -0,0 +1,172 @@
+/*
+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
+ * Author: Liviu Dudau <Liviu.Dudau@arm.com>
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * ARM Mali DP500/DP550/DP650 registers definition.
+ */
+
+#ifndef __MALIDP_REGS_H__
+#define __MALIDP_REGS_H__
+
+/*
+ * abbreviations used:
+ * - DC - display core (general settings)
+ * - DE - display engine
+ * - SE - scaling engine
+ */
+
+/* interrupt bit masks */
+#define MALIDP_DE_IRQ_UNDERRUN (1 << 0)
+
+#define MALIDP500_DE_IRQ_AXI_ERR (1 << 4)
+#define MALIDP500_DE_IRQ_VSYNC (1 << 5)
+#define MALIDP500_DE_IRQ_PROG_LINE (1 << 6)
+#define MALIDP500_DE_IRQ_SATURATION (1 << 7)
+#define MALIDP500_DE_IRQ_CONF_VALID (1 << 8)
+#define MALIDP500_DE_IRQ_CONF_MODE (1 << 11)
+#define MALIDP500_DE_IRQ_CONF_ACTIVE (1 << 17)
+#define MALIDP500_DE_IRQ_PM_ACTIVE (1 << 18)
+#define MALIDP500_DE_IRQ_TESTMODE_ACTIVE (1 << 19)
+#define MALIDP500_DE_IRQ_FORCE_BLNK_ACTIVE (1 << 24)
+#define MALIDP500_DE_IRQ_AXI_BUSY (1 << 28)
+#define MALIDP500_DE_IRQ_GLOBAL (1 << 31)
+#define MALIDP500_SE_IRQ_CONF_MODE (1 << 0)
+#define MALIDP500_SE_IRQ_CONF_VALID (1 << 4)
+#define MALIDP500_SE_IRQ_INIT_BUSY (1 << 5)
+#define MALIDP500_SE_IRQ_AXI_ERROR (1 << 8)
+#define MALIDP500_SE_IRQ_OVERRUN (1 << 9)
+#define MALIDP500_SE_IRQ_PROG_LINE1 (1 << 12)
+#define MALIDP500_SE_IRQ_PROG_LINE2 (1 << 13)
+#define MALIDP500_SE_IRQ_CONF_ACTIVE (1 << 17)
+#define MALIDP500_SE_IRQ_PM_ACTIVE (1 << 18)
+#define MALIDP500_SE_IRQ_AXI_BUSY (1 << 28)
+#define MALIDP500_SE_IRQ_GLOBAL (1 << 31)
+
+#define MALIDP550_DE_IRQ_SATURATION (1 << 8)
+#define MALIDP550_DE_IRQ_VSYNC (1 << 12)
+#define MALIDP550_DE_IRQ_PROG_LINE (1 << 13)
+#define MALIDP550_DE_IRQ_AXI_ERR (1 << 16)
+#define MALIDP550_SE_IRQ_EOW (1 << 0)
+#define MALIDP550_SE_IRQ_AXI_ERR (1 << 16)
+#define MALIDP550_DC_IRQ_CONF_VALID (1 << 0)
+#define MALIDP550_DC_IRQ_CONF_MODE (1 << 4)
+#define MALIDP550_DC_IRQ_CONF_ACTIVE (1 << 16)
+#define MALIDP550_DC_IRQ_DE (1 << 20)
+#define MALIDP550_DC_IRQ_SE (1 << 24)
+
+#define MALIDP650_DE_IRQ_DRIFT (1 << 4)
+
+/* bit masks that are common between products */
+#define MALIDP_CFG_VALID (1 << 0)
+#define MALIDP_DISP_FUNC_ILACED (1 << 8)
+
+/* register offsets for IRQ management */
+#define MALIDP_REG_STATUS 0x00000
+#define MALIDP_REG_SETIRQ 0x00004
+#define MALIDP_REG_MASKIRQ 0x00008
+#define MALIDP_REG_CLEARIRQ 0x0000c
+
+/* register offsets */
+#define MALIDP_DE_CORE_ID 0x00018
+#define MALIDP_DE_DISPLAY_FUNC 0x00020
+
+/* these offsets are relative to MALIDP5x0_TIMINGS_BASE */
+#define MALIDP_DE_H_TIMINGS 0x0
+#define MALIDP_DE_V_TIMINGS 0x4
+#define MALIDP_DE_SYNC_WIDTH 0x8
+#define MALIDP_DE_HV_ACTIVE 0xc
+
+/* macros to set values into registers */
+#define MALIDP_DE_H_FRONTPORCH(x) (((x) & 0xfff) << 0)
+#define MALIDP_DE_H_BACKPORCH(x) (((x) & 0x3ff) << 16)
+#define MALIDP500_DE_V_FRONTPORCH(x) (((x) & 0xff) << 0)
+#define MALIDP550_DE_V_FRONTPORCH(x) (((x) & 0xfff) << 0)
+#define MALIDP_DE_V_BACKPORCH(x) (((x) & 0xff) << 16)
+#define MALIDP_DE_H_SYNCWIDTH(x) (((x) & 0x3ff) << 0)
+#define MALIDP_DE_V_SYNCWIDTH(x) (((x) & 0xff) << 16)
+#define MALIDP_DE_H_ACTIVE(x) (((x) & 0x1fff) << 0)
+#define MALIDP_DE_V_ACTIVE(x) (((x) & 0x1fff) << 16)
+
+/* register offsets and bits specific to DP500 */
+#define MALIDP500_DC_BASE 0x00000
+#define MALIDP500_DC_CONTROL 0x0000c
+#define MALIDP500_DC_CONFIG_REQ (1 << 17)
+#define MALIDP500_HSYNCPOL (1 << 20)
+#define MALIDP500_VSYNCPOL (1 << 21)
+#define MALIDP500_DC_CLEAR_MASK 0x300fff
+#define MALIDP500_DE_LINE_COUNTER 0x00010
+#define MALIDP500_DE_AXI_CONTROL 0x00014
+#define MALIDP500_DE_SECURE_CTRL 0x0001c
+#define MALIDP500_DE_CHROMA_KEY 0x00024
+#define MALIDP500_TIMINGS_BASE 0x00028
+
+#define MALIDP500_CONFIG_3D 0x00038
+#define MALIDP500_BGND_COLOR 0x0003c
+#define MALIDP500_OUTPUT_DEPTH 0x00044
+#define MALIDP500_YUV_RGB_COEF 0x00048
+#define MALIDP500_COLOR_ADJ_COEF 0x00078
+#define MALIDP500_COEF_TABLE_ADDR 0x000a8
+#define MALIDP500_COEF_TABLE_DATA 0x000ac
+#define MALIDP500_DE_LV_BASE 0x00100
+#define MALIDP500_DE_LV_PTR_BASE 0x00124
+#define MALIDP500_DE_LG1_BASE 0x00200
+#define MALIDP500_DE_LG1_PTR_BASE 0x0021c
+#define MALIDP500_DE_LG2_BASE 0x00300
+#define MALIDP500_DE_LG2_PTR_BASE 0x0031c
+#define MALIDP500_SE_BASE 0x00c00
+#define MALIDP500_SE_PTR_BASE 0x00e0c
+#define MALIDP500_DC_IRQ_BASE 0x00f00
+#define MALIDP500_CONFIG_VALID 0x00f00
+#define MALIDP500_CONFIG_ID 0x00fd4
+
+/* register offsets and bits specific to DP550/DP650 */
+#define MALIDP550_DE_CONTROL 0x00010
+#define MALIDP550_DE_LINE_COUNTER 0x00014
+#define MALIDP550_DE_AXI_CONTROL 0x00018
+#define MALIDP550_DE_QOS 0x0001c
+#define MALIDP550_TIMINGS_BASE 0x00030
+#define MALIDP550_HSYNCPOL (1 << 12)
+#define MALIDP550_VSYNCPOL (1 << 28)
+
+#define MALIDP550_DE_DISP_SIDEBAND 0x00040
+#define MALIDP550_DE_BGND_COLOR 0x00044
+#define MALIDP550_DE_OUTPUT_DEPTH 0x0004c
+#define MALIDP550_DE_COLOR_COEF 0x00050
+#define MALIDP550_DE_COEF_TABLE_ADDR 0x00080
+#define MALIDP550_DE_COEF_TABLE_DATA 0x00084
+#define MALIDP550_DE_LV1_BASE 0x00100
+#define MALIDP550_DE_LV1_PTR_BASE 0x00124
+#define MALIDP550_DE_LV2_BASE 0x00200
+#define MALIDP550_DE_LV2_PTR_BASE 0x00224
+#define MALIDP550_DE_LG_BASE 0x00300
+#define MALIDP550_DE_LG_PTR_BASE 0x0031c
+#define MALIDP550_DE_LS_BASE 0x00400
+#define MALIDP550_DE_LS_PTR_BASE 0x0042c
+#define MALIDP550_DE_PERF_BASE 0x00500
+#define MALIDP550_SE_BASE 0x08000
+#define MALIDP550_DC_BASE 0x0c000
+#define MALIDP550_DC_CONTROL 0x0c010
+#define MALIDP550_DC_CONFIG_REQ (1 << 16)
+#define MALIDP550_CONFIG_VALID 0x0c014
+#define MALIDP550_CONFIG_ID 0x0ffd4
+
+/*
+ * Starting with DP550 the register map blocks has been standardised to the
+ * following layout:
+ *
+ * Offset Block registers
+ * 0x00000 Display Engine
+ * 0x08000 Scaling Engine
+ * 0x0c000 Display Core
+ * 0x10000 Secure control
+ *
+ * The old DP500 IP mixes some DC with the DE registers, hence the need
+ * for a mapping structure.
+ */
+
+#endif /* __MALIDP_REGS_H__ */
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index cb21c0b..f5ebdd6 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -189,7 +189,6 @@ static struct drm_driver armada_drm_driver = {
.load = armada_drm_load,
.lastclose = armada_drm_lastclose,
.unload = armada_drm_unload,
- .set_busid = drm_platform_set_busid,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = armada_drm_enable_vblank,
.disable_vblank = armada_drm_disable_vblank,
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index 148e8a4..1ee707e 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -121,6 +121,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
int ret;
ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip,
+ BIT(DRM_ROTATE_0),
0, INT_MAX, true, false, &visible);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 9ecf16c..d4a3d61 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -691,13 +691,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
destroy_workqueue(dc->wq);
}
-static void atmel_hlcdc_dc_connector_unplug_all(struct drm_device *dev)
-{
- mutex_lock(&dev->mode_config.mutex);
- drm_connector_unregister_all(dev);
- mutex_unlock(&dev->mode_config.mutex);
-}
-
static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
@@ -815,15 +808,8 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
if (ret)
goto err_unload;
- ret = drm_connector_register_all(ddev);
- if (ret)
- goto err_unregister;
-
return 0;
-err_unregister:
- drm_dev_unregister(ddev);
-
err_unload:
atmel_hlcdc_dc_unload(ddev);
@@ -837,7 +823,6 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
{
struct drm_device *ddev = platform_get_drvdata(pdev);
- atmel_hlcdc_dc_connector_unplug_all(ddev);
drm_dev_unregister(ddev);
atmel_hlcdc_dc_unload(ddev);
drm_dev_unref(ddev);
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8f7423f..a1419214 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -50,6 +50,14 @@ config DRM_PARADE_PS8622
---help---
Parade eDP-LVDS bridge chip driver.
+config DRM_SII902X
+ tristate "Silicon Image sii902x RGB/HDMI bridge"
+ depends on OF
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ ---help---
+ Silicon Image sii902x bridge chip driver.
+
source "drivers/gpu/drm/bridge/analogix/Kconfig"
endmenu
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 96b13b3..bfec9f8 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
+obj-$(CONFIG_DRM_SII902X) += sii902x.o
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
new file mode 100644
index 0000000..9126d03
--- /dev/null
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2016 Atmel
+ * Bo Shen <voice.shen@atmel.com>
+ *
+ * Authors: Bo Shen <voice.shen@atmel.com>
+ * Boris Brezillon <boris.brezillon@free-electrons.com>
+ * Wu, Songjun <Songjun.Wu@atmel.com>
+ *
+ *
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+
+#define SII902X_TPI_VIDEO_DATA 0x0
+
+#define SII902X_TPI_PIXEL_REPETITION 0x8
+#define SII902X_TPI_AVI_PIXEL_REP_BUS_24BIT BIT(5)
+#define SII902X_TPI_AVI_PIXEL_REP_RISING_EDGE BIT(4)
+#define SII902X_TPI_AVI_PIXEL_REP_4X 3
+#define SII902X_TPI_AVI_PIXEL_REP_2X 1
+#define SII902X_TPI_AVI_PIXEL_REP_NONE 0
+#define SII902X_TPI_CLK_RATIO_HALF (0 << 6)
+#define SII902X_TPI_CLK_RATIO_1X (1 << 6)
+#define SII902X_TPI_CLK_RATIO_2X (2 << 6)
+#define SII902X_TPI_CLK_RATIO_4X (3 << 6)
+
+#define SII902X_TPI_AVI_IN_FORMAT 0x9
+#define SII902X_TPI_AVI_INPUT_BITMODE_12BIT BIT(7)
+#define SII902X_TPI_AVI_INPUT_DITHER BIT(6)
+#define SII902X_TPI_AVI_INPUT_RANGE_LIMITED (2 << 2)
+#define SII902X_TPI_AVI_INPUT_RANGE_FULL (1 << 2)
+#define SII902X_TPI_AVI_INPUT_RANGE_AUTO (0 << 2)
+#define SII902X_TPI_AVI_INPUT_COLORSPACE_BLACK (3 << 0)
+#define SII902X_TPI_AVI_INPUT_COLORSPACE_YUV422 (2 << 0)
+#define SII902X_TPI_AVI_INPUT_COLORSPACE_YUV444 (1 << 0)
+#define SII902X_TPI_AVI_INPUT_COLORSPACE_RGB (0 << 0)
+
+#define SII902X_TPI_AVI_INFOFRAME 0x0c
+
+#define SII902X_SYS_CTRL_DATA 0x1a
+#define SII902X_SYS_CTRL_PWR_DWN BIT(4)
+#define SII902X_SYS_CTRL_AV_MUTE BIT(3)
+#define SII902X_SYS_CTRL_DDC_BUS_REQ BIT(2)
+#define SII902X_SYS_CTRL_DDC_BUS_GRTD BIT(1)
+#define SII902X_SYS_CTRL_OUTPUT_MODE BIT(0)
+#define SII902X_SYS_CTRL_OUTPUT_HDMI 1
+#define SII902X_SYS_CTRL_OUTPUT_DVI 0
+
+#define SII902X_REG_CHIPID(n) (0x1b + (n))
+
+#define SII902X_PWR_STATE_CTRL 0x1e
+#define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0)
+#define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK)
+
+#define SII902X_INT_ENABLE 0x3c
+#define SII902X_INT_STATUS 0x3d
+#define SII902X_HOTPLUG_EVENT BIT(0)
+#define SII902X_PLUGGED_STATUS BIT(2)
+
+#define SII902X_REG_TPI_RQB 0xc7
+
+#define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500
+
+struct sii902x {
+ struct i2c_client *i2c;
+ struct regmap *regmap;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct sii902x, bridge);
+}
+
+static inline struct sii902x *connector_to_sii902x(struct drm_connector *con)
+{
+ return container_of(con, struct sii902x, connector);
+}
+
+static void sii902x_reset(struct sii902x *sii902x)
+{
+ if (!sii902x->reset_gpio)
+ return;
+
+ gpiod_set_value(sii902x->reset_gpio, 1);
+
+ /* The datasheet says treset-min = 100us. Make it 150us to be sure. */
+ usleep_range(150, 200);
+
+ gpiod_set_value(sii902x->reset_gpio, 0);
+}
+
+static enum drm_connector_status
+sii902x_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct sii902x *sii902x = connector_to_sii902x(connector);
+ unsigned int status;
+
+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
+
+ return (status & SII902X_PLUGGED_STATUS) ?
+ connector_status_connected : connector_status_disconnected;
+}
+
+static const struct drm_connector_funcs sii902x_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = sii902x_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int sii902x_get_modes(struct drm_connector *connector)
+{
+ struct sii902x *sii902x = connector_to_sii902x(connector);
+ struct regmap *regmap = sii902x->regmap;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ unsigned long timeout;
+ unsigned int status;
+ struct edid *edid;
+ int num = 0;
+ int ret;
+
+ ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
+ SII902X_SYS_CTRL_DDC_BUS_REQ,
+ SII902X_SYS_CTRL_DDC_BUS_REQ);
+ if (ret)
+ return ret;
+
+ timeout = jiffies +
+ msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
+ do {
+ ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
+ if (ret)
+ return ret;
+ } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
+ time_before(jiffies, timeout));
+
+ if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
+ dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus");
+ return -ETIMEDOUT;
+ }
+
+ ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status);
+ if (ret)
+ return ret;
+
+ edid = drm_get_edid(connector, sii902x->i2c->adapter);
+ drm_mode_connector_update_edid_property(connector, edid);
+ if (edid) {
+ num = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+ }
+
+ ret = drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
+ SII902X_SYS_CTRL_DDC_BUS_REQ |
+ SII902X_SYS_CTRL_DDC_BUS_GRTD, 0);
+ if (ret)
+ return ret;
+
+ timeout = jiffies +
+ msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
+ do {
+ ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
+ if (ret)
+ return ret;
+ } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
+ SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
+ time_before(jiffies, timeout));
+
+ if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
+ SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
+ dev_err(&sii902x->i2c->dev, "failed to release the i2c bus");
+ return -ETIMEDOUT;
+ }
+
+ return num;
+}
+
+static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /* TODO: check mode */
+
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs = {
+ .get_modes = sii902x_get_modes,
+ .mode_valid = sii902x_mode_valid,
+};
+
+static void sii902x_bridge_disable(struct drm_bridge *bridge)
+{
+ struct sii902x *sii902x = bridge_to_sii902x(bridge);
+
+ regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
+ SII902X_SYS_CTRL_PWR_DWN,
+ SII902X_SYS_CTRL_PWR_DWN);
+}
+
+static void sii902x_bridge_enable(struct drm_bridge *bridge)
+{
+ struct sii902x *sii902x = bridge_to_sii902x(bridge);
+
+ regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL,
+ SII902X_AVI_POWER_STATE_MSK,
+ SII902X_AVI_POWER_STATE_D(0));
+ regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
+ SII902X_SYS_CTRL_PWR_DWN, 0);
+}
+
+static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj)
+{
+ struct sii902x *sii902x = bridge_to_sii902x(bridge);
+ struct regmap *regmap = sii902x->regmap;
+ u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
+ struct hdmi_avi_infoframe frame;
+ int ret;
+
+ buf[0] = adj->clock;
+ buf[1] = adj->clock >> 8;
+ buf[2] = adj->vrefresh;
+ buf[3] = 0x00;
+ buf[4] = adj->hdisplay;
+ buf[5] = adj->hdisplay >> 8;
+ buf[6] = adj->vdisplay;
+ buf[7] = adj->vdisplay >> 8;
+ buf[8] = SII902X_TPI_CLK_RATIO_1X | SII902X_TPI_AVI_PIXEL_REP_NONE |
+ SII902X_TPI_AVI_PIXEL_REP_BUS_24BIT;
+ buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO |
+ SII902X_TPI_AVI_INPUT_COLORSPACE_RGB;
+
+ ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10);
+ if (ret)
+ return;
+
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj);
+ if (ret < 0) {
+ DRM_ERROR("couldn't fill AVI infoframe\n");
+ return;
+ }
+
+ ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf));
+ if (ret < 0) {
+ DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
+ return;
+ }
+
+ /* Do not send the infoframe header, but keep the CRC field. */
+ regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME,
+ buf + HDMI_INFOFRAME_HEADER_SIZE - 1,
+ HDMI_AVI_INFOFRAME_SIZE + 1);
+}
+
+static int sii902x_bridge_attach(struct drm_bridge *bridge)
+{
+ struct sii902x *sii902x = bridge_to_sii902x(bridge);
+ struct drm_device *drm = bridge->dev;
+ int ret;
+
+ drm_connector_helper_add(&sii902x->connector,
+ &sii902x_connector_helper_funcs);
+
+ if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
+ dev_err(&sii902x->i2c->dev,
+ "sii902x driver is only compatible with DRM devices supporting atomic updates");
+ return -ENOTSUPP;
+ }
+
+ ret = drm_connector_init(drm, &sii902x->connector,
+ &sii902x_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ if (ret)
+ return ret;
+
+ if (sii902x->i2c->irq > 0)
+ sii902x->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ else
+ sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
+
+ drm_mode_connector_attach_encoder(&sii902x->connector, bridge->encoder);
+
+ return 0;
+}
+
+static const struct drm_bridge_funcs sii902x_bridge_funcs = {
+ .attach = sii902x_bridge_attach,
+ .mode_set = sii902x_bridge_mode_set,
+ .disable = sii902x_bridge_disable,
+ .enable = sii902x_bridge_enable,
+};
+
+static const struct regmap_range sii902x_volatile_ranges[] = {
+ { .range_min = 0, .range_max = 0xff },
+};
+
+static const struct regmap_access_table sii902x_volatile_table = {
+ .yes_ranges = sii902x_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sii902x_volatile_ranges),
+};
+
+static const struct regmap_config sii902x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &sii902x_volatile_table,
+ .cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t sii902x_interrupt(int irq, void *data)
+{
+ struct sii902x *sii902x = data;
+ unsigned int status = 0;
+
+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
+ regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
+
+ if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev)
+ drm_helper_hpd_irq_event(sii902x->bridge.dev);
+
+ return IRQ_HANDLED;
+}
+
+static int sii902x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ unsigned int status = 0;
+ struct sii902x *sii902x;
+ u8 chipid[4];
+ int ret;
+
+ sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL);
+ if (!sii902x)
+ return -ENOMEM;
+
+ sii902x->i2c = client;
+ sii902x->regmap = devm_regmap_init_i2c(client, &sii902x_regmap_config);
+ if (IS_ERR(sii902x->regmap))
+ return PTR_ERR(sii902x->regmap);
+
+ sii902x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(sii902x->reset_gpio)) {
+ dev_err(dev, "Failed to retrieve/request reset gpio: %ld\n",
+ PTR_ERR(sii902x->reset_gpio));
+ return PTR_ERR(sii902x->reset_gpio);
+ }
+
+ sii902x_reset(sii902x);
+
+ ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(sii902x->regmap, SII902X_REG_CHIPID(0),
+ &chipid, 4);
+ if (ret) {
+ dev_err(dev, "regmap_read failed %d\n", ret);
+ return ret;
+ }
+
+ if (chipid[0] != 0xb0) {
+ dev_err(dev, "Invalid chipid: %02x (expecting 0xb0)\n",
+ chipid[0]);
+ return -EINVAL;
+ }
+
+ /* Clear all pending interrupts */
+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
+ regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
+
+ if (client->irq > 0) {
+ regmap_write(sii902x->regmap, SII902X_INT_ENABLE,
+ SII902X_HOTPLUG_EVENT);
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ sii902x_interrupt,
+ IRQF_ONESHOT, dev_name(dev),
+ sii902x);
+ if (ret)
+ return ret;
+ }
+
+ sii902x->bridge.funcs = &sii902x_bridge_funcs;
+ sii902x->bridge.of_node = dev->of_node;
+ ret = drm_bridge_add(&sii902x->bridge);
+ if (ret) {
+ dev_err(dev, "Failed to add drm_bridge\n");
+ return ret;
+ }
+
+ i2c_set_clientdata(client, sii902x);
+
+ return 0;
+}
+
+static int sii902x_remove(struct i2c_client *client)
+
+{
+ struct sii902x *sii902x = i2c_get_clientdata(client);
+
+ drm_bridge_remove(&sii902x->bridge);
+
+ return 0;
+}
+
+static const struct of_device_id sii902x_dt_ids[] = {
+ { .compatible = "sil,sii9022", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sii902x_dt_ids);
+
+static const struct i2c_device_id sii902x_i2c_ids[] = {
+ { "sii9022", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);
+
+static struct i2c_driver sii902x_driver = {
+ .probe = sii902x_probe,
+ .remove = sii902x_remove,
+ .driver = {
+ .name = "sii902x",
+ .of_match_table = sii902x_dt_ids,
+ },
+ .id_table = sii902x_i2c_ids,
+};
+module_i2c_driver(sii902x_driver);
+
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("SII902x RGB -> HDMI bridges");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 50d0baa..4153e8a 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -30,25 +30,36 @@
#include <drm/drmP.h>
#include "drm_internal.h"
+#include "drm_legacy.h"
/**
- * drm_getmagic - Get unique magic of a client
- * @dev: DRM device to operate on
- * @data: ioctl data containing the drm_auth object
- * @file_priv: DRM file that performs the operation
+ * DOC: master and authentication
*
- * This looks up the unique magic of the passed client and returns it. If the
- * client did not have a magic assigned, yet, a new one is registered. The magic
- * is stored in the passed drm_auth object.
+ * struct &drm_master is used to track groups of clients with open
+ * primary/legacy device nodes. For every struct &drm_file which has had at
+ * least once successfully became the device master (either through the
+ * SET_MASTER IOCTL, or implicitly through opening the primary device node when
+ * no one else is the current master that time) there exists one &drm_master.
+ * This is noted in the is_master member of &drm_file. All other clients have
+ * just a pointer to the &drm_master they are associated with.
*
- * Returns: 0 on success, negative error code on failure.
+ * In addition only one &drm_master can be the current master for a &drm_device.
+ * It can be switched through the DROP_MASTER and SET_MASTER IOCTL, or
+ * implicitly through closing/openeing the primary device node. See also
+ * drm_is_current_master().
+ *
+ * Clients can authenticate against the current master (if it matches their own)
+ * using the GETMAGIC and AUTHMAGIC IOCTLs. Together with exchanging masters,
+ * this allows controlled access to the device for an entire group of mutually
+ * trusted clients.
*/
+
int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_auth *auth = data;
int ret = 0;
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&dev->master_mutex);
if (!file_priv->magic) {
ret = idr_alloc(&file_priv->master->magic_map, file_priv,
1, 0, GFP_KERNEL);
@@ -56,23 +67,13 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
file_priv->magic = ret;
}
auth->magic = file_priv->magic;
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&dev->master_mutex);
DRM_DEBUG("%u\n", auth->magic);
return ret < 0 ? ret : 0;
}
-/**
- * drm_authmagic - Authenticate client with a magic
- * @dev: DRM device to operate on
- * @data: ioctl data containing the drm_auth object
- * @file_priv: DRM file that performs the operation
- *
- * This looks up a DRM client by the passed magic and authenticates it.
- *
- * Returns: 0 on success, negative error code on failure.
- */
int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -81,13 +82,253 @@ int drm_authmagic(struct drm_device *dev, void *data,
DRM_DEBUG("%u\n", auth->magic);
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&dev->master_mutex);
file = idr_find(&file_priv->master->magic_map, auth->magic);
if (file) {
file->authenticated = 1;
idr_replace(&file_priv->master->magic_map, NULL, auth->magic);
}
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&dev->master_mutex);
return file ? 0 : -EINVAL;
}
+
+static struct drm_master *drm_master_create(struct drm_device *dev)
+{
+ struct drm_master *master;
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return NULL;
+
+ kref_init(&master->refcount);
+ spin_lock_init(&master->lock.spinlock);
+ init_waitqueue_head(&master->lock.lock_queue);
+ idr_init(&master->magic_map);
+ master->dev = dev;
+
+ return master;
+}
+
+static int drm_set_master(struct drm_device *dev, struct drm_file *fpriv,
+ bool new_master)
+{
+ int ret = 0;
+
+ dev->master = drm_master_get(fpriv->master);
+ if (dev->driver->master_set) {
+ ret = dev->driver->master_set(dev, fpriv, new_master);
+ if (unlikely(ret != 0)) {
+ drm_master_put(&dev->master);
+ }
+ }
+
+ return ret;
+}
+
+static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
+{
+ struct drm_master *old_master;
+ int ret;
+
+ lockdep_assert_held_once(&dev->master_mutex);
+
+ old_master = fpriv->master;
+ fpriv->master = drm_master_create(dev);
+ if (!fpriv->master) {
+ fpriv->master = old_master;
+ return -ENOMEM;
+ }
+
+ if (dev->driver->master_create) {
+ ret = dev->driver->master_create(dev, fpriv->master);
+ if (ret)
+ goto out_err;
+ }
+ fpriv->is_master = 1;
+ fpriv->authenticated = 1;
+
+ ret = drm_set_master(dev, fpriv, true);
+ if (ret)
+ goto out_err;
+
+ if (old_master)
+ drm_master_put(&old_master);
+
+ return 0;
+
+out_err:
+ /* drop references and restore old master on failure */
+ drm_master_put(&fpriv->master);
+ fpriv->master = old_master;
+
+ return ret;
+}
+
+int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ int ret = 0;
+
+ mutex_lock(&dev->master_mutex);
+ if (drm_is_current_master(file_priv))
+ goto out_unlock;
+
+ if (dev->master) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (!file_priv->master) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (!file_priv->is_master) {
+ ret = drm_new_set_master(dev, file_priv);
+ goto out_unlock;
+ }
+
+ ret = drm_set_master(dev, file_priv, false);
+out_unlock:
+ mutex_unlock(&dev->master_mutex);
+ return ret;
+}
+
+static void drm_drop_master(struct drm_device *dev,
+ struct drm_file *fpriv)
+{
+ if (dev->driver->master_drop)
+ dev->driver->master_drop(dev, fpriv);
+ drm_master_put(&dev->master);
+}
+
+int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ int ret = -EINVAL;
+
+ mutex_lock(&dev->master_mutex);
+ if (!drm_is_current_master(file_priv))
+ goto out_unlock;
+
+ if (!dev->master)
+ goto out_unlock;
+
+ ret = 0;
+ drm_drop_master(dev, file_priv);
+out_unlock:
+ mutex_unlock(&dev->master_mutex);
+ return ret;
+}
+
+int drm_master_open(struct drm_file *file_priv)
+{
+ struct drm_device *dev = file_priv->minor->dev;
+ int ret = 0;
+
+ /* if there is no current master make this fd it, but do not create
+ * any master object for render clients */
+ mutex_lock(&dev->master_mutex);
+ if (!dev->master)
+ ret = drm_new_set_master(dev, file_priv);
+ else
+ file_priv->master = drm_master_get(dev->master);
+ mutex_unlock(&dev->master_mutex);
+
+ return ret;
+}
+
+void drm_master_release(struct drm_file *file_priv)
+{
+ struct drm_device *dev = file_priv->minor->dev;
+ struct drm_master *master = file_priv->master;
+
+ mutex_lock(&dev->master_mutex);
+ if (file_priv->magic)
+ idr_remove(&file_priv->master->magic_map, file_priv->magic);
+
+ if (!drm_is_current_master(file_priv))
+ goto out;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
+ /*
+ * Since the master is disappearing, so is the
+ * possibility to lock.
+ */
+ mutex_lock(&dev->struct_mutex);
+ if (master->lock.hw_lock) {
+ if (dev->sigdata.lock == master->lock.hw_lock)
+ dev->sigdata.lock = NULL;
+ master->lock.hw_lock = NULL;
+ master->lock.file_priv = NULL;
+ wake_up_interruptible_all(&master->lock.lock_queue);
+ }
+ mutex_unlock(&dev->struct_mutex);
+ }
+
+ if (dev->master == file_priv->master)
+ drm_drop_master(dev, file_priv);
+out:
+ /* drop the master reference held by the file priv */
+ if (file_priv->master)
+ drm_master_put(&file_priv->master);
+ mutex_unlock(&dev->master_mutex);
+}
+
+/**
+ * drm_is_current_master - checks whether @priv is the current master
+ * @fpriv: DRM file private
+ *
+ * Checks whether @fpriv is current master on its device. This decides whether a
+ * client is allowed to run DRM_MASTER IOCTLs.
+ *
+ * Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
+ * - the current master is assumed to own the non-shareable display hardware.
+ */
+bool drm_is_current_master(struct drm_file *fpriv)
+{
+ return fpriv->is_master && fpriv->master == fpriv->minor->dev->master;
+}
+EXPORT_SYMBOL(drm_is_current_master);
+
+/**
+ * drm_master_get - reference a master pointer
+ * @master: struct &drm_master
+ *
+ * Increments the reference count of @master and returns a pointer to @master.
+ */
+struct drm_master *drm_master_get(struct drm_master *master)
+{
+ kref_get(&master->refcount);
+ return master;
+}
+EXPORT_SYMBOL(drm_master_get);
+
+static void drm_master_destroy(struct kref *kref)
+{
+ struct drm_master *master = container_of(kref, struct drm_master, refcount);
+ struct drm_device *dev = master->dev;
+
+ if (dev->driver->master_destroy)
+ dev->driver->master_destroy(dev, master);
+
+ drm_legacy_master_rmmaps(dev, master);
+
+ idr_destroy(&master->magic_map);
+ kfree(master->unique);
+ kfree(master);
+}
+
+/**
+ * drm_master_put - unreference and clear a master pointer
+ * @master: pointer to a pointer of struct &drm_master
+ *
+ * This decrements the &drm_master behind @master and sets it to NULL.
+ */
+void drm_master_put(struct drm_master **master)
+{
+ kref_put(&(*master)->refcount, drm_master_destroy);
+ *master = NULL;
+}
+EXPORT_SYMBOL(drm_master_put);
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 9b34158..c3a12cd 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -51,7 +51,7 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
*/
if (!entry->map ||
map->type != entry->map->type ||
- entry->master != dev->primary->master)
+ entry->master != dev->master)
continue;
switch (map->type) {
case _DRM_SHM:
@@ -245,12 +245,12 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
map->offset = (unsigned long)map->handle;
if (map->flags & _DRM_CONTAINS_LOCK) {
/* Prevent a 2nd X Server from creating a 2nd lock */
- if (dev->primary->master->lock.hw_lock != NULL) {
+ if (dev->master->lock.hw_lock != NULL) {
vfree(map->handle);
kfree(map);
return -EBUSY;
}
- dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */
+ dev->sigdata.lock = dev->master->lock.hw_lock = map->handle; /* Pointer to lock */
}
break;
case _DRM_AGP: {
@@ -356,7 +356,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
mutex_unlock(&dev->struct_mutex);
if (!(map->flags & _DRM_DRIVER))
- list->master = dev->primary->master;
+ list->master = dev->master;
*maplist = list;
return 0;
}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 4ec35f9..fd93e9c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -39,6 +39,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_lock.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_auth.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@@ -608,6 +609,31 @@ static unsigned int drm_num_crtcs(struct drm_device *dev)
return num;
}
+static int drm_crtc_register_all(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+ int ret = 0;
+
+ drm_for_each_crtc(crtc, dev) {
+ if (crtc->funcs->late_register)
+ ret = crtc->funcs->late_register(crtc);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void drm_crtc_unregister_all(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+
+ drm_for_each_crtc(crtc, dev) {
+ if (crtc->funcs->early_unregister)
+ crtc->funcs->early_unregister(crtc);
+ }
+}
+
/**
* drm_crtc_init_with_planes - Initialise a new CRTC object with
* specified primary and cursor planes.
@@ -938,6 +964,12 @@ void drm_connector_cleanup(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode, *t;
+ /* The connector should have been removed from userspace long before
+ * it is finally destroyed.
+ */
+ if (WARN_ON(connector->registered))
+ drm_connector_unregister(connector);
+
if (connector->tile_group) {
drm_mode_put_tile_group(dev, connector->tile_group);
connector->tile_group = NULL;
@@ -984,19 +1016,34 @@ int drm_connector_register(struct drm_connector *connector)
{
int ret;
+ if (connector->registered)
+ return 0;
+
ret = drm_sysfs_connector_add(connector);
if (ret)
return ret;
ret = drm_debugfs_connector_add(connector);
if (ret) {
- drm_sysfs_connector_remove(connector);
- return ret;
+ goto err_sysfs;
+ }
+
+ if (connector->funcs->late_register) {
+ ret = connector->funcs->late_register(connector);
+ if (ret)
+ goto err_debugfs;
}
drm_mode_object_register(connector->dev, &connector->base);
+ connector->registered = true;
return 0;
+
+err_debugfs:
+ drm_debugfs_connector_remove(connector);
+err_sysfs:
+ drm_sysfs_connector_remove(connector);
+ return ret;
}
EXPORT_SYMBOL(drm_connector_register);
@@ -1008,8 +1055,16 @@ EXPORT_SYMBOL(drm_connector_register);
*/
void drm_connector_unregister(struct drm_connector *connector)
{
+ if (!connector->registered)
+ return;
+
+ if (connector->funcs->early_unregister)
+ connector->funcs->early_unregister(connector);
+
drm_sysfs_connector_remove(connector);
drm_debugfs_connector_remove(connector);
+
+ connector->registered = false;
}
EXPORT_SYMBOL(drm_connector_unregister);
@@ -1018,9 +1073,9 @@ EXPORT_SYMBOL(drm_connector_unregister);
* @dev: drm device
*
* This function registers all connectors in sysfs and other places so that
- * userspace can start to access them. Drivers can call it after calling
- * drm_dev_register() to complete the device registration, if they don't call
- * drm_connector_register() on each connector individually.
+ * userspace can start to access them. drm_connector_register_all() is called
+ * automatically from drm_dev_register() to complete the device registration,
+ * if they don't call drm_connector_register() on each connector individually.
*
* When a device is unplugged and should be removed from userspace access,
* call drm_connector_unregister_all(), which is the inverse of this
@@ -1073,6 +1128,31 @@ void drm_connector_unregister_all(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_connector_unregister_all);
+static int drm_encoder_register_all(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+ int ret = 0;
+
+ drm_for_each_encoder(encoder, dev) {
+ if (encoder->funcs->late_register)
+ ret = encoder->funcs->late_register(encoder);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void drm_encoder_unregister_all(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder(encoder, dev) {
+ if (encoder->funcs->early_unregister)
+ encoder->funcs->early_unregister(encoder);
+ }
+}
+
/**
* drm_encoder_init - Init a preallocated encoder
* @dev: drm device
@@ -1261,6 +1341,31 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
}
EXPORT_SYMBOL(drm_universal_plane_init);
+static int drm_plane_register_all(struct drm_device *dev)
+{
+ struct drm_plane *plane;
+ int ret = 0;
+
+ drm_for_each_plane(plane, dev) {
+ if (plane->funcs->late_register)
+ ret = plane->funcs->late_register(plane);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void drm_plane_unregister_all(struct drm_device *dev)
+{
+ struct drm_plane *plane;
+
+ drm_for_each_plane(plane, dev) {
+ if (plane->funcs->early_unregister)
+ plane->funcs->early_unregister(plane);
+ }
+}
+
/**
* drm_plane_init - Initialize a legacy plane
* @dev: DRM device
@@ -1383,6 +1488,46 @@ void drm_plane_force_disable(struct drm_plane *plane)
}
EXPORT_SYMBOL(drm_plane_force_disable);
+int drm_modeset_register_all(struct drm_device *dev)
+{
+ int ret;
+
+ ret = drm_plane_register_all(dev);
+ if (ret)
+ goto err_plane;
+
+ ret = drm_crtc_register_all(dev);
+ if (ret)
+ goto err_crtc;
+
+ ret = drm_encoder_register_all(dev);
+ if (ret)
+ goto err_encoder;
+
+ ret = drm_connector_register_all(dev);
+ if (ret)
+ goto err_connector;
+
+ return 0;
+
+err_connector:
+ drm_encoder_unregister_all(dev);
+err_encoder:
+ drm_crtc_unregister_all(dev);
+err_crtc:
+ drm_plane_unregister_all(dev);
+err_plane:
+ return ret;
+}
+
+void drm_modeset_unregister_all(struct drm_device *dev)
+{
+ drm_connector_unregister_all(dev);
+ drm_encoder_unregister_all(dev);
+ drm_crtc_unregister_all(dev);
+ drm_plane_unregister_all(dev);
+}
+
static int drm_mode_create_standard_properties(struct drm_device *dev)
{
struct drm_property *prop;
@@ -3499,7 +3644,7 @@ int drm_mode_getfb(struct drm_device *dev,
r->bpp = fb->bits_per_pixel;
r->pitch = fb->pitches[0];
if (fb->funcs->create_handle) {
- if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
+ if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) ||
drm_is_control_client(file_priv)) {
ret = fb->funcs->create_handle(fb, file_priv,
&r->handle);
@@ -3656,6 +3801,13 @@ void drm_fb_release(struct drm_file *priv)
}
}
+static bool drm_property_type_valid(struct drm_property *property)
+{
+ if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+ return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+ return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+}
+
/**
* drm_property_create - create a new property type
* @dev: drm device
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index bf10d70..d615912 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -232,6 +232,9 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
*/
void drm_helper_disable_unused_functions(struct drm_device *dev)
{
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC))
+ DRM_ERROR("Called for atomic driver, this is not what you want.\n");
+
drm_modeset_lock_all(dev);
__drm_helper_disable_unused_functions(dev);
drm_modeset_unlock_all(dev);
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index a78c138..47a500b 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -31,14 +31,100 @@
* and are not exported to drivers.
*/
+
+/* drm_crtc.c */
+void drm_connector_ida_init(void);
+void drm_connector_ida_destroy(void);
int drm_mode_object_get(struct drm_device *dev,
struct drm_mode_object *obj, uint32_t obj_type);
void drm_mode_object_unregister(struct drm_device *dev,
struct drm_mode_object *object);
+bool drm_property_change_valid_get(struct drm_property *property,
+ uint64_t value,
+ struct drm_mode_object **ref);
+void drm_property_change_valid_put(struct drm_property *property,
+ struct drm_mode_object *ref);
+
+int drm_plane_check_pixel_format(const struct drm_plane *plane,
+ u32 format);
+int drm_crtc_check_viewport(const struct drm_crtc *crtc,
+ int x, int y,
+ const struct drm_display_mode *mode,
+ const struct drm_framebuffer *fb);
+
+void drm_fb_release(struct drm_file *file_priv);
+void drm_property_destroy_user_blobs(struct drm_device *dev,
+ struct drm_file *file_priv);
+
+/* dumb buffer support IOCTLs */
+int drm_mode_create_dumb_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+
+/* framebuffer IOCTLs */
+extern int drm_mode_addfb(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+extern int drm_mode_addfb2(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_rmfb(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getfb(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+
+/* IOCTLs */
+int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
+int drm_mode_getresources(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getplane_res(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int drm_mode_getcrtc(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getconnector(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_setcrtc(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getplane(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_setplane(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_cursor2_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getproperty_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getblob_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_createblob_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_destroyblob_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_getencoder(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_gamma_get_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+int drm_mode_gamma_set_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+
+int drm_mode_page_flip_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
/* drm_atomic.c */
int drm_atomic_get_property(struct drm_mode_object *obj,
- struct drm_property *property, uint64_t *val);
+ struct drm_property *property, uint64_t *val);
int drm_mode_atomic_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
+int drm_modeset_register_all(struct drm_device *dev);
+void drm_modeset_unregister_all(struct drm_device *dev);
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 3bcf8e6..fa10cef 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -46,11 +46,8 @@
static const struct drm_info_list drm_debugfs_list[] = {
{"name", drm_name_info, 0},
- {"vm", drm_vm_info, 0},
{"clients", drm_clients_info, 0},
- {"bufs", drm_bufs_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
- {"vma", drm_vma_info, 0},
};
#define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index eeaf5a7..091053e 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -708,8 +708,6 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
memset(&msg, 0, sizeof(msg));
- mutex_lock(&aux->hw_mutex);
-
for (i = 0; i < num; i++) {
msg.address = msgs[i].addr;
drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
@@ -764,8 +762,6 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
msg.size = 0;
(void)drm_dp_i2c_do_msg(aux, &msg);
- mutex_unlock(&aux->hw_mutex);
-
return err;
}
@@ -774,22 +770,64 @@ static const struct i2c_algorithm drm_dp_i2c_algo = {
.master_xfer = drm_dp_i2c_xfer,
};
+static struct drm_dp_aux *i2c_to_aux(struct i2c_adapter *i2c)
+{
+ return container_of(i2c, struct drm_dp_aux, ddc);
+}
+
+static void lock_bus(struct i2c_adapter *i2c, unsigned int flags)
+{
+ mutex_lock(&i2c_to_aux(i2c)->hw_mutex);
+}
+
+static int trylock_bus(struct i2c_adapter *i2c, unsigned int flags)
+{
+ return mutex_trylock(&i2c_to_aux(i2c)->hw_mutex);
+}
+
+static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags)
+{
+ mutex_unlock(&i2c_to_aux(i2c)->hw_mutex);
+}
+
/**
- * drm_dp_aux_register() - initialise and register aux channel
+ * drm_dp_aux_init() - minimally initialise an aux channel
* @aux: DisplayPort AUX channel
*
- * Returns 0 on success or a negative error code on failure.
+ * If you need to use the drm_dp_aux's i2c adapter prior to registering it
+ * with the outside world, call drm_dp_aux_init() first. You must still
+ * call drm_dp_aux_register() once the connector has been registered to
+ * allow userspace access to the auxiliary DP channel.
*/
-int drm_dp_aux_register(struct drm_dp_aux *aux)
+void drm_dp_aux_init(struct drm_dp_aux *aux)
{
- int ret;
-
mutex_init(&aux->hw_mutex);
aux->ddc.algo = &drm_dp_i2c_algo;
aux->ddc.algo_data = aux;
aux->ddc.retries = 3;
+ aux->ddc.lock_bus = lock_bus;
+ aux->ddc.trylock_bus = trylock_bus;
+ aux->ddc.unlock_bus = unlock_bus;
+}
+EXPORT_SYMBOL(drm_dp_aux_init);
+
+/**
+ * drm_dp_aux_register() - initialise and register aux channel
+ * @aux: DisplayPort AUX channel
+ *
+ * Automatically calls drm_dp_aux_init() if this hasn't been done yet.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_aux_register(struct drm_dp_aux *aux)
+{
+ int ret;
+
+ if (!aux->ddc.algo)
+ drm_dp_aux_init(aux);
+
aux->ddc.class = I2C_CLASS_DDC;
aux->ddc.owner = THIS_MODULE;
aux->ddc.dev.parent = aux->dev;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 8b2582a..aead9ff 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -34,8 +34,10 @@
#include <linux/slab.h>
#include <drm/drmP.h>
#include <drm/drm_core.h>
+#include "drm_crtc_internal.h"
#include "drm_legacy.h"
#include "drm_internal.h"
+#include "drm_crtc_internal.h"
/*
* drm_debug: Enable debug output.
@@ -93,114 +95,6 @@ void drm_ut_debug_printk(const char *function_name, const char *format, ...)
}
EXPORT_SYMBOL(drm_ut_debug_printk);
-struct drm_master *drm_master_create(struct drm_minor *minor)
-{
- struct drm_master *master;
-
- master = kzalloc(sizeof(*master), GFP_KERNEL);
- if (!master)
- return NULL;
-
- kref_init(&master->refcount);
- spin_lock_init(&master->lock.spinlock);
- init_waitqueue_head(&master->lock.lock_queue);
- idr_init(&master->magic_map);
- master->minor = minor;
-
- return master;
-}
-
-struct drm_master *drm_master_get(struct drm_master *master)
-{
- kref_get(&master->refcount);
- return master;
-}
-EXPORT_SYMBOL(drm_master_get);
-
-static void drm_master_destroy(struct kref *kref)
-{
- struct drm_master *master = container_of(kref, struct drm_master, refcount);
- struct drm_device *dev = master->minor->dev;
-
- if (dev->driver->master_destroy)
- dev->driver->master_destroy(dev, master);
-
- drm_legacy_master_rmmaps(dev, master);
-
- idr_destroy(&master->magic_map);
- kfree(master->unique);
- kfree(master);
-}
-
-void drm_master_put(struct drm_master **master)
-{
- kref_put(&(*master)->refcount, drm_master_destroy);
- *master = NULL;
-}
-EXPORT_SYMBOL(drm_master_put);
-
-int drm_setmaster_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- int ret = 0;
-
- mutex_lock(&dev->master_mutex);
- if (file_priv->is_master)
- goto out_unlock;
-
- if (file_priv->minor->master) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- if (!file_priv->master) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- if (!file_priv->allowed_master) {
- ret = drm_new_set_master(dev, file_priv);
- goto out_unlock;
- }
-
- file_priv->minor->master = drm_master_get(file_priv->master);
- file_priv->is_master = 1;
- if (dev->driver->master_set) {
- ret = dev->driver->master_set(dev, file_priv, false);
- if (unlikely(ret != 0)) {
- file_priv->is_master = 0;
- drm_master_put(&file_priv->minor->master);
- }
- }
-
-out_unlock:
- mutex_unlock(&dev->master_mutex);
- return ret;
-}
-
-int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- int ret = -EINVAL;
-
- mutex_lock(&dev->master_mutex);
- if (!file_priv->is_master)
- goto out_unlock;
-
- if (!file_priv->minor->master)
- goto out_unlock;
-
- ret = 0;
- if (dev->driver->master_drop)
- dev->driver->master_drop(dev, file_priv, false);
- drm_master_put(&file_priv->minor->master);
- file_priv->is_master = 0;
-
-out_unlock:
- mutex_unlock(&dev->master_mutex);
- return ret;
-}
-
/*
* DRM Minors
* A DRM device can provide several char-dev interfaces on the DRM-Major. Each
@@ -405,10 +299,9 @@ void drm_minor_release(struct drm_minor *minor)
* callbacks implemented by the driver. The driver then needs to initialize all
* the various subsystems for the drm device like memory management, vblank
* handling, modesetting support and intial output configuration plus obviously
- * initialize all the corresponding hardware bits. An important part of this is
- * also calling drm_dev_set_unique() to set the userspace-visible unique name of
- * this device instance. Finally when everything is up and running and ready for
- * userspace the device instance can be published using drm_dev_register().
+ * initialize all the corresponding hardware bits. Finally when everything is up
+ * and running and ready for userspace the device instance can be published
+ * using drm_dev_register().
*
* There is also deprecated support for initalizing device instances using
* bus-specific helpers and the ->load() callback. But due to
@@ -430,6 +323,14 @@ void drm_minor_release(struct drm_minor *minor)
* dev_priv field of &drm_device.
*/
+static int drm_dev_set_unique(struct drm_device *dev, const char *name)
+{
+ kfree(dev->unique);
+ dev->unique = kstrdup(name, GFP_KERNEL);
+
+ return dev->unique ? 0 : -ENOMEM;
+}
+
/**
* drm_put_dev - Unregister and release a DRM device
* @dev: DRM device
@@ -549,11 +450,12 @@ static void drm_fs_inode_free(struct inode *inode)
}
/**
- * drm_dev_alloc - Allocate new DRM device
- * @driver: DRM driver to allocate device for
+ * drm_dev_init - Initialise new DRM device
+ * @dev: DRM device
+ * @driver: DRM driver
* @parent: Parent device object
*
- * Allocate and initialize a new DRM device. No device registration is done.
+ * Initialize a new DRM device. No device registration is done.
* Call drm_dev_register() to advertice the device to user space and register it
* with other core subsystems. This should be done last in the device
* initialization sequence to make sure userspace can't access an inconsistent
@@ -564,19 +466,18 @@ static void drm_fs_inode_free(struct inode *inode)
*
* Note that for purely virtual devices @parent can be NULL.
*
+ * Drivers that do not want to allocate their own device struct
+ * embedding struct &drm_device can call drm_dev_alloc() instead.
+ *
* RETURNS:
- * Pointer to new DRM device, or NULL if out of memory.
+ * 0 on success, or error code on failure.
*/
-struct drm_device *drm_dev_alloc(struct drm_driver *driver,
- struct device *parent)
+int drm_dev_init(struct drm_device *dev,
+ struct drm_driver *driver,
+ struct device *parent)
{
- struct drm_device *dev;
int ret;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
-
kref_init(&dev->ref);
dev->dev = parent;
dev->driver = driver;
@@ -617,7 +518,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
if (ret)
goto err_minors;
- if (drm_ht_create(&dev->map_hash, 12))
+ ret = drm_ht_create(&dev->map_hash, 12);
+ if (ret)
goto err_minors;
drm_legacy_ctxbitmap_init(dev);
@@ -630,13 +532,13 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
}
}
- if (parent) {
- ret = drm_dev_set_unique(dev, dev_name(parent));
- if (ret)
- goto err_setunique;
- }
+ /* Use the parent device name as DRM device unique identifier, but fall
+ * back to the driver name for virtual devices like vgem. */
+ ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
+ if (ret)
+ goto err_setunique;
- return dev;
+ return 0;
err_setunique:
if (drm_core_check_feature(dev, DRIVER_GEM))
@@ -651,8 +553,49 @@ err_minors:
drm_fs_inode_free(dev->anon_inode);
err_free:
mutex_destroy(&dev->master_mutex);
- kfree(dev);
- return NULL;
+ return ret;
+}
+EXPORT_SYMBOL(drm_dev_init);
+
+/**
+ * drm_dev_alloc - Allocate new DRM device
+ * @driver: DRM driver to allocate device for
+ * @parent: Parent device object
+ *
+ * Allocate and initialize a new DRM device. No device registration is done.
+ * Call drm_dev_register() to advertice the device to user space and register it
+ * with other core subsystems. This should be done last in the device
+ * initialization sequence to make sure userspace can't access an inconsistent
+ * state.
+ *
+ * The initial ref-count of the object is 1. Use drm_dev_ref() and
+ * drm_dev_unref() to take and drop further ref-counts.
+ *
+ * Note that for purely virtual devices @parent can be NULL.
+ *
+ * Drivers that wish to subclass or embed struct &drm_device into their
+ * own struct should look at using drm_dev_init() instead.
+ *
+ * RETURNS:
+ * Pointer to new DRM device, or NULL if out of memory.
+ */
+struct drm_device *drm_dev_alloc(struct drm_driver *driver,
+ struct device *parent)
+{
+ struct drm_device *dev;
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ ret = drm_dev_init(dev, driver, parent);
+ if (ret) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
}
EXPORT_SYMBOL(drm_dev_alloc);
@@ -716,11 +659,7 @@ EXPORT_SYMBOL(drm_dev_unref);
*
* 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()
- * previously. Right after drm_dev_register() the driver should call
- * drm_connector_register_all() to register all connectors in sysfs. This is
- * a separate call for backward compatibility with drivers still using
- * the deprecated ->load() callback, where connectors are registered from within
- * the ->load() callback.
+ * previously.
*
* Never call this twice on any device!
*
@@ -757,6 +696,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
goto err_minors;
}
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_modeset_register_all(dev);
+
ret = 0;
goto out_unlock;
@@ -787,6 +729,9 @@ void drm_dev_unregister(struct drm_device *dev)
drm_lastclose(dev);
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_modeset_unregister_all(dev);
+
if (dev->driver->unload)
dev->driver->unload(dev);
@@ -804,26 +749,6 @@ void drm_dev_unregister(struct drm_device *dev)
}
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
- * @name: unique name
- *
- * Sets the unique name of a DRM device using the specified string. 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 *name)
-{
- kfree(dev->unique);
- dev->unique = kstrdup(name, GFP_KERNEL);
-
- return dev->unique ? 0 : -ENOMEM;
-}
-EXPORT_SYMBOL(drm_dev_set_unique);
-
/*
* DRM Core
* The DRM core module initializes all global DRM objects and makes them
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0bac524..ce54e98 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -464,7 +464,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
/* Sometimes user space wants everything disabled, so don't steal the
* display if there's a master. */
- if (dev->primary->master)
+ if (lockless_dereference(dev->master))
return false;
drm_for_each_crtc(crtc, dev) {
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index a27bc7cd..323c238 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -40,6 +40,7 @@
#include <linux/module.h>
#include "drm_legacy.h"
#include "drm_internal.h"
+#include "drm_crtc_internal.h"
/* from BKL pushdown */
DEFINE_MUTEX(drm_global_mutex);
@@ -168,60 +169,6 @@ static int drm_cpu_valid(void)
}
/*
- * drm_new_set_master - Allocate a new master object and become master for the
- * associated master realm.
- *
- * @dev: The associated device.
- * @fpriv: File private identifying the client.
- *
- * This function must be called with dev::struct_mutex held.
- * Returns negative error code on failure. Zero on success.
- */
-int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
-{
- struct drm_master *old_master;
- int ret;
-
- lockdep_assert_held_once(&dev->master_mutex);
-
- /* create a new master */
- fpriv->minor->master = drm_master_create(fpriv->minor);
- if (!fpriv->minor->master)
- return -ENOMEM;
-
- /* take another reference for the copy in the local file priv */
- old_master = fpriv->master;
- fpriv->master = drm_master_get(fpriv->minor->master);
-
- if (dev->driver->master_create) {
- ret = dev->driver->master_create(dev, fpriv->master);
- if (ret)
- goto out_err;
- }
- if (dev->driver->master_set) {
- ret = dev->driver->master_set(dev, fpriv, true);
- if (ret)
- goto out_err;
- }
-
- fpriv->is_master = 1;
- fpriv->allowed_master = 1;
- fpriv->authenticated = 1;
- if (old_master)
- drm_master_put(&old_master);
-
- return 0;
-
-out_err:
- /* drop both references and restore old master on failure */
- drm_master_put(&fpriv->minor->master);
- drm_master_put(&fpriv->master);
- fpriv->master = old_master;
-
- return ret;
-}
-
-/*
* Called whenever a process opens /dev/drm.
*
* \param filp file pointer.
@@ -283,19 +230,11 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
goto out_prime_destroy;
}
- /* if there is no current master make this fd it, but do not create
- * any master object for render clients */
- mutex_lock(&dev->master_mutex);
- if (drm_is_primary_client(priv) && !priv->minor->master) {
- /* create a new master */
- ret = drm_new_set_master(dev, priv);
+ if (drm_is_primary_client(priv)) {
+ ret = drm_master_open(priv);
if (ret)
goto out_close;
- } else if (drm_is_primary_client(priv)) {
- /* get a reference to the master */
- priv->master = drm_master_get(priv->minor->master);
}
- mutex_unlock(&dev->master_mutex);
mutex_lock(&dev->filelist_mutex);
list_add(&priv->lhead, &dev->filelist);
@@ -324,7 +263,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
return 0;
out_close:
- mutex_unlock(&dev->master_mutex);
if (dev->driver->postclose)
dev->driver->postclose(dev, priv);
out_prime_destroy:
@@ -338,18 +276,6 @@ out_prime_destroy:
return ret;
}
-static void drm_master_release(struct drm_device *dev, struct file *filp)
-{
- struct drm_file *file_priv = filp->private_data;
-
- if (drm_legacy_i_have_hw_lock(dev, file_priv)) {
- DRM_DEBUG("File %p released, freeing lock for context %d\n",
- filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
- drm_legacy_lock_free(&file_priv->master->lock,
- _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
- }
-}
-
static void drm_events_release(struct drm_file *file_priv)
{
struct drm_device *dev = file_priv->minor->dev;
@@ -451,11 +377,6 @@ int drm_release(struct inode *inode, struct file *filp)
list_del(&file_priv->lhead);
mutex_unlock(&dev->filelist_mutex);
- mutex_lock(&dev->struct_mutex);
- if (file_priv->magic)
- idr_remove(&file_priv->master->magic_map, file_priv->magic);
- mutex_unlock(&dev->struct_mutex);
-
if (dev->driver->preclose)
dev->driver->preclose(dev, file_priv);
@@ -468,9 +389,8 @@ int drm_release(struct inode *inode, struct file *filp)
(long)old_encode_dev(file_priv->minor->kdev->devt),
dev->open_count);
- /* if the master has gone away we can't do anything with the lock */
- if (file_priv->minor->master)
- drm_master_release(dev, filp);
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_legacy_lock_release(dev, filp);
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
drm_legacy_reclaim_buffers(dev, file_priv);
@@ -487,43 +407,12 @@ int drm_release(struct inode *inode, struct file *filp)
drm_legacy_ctxbitmap_flush(dev, file_priv);
- mutex_lock(&dev->master_mutex);
-
- if (file_priv->is_master) {
- struct drm_master *master = file_priv->master;
-
- /*
- * Since the master is disappearing, so is the
- * possibility to lock.
- */
- mutex_lock(&dev->struct_mutex);
- if (master->lock.hw_lock) {
- if (dev->sigdata.lock == master->lock.hw_lock)
- dev->sigdata.lock = NULL;
- master->lock.hw_lock = NULL;
- master->lock.file_priv = NULL;
- wake_up_interruptible_all(&master->lock.lock_queue);
- }
- mutex_unlock(&dev->struct_mutex);
-
- if (file_priv->minor->master == file_priv->master) {
- /* drop the reference held my the minor */
- if (dev->driver->master_drop)
- dev->driver->master_drop(dev, file_priv, true);
- drm_master_put(&file_priv->minor->master);
- }
- }
-
- /* drop the master reference held by the file priv */
- if (file_priv->master)
- drm_master_put(&file_priv->master);
- file_priv->is_master = 0;
- mutex_unlock(&dev->master_mutex);
+ if (drm_is_primary_client(file_priv))
+ drm_master_release(file_priv);
if (dev->driver->postclose)
dev->driver->postclose(dev, file_priv);
-
if (drm_core_check_feature(dev, DRIVER_PRIME))
drm_prime_destroy_file_private(&file_priv->prime);
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 5d469b2..9ae353f 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -50,106 +50,24 @@ int drm_name_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_minor *minor = node->minor;
struct drm_device *dev = minor->dev;
- struct drm_master *master = minor->master;
- if (!master)
- return 0;
-
- if (master->unique) {
- seq_printf(m, "%s %s %s\n",
- dev->driver->name,
- dev_name(dev->dev), master->unique);
- } else {
- seq_printf(m, "%s %s\n",
- dev->driver->name, dev_name(dev->dev));
- }
- return 0;
-}
-
-/**
- * Called when "/proc/dri/.../vm" is read.
- *
- * Prints information about all mappings in drm_device::maplist.
- */
-int drm_vm_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- struct drm_local_map *map;
- struct drm_map_list *r_list;
-
- /* Hardcoded from _DRM_FRAME_BUFFER,
- _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
- _DRM_SCATTER_GATHER and _DRM_CONSISTENT */
- const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
- const char *type;
- int i;
-
- mutex_lock(&dev->struct_mutex);
- seq_printf(m, "slot offset size type flags address mtrr\n\n");
- i = 0;
- list_for_each_entry(r_list, &dev->maplist, head) {
- map = r_list->map;
- if (!map)
- continue;
- if (map->type < 0 || map->type > 5)
- type = "??";
- else
- type = types[map->type];
-
- seq_printf(m, "%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%08lx ",
- i,
- (unsigned long long)map->offset,
- map->size, type, map->flags,
- (unsigned long) r_list->user_token);
- if (map->mtrr < 0)
- seq_printf(m, "none\n");
- else
- seq_printf(m, "%4d\n", map->mtrr);
- i++;
- }
- mutex_unlock(&dev->struct_mutex);
- return 0;
-}
+ struct drm_master *master;
-/**
- * Called when "/proc/dri/.../bufs" is read.
- */
-int drm_bufs_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- struct drm_device_dma *dma;
- int i, seg_pages;
-
- mutex_lock(&dev->struct_mutex);
- dma = dev->dma;
- if (!dma) {
- mutex_unlock(&dev->struct_mutex);
- return 0;
- }
-
- seq_printf(m, " o size count free segs pages kB\n\n");
- for (i = 0; i <= DRM_MAX_ORDER; i++) {
- if (dma->bufs[i].buf_count) {
- seg_pages = dma->bufs[i].seg_count * (1 << dma->bufs[i].page_order);
- seq_printf(m, "%2d %8d %5d %5d %5d %5d %5ld\n",
- i,
- dma->bufs[i].buf_size,
- dma->bufs[i].buf_count,
- 0,
- dma->bufs[i].seg_count,
- seg_pages,
- seg_pages * PAGE_SIZE / 1024);
- }
- }
- seq_printf(m, "\n");
- for (i = 0; i < dma->buf_count; i++) {
- if (i && !(i % 32))
- seq_printf(m, "\n");
- seq_printf(m, " %d", dma->buflist[i]->list);
- }
+ mutex_lock(&dev->master_mutex);
+ master = dev->master;
+ if (!master)
+ goto out_unlock;
+
+ seq_printf(m, "%s", dev->driver->name);
+ if (dev->dev)
+ seq_printf(m, " dev=%s", dev_name(dev->dev));
+ if (master && master->unique)
+ seq_printf(m, " master=%s", master->unique);
+ if (dev->unique)
+ seq_printf(m, " unique=%s", dev->unique);
seq_printf(m, "\n");
- mutex_unlock(&dev->struct_mutex);
+out_unlock:
+ mutex_unlock(&dev->master_mutex);
+
return 0;
}
@@ -184,7 +102,7 @@ int drm_clients_info(struct seq_file *m, void *data)
task ? task->comm : "<unknown>",
pid_vnr(priv->pid),
priv->minor->index,
- priv->is_master ? 'y' : 'n',
+ drm_is_current_master(priv) ? 'y' : 'n',
priv->authenticated ? 'y' : 'n',
from_kuid_munged(seq_user_ns(m), priv->uid),
priv->magic);
@@ -194,7 +112,6 @@ int drm_clients_info(struct seq_file *m, void *data)
return 0;
}
-
static int drm_gem_one_name_info(int id, void *ptr, void *data)
{
struct drm_gem_object *obj = ptr;
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 902cf6a..b86dc9b 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -29,15 +29,9 @@ extern struct mutex drm_global_mutex;
void drm_lastclose(struct drm_device *dev);
/* drm_pci.c */
-int drm_pci_set_unique(struct drm_device *dev,
- struct drm_master *master,
- struct drm_unique *u);
int drm_irq_by_busid(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-/* drm_vm.c */
-int drm_vma_info(struct seq_file *m, void *data);
-
/* drm_prime.c */
int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -51,8 +45,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr
/* drm_info.c */
int drm_name_info(struct seq_file *m, void *data);
-int drm_vm_info(struct seq_file *m, void *data);
-int drm_bufs_info(struct seq_file *m, void *data);
int drm_clients_info(struct seq_file *m, void* data);
int drm_gem_name_info(struct seq_file *m, void *data);
@@ -67,6 +59,12 @@ int drm_getmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int drm_master_open(struct drm_file *file_priv);
+void drm_master_release(struct drm_file *file_priv);
/* drm_sysfs.c */
extern struct class *drm_class;
@@ -92,13 +90,6 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data,
void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
-/* drm_drv.c */
-int drm_setmaster_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-struct drm_master *drm_master_create(struct drm_minor *minor);
-
/* drm_debugfs.c */
#if defined(CONFIG_DEBUG_FS)
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index b7a39771c..1f84ff5 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -30,6 +30,7 @@
#include <drm/drmP.h>
#include <drm/drm_core.h>
+#include <drm/drm_auth.h>
#include "drm_legacy.h"
#include "drm_internal.h"
#include "drm_crtc_internal.h"
@@ -37,6 +38,64 @@
#include <linux/pci.h>
#include <linux/export.h>
+/**
+ * DOC: getunique and setversion story
+ *
+ * BEWARE THE DRAGONS! MIND THE TRAPDOORS!
+ *
+ * In an attempt to warn anyone else who's trying to figure out what's going
+ * on here, I'll try to summarize the story. First things first, let's clear up
+ * the names, because the kernel internals, libdrm and the ioctls are all named
+ * differently:
+ *
+ * - GET_UNIQUE ioctl, implemented by drm_getunique is wrapped up in libdrm
+ * through the drmGetBusid function.
+ * - The libdrm drmSetBusid function is backed by the SET_UNIQUE ioctl. All
+ * that code is nerved in the kernel with drm_invalid_op().
+ * - The internal set_busid kernel functions and driver callbacks are
+ * exclusively use by the SET_VERSION ioctl, because only drm 1.0 (which is
+ * nerved) allowed userspace to set the busid through the above ioctl.
+ * - Other ioctls and functions involved are named consistently.
+ *
+ * For anyone wondering what's the difference between drm 1.1 and 1.4: Correctly
+ * handling pci domains in the busid on ppc. Doing this correctly was only
+ * implemented in libdrm in 2010, hence can't be nerved yet. No one knows what's
+ * special with drm 1.2 and 1.3.
+ *
+ * Now the actual horror story of how device lookup in drm works. At large,
+ * there's 2 different ways, either by busid, or by device driver name.
+ *
+ * Opening by busid is fairly simple:
+ *
+ * 1. First call SET_VERSION to make sure pci domains are handled properly. As a
+ * side-effect this fills out the unique name in the master structure.
+ * 2. Call GET_UNIQUE to read out the unique name from the master structure,
+ * which matches the busid thanks to step 1. If it doesn't, proceed to try
+ * the next device node.
+ *
+ * Opening by name is slightly different:
+ *
+ * 1. Directly call VERSION to get the version and to match against the driver
+ * name returned by that ioctl. Note that SET_VERSION is not called, which
+ * means the the unique name for the master node just opening is _not_ filled
+ * out. This despite that with current drm device nodes are always bound to
+ * one device, and can't be runtime assigned like with drm 1.0.
+ * 2. Match driver name. If it mismatches, proceed to the next device node.
+ * 3. Call GET_UNIQUE, and check whether the unique name has length zero (by
+ * checking that the first byte in the string is 0). If that's not the case
+ * libdrm skips and proceeds to the next device node. Probably this is just
+ * copypasta from drm 1.0 times where a set unique name meant that the driver
+ * was in use already, but that's just conjecture.
+ *
+ * Long story short: To keep the open by name logic working, GET_UNIQUE must
+ * _not_ return a unique string when SET_VERSION hasn't been called yet,
+ * otherwise libdrm breaks. Even when that unique string can't ever change, and
+ * is totally irrelevant for actually opening the device because runtime
+ * assignable device instances were only support in drm 1.0, which is long dead.
+ * But the libdrm code in drmOpenByName somehow survived, hence this can't be
+ * broken.
+ */
+
static int drm_version(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -75,51 +134,6 @@ drm_unset_busid(struct drm_device *dev,
master->unique_len = 0;
}
-/*
- * Set the bus id.
- *
- * \param inode device inode.
- * \param file_priv DRM file private.
- * \param cmd command.
- * \param arg user argument, pointing to a drm_unique structure.
- * \return zero on success or a negative number on failure.
- *
- * Copies the bus id from userspace into drm_device::unique, and verifies that
- * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated
- * in interface version 1.1 and will return EBUSY when setversion has requested
- * version 1.1 or greater. Also note that KMS is all version 1.1 and later and
- * UMS was only ever supported on pci devices.
- */
-static int drm_setunique(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_unique *u = data;
- struct drm_master *master = file_priv->master;
- int ret;
-
- if (master->unique_len || master->unique)
- return -EBUSY;
-
- if (!u->unique_len || u->unique_len > 1024)
- return -EINVAL;
-
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- return 0;
-
- if (WARN_ON(!dev->pdev))
- return -EINVAL;
-
- ret = drm_pci_set_unique(dev, master, u);
- if (ret)
- goto err;
-
- return 0;
-
-err:
- drm_unset_busid(dev, master);
- return ret;
-}
-
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_master *master = file_priv->master;
@@ -135,12 +149,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
return ret;
}
} else {
- if (WARN(dev->unique == NULL,
- "No drm_driver.set_busid() implementation provided by "
- "%ps. Use drm_dev_set_unique() to set the unique "
- "name explicitly.", dev->driver))
- return -EINVAL;
-
+ WARN_ON(!dev->unique);
master->unique = kstrdup(dev->unique, GFP_KERNEL);
if (master->unique)
master->unique_len = strlen(dev->unique);
@@ -473,7 +482,8 @@ int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
return -EACCES;
/* MASTER is only for master or control clients */
- if (unlikely((flags & DRM_MASTER) && !file_priv->is_master &&
+ if (unlikely((flags & DRM_MASTER) &&
+ !drm_is_current_master(file_priv) &&
!drm_is_control_client(file_priv)))
return -EACCES;
@@ -504,7 +514,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version,
DRM_UNLOCKED|DRM_RENDER_ALLOW|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
- DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED),
@@ -513,10 +523,10 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0),
DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
- DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_UNLOCKED|DRM_MASTER),
DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH),
@@ -524,8 +534,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_UNLOCKED|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_UNLOCKED|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 76e39c5..8ca3d2b 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -994,10 +994,10 @@ static void send_vblank_event(struct drm_device *dev,
e->event.tv_sec = now->tv_sec;
e->event.tv_usec = now->tv_usec;
- drm_send_event_locked(dev, &e->base);
-
trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
e->event.sequence);
+
+ drm_send_event_locked(dev, &e->base);
}
/**
diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h
index d3b6ee3..c6f422e 100644
--- a/drivers/gpu/drm/drm_legacy.h
+++ b/drivers/gpu/drm/drm_legacy.h
@@ -88,14 +88,10 @@ struct drm_agp_mem {
struct list_head head;
};
-/*
- * Generic Userspace Locking-API
- */
-
-int drm_legacy_i_have_hw_lock(struct drm_device *d, struct drm_file *f);
+/* drm_lock.c */
int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f);
-int drm_legacy_lock_free(struct drm_lock_data *lock, unsigned int ctx);
+void drm_legacy_lock_release(struct drm_device *dev, struct file *filp);
/* DMA support */
int drm_legacy_dma_setup(struct drm_device *dev);
diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c
index daa2ff1..48ac0eb 100644
--- a/drivers/gpu/drm/drm_lock.c
+++ b/drivers/gpu/drm/drm_lock.c
@@ -41,6 +41,110 @@
static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
/**
+ * Take the heavyweight lock.
+ *
+ * \param lock lock pointer.
+ * \param context locking context.
+ * \return one if the lock is held, or zero otherwise.
+ *
+ * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
+ */
+static
+int drm_lock_take(struct drm_lock_data *lock_data,
+ unsigned int context)
+{
+ unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ spin_lock_bh(&lock_data->spinlock);
+ do {
+ old = *lock;
+ if (old & _DRM_LOCK_HELD)
+ new = old | _DRM_LOCK_CONT;
+ else {
+ new = context | _DRM_LOCK_HELD |
+ ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
+ _DRM_LOCK_CONT : 0);
+ }
+ prev = cmpxchg(lock, old, new);
+ } while (prev != old);
+ spin_unlock_bh(&lock_data->spinlock);
+
+ if (_DRM_LOCKING_CONTEXT(old) == context) {
+ if (old & _DRM_LOCK_HELD) {
+ if (context != DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("%d holds heavyweight lock\n",
+ context);
+ }
+ return 0;
+ }
+ }
+
+ if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
+ /* Have lock */
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * This takes a lock forcibly and hands it to context. Should ONLY be used
+ * inside *_unlock to give lock to kernel before calling *_dma_schedule.
+ *
+ * \param dev DRM device.
+ * \param lock lock pointer.
+ * \param context locking context.
+ * \return always one.
+ *
+ * Resets the lock file pointer.
+ * Marks the lock as held by the given context, via the \p cmpxchg instruction.
+ */
+static int drm_lock_transfer(struct drm_lock_data *lock_data,
+ unsigned int context)
+{
+ unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ lock_data->file_priv = NULL;
+ do {
+ old = *lock;
+ new = context | _DRM_LOCK_HELD;
+ prev = cmpxchg(lock, old, new);
+ } while (prev != old);
+ return 1;
+}
+
+static int drm_legacy_lock_free(struct drm_lock_data *lock_data,
+ unsigned int context)
+{
+ unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ spin_lock_bh(&lock_data->spinlock);
+ if (lock_data->kernel_waiters != 0) {
+ drm_lock_transfer(lock_data, 0);
+ lock_data->idle_has_lock = 1;
+ spin_unlock_bh(&lock_data->spinlock);
+ return 1;
+ }
+ spin_unlock_bh(&lock_data->spinlock);
+
+ do {
+ old = *lock;
+ new = _DRM_LOCKING_CONTEXT(old);
+ prev = cmpxchg(lock, old, new);
+ } while (prev != old);
+
+ if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+ DRM_ERROR("%d freed heavyweight lock held by %d\n",
+ context, _DRM_LOCKING_CONTEXT(old));
+ return 1;
+ }
+ wake_up_interruptible(&lock_data->lock_queue);
+ return 0;
+}
+
+/**
* Lock ioctl.
*
* \param inode device inode.
@@ -115,7 +219,7 @@ int drm_legacy_lock(struct drm_device *dev, void *data,
/* don't set the block all signals on the master process for now
* really probably not the correct answer but lets us debug xkb
* xserver for now */
- if (!file_priv->is_master) {
+ if (!drm_is_current_master(file_priv)) {
dev->sigdata.context = lock->context;
dev->sigdata.lock = master->lock.hw_lock;
}
@@ -165,120 +269,6 @@ int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_
}
/**
- * Take the heavyweight lock.
- *
- * \param lock lock pointer.
- * \param context locking context.
- * \return one if the lock is held, or zero otherwise.
- *
- * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
- */
-static
-int drm_lock_take(struct drm_lock_data *lock_data,
- unsigned int context)
-{
- unsigned int old, new, prev;
- volatile unsigned int *lock = &lock_data->hw_lock->lock;
-
- spin_lock_bh(&lock_data->spinlock);
- do {
- old = *lock;
- if (old & _DRM_LOCK_HELD)
- new = old | _DRM_LOCK_CONT;
- else {
- new = context | _DRM_LOCK_HELD |
- ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
- _DRM_LOCK_CONT : 0);
- }
- prev = cmpxchg(lock, old, new);
- } while (prev != old);
- spin_unlock_bh(&lock_data->spinlock);
-
- if (_DRM_LOCKING_CONTEXT(old) == context) {
- if (old & _DRM_LOCK_HELD) {
- if (context != DRM_KERNEL_CONTEXT) {
- DRM_ERROR("%d holds heavyweight lock\n",
- context);
- }
- return 0;
- }
- }
-
- if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
- /* Have lock */
- return 1;
- }
- return 0;
-}
-
-/**
- * This takes a lock forcibly and hands it to context. Should ONLY be used
- * inside *_unlock to give lock to kernel before calling *_dma_schedule.
- *
- * \param dev DRM device.
- * \param lock lock pointer.
- * \param context locking context.
- * \return always one.
- *
- * Resets the lock file pointer.
- * Marks the lock as held by the given context, via the \p cmpxchg instruction.
- */
-static int drm_lock_transfer(struct drm_lock_data *lock_data,
- unsigned int context)
-{
- unsigned int old, new, prev;
- volatile unsigned int *lock = &lock_data->hw_lock->lock;
-
- lock_data->file_priv = NULL;
- do {
- old = *lock;
- new = context | _DRM_LOCK_HELD;
- prev = cmpxchg(lock, old, new);
- } while (prev != old);
- return 1;
-}
-
-/**
- * Free lock.
- *
- * \param dev DRM device.
- * \param lock lock.
- * \param context context.
- *
- * Resets the lock file pointer.
- * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
- * waiting on the lock queue.
- */
-int drm_legacy_lock_free(struct drm_lock_data *lock_data, unsigned int context)
-{
- unsigned int old, new, prev;
- volatile unsigned int *lock = &lock_data->hw_lock->lock;
-
- spin_lock_bh(&lock_data->spinlock);
- if (lock_data->kernel_waiters != 0) {
- drm_lock_transfer(lock_data, 0);
- lock_data->idle_has_lock = 1;
- spin_unlock_bh(&lock_data->spinlock);
- return 1;
- }
- spin_unlock_bh(&lock_data->spinlock);
-
- do {
- old = *lock;
- new = _DRM_LOCKING_CONTEXT(old);
- prev = cmpxchg(lock, old, new);
- } while (prev != old);
-
- if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
- DRM_ERROR("%d freed heavyweight lock held by %d\n",
- context, _DRM_LOCKING_CONTEXT(old));
- return 1;
- }
- wake_up_interruptible(&lock_data->lock_queue);
- return 0;
-}
-
-/**
* This function returns immediately and takes the hw lock
* with the kernel context if it is free, otherwise it gets the highest priority when and if
* it is eventually released.
@@ -330,11 +320,27 @@ void drm_legacy_idlelock_release(struct drm_lock_data *lock_data)
}
EXPORT_SYMBOL(drm_legacy_idlelock_release);
-int drm_legacy_i_have_hw_lock(struct drm_device *dev,
- struct drm_file *file_priv)
+static int drm_legacy_i_have_hw_lock(struct drm_device *dev,
+ struct drm_file *file_priv)
{
struct drm_master *master = file_priv->master;
return (file_priv->lock_count && master->lock.hw_lock &&
_DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
master->lock.file_priv == file_priv);
}
+
+void drm_legacy_lock_release(struct drm_device *dev, struct file *filp)
+{
+ struct drm_file *file_priv = filp->private_data;
+
+ /* if the master has gone away we can't do anything with the lock */
+ if (!dev->master)
+ return;
+
+ if (drm_legacy_i_have_hw_lock(dev, file_priv)) {
+ DRM_DEBUG("File %p released, freeing lock for context %d\n",
+ filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+ drm_legacy_lock_free(&file_priv->master->lock,
+ _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+ }
+}
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 29d5a54..b2f8f10 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -144,50 +144,6 @@ int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
}
EXPORT_SYMBOL(drm_pci_set_busid);
-int drm_pci_set_unique(struct drm_device *dev,
- struct drm_master *master,
- struct drm_unique *u)
-{
- int domain, bus, slot, func, ret;
-
- master->unique_len = u->unique_len;
- master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
- if (!master->unique) {
- ret = -ENOMEM;
- goto err;
- }
-
- if (copy_from_user(master->unique, u->unique, master->unique_len)) {
- ret = -EFAULT;
- goto err;
- }
-
- master->unique[master->unique_len] = '\0';
-
- /* Return error if the busid submitted doesn't match the device's actual
- * busid.
- */
- ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
- if (ret != 3) {
- ret = -EINVAL;
- goto err;
- }
-
- domain = bus >> 8;
- bus &= 0xff;
-
- if ((domain != drm_get_pci_domain(dev)) ||
- (bus != dev->pdev->bus->number) ||
- (slot != PCI_SLOT(dev->pdev->devfn)) ||
- (func != PCI_FUNC(dev->pdev->devfn))) {
- ret = -EINVAL;
- goto err;
- }
- return 0;
-err:
- return ret;
-}
-
static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
{
if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
@@ -444,13 +400,6 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
{
return -EINVAL;
}
-
-int drm_pci_set_unique(struct drm_device *dev,
- struct drm_master *master,
- struct drm_unique *u)
-{
- return -EINVAL;
-}
#endif
EXPORT_SYMBOL(drm_pci_init);
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index fc51306..16c4a7b 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -115,6 +115,7 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
* @src: source coordinates in 16.16 fixed point
* @dest: integer destination coordinates
* @clip: integer clipping coordinates
+ * @rotation: plane rotation
* @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
* @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
* @can_position: is it legal to position the plane such that it
@@ -134,16 +135,17 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
* Zero if update appears valid, error code on failure
*/
int drm_plane_helper_check_update(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_rect *src,
- struct drm_rect *dest,
- const struct drm_rect *clip,
- int min_scale,
- int max_scale,
- bool can_position,
- bool can_update_disabled,
- bool *visible)
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_rect *src,
+ struct drm_rect *dest,
+ const struct drm_rect *clip,
+ unsigned int rotation,
+ int min_scale,
+ int max_scale,
+ bool can_position,
+ bool can_update_disabled,
+ bool *visible)
{
int hscale, vscale;
@@ -163,6 +165,8 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
return -EINVAL;
}
+ drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
+
/* Check scaling */
hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale);
vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
@@ -174,6 +178,9 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
}
*visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
+
+ drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
+
if (!*visible)
/*
* Plane isn't visible; some drivers can handle this
@@ -267,6 +274,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
ret = drm_plane_helper_check_update(plane, crtc, fb,
&src, &dest, &clip,
+ BIT(DRM_ROTATE_0),
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, false, &visible);
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index 644169e..2c819ef 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -68,24 +68,6 @@ err_free:
return ret;
}
-int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
-{
- int id;
-
- id = dev->platformdev->id;
- if (id < 0)
- id = 0;
-
- master->unique = kasprintf(GFP_KERNEL, "platform:%s:%02d",
- dev->platformdev->name, id);
- if (!master->unique)
- return -ENOMEM;
-
- master->unique_len = strlen(master->unique);
- return 0;
-}
-EXPORT_SYMBOL(drm_platform_set_busid);
-
/**
* drm_platform_init - Register a platform device with the DRM subsystem
* @driver: DRM device driver
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index b2071d4..0db36d2 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -105,6 +105,7 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
ret = drm_plane_helper_check_update(plane, &pipe->crtc,
plane_state->fb,
&src, &dest, &clip,
+ plane_state->rotation,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true, &visible);
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index ac9f4b3..43ff44a 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -670,57 +670,3 @@ void drm_legacy_vma_flush(struct drm_device *dev)
kfree(vma);
}
}
-
-int drm_vma_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- struct drm_vma_entry *pt;
- struct vm_area_struct *vma;
- unsigned long vma_count = 0;
-#if defined(__i386__)
- unsigned int pgprot;
-#endif
-
- mutex_lock(&dev->struct_mutex);
- list_for_each_entry(pt, &dev->vmalist, head)
- vma_count++;
-
- seq_printf(m, "vma use count: %lu, high_memory = %pK, 0x%pK\n",
- vma_count, high_memory,
- (void *)(unsigned long)virt_to_phys(high_memory));
-
- list_for_each_entry(pt, &dev->vmalist, head) {
- vma = pt->vma;
- if (!vma)
- continue;
- seq_printf(m,
- "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
- pt->pid,
- (void *)vma->vm_start, (void *)vma->vm_end,
- vma->vm_flags & VM_READ ? 'r' : '-',
- vma->vm_flags & VM_WRITE ? 'w' : '-',
- vma->vm_flags & VM_EXEC ? 'x' : '-',
- vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
- vma->vm_flags & VM_LOCKED ? 'l' : '-',
- vma->vm_flags & VM_IO ? 'i' : '-',
- vma->vm_pgoff);
-
-#if defined(__i386__)
- pgprot = pgprot_val(vma->vm_page_prot);
- seq_printf(m, " %c%c%c%c%c%c%c%c%c",
- pgprot & _PAGE_PRESENT ? 'p' : '-',
- pgprot & _PAGE_RW ? 'w' : 'r',
- pgprot & _PAGE_USER ? 'u' : 's',
- pgprot & _PAGE_PWT ? 't' : 'b',
- pgprot & _PAGE_PCD ? 'u' : 'c',
- pgprot & _PAGE_ACCESSED ? 'a' : '-',
- pgprot & _PAGE_DIRTY ? 'd' : '-',
- pgprot & _PAGE_PSE ? 'm' : 'k',
- pgprot & _PAGE_GLOBAL ? 'g' : 'l');
-#endif
- seq_printf(m, "\n");
- }
- mutex_unlock(&dev->struct_mutex);
- return 0;
-}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 3d4f56d..340d390 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -496,7 +496,6 @@ static struct drm_driver etnaviv_drm_driver = {
DRIVER_RENDER,
.open = etnaviv_open,
.preclose = etnaviv_preclose,
- .set_busid = drm_platform_set_busid,
.gem_free_object_unlocked = etnaviv_gem_free_object,
.gem_vm_ops = &vm_ops,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 4a679fb..13d28d4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -407,7 +407,6 @@ static struct drm_driver exynos_drm_driver = {
.preclose = exynos_drm_preclose,
.lastclose = exynos_drm_lastclose,
.postclose = exynos_drm_postclose,
- .set_busid = drm_platform_set_busid,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = exynos_drm_crtc_enable_vblank,
.disable_vblank = exynos_drm_crtc_disable_vblank,
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
index c564ec6..a6e4cd5 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
@@ -37,23 +37,22 @@ int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
ret = fsl_dcu_drm_crtc_create(fsl_dev);
if (ret)
- return ret;
+ goto err;
ret = fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
if (ret)
- goto fail_encoder;
+ goto err;
ret = fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
if (ret)
- goto fail_connector;
+ goto err;
drm_mode_config_reset(fsl_dev->drm);
drm_kms_helper_poll_init(fsl_dev->drm);
return 0;
-fail_encoder:
- fsl_dev->crtc.funcs->destroy(&fsl_dev->crtc);
-fail_connector:
- fsl_dev->encoder.funcs->destroy(&fsl_dev->encoder);
+
+err:
+ drm_mode_config_cleanup(fsl_dev->drm);
return ret;
}
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
index 1936572..1edd9bc 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -171,7 +171,6 @@ static struct drm_driver kirin_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
.fops = &kirin_drm_fops,
- .set_busid = drm_platform_set_busid,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
@@ -221,19 +220,12 @@ static int kirin_drm_bind(struct device *dev)
if (ret)
goto err_kms_cleanup;
- /* connectors should be registered after drm device register */
- ret = drm_connector_register_all(drm_dev);
- if (ret)
- goto err_drm_dev_unregister;
-
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, drm_dev->primary->index);
return 0;
-err_drm_dev_unregister:
- drm_dev_unregister(drm_dev);
err_kms_cleanup:
kirin_drm_kms_cleanup(drm_dev);
err_drm_dev_unref:
@@ -246,7 +238,6 @@ static void kirin_drm_unbind(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
- drm_connector_unregister_all(drm_dev);
drm_dev_unregister(drm_dev);
kirin_drm_kms_cleanup(drm_dev);
drm_dev_unref(drm_dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index de4bf36..24a86c6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -47,6 +47,7 @@
#include <drm/intel-gtt.h>
#include <drm/drm_legacy.h> /* for struct drm_dma_handle */
#include <drm/drm_gem.h>
+#include <drm/drm_auth.h>
#include "i915_params.h"
#include "i915_reg.h"
@@ -3720,7 +3721,7 @@ extern void intel_modeset_init_hw(struct drm_device *dev);
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
-extern void intel_connector_unregister(struct intel_connector *);
+extern void intel_connector_unregister(struct drm_connector *);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void intel_display_resume(struct drm_device *dev);
extern void i915_redisable_vga(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 8097698..7941f1f 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1446,7 +1446,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
dispatch_flags = 0;
if (args->flags & I915_EXEC_SECURE) {
- if (!file->is_master || !capable(CAP_SYS_ADMIN))
+ if (!drm_is_current_master(file) || !capable(CAP_SYS_ADMIN))
return -EPERM;
dispatch_flags |= I915_DISPATCH_SECURE;
@@ -1553,7 +1553,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
batch_obj,
args->batch_start_offset,
args->batch_len,
- file->is_master);
+ drm_is_current_master(file));
if (IS_ERR(parsed_batch_obj)) {
ret = PTR_ERR(parsed_batch_obj);
goto err;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 9465de4..e115bcc 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -743,6 +743,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = intel_crt_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_crt_destroy,
.set_property = intel_crt_set_property,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -875,7 +876,6 @@ void intel_crt_init(struct drm_device *dev)
crt->base.get_hw_state = intel_crt_get_hw_state;
}
intel_connector->get_hw_state = intel_connector_get_hw_state;
- intel_connector->unregister = intel_connector_unregister;
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8c6f4e2..0b2cd66 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -14184,6 +14184,7 @@ intel_check_primary_plane(struct drm_plane *plane,
return drm_plane_helper_check_update(plane, crtc, fb, &state->src,
&state->dst, &state->clip,
+ state->base.rotation,
min_scale, max_scale,
can_position, true,
&state->visible);
@@ -14375,6 +14376,7 @@ intel_check_cursor_plane(struct drm_plane *plane,
ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src,
&state->dst, &state->clip,
+ state->base.rotation,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true, &state->visible);
@@ -16311,23 +16313,20 @@ void intel_modeset_gem_init(struct drm_device *dev)
intel_backlight_register(dev);
}
-void intel_connector_unregister(struct intel_connector *intel_connector)
+void intel_connector_unregister(struct drm_connector *connector)
{
- struct drm_connector *connector = &intel_connector->base;
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+ intel_backlight_device_unregister(intel_connector);
intel_panel_destroy_backlight(connector);
- drm_connector_unregister(connector);
}
void intel_modeset_cleanup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_connector *connector;
intel_disable_gt_powersave(dev_priv);
- intel_backlight_unregister(dev);
-
/*
* Interrupts and polling as the first thing to avoid creating havoc.
* Too much stuff here (turning of connectors, ...) would
@@ -16348,9 +16347,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
/* flush any delayed tasks or pending work */
flush_scheduled_work();
- /* destroy the backlight and sysfs files before encoders/connectors */
- for_each_intel_connector(dev, connector)
- connector->unregister(connector);
+ drm_connector_unregister_all(dev);
drm_mode_config_cleanup(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index be08351..0b84f8e 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1177,7 +1177,6 @@ static void intel_aux_reg_init(struct intel_dp *intel_dp)
static void
intel_dp_aux_fini(struct intel_dp *intel_dp)
{
- drm_dp_aux_unregister(&intel_dp->aux);
kfree(intel_dp->aux.name);
}
@@ -1212,15 +1211,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
return 0;
}
-static void
-intel_dp_connector_unregister(struct intel_connector *intel_connector)
-{
- struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
-
- intel_dp_aux_fini(intel_dp);
- intel_connector_unregister(intel_connector);
-}
-
static int
intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
{
@@ -4457,6 +4447,13 @@ done:
}
static void
+intel_dp_connector_unregister(struct drm_connector *connector)
+{
+ drm_dp_aux_unregister(&intel_attached_dp(connector)->aux);
+ intel_connector_unregister(connector);
+}
+
+static void
intel_dp_connector_destroy(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -4496,6 +4493,9 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
intel_dp->edp_notifier.notifier_call = NULL;
}
}
+
+ intel_dp_aux_fini(intel_dp);
+
drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
}
@@ -4572,6 +4572,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property,
.atomic_get_property = intel_connector_atomic_get_property,
+ .early_unregister = intel_dp_connector_unregister,
.destroy = intel_dp_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -5487,7 +5488,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
else
intel_connector->get_hw_state = intel_connector_get_hw_state;
- intel_connector->unregister = intel_dp_connector_unregister;
/* Set up the hotplug pin. */
switch (port) {
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index f62ca9a..9646816 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -336,6 +336,7 @@ static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_mst_set_property,
.atomic_get_property = intel_connector_atomic_get_property,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_dp_mst_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -455,7 +456,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
- intel_connector->unregister = intel_connector_unregister;
intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
intel_connector->mst_port = intel_dp;
intel_connector->port = port;
@@ -489,7 +489,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_device *dev = connector->dev;
- intel_connector->unregister(intel_connector);
+ drm_connector_unregister(connector);
/* need to nuke the connector */
drm_modeset_lock_all(dev);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0c1dc9b..7d0e071 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -242,14 +242,6 @@ struct intel_connector {
* and active (i.e. dpms ON state). */
bool (*get_hw_state)(struct intel_connector *);
- /*
- * Removes all interfaces through which the connector is accessible
- * - like sysfs, debugfs entries -, so that no new operations can be
- * started on the connector. Also makes sure all currently pending
- * operations finish before returing.
- */
- void (*unregister)(struct intel_connector *);
-
/* Panel info for eDP and LVDS */
struct intel_panel panel;
@@ -1509,7 +1501,14 @@ extern struct drm_display_mode *intel_find_panel_downclock(
struct drm_display_mode *fixed_mode,
struct drm_connector *connector);
void intel_backlight_register(struct drm_device *dev);
-void intel_backlight_unregister(struct drm_device *dev);
+
+#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
+void intel_backlight_device_unregister(struct intel_connector *connector);
+#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+static inline void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+}
+#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
/* intel_psr.c */
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 10e1282..b444d0e3 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -1390,6 +1390,7 @@ static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs
static const struct drm_connector_funcs intel_dsi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = intel_dsi_detect,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_dsi_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dsi_set_property,
@@ -1466,7 +1467,6 @@ void intel_dsi_init(struct drm_device *dev)
intel_encoder->get_config = intel_dsi_get_config;
intel_connector->get_hw_state = intel_connector_get_hw_state;
- intel_connector->unregister = intel_connector_unregister;
/*
* On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index c86f88e..60e4ddf 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -341,6 +341,7 @@ static void intel_dvo_destroy(struct drm_connector *connector)
static const struct drm_connector_funcs intel_dvo_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = intel_dvo_detect,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_dvo_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_connector_atomic_get_property,
@@ -447,7 +448,6 @@ void intel_dvo_init(struct drm_device *dev)
intel_encoder->compute_config = intel_dvo_compute_config;
intel_encoder->pre_enable = intel_dvo_pre_enable;
intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
- intel_connector->unregister = intel_connector_unregister;
/* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index ad0c71b..fb21626 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1774,6 +1774,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_hdmi_set_property,
.atomic_get_property = intel_connector_atomic_get_property,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_hdmi_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1909,7 +1910,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
else
intel_connector->get_hw_state = intel_connector_get_hw_state;
- intel_connector->unregister = intel_connector_unregister;
intel_hdmi_add_properties(intel_hdmi, connector);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index e06b903..e908218 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -555,6 +555,7 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_lvds_set_property,
.atomic_get_property = intel_connector_atomic_get_property,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_lvds_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -991,7 +992,6 @@ void intel_lvds_init(struct drm_device *dev)
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
intel_encoder->get_config = intel_lvds_get_config;
intel_connector->get_hw_state = intel_connector_get_hw_state;
- intel_connector->unregister = intel_connector_unregister;
intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_LVDS;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index f0b1602c..bf72178 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -1216,7 +1216,7 @@ static int intel_backlight_device_register(struct intel_connector *connector)
return 0;
}
-static void intel_backlight_device_unregister(struct intel_connector *connector)
+void intel_backlight_device_unregister(struct intel_connector *connector)
{
struct intel_panel *panel = &connector->panel;
@@ -1230,9 +1230,6 @@ static int intel_backlight_device_register(struct intel_connector *connector)
{
return 0;
}
-static void intel_backlight_device_unregister(struct intel_connector *connector)
-{
-}
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
/*
@@ -1820,11 +1817,3 @@ void intel_backlight_register(struct drm_device *dev)
for_each_intel_connector(dev, connector)
intel_backlight_device_register(connector);
}
-
-void intel_backlight_unregister(struct drm_device *dev)
-{
- struct intel_connector *connector;
-
- for_each_intel_connector(dev, connector)
- intel_backlight_device_unregister(connector);
-}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index ab2d065..02b4a66 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2177,12 +2177,23 @@ done:
#undef CHECK_PROPERTY
}
+static void
+intel_sdvo_connector_unregister(struct drm_connector *connector)
+{
+ struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+
+ sysfs_remove_link(&connector->kdev->kobj,
+ sdvo->ddc.dev.kobj.name);
+ intel_connector_unregister(connector);
+}
+
static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = intel_sdvo_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_sdvo_set_property,
.atomic_get_property = intel_connector_atomic_get_property,
+ .early_unregister = intel_sdvo_connector_unregister,
.destroy = intel_sdvo_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -2345,20 +2356,6 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo)
return 0x72;
}
-static void
-intel_sdvo_connector_unregister(struct intel_connector *intel_connector)
-{
- struct drm_connector *drm_connector;
- struct intel_sdvo *sdvo_encoder;
-
- drm_connector = &intel_connector->base;
- sdvo_encoder = intel_attached_sdvo(&intel_connector->base);
-
- sysfs_remove_link(&drm_connector->kdev->kobj,
- sdvo_encoder->ddc.dev.kobj.name);
- intel_connector_unregister(intel_connector);
-}
-
static int
intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
struct intel_sdvo *encoder)
@@ -2381,7 +2378,6 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
connector->base.base.doublescan_allowed = 0;
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
- connector->base.unregister = intel_sdvo_connector_unregister;
intel_connector_attach_encoder(&connector->base, &encoder->base);
ret = drm_connector_register(drm_connector);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 7ac9e9b..4ce70a9 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1501,6 +1501,7 @@ out:
static const struct drm_connector_funcs intel_tv_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = intel_tv_detect,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_tv_destroy,
.set_property = intel_tv_set_property,
.atomic_get_property = intel_connector_atomic_get_property,
@@ -1599,7 +1600,6 @@ intel_tv_init(struct drm_device *dev)
intel_encoder->disable = intel_disable_tv;
intel_encoder->get_hw_state = intel_tv_get_hw_state;
intel_connector->get_hw_state = intel_connector_get_hw_state;
- intel_connector->unregister = intel_connector_unregister;
intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_encoder->type = INTEL_OUTPUT_TVOUT;
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 8265665..7746418 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -407,7 +407,6 @@ static struct drm_driver imx_drm_driver = {
.load = imx_drm_driver_load,
.unload = imx_drm_driver_unload,
.lastclose = imx_drm_driver_lastclose,
- .set_busid = drm_platform_set_busid,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create,
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
index eeefc97..9eefece 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -6,7 +6,6 @@ config DRM_MEDIATEK
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
- select IOMMU_DMA
select MEMORY
select MTK_SMI
help
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index c33bf98..eebb7d8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -280,8 +280,6 @@ static int mtk_drm_bind(struct device *dev)
if (!drm)
return -ENOMEM;
- drm_dev_set_unique(drm, dev_name(dev));
-
drm->dev_private = private;
private->drm = drm;
@@ -293,14 +291,8 @@ static int mtk_drm_bind(struct device *dev)
if (ret < 0)
goto err_deinit;
- ret = drm_connector_register_all(drm);
- if (ret < 0)
- goto err_unregister;
-
return 0;
-err_unregister:
- drm_dev_unregister(drm);
err_deinit:
mtk_drm_kms_deinit(drm);
err_free:
@@ -455,7 +447,6 @@ static int mtk_drm_remove(struct platform_device *pdev)
struct drm_device *drm = private->drm;
int i;
- drm_connector_unregister_all(drm);
drm_dev_unregister(drm);
mtk_drm_kms_deinit(drm);
drm_dev_unref(drm);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 51bc898..3995765 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -170,6 +170,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
return drm_plane_helper_check_update(plane, state->crtc, fb,
&src, &dest, &clip,
+ state->rotation,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true, &visible);
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 9c65409..a02dc2b 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -197,8 +197,6 @@ static int msm_drm_uninit(struct device *dev)
drm_kms_helper_poll_fini(ddev);
- drm_connector_unregister_all(ddev);
-
drm_dev_unregister(ddev);
#ifdef CONFIG_DRM_FBDEV_EMULATION
@@ -431,12 +429,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
if (ret)
goto fail;
- ret = drm_connector_register_all(ddev);
- if (ret) {
- dev_err(dev, "failed to register connectors\n");
- goto fail;
- }
-
drm_mode_config_reset(ddev);
#ifdef CONFIG_DRM_FBDEV_EMULATION
@@ -730,7 +722,6 @@ static struct drm_driver msm_driver = {
.open = msm_open,
.preclose = msm_preclose,
.lastclose = msm_lastclose,
- .set_busid = drm_platform_set_busid,
.irq_handler = msm_irq,
.irq_preinstall = msm_irq_preinstall,
.irq_postinstall = msm_irq_postinstall,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index c00ff6e..295e762 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -1070,7 +1070,6 @@ nouveau_drm_init(void)
driver_pci = driver_stub;
driver_pci.set_busid = drm_pci_set_busid;
driver_platform = driver_stub;
- driver_platform.set_busid = drm_platform_set_busid;
nouveau_display_options();
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 6b97011..26c6134 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -801,7 +801,6 @@ static struct drm_driver omap_drm_driver = {
.unload = dev_unload,
.open = dev_open,
.lastclose = dev_lastclose,
- .set_busid = drm_platform_set_busid,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = omap_irq_enable_vblank,
.disable_vblank = omap_irq_disable_vblank,
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 31dfa08..adb10fb 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -279,9 +279,6 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
if (ret)
goto fini;
- /* disable all the possible outputs/crtcs before entering KMS mode */
- drm_helper_disable_unused_functions(dev);
-
ret = drm_fb_helper_initial_config(helper, 32);
if (ret)
goto fini;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 48ec4b6..d1c0512 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -278,7 +278,6 @@ static int rcar_du_remove(struct platform_device *pdev)
struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
struct drm_device *ddev = rcdu->ddev;
- drm_connector_unregister_all(ddev);
drm_dev_unregister(ddev);
if (rcdu->fbdev)
@@ -320,8 +319,6 @@ static int rcar_du_probe(struct platform_device *pdev)
if (!ddev)
return -ENOMEM;
- drm_dev_set_unique(ddev, dev_name(&pdev->dev));
-
rcdu->ddev = ddev;
ddev->dev_private = rcdu;
@@ -360,10 +357,6 @@ static int rcar_du_probe(struct platform_device *pdev)
if (ret)
goto error;
- ret = drm_connector_register_all(ddev);
- if (ret < 0)
- goto error;
-
DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
return 0;
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index d30bdc3..e48611e 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -2,6 +2,7 @@ config DRM_ROCKCHIP
tristate "DRM Support for Rockchip"
depends on DRM && ROCKCHIP_IOMMU
depends on RESET_CONTROLLER
+ select DRM_GEM_CMA_HELPER
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select DRM_PANEL
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index c2bcc5e..d665fb0 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -146,16 +146,12 @@ static int rockchip_drm_bind(struct device *dev)
if (!drm_dev)
return -ENOMEM;
- ret = drm_dev_register(drm_dev, 0);
- if (ret)
- goto err_free;
-
dev_set_drvdata(dev, drm_dev);
private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
if (!private) {
ret = -ENOMEM;
- goto err_unregister;
+ goto err_free;
}
drm_dev->dev_private = private;
@@ -197,12 +193,6 @@ static int rockchip_drm_bind(struct device *dev)
if (ret)
goto err_detach_device;
- ret = drm_connector_register_all(drm_dev);
- if (ret) {
- dev_err(dev, "failed to register connectors\n");
- goto err_unbind;
- }
-
/* init kms poll for handling hpd */
drm_kms_helper_poll_init(drm_dev);
@@ -222,14 +212,19 @@ static int rockchip_drm_bind(struct device *dev)
if (ret)
goto err_vblank_cleanup;
+ ret = drm_dev_register(drm_dev, 0);
+ if (ret)
+ goto err_fbdev_fini;
+
if (is_support_iommu)
arm_iommu_release_mapping(mapping);
return 0;
+err_fbdev_fini:
+ rockchip_drm_fbdev_fini(drm_dev);
err_vblank_cleanup:
drm_vblank_cleanup(drm_dev);
err_kms_helper_poll_fini:
drm_kms_helper_poll_fini(drm_dev);
-err_unbind:
component_unbind_all(dev, drm_dev);
err_detach_device:
if (is_support_iommu)
@@ -240,8 +235,6 @@ err_release_mapping:
err_config_cleanup:
drm_mode_config_cleanup(drm_dev);
drm_dev->dev_private = NULL;
-err_unregister:
- drm_dev_unregister(drm_dev);
err_free:
drm_dev_unref(drm_dev);
return ret;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 8cd840f..6255e5b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -626,6 +626,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
ret = drm_plane_helper_check_update(plane, crtc, state->fb,
src, dest, &clip,
+ state->rotation,
min_scale,
max_scale,
true, true, &visible);
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index ee79264..f049260 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -259,7 +259,6 @@ static struct drm_driver shmob_drm_driver = {
| DRIVER_PRIME,
.load = shmob_drm_load,
.unload = shmob_drm_unload,
- .set_busid = drm_platform_set_busid,
.irq_handler = shmob_drm_irq,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = shmob_drm_enable_vblank,
diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c
index 93ad8a5..03defda 100644
--- a/drivers/gpu/drm/sis/sis_mm.c
+++ b/drivers/gpu/drm/sis/sis_mm.c
@@ -316,7 +316,7 @@ void sis_reclaim_buffers_locked(struct drm_device *dev,
struct sis_file_private *file_priv = file->driver_priv;
struct sis_memblock *entry, *next;
- if (!(file->minor->master && file->master->lock.hw_lock))
+ if (!(dev->master && file->master->lock.hw_lock))
return;
drm_legacy_idlelock_take(&file->master->lock);
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index 3d2fa3a..794148f 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -55,6 +55,26 @@ struct sti_compositor_data stih416_compositor_data = {
},
};
+int sti_compositor_debufs_init(struct sti_compositor *compo,
+ struct drm_minor *minor)
+{
+ int ret = 0, i;
+
+ for (i = 0; compo->vid[i]; i++) {
+ ret = vid_debugfs_init(compo->vid[i], minor);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; compo->mixer[i]; i++) {
+ ret = sti_mixer_debugfs_init(compo->mixer[i], minor);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int sti_compositor_bind(struct device *dev,
struct device *master,
void *data)
diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h
index 1a4a73d..24444ef 100644
--- a/drivers/gpu/drm/sti/sti_compositor.h
+++ b/drivers/gpu/drm/sti/sti_compositor.h
@@ -81,4 +81,7 @@ struct sti_compositor {
struct notifier_block vtg_vblank_nb;
};
+int sti_compositor_debufs_init(struct sti_compositor *compo,
+ struct drm_minor *minor);
+
#endif
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index e04deed..7fab3af 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -331,6 +331,17 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
}
}
+static int sti_crtc_late_register(struct drm_crtc *crtc)
+{
+ struct sti_mixer *mixer = to_sti_mixer(crtc);
+ struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
+
+ if (drm_crtc_index(crtc) == 0)
+ return sti_compositor_debufs_init(compo, crtc->dev->primary);
+
+ return 0;
+}
+
static const struct drm_crtc_funcs sti_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
@@ -339,6 +350,7 @@ static const struct drm_crtc_funcs sti_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .late_register = sti_crtc_late_register,
};
bool sti_crtc_is_main(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 53aa002..a263bbb 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -329,6 +329,33 @@ static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
.atomic_disable = sti_cursor_atomic_disable,
};
+static void sti_cursor_destroy(struct drm_plane *drm_plane)
+{
+ DRM_DEBUG_DRIVER("\n");
+
+ drm_plane_helper_disable(drm_plane);
+ drm_plane_cleanup(drm_plane);
+}
+
+static int sti_cursor_late_register(struct drm_plane *drm_plane)
+{
+ struct sti_plane *plane = to_sti_plane(drm_plane);
+ struct sti_cursor *cursor = to_sti_cursor(plane);
+
+ return cursor_debugfs_init(cursor, drm_plane->dev->primary);
+}
+
+struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = sti_cursor_destroy,
+ .set_property = sti_plane_set_property,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .late_register = sti_cursor_late_register,
+};
+
struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
struct device *dev, int desc,
void __iomem *baseaddr,
@@ -363,7 +390,7 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
possible_crtcs,
- &sti_plane_helpers_funcs,
+ &sti_cursor_plane_helpers_funcs,
cursor_supported_formats,
ARRAY_SIZE(cursor_supported_formats),
DRM_PLANE_TYPE_CURSOR, NULL);
@@ -377,9 +404,6 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
- if (cursor_debugfs_init(cursor, drm_dev->primary))
- DRM_ERROR("CURSOR debugfs setup failed\n");
-
return &cursor->plane.drm_plane;
err_plane:
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index dd2c400..96bd3d0 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -226,8 +226,28 @@ static int sti_atomic_commit(struct drm_device *drm,
return 0;
}
+static void sti_output_poll_changed(struct drm_device *ddev)
+{
+ struct sti_private *private = ddev->dev_private;
+
+ if (!ddev->mode_config.num_connector)
+ return;
+
+ if (private->fbdev) {
+ drm_fbdev_cma_hotplug_event(private->fbdev);
+ return;
+ }
+
+ private->fbdev = drm_fbdev_cma_init(ddev, 32,
+ ddev->mode_config.num_crtc,
+ ddev->mode_config.num_connector);
+ if (IS_ERR(private->fbdev))
+ private->fbdev = NULL;
+}
+
static const struct drm_mode_config_funcs sti_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
+ .output_poll_changed = sti_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = sti_atomic_commit,
};
@@ -248,45 +268,6 @@ static void sti_mode_config_init(struct drm_device *dev)
dev->mode_config.funcs = &sti_mode_config_funcs;
}
-static int sti_load(struct drm_device *dev, unsigned long flags)
-{
- struct sti_private *private;
- int ret;
-
- private = kzalloc(sizeof(*private), GFP_KERNEL);
- if (!private) {
- DRM_ERROR("Failed to allocate private\n");
- return -ENOMEM;
- }
- dev->dev_private = (void *)private;
- private->drm_dev = dev;
-
- mutex_init(&private->commit.lock);
- INIT_WORK(&private->commit.work, sti_atomic_work);
-
- drm_mode_config_init(dev);
- drm_kms_helper_poll_init(dev);
-
- sti_mode_config_init(dev);
-
- ret = component_bind_all(dev->dev, dev);
- if (ret) {
- drm_kms_helper_poll_fini(dev);
- drm_mode_config_cleanup(dev);
- kfree(private);
- return ret;
- }
-
- drm_mode_config_reset(dev);
-
- drm_helper_disable_unused_functions(dev);
- drm_fbdev_cma_init(dev, 32,
- dev->mode_config.num_crtc,
- dev->mode_config.num_connector);
-
- return 0;
-}
-
static const struct file_operations sti_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
@@ -303,7 +284,6 @@ static const struct file_operations sti_driver_fops = {
static struct drm_driver sti_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
- .load = sti_load,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create,
@@ -340,14 +320,88 @@ static int compare_of(struct device *dev, void *data)
return dev->of_node == data;
}
+static int sti_init(struct drm_device *ddev)
+{
+ struct sti_private *private;
+
+ private = kzalloc(sizeof(*private), GFP_KERNEL);
+ if (!private)
+ return -ENOMEM;
+
+ ddev->dev_private = (void *)private;
+ dev_set_drvdata(ddev->dev, ddev);
+ private->drm_dev = ddev;
+
+ mutex_init(&private->commit.lock);
+ INIT_WORK(&private->commit.work, sti_atomic_work);
+
+ drm_mode_config_init(ddev);
+
+ sti_mode_config_init(ddev);
+
+ drm_kms_helper_poll_init(ddev);
+
+ return 0;
+}
+
+static void sti_cleanup(struct drm_device *ddev)
+{
+ struct sti_private *private = ddev->dev_private;
+
+ if (private->fbdev) {
+ drm_fbdev_cma_fini(private->fbdev);
+ private->fbdev = NULL;
+ }
+
+ drm_kms_helper_poll_fini(ddev);
+ drm_vblank_cleanup(ddev);
+ kfree(private);
+ ddev->dev_private = NULL;
+}
+
static int sti_bind(struct device *dev)
{
- return drm_platform_init(&sti_driver, to_platform_device(dev));
+ struct drm_device *ddev;
+ int ret;
+
+ ddev = drm_dev_alloc(&sti_driver, dev);
+ if (!ddev)
+ return -ENOMEM;
+
+ ddev->platformdev = to_platform_device(dev);
+
+ ret = sti_init(ddev);
+ if (ret)
+ goto err_drm_dev_unref;
+
+ ret = component_bind_all(ddev->dev, ddev);
+ if (ret)
+ goto err_cleanup;
+
+ ret = drm_dev_register(ddev, 0);
+ if (ret)
+ goto err_register;
+
+ drm_mode_config_reset(ddev);
+
+ return 0;
+
+err_register:
+ drm_mode_config_cleanup(ddev);
+err_cleanup:
+ sti_cleanup(ddev);
+err_drm_dev_unref:
+ drm_dev_unref(ddev);
+ return ret;
}
static void sti_unbind(struct device *dev)
{
- drm_put_dev(dev_get_drvdata(dev));
+ struct drm_device *ddev = dev_get_drvdata(dev);
+
+ drm_dev_unregister(ddev);
+ sti_cleanup(ddev);
+ drm_dev_unref(ddev);
}
static const struct component_master_ops sti_ops = {
diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h
index 30ddc20..78ebe5e 100644
--- a/drivers/gpu/drm/sti/sti_drv.h
+++ b/drivers/gpu/drm/sti/sti_drv.h
@@ -24,6 +24,7 @@ struct sti_private {
struct sti_compositor *compo;
struct drm_property *plane_zorder_property;
struct drm_device *drm_dev;
+ struct drm_fbdev_cma *fbdev;
struct {
struct drm_atomic_state *state;
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index e290166..ec31080 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -404,24 +404,29 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
return connector_status_disconnected;
}
-static void sti_dvo_connector_destroy(struct drm_connector *connector)
+static int sti_dvo_late_register(struct drm_connector *connector)
{
struct sti_dvo_connector *dvo_connector
= to_sti_dvo_connector(connector);
+ struct sti_dvo *dvo = dvo_connector->dvo;
+
+ if (dvo_debugfs_init(dvo, dvo->drm_dev->primary)) {
+ DRM_ERROR("DVO debugfs setup failed\n");
+ return -EINVAL;
+ }
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- kfree(dvo_connector);
+ return 0;
}
static const struct drm_connector_funcs sti_dvo_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_dvo_connector_detect,
- .destroy = sti_dvo_connector_destroy,
+ .destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .late_register = sti_dvo_late_register,
};
static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
@@ -492,26 +497,16 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
drm_connector_helper_add(drm_connector,
&sti_dvo_connector_helper_funcs);
- err = drm_connector_register(drm_connector);
- if (err)
- goto err_connector;
-
err = drm_mode_connector_attach_encoder(drm_connector, encoder);
if (err) {
DRM_ERROR("Failed to attach a connector to a encoder\n");
goto err_sysfs;
}
- if (dvo_debugfs_init(dvo, drm_dev->primary))
- DRM_ERROR("DVO debugfs setup failed\n");
-
return 0;
err_sysfs:
- drm_connector_unregister(drm_connector);
-err_connector:
drm_bridge_remove(bridge);
- drm_connector_cleanup(drm_connector);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index fdf69b5..bf63086 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -866,6 +866,33 @@ static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
.atomic_disable = sti_gdp_atomic_disable,
};
+static void sti_gdp_destroy(struct drm_plane *drm_plane)
+{
+ DRM_DEBUG_DRIVER("\n");
+
+ drm_plane_helper_disable(drm_plane);
+ drm_plane_cleanup(drm_plane);
+}
+
+static int sti_gdp_late_register(struct drm_plane *drm_plane)
+{
+ struct sti_plane *plane = to_sti_plane(drm_plane);
+ struct sti_gdp *gdp = to_sti_gdp(plane);
+
+ return gdp_debugfs_init(gdp, drm_plane->dev->primary);
+}
+
+struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = sti_gdp_destroy,
+ .set_property = sti_plane_set_property,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .late_register = sti_gdp_late_register,
+};
+
struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
struct device *dev, int desc,
void __iomem *baseaddr,
@@ -892,7 +919,7 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane,
possible_crtcs,
- &sti_plane_helpers_funcs,
+ &sti_gdp_plane_helpers_funcs,
gdp_supported_formats,
ARRAY_SIZE(gdp_supported_formats),
type, NULL);
@@ -905,9 +932,6 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
sti_plane_init_property(&gdp->plane, type);
- if (gdp_debugfs_init(gdp, drm_dev->primary))
- DRM_ERROR("GDP debugfs setup failed\n");
-
return &gdp->plane.drm_plane;
err:
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index dcec5a8..8505569 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -681,24 +681,29 @@ sti_hda_connector_detect(struct drm_connector *connector, bool force)
return connector_status_connected;
}
-static void sti_hda_connector_destroy(struct drm_connector *connector)
+static int sti_hda_late_register(struct drm_connector *connector)
{
struct sti_hda_connector *hda_connector
= to_sti_hda_connector(connector);
+ struct sti_hda *hda = hda_connector->hda;
+
+ if (hda_debugfs_init(hda, hda->drm_dev->primary)) {
+ DRM_ERROR("HDA debugfs setup failed\n");
+ return -EINVAL;
+ }
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- kfree(hda_connector);
+ return 0;
}
static const struct drm_connector_funcs sti_hda_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_hda_connector_detect,
- .destroy = sti_hda_connector_destroy,
+ .destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .late_register = sti_hda_late_register,
};
static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev)
@@ -756,10 +761,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
drm_connector_helper_add(drm_connector,
&sti_hda_connector_helper_funcs);
- err = drm_connector_register(drm_connector);
- if (err)
- goto err_connector;
-
err = drm_mode_connector_attach_encoder(drm_connector, encoder);
if (err) {
DRM_ERROR("Failed to attach a connector to a encoder\n");
@@ -769,15 +770,10 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
/* force to disable hd dacs at startup */
hda_enable_hd_dacs(hda, false);
- if (hda_debugfs_init(hda, drm_dev->primary))
- DRM_ERROR("HDA debugfs setup failed\n");
-
return 0;
err_sysfs:
- drm_connector_unregister(drm_connector);
-err_connector:
- drm_connector_cleanup(drm_connector);
+ drm_bridge_remove(bridge);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 36d9d66..8d1402b 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -915,16 +915,6 @@ sti_hdmi_connector_detect(struct drm_connector *connector, bool force)
return connector_status_disconnected;
}
-static void sti_hdmi_connector_destroy(struct drm_connector *connector)
-{
- struct sti_hdmi_connector *hdmi_connector
- = to_sti_hdmi_connector(connector);
-
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- kfree(hdmi_connector);
-}
-
static void sti_hdmi_connector_init_property(struct drm_device *drm_dev,
struct drm_connector *connector)
{
@@ -1007,17 +997,31 @@ sti_hdmi_connector_get_property(struct drm_connector *connector,
return -EINVAL;
}
+static int sti_hdmi_late_register(struct drm_connector *connector)
+{
+ struct sti_hdmi_connector *hdmi_connector
+ = to_sti_hdmi_connector(connector);
+ struct sti_hdmi *hdmi = hdmi_connector->hdmi;
+
+ if (hdmi_debugfs_init(hdmi, hdmi->drm_dev->primary)) {
+ DRM_ERROR("HDMI debugfs setup failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
- .dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_hdmi_connector_detect,
- .destroy = sti_hdmi_connector_destroy,
+ .destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.set_property = drm_atomic_helper_connector_set_property,
.atomic_set_property = sti_hdmi_connector_set_property,
.atomic_get_property = sti_hdmi_connector_get_property,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .late_register = sti_hdmi_late_register,
};
static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
@@ -1078,10 +1082,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
/* initialise property */
sti_hdmi_connector_init_property(drm_dev, drm_connector);
- err = drm_connector_register(drm_connector);
- if (err)
- goto err_connector;
-
err = drm_mode_connector_attach_encoder(drm_connector, encoder);
if (err) {
DRM_ERROR("Failed to attach a connector to a encoder\n");
@@ -1091,16 +1091,10 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Enable default interrupts */
hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
- if (hdmi_debugfs_init(hdmi, drm_dev->primary))
- DRM_ERROR("HDMI debugfs setup failed\n");
-
return 0;
err_sysfs:
- drm_connector_unregister(drm_connector);
-err_connector:
- drm_connector_cleanup(drm_connector);
-
+ drm_bridge_remove(bridge);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 1c06a50..33d2f42 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1234,6 +1234,33 @@ static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
.atomic_disable = sti_hqvdp_atomic_disable,
};
+static void sti_hqvdp_destroy(struct drm_plane *drm_plane)
+{
+ DRM_DEBUG_DRIVER("\n");
+
+ drm_plane_helper_disable(drm_plane);
+ drm_plane_cleanup(drm_plane);
+}
+
+static int sti_hqvdp_late_register(struct drm_plane *drm_plane)
+{
+ struct sti_plane *plane = to_sti_plane(drm_plane);
+ struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
+
+ return hqvdp_debugfs_init(hqvdp, drm_plane->dev->primary);
+}
+
+struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = sti_hqvdp_destroy,
+ .set_property = sti_plane_set_property,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .late_register = sti_hqvdp_late_register,
+};
+
static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
struct device *dev, int desc)
{
@@ -1246,7 +1273,7 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
sti_hqvdp_init(hqvdp);
res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1,
- &sti_plane_helpers_funcs,
+ &sti_hqvdp_plane_helpers_funcs,
hqvdp_supported_formats,
ARRAY_SIZE(hqvdp_supported_formats),
DRM_PLANE_TYPE_OVERLAY, NULL);
@@ -1259,9 +1286,6 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
- if (hqvdp_debugfs_init(hqvdp, drm_dev->primary))
- DRM_ERROR("HQVDP debugfs setup failed\n");
-
return &hqvdp->plane.drm_plane;
}
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
index 6f86f2b..1885c7a 100644
--- a/drivers/gpu/drm/sti/sti_mixer.c
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -181,7 +181,7 @@ static struct drm_info_list mixer1_debugfs_files[] = {
{ "mixer_aux", mixer_dbg_show, 0, NULL },
};
-static int mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
+int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
{
unsigned int i;
struct drm_info_list *mixer_debugfs_files;
@@ -393,8 +393,5 @@ struct sti_mixer *sti_mixer_create(struct device *dev,
DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
sti_mixer_to_str(mixer), mixer->regs);
- if (mixer_debugfs_init(mixer, drm_dev->primary))
- DRM_ERROR("MIXER debugfs setup failed\n");
-
return mixer;
}
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h
index 6f35fc0..830a3c4 100644
--- a/drivers/gpu/drm/sti/sti_mixer.h
+++ b/drivers/gpu/drm/sti/sti_mixer.h
@@ -55,6 +55,8 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer,
void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable);
+int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor);
+
/* depth in Cross-bar control = z order */
#define GAM_MIXER_NB_DEPTH_LEVEL 6
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index f10c98d..85cee90 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -106,17 +106,9 @@ void sti_plane_update_fps(struct sti_plane *plane,
plane->fps_info.fips_str);
}
-static void sti_plane_destroy(struct drm_plane *drm_plane)
-{
- DRM_DEBUG_DRIVER("\n");
-
- drm_plane_helper_disable(drm_plane);
- drm_plane_cleanup(drm_plane);
-}
-
-static int sti_plane_set_property(struct drm_plane *drm_plane,
- struct drm_property *property,
- uint64_t val)
+int sti_plane_set_property(struct drm_plane *drm_plane,
+ struct drm_property *property,
+ uint64_t val)
{
struct drm_device *dev = drm_plane->dev;
struct sti_private *private = dev->dev_private;
@@ -170,13 +162,3 @@ void sti_plane_init_property(struct sti_plane *plane,
plane->drm_plane.base.id,
sti_plane_to_str(plane), plane->zorder);
}
-
-struct drm_plane_funcs sti_plane_helpers_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = sti_plane_destroy,
- .set_property = sti_plane_set_property,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
index c50a3b9..39d39f5 100644
--- a/drivers/gpu/drm/sti/sti_plane.h
+++ b/drivers/gpu/drm/sti/sti_plane.h
@@ -11,8 +11,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
-extern struct drm_plane_funcs sti_plane_helpers_funcs;
-
#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane)
#define STI_PLANE_TYPE_SHIFT 8
@@ -83,6 +81,11 @@ const char *sti_plane_to_str(struct sti_plane *plane);
void sti_plane_update_fps(struct sti_plane *plane,
bool new_frame,
bool new_field);
+
+int sti_plane_set_property(struct drm_plane *drm_plane,
+ struct drm_property *property,
+ uint64_t val);
+
void sti_plane_init_property(struct sti_plane *plane,
enum drm_plane_type type);
#endif
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index 60fe0af..e25995b 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -112,6 +112,7 @@ struct sti_tvout {
struct drm_encoder *hdmi;
struct drm_encoder *hda;
struct drm_encoder *dvo;
+ bool debugfs_registered;
};
struct sti_tvout_encoder {
@@ -625,8 +626,37 @@ static void sti_tvout_encoder_destroy(struct drm_encoder *encoder)
kfree(sti_encoder);
}
+static int sti_tvout_late_register(struct drm_encoder *encoder)
+{
+ struct sti_tvout *tvout = to_sti_tvout(encoder);
+ int ret;
+
+ if (tvout->debugfs_registered)
+ return 0;
+
+ ret = tvout_debugfs_init(tvout, encoder->dev->primary);
+ if (ret)
+ return ret;
+
+ tvout->debugfs_registered = true;
+ return 0;
+}
+
+static void sti_tvout_early_unregister(struct drm_encoder *encoder)
+{
+ struct sti_tvout *tvout = to_sti_tvout(encoder);
+
+ if (!tvout->debugfs_registered)
+ return;
+
+ tvout_debugfs_exit(tvout, encoder->dev->primary);
+ tvout->debugfs_registered = false;
+}
+
static const struct drm_encoder_funcs sti_tvout_encoder_funcs = {
.destroy = sti_tvout_encoder_destroy,
+ .late_register = sti_tvout_late_register,
+ .early_unregister = sti_tvout_early_unregister,
};
static void sti_dvo_encoder_enable(struct drm_encoder *encoder)
@@ -813,9 +843,6 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
sti_tvout_create_encoders(drm_dev, tvout);
- if (tvout_debugfs_init(tvout, drm_dev->primary))
- DRM_ERROR("TVOUT debugfs setup failed\n");
-
return 0;
}
@@ -823,11 +850,8 @@ static void sti_tvout_unbind(struct device *dev, struct device *master,
void *data)
{
struct sti_tvout *tvout = dev_get_drvdata(dev);
- struct drm_device *drm_dev = data;
sti_tvout_destroy_encoders(tvout);
-
- tvout_debugfs_exit(tvout, drm_dev->primary);
}
static const struct component_ops sti_tvout_ops = {
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c
index 0132aae..47634a0 100644
--- a/drivers/gpu/drm/sti/sti_vid.c
+++ b/drivers/gpu/drm/sti/sti_vid.c
@@ -123,7 +123,7 @@ static struct drm_info_list vid_debugfs_files[] = {
{ "vid", vid_dbg_show, 0, NULL },
};
-static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor)
+int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor)
{
unsigned int i;
@@ -220,8 +220,5 @@ struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
sti_vid_init(vid);
- if (vid_debugfs_init(vid, drm_dev->primary))
- DRM_ERROR("VID debugfs setup failed\n");
-
return vid;
}
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h
index 6c84234..fdc90f9 100644
--- a/drivers/gpu/drm/sti/sti_vid.h
+++ b/drivers/gpu/drm/sti/sti_vid.h
@@ -26,4 +26,6 @@ void sti_vid_disable(struct sti_vid *vid);
struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
int id, void __iomem *baseaddr);
+int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor);
+
#endif
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 68e9d85..9a67f92 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -24,34 +24,6 @@
#include "sun4i_layer.h"
#include "sun4i_tcon.h"
-static int sun4i_drv_connector_plug_all(struct drm_device *drm)
-{
- struct drm_connector *connector, *failed;
- int ret;
-
- mutex_lock(&drm->mode_config.mutex);
- list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
- ret = drm_connector_register(connector);
- if (ret) {
- failed = connector;
- goto err;
- }
- }
- mutex_unlock(&drm->mode_config.mutex);
- return 0;
-
-err:
- list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
- if (failed == connector)
- break;
-
- drm_connector_unregister(connector);
- }
- mutex_unlock(&drm->mode_config.mutex);
-
- return ret;
-}
-
static int sun4i_drv_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
struct sun4i_drv *drv = drm->dev_private;
@@ -135,10 +107,6 @@ static int sun4i_drv_bind(struct device *dev)
if (!drm)
return -ENOMEM;
- ret = drm_dev_set_unique(drm, dev_name(drm->dev));
- if (ret)
- goto free_drm;
-
drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
if (!drv) {
ret = -ENOMEM;
@@ -187,14 +155,8 @@ static int sun4i_drv_bind(struct device *dev)
if (ret)
goto free_drm;
- ret = sun4i_drv_connector_plug_all(drm);
- if (ret)
- goto unregister_drm;
-
return 0;
-unregister_drm:
- drm_dev_unregister(drm);
free_drm:
drm_dev_unref(drm);
return ret;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 308e197..d278093 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -541,7 +541,6 @@ static struct drm_driver tilcdc_driver = {
.load = tilcdc_load,
.unload = tilcdc_unload,
.lastclose = tilcdc_lastclose,
- .set_busid = drm_platform_set_busid,
.irq_handler = tilcdc_irq,
.irq_preinstall = tilcdc_irq_preinstall,
.irq_postinstall = tilcdc_irq_postinstall,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 58b8fc0..9e88231 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -176,7 +176,6 @@ static int vc4_drm_bind(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm;
- struct drm_connector *connector;
struct vc4_dev *vc4;
int ret = 0;
@@ -211,22 +210,10 @@ static int vc4_drm_bind(struct device *dev)
if (ret < 0)
goto unbind_all;
- /* Connector registration has to occur after DRM device
- * registration, because it creates sysfs entries based on the
- * DRM device.
- */
- list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
- ret = drm_connector_register(connector);
- if (ret)
- goto unregister;
- }
-
vc4_kms_load(drm);
return 0;
-unregister:
- drm_dev_unregister(drm);
unbind_all:
component_unbind_all(dev, drm);
gem_destroy:
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index 1b4cc8b..35ea5d0 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -260,8 +260,6 @@ static int __init vgem_init(void)
goto out;
}
- drm_dev_set_unique(vgem_device, "vgem");
-
ret = drm_dev_register(vgem_device, 0);
if (ret)
diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c
index 4f20742..a04ef1c 100644
--- a/drivers/gpu/drm/via/via_mm.c
+++ b/drivers/gpu/drm/via/via_mm.c
@@ -208,7 +208,7 @@ void via_reclaim_buffers_locked(struct drm_device *dev,
struct via_file_private *file_priv = file->driver_priv;
struct via_memblock *entry, *next;
- if (!(file->minor->master && file->master->lock.hw_lock))
+ if (!(dev->master && file->master->lock.hw_lock))
return;
drm_legacy_idlelock_take(&file->master->lock);
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
index 88a3916..7f0e93f87 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
@@ -27,16 +27,6 @@
#include "virtgpu_drv.h"
-int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master)
-{
- struct pci_dev *pdev = dev->pdev;
-
- if (pdev) {
- return drm_pci_set_busid(dev, master);
- }
- return 0;
-}
-
static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev)
{
struct apertures_struct *ap;
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
index 5820b702..c13f70c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -117,7 +117,6 @@ static const struct file_operations virtio_gpu_driver_fops = {
static struct drm_driver driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC,
- .set_busid = drm_virtio_set_busid,
.load = virtio_gpu_driver_load,
.unload = virtio_gpu_driver_unload,
.open = virtio_gpu_driver_open,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index acf556a..b18ef31 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -49,7 +49,6 @@
#define DRIVER_PATCHLEVEL 1
/* virtgpu_drm_bus.c */
-int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master);
int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev);
struct virtio_gpu_object {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 9fcd820..6064664 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1049,7 +1049,7 @@ static struct vmw_master *vmw_master_check(struct drm_device *dev,
if (unlikely(ret != 0))
return ERR_PTR(-ERESTARTSYS);
- if (file_priv->is_master) {
+ if (drm_is_current_master(file_priv)) {
mutex_unlock(&dev->master_mutex);
return NULL;
}
@@ -1228,8 +1228,7 @@ static int vmw_master_set(struct drm_device *dev,
}
static void vmw_master_drop(struct drm_device *dev,
- struct drm_file *file_priv,
- bool from_release)
+ struct drm_file *file_priv)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 1980e2a..9a90f82 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -32,6 +32,7 @@
#include <drm/drmP.h>
#include <drm/vmwgfx_drm.h>
#include <drm/drm_hashtab.h>
+#include <drm/drm_auth.h>
#include <linux/suspend.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_object.h>