aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-11-18 19:40:00 -0500
committerDave Airlie <airlied@redhat.com>2018-11-18 19:40:33 -0500
commitd7563c55ef9fc1fd2301b8708b3c1f53509d6745 (patch)
treed7c8ba37972ecab71b056356366e136d5f2527ec /drivers/gpu
parent9ff01193a20d391e8dbce4403dd5ef87c7eaaca6 (diff)
parente7afb623b4fb82089c9a50c733c740522b8220bc (diff)
Merge tag 'drm-misc-next-2018-11-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v4.21, part 1: UAPI Changes: - Add syncobj timeline support to drm. Cross-subsystem Changes: - Remove shared fence staging in dma-buf's fence object, and allow reserving more than 1 fence and add more paranoia when debugging. - Constify infoframe functions in video/hdmi. Core Changes: - Add vkms todo, and a lot of assorted doc fixes. - Drop transitional helpers and convert drivers to use drm_atomic_helper_shutdown(). - Move atomic state helper functions to drm_atomic_state_helper.[ch] - Refactor drm selftests, and add new tests. - DP MST atomic state cleanups. - Drop EXPORT_SYMBOL from drm leases. - Lease cleanups and fixes. - Create render node for vgem. Driver Changes: - Fix build failure in imx without fbdev emulation. - Add rotation quirk for GPD win2 panel. - Add support for various CDTech panels, Banana Pi Panel, DLC1010GIG, Olimex LCD-O-LinuXino, Samsung S6D16D0, Truly NT35597 WQXGA, Himax HX8357D, simulated RTSM AEMv8. - Add dw_hdmi support to rockchip driver. - Fix YUV support in vc4. - Fix resource id handling in virtio. - Make rockchip use dw-mipi-dsi bridge driver, and add dual dsi support. - Advertise that tinydrm only supports DRM_FORMAT_MOD_LINEAR. - Convert many drivers to use atomic helpers, and drm_fbdev_generic_setup(). - Add Mali linear tiled formats, and enable them in the Mali-DP driver. - Add support for H6 DE3 mixer 0, DW HDMI, HDMI PHY and TCON TOP. - Assorted driver cleanups and fixes. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/be7ebd91-edd9-8fa4-4286-1c57e3165113@linux.intel.com
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c14
-rw-r--r--drivers/gpu/drm/arc/arcpgu.h4
-rw-r--r--drivers/gpu/drm/arc/arcpgu_crtc.c3
-rw-r--r--drivers/gpu/drm/arc/arcpgu_drv.c34
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c14
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c28
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c15
-rw-r--r--drivers/gpu/drm/bochs/bochs.h2
-rw-r--r--drivers/gpu/drm/bochs/bochs_hw.c30
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c20
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c4
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c12
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c6
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c114
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c598
-rw-r--r--drivers/gpu/drm/drm_atomic_state_helper.c601
-rw-r--r--drivers/gpu/drm/drm_bufs.c3
-rw-r--r--drivers/gpu/drm/drm_connector.c22
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c115
-rw-r--r--drivers/gpu/drm/drm_dp_cec.c2
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c9
-rw-r--r--drivers/gpu/drm/drm_drv.c8
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c43
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c6
-rw-r--r--drivers/gpu/drm/drm_fourcc.c78
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c13
-rw-r--r--drivers/gpu/drm/drm_gem_framebuffer_helper.c2
-rw-r--r--drivers/gpu/drm/drm_lease.c38
-rw-r--r--drivers/gpu/drm/drm_memory.c10
-rw-r--r--drivers/gpu/drm/drm_mode_object.c3
-rw-r--r--drivers/gpu/drm/drm_modes.c4
-rw-r--r--drivers/gpu/drm/drm_modeset_helper.c15
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c16
-rw-r--r--drivers/gpu/drm/drm_pci.c5
-rw-r--r--drivers/gpu/drm/drm_plane.c23
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c331
-rw-r--r--drivers/gpu/drm/drm_prime.c30
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c8
-rw-r--r--drivers/gpu/drm/drm_syncobj.c359
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c33
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c25
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/i915_vma.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c3
-rw-r--r--drivers/gpu/drm/meson/meson_drv.c19
-rw-r--r--drivers/gpu/drm/meson/meson_drv.h1
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c5
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c1
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c1
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c2
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c1
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig25
-rw-r--r--drivers/gpu/drm/panel/Makefile3
-rw-r--r--drivers/gpu/drm/panel/panel-innolux-p079zca.c3
-rw-r--r--drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c330
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6d16d0.c264
-rw-r--r--drivers/gpu/drm/panel/panel-seiko-43wvf1g.c7
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c157
-rw-r--r--drivers/gpu/drm/panel/panel-truly-nt35597.c675
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c7
-rw-r--r--drivers/gpu/drm/qxl/qxl_debugfs.c5
-rw-r--r--drivers/gpu/drm/qxl/qxl_dev.h1
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c19
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c11
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h31
-rw-r--r--drivers/gpu/drm/qxl/qxl_dumb.c3
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_image.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c5
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.h2
-rw-r--r--drivers/gpu/drm/qxl/qxl_prime.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_release.c3
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c21
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h1
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig2
-rw-r--r--drivers/gpu/drm/rockchip/Makefile2
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c1076
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi.c1349
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c128
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h3
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_psr.c4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c3
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.c7
-rw-r--r--drivers/gpu/drm/selftests/Makefile5
-rw-r--r--drivers/gpu/drm/selftests/drm_modeset_selftests.h (renamed from drivers/gpu/drm/selftests/drm_helper_selftests.h)4
-rw-r--r--drivers/gpu/drm/selftests/test-drm_format.c280
-rw-r--r--drivers/gpu/drm/selftests/test-drm_framebuffer.c346
-rw-r--r--drivers/gpu/drm/selftests/test-drm_modeset_common.c32
-rw-r--r--drivers/gpu/drm/selftests/test-drm_modeset_common.h22
-rw-r--r--drivers/gpu/drm/selftests/test-drm_plane_helper.c (renamed from drivers/gpu/drm/selftests/test-drm-helper.c)38
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c1
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c6
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c3
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c1
-rw-r--r--drivers/gpu/drm/stm/drv.c13
-rw-r--r--drivers/gpu/drm/stm/ltdc.c45
-rw-r--r--drivers/gpu/drm/stm/ltdc.h5
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.h3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.c83
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c45
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h14
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c201
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c57
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.h80
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_tcon_top.c52
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.c47
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.h37
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.c47
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.h28
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.c55
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.h25
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.c70
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.h68
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c11
-rw-r--r--drivers/gpu/drm/tinydrm/Kconfig11
-rw-r--r--drivers/gpu/drm/tinydrm/Makefile1
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-core.c1
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c6
-rw-r--r--drivers/gpu/drm/tinydrm/hx8357d.c270
-rw-r--r--drivers/gpu/drm/tinydrm/mipi-dbi.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c4
-rw-r--r--drivers/gpu/drm/udl/udl_main.c7
-rw-r--r--drivers/gpu/drm/v3d/v3d_debugfs.c46
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.h5
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c14
-rw-r--r--drivers/gpu/drm/v3d/v3d_regs.h30
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c4
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c164
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h8
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c19
-rw-r--r--drivers/gpu/drm/vgem/vgem_fence.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drm_bus.c31
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h14
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fb.c7
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_gem.c8
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ioctl.c25
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_kms.c45
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_object.c17
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ttm.c3
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c37
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c21
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c24
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c1
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c5
-rw-r--r--drivers/gpu/drm/zte/zx_plane.c1
-rw-r--r--drivers/gpu/vga/vgaarb.c21
171 files changed, 6245 insertions, 3318 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index bc6a16a3c36e..576ba985e138 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -36,7 +36,8 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
36 drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ 36 drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
37 drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ 37 drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
38 drm_simple_kms_helper.o drm_modeset_helper.o \ 38 drm_simple_kms_helper.o drm_modeset_helper.o \
39 drm_scdc_helper.o drm_gem_framebuffer_helper.o 39 drm_scdc_helper.o drm_gem_framebuffer_helper.o \
40 drm_atomic_state_helper.o
40 41
41drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o 42drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
42drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o 43drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 663043c8f0f5..35bc8fc3bc70 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -955,7 +955,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
955 if (r) 955 if (r)
956 return r; 956 return r;
957 957
958 r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv); 958 r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv, 1);
959 if (r) 959 if (r)
960 return r; 960 return r;
961 961
@@ -1104,7 +1104,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
1104{ 1104{
1105 int r; 1105 int r;
1106 struct dma_fence *fence; 1106 struct dma_fence *fence;
1107 r = drm_syncobj_find_fence(p->filp, handle, 0, &fence); 1107 r = drm_syncobj_find_fence(p->filp, handle, 0, 0, &fence);
1108 if (r) 1108 if (r)
1109 return r; 1109 return r;
1110 1110
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 904014dc5915..cf768acb51dc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -640,7 +640,7 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
640 bo_addr = amdgpu_bo_gpu_offset(bo); 640 bo_addr = amdgpu_bo_gpu_offset(bo);
641 shadow_addr = amdgpu_bo_gpu_offset(bo->shadow); 641 shadow_addr = amdgpu_bo_gpu_offset(bo->shadow);
642 642
643 r = reservation_object_reserve_shared(bo->tbo.resv); 643 r = reservation_object_reserve_shared(bo->tbo.resv, 1);
644 if (r) 644 if (r)
645 goto err; 645 goto err;
646 646
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
index e45e929aaab5..3e44d889f7af 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
@@ -339,8 +339,6 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = {
339 .unmap_dma_buf = drm_gem_unmap_dma_buf, 339 .unmap_dma_buf = drm_gem_unmap_dma_buf,
340 .release = drm_gem_dmabuf_release, 340 .release = drm_gem_dmabuf_release,
341 .begin_cpu_access = amdgpu_gem_begin_cpu_access, 341 .begin_cpu_access = amdgpu_gem_begin_cpu_access,
342 .map = drm_gem_dmabuf_kmap,
343 .unmap = drm_gem_dmabuf_kunmap,
344 .mmap = drm_gem_dmabuf_mmap, 342 .mmap = drm_gem_dmabuf_mmap,
345 .vmap = drm_gem_dmabuf_vmap, 343 .vmap = drm_gem_dmabuf_vmap,
346 .vunmap = drm_gem_dmabuf_vunmap, 344 .vunmap = drm_gem_dmabuf_vunmap,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index dad0e2342df9..58a2363040dd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -773,7 +773,7 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
773 773
774 ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched); 774 ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched);
775 775
776 r = reservation_object_reserve_shared(bo->tbo.resv); 776 r = reservation_object_reserve_shared(bo->tbo.resv, 1);
777 if (r) 777 if (r)
778 return r; 778 return r;
779 779
@@ -1842,7 +1842,7 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
1842 if (r) 1842 if (r)
1843 goto error_free; 1843 goto error_free;
1844 1844
1845 r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv); 1845 r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv, 1);
1846 if (r) 1846 if (r)
1847 goto error_free; 1847 goto error_free;
1848 1848
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index c1262f62cd9f..5064768642f3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3185,7 +3185,6 @@ amdgpu_dm_connector_helper_funcs = {
3185 */ 3185 */
3186 .get_modes = get_modes, 3186 .get_modes = get_modes,
3187 .mode_valid = amdgpu_dm_connector_mode_valid, 3187 .mode_valid = amdgpu_dm_connector_mode_valid,
3188 .best_encoder = drm_atomic_helper_best_encoder
3189}; 3188};
3190 3189
3191static void dm_crtc_helper_disable(struct drm_crtc *crtc) 3190static void dm_crtc_helper_disable(struct drm_crtc *crtc)
@@ -3588,14 +3587,17 @@ static int to_drm_connector_type(enum signal_type st)
3588 } 3587 }
3589} 3588}
3590 3589
3590static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
3591{
3592 return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
3593}
3594
3591static void amdgpu_dm_get_native_mode(struct drm_connector *connector) 3595static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
3592{ 3596{
3593 const struct drm_connector_helper_funcs *helper =
3594 connector->helper_private;
3595 struct drm_encoder *encoder; 3597 struct drm_encoder *encoder;
3596 struct amdgpu_encoder *amdgpu_encoder; 3598 struct amdgpu_encoder *amdgpu_encoder;
3597 3599
3598 encoder = helper->best_encoder(connector); 3600 encoder = amdgpu_dm_connector_to_encoder(connector);
3599 3601
3600 if (encoder == NULL) 3602 if (encoder == NULL)
3601 return; 3603 return;
@@ -3722,14 +3724,12 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
3722 3724
3723static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) 3725static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
3724{ 3726{
3725 const struct drm_connector_helper_funcs *helper =
3726 connector->helper_private;
3727 struct amdgpu_dm_connector *amdgpu_dm_connector = 3727 struct amdgpu_dm_connector *amdgpu_dm_connector =
3728 to_amdgpu_dm_connector(connector); 3728 to_amdgpu_dm_connector(connector);
3729 struct drm_encoder *encoder; 3729 struct drm_encoder *encoder;
3730 struct edid *edid = amdgpu_dm_connector->edid; 3730 struct edid *edid = amdgpu_dm_connector->edid;
3731 3731
3732 encoder = helper->best_encoder(connector); 3732 encoder = amdgpu_dm_connector_to_encoder(connector);
3733 3733
3734 if (!edid || !drm_edid_is_valid(edid)) { 3734 if (!edid || !drm_edid_is_valid(edid)) {
3735 amdgpu_dm_connector->num_modes = 3735 amdgpu_dm_connector->num_modes =
diff --git a/drivers/gpu/drm/arc/arcpgu.h b/drivers/gpu/drm/arc/arcpgu.h
index e8fcf3ab1d9a..90ef76b19f8a 100644
--- a/drivers/gpu/drm/arc/arcpgu.h
+++ b/drivers/gpu/drm/arc/arcpgu.h
@@ -20,7 +20,6 @@
20struct arcpgu_drm_private { 20struct arcpgu_drm_private {
21 void __iomem *regs; 21 void __iomem *regs;
22 struct clk *clk; 22 struct clk *clk;
23 struct drm_fbdev_cma *fbdev;
24 struct drm_framebuffer *fb; 23 struct drm_framebuffer *fb;
25 struct drm_crtc crtc; 24 struct drm_crtc crtc;
26 struct drm_plane *plane; 25 struct drm_plane *plane;
@@ -43,8 +42,5 @@ static inline u32 arc_pgu_read(struct arcpgu_drm_private *arcpgu,
43int arc_pgu_setup_crtc(struct drm_device *dev); 42int arc_pgu_setup_crtc(struct drm_device *dev);
44int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np); 43int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np);
45int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np); 44int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np);
46struct drm_fbdev_cma *arcpgu_fbdev_cma_init(struct drm_device *dev,
47 unsigned int preferred_bpp, unsigned int num_crtc,
48 unsigned int max_conn_count);
49 45
50#endif 46#endif
diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c
index 965cda48dc13..62f51f70606d 100644
--- a/drivers/gpu/drm/arc/arcpgu_crtc.c
+++ b/drivers/gpu/drm/arc/arcpgu_crtc.c
@@ -158,8 +158,6 @@ static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc,
158 158
159static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = { 159static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = {
160 .mode_valid = arc_pgu_crtc_mode_valid, 160 .mode_valid = arc_pgu_crtc_mode_valid,
161 .mode_set = drm_helper_crtc_mode_set,
162 .mode_set_base = drm_helper_crtc_mode_set_base,
163 .mode_set_nofb = arc_pgu_crtc_mode_set_nofb, 161 .mode_set_nofb = arc_pgu_crtc_mode_set_nofb,
164 .atomic_begin = arc_pgu_crtc_atomic_begin, 162 .atomic_begin = arc_pgu_crtc_atomic_begin,
165 .atomic_enable = arc_pgu_crtc_atomic_enable, 163 .atomic_enable = arc_pgu_crtc_atomic_enable,
@@ -186,7 +184,6 @@ static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = {
186 184
187static void arc_pgu_plane_destroy(struct drm_plane *plane) 185static void arc_pgu_plane_destroy(struct drm_plane *plane)
188{ 186{
189 drm_plane_helper_disable(plane, NULL);
190 drm_plane_cleanup(plane); 187 drm_plane_cleanup(plane);
191} 188}
192 189
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c
index f067de4e1e82..2af847ebca34 100644
--- a/drivers/gpu/drm/arc/arcpgu_drv.c
+++ b/drivers/gpu/drm/arc/arcpgu_drv.c
@@ -17,6 +17,7 @@
17#include <linux/clk.h> 17#include <linux/clk.h>
18#include <drm/drm_crtc_helper.h> 18#include <drm/drm_crtc_helper.h>
19#include <drm/drm_fb_cma_helper.h> 19#include <drm/drm_fb_cma_helper.h>
20#include <drm/drm_fb_helper.h>
20#include <drm/drm_gem_cma_helper.h> 21#include <drm/drm_gem_cma_helper.h>
21#include <drm/drm_gem_framebuffer_helper.h> 22#include <drm/drm_gem_framebuffer_helper.h>
22#include <drm/drm_atomic_helper.h> 23#include <drm/drm_atomic_helper.h>
@@ -25,16 +26,8 @@
25#include "arcpgu.h" 26#include "arcpgu.h"
26#include "arcpgu_regs.h" 27#include "arcpgu_regs.h"
27 28
28static void arcpgu_fb_output_poll_changed(struct drm_device *dev)
29{
30 struct arcpgu_drm_private *arcpgu = dev->dev_private;
31
32 drm_fbdev_cma_hotplug_event(arcpgu->fbdev);
33}
34
35static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { 29static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = {
36 .fb_create = drm_gem_fb_create, 30 .fb_create = drm_gem_fb_create,
37 .output_poll_changed = arcpgu_fb_output_poll_changed,
38 .atomic_check = drm_atomic_helper_check, 31 .atomic_check = drm_atomic_helper_check,
39 .atomic_commit = drm_atomic_helper_commit, 32 .atomic_commit = drm_atomic_helper_commit,
40}; 33};
@@ -51,13 +44,6 @@ static void arcpgu_setup_mode_config(struct drm_device *drm)
51 44
52DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops); 45DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops);
53 46
54static void arcpgu_lastclose(struct drm_device *drm)
55{
56 struct arcpgu_drm_private *arcpgu = drm->dev_private;
57
58 drm_fbdev_cma_restore_mode(arcpgu->fbdev);
59}
60
61static int arcpgu_load(struct drm_device *drm) 47static int arcpgu_load(struct drm_device *drm)
62{ 48{
63 struct platform_device *pdev = to_platform_device(drm->dev); 49 struct platform_device *pdev = to_platform_device(drm->dev);
@@ -113,27 +99,14 @@ static int arcpgu_load(struct drm_device *drm)
113 drm_mode_config_reset(drm); 99 drm_mode_config_reset(drm);
114 drm_kms_helper_poll_init(drm); 100 drm_kms_helper_poll_init(drm);
115 101
116 arcpgu->fbdev = drm_fbdev_cma_init(drm, 16,
117 drm->mode_config.num_connector);
118 if (IS_ERR(arcpgu->fbdev)) {
119 ret = PTR_ERR(arcpgu->fbdev);
120 arcpgu->fbdev = NULL;
121 return -ENODEV;
122 }
123
124 platform_set_drvdata(pdev, drm); 102 platform_set_drvdata(pdev, drm);
125 return 0; 103 return 0;
126} 104}
127 105
128static int arcpgu_unload(struct drm_device *drm) 106static int arcpgu_unload(struct drm_device *drm)
129{ 107{
130 struct arcpgu_drm_private *arcpgu = drm->dev_private;
131
132 if (arcpgu->fbdev) {
133 drm_fbdev_cma_fini(arcpgu->fbdev);
134 arcpgu->fbdev = NULL;
135 }
136 drm_kms_helper_poll_fini(drm); 108 drm_kms_helper_poll_fini(drm);
109 drm_atomic_helper_shutdown(drm);
137 drm_mode_config_cleanup(drm); 110 drm_mode_config_cleanup(drm);
138 111
139 return 0; 112 return 0;
@@ -167,7 +140,6 @@ static int arcpgu_debugfs_init(struct drm_minor *minor)
167static struct drm_driver arcpgu_drm_driver = { 140static struct drm_driver arcpgu_drm_driver = {
168 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 141 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
169 DRIVER_ATOMIC, 142 DRIVER_ATOMIC,
170 .lastclose = arcpgu_lastclose,
171 .name = "arcpgu", 143 .name = "arcpgu",
172 .desc = "ARC PGU Controller", 144 .desc = "ARC PGU Controller",
173 .date = "20160219", 145 .date = "20160219",
@@ -210,6 +182,8 @@ static int arcpgu_probe(struct platform_device *pdev)
210 if (ret) 182 if (ret)
211 goto err_unload; 183 goto err_unload;
212 184
185 drm_fbdev_generic_setup(drm, 16);
186
213 return 0; 187 return 0;
214 188
215err_unload: 189err_unload:
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 7aad7dd80d8c..b9bed1138fa3 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -77,12 +77,18 @@ static const struct malidp_format_id malidp500_de_formats[] = {
77 { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \ 77 { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \
78 { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \ 78 { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \
79 { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \ 79 { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \
80 { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) } 80 { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
81 { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}
81 82
82static const struct malidp_format_id malidp550_de_formats[] = { 83static const struct malidp_format_id malidp550_de_formats[] = {
83 MALIDP_COMMON_FORMATS, 84 MALIDP_COMMON_FORMATS,
84}; 85};
85 86
87static const struct malidp_format_id malidp650_de_formats[] = {
88 MALIDP_COMMON_FORMATS,
89 { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
90};
91
86static const struct malidp_layer malidp500_layers[] = { 92static const struct malidp_layer malidp500_layers[] = {
87 /* id, base address, fb pointer address base, stride offset, 93 /* id, base address, fb pointer address base, stride offset,
88 * yuv2rgb matrix offset, mmu control register offset, rotation_features 94 * yuv2rgb matrix offset, mmu control register offset, rotation_features
@@ -630,6 +636,8 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
630 case DRM_FORMAT_BGR565: 636 case DRM_FORMAT_BGR565:
631 case DRM_FORMAT_UYVY: 637 case DRM_FORMAT_UYVY:
632 case DRM_FORMAT_YUYV: 638 case DRM_FORMAT_YUYV:
639 case DRM_FORMAT_X0L0:
640 case DRM_FORMAT_X0L2:
633 bytes_per_col = 32; 641 bytes_per_col = 32;
634 break; 642 break;
635 /* 16 lines at 1.5 bytes per pixel */ 643 /* 16 lines at 1.5 bytes per pixel */
@@ -905,8 +913,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
905 MALIDP550_DC_IRQ_SE, 913 MALIDP550_DC_IRQ_SE,
906 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 914 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
907 }, 915 },
908 .pixel_formats = malidp550_de_formats, 916 .pixel_formats = malidp650_de_formats,
909 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), 917 .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
910 .bus_align_bytes = 16, 918 .bus_align_bytes = 16,
911 }, 919 },
912 .query_hw = malidp650_query_hw, 920 .query_hw = malidp650_query_hw,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 837a24d56675..c9a6d3e0cada 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -398,6 +398,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,
398 struct drm_framebuffer *fb; 398 struct drm_framebuffer *fb;
399 u16 pixel_alpha = state->pixel_blend_mode; 399 u16 pixel_alpha = state->pixel_blend_mode;
400 int i, ret; 400 int i, ret;
401 unsigned int block_w, block_h;
401 402
402 if (!state->crtc || !state->fb) 403 if (!state->crtc || !state->fb)
403 return 0; 404 return 0;
@@ -413,13 +414,26 @@ static int malidp_de_plane_check(struct drm_plane *plane,
413 ms->n_planes = fb->format->num_planes; 414 ms->n_planes = fb->format->num_planes;
414 for (i = 0; i < ms->n_planes; i++) { 415 for (i = 0; i < ms->n_planes; i++) {
415 u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated); 416 u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated);
416 if (fb->pitches[i] & (alignment - 1)) { 417
418 if ((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
419 & (alignment - 1)) {
417 DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n", 420 DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
418 fb->pitches[i], i); 421 fb->pitches[i], i);
419 return -EINVAL; 422 return -EINVAL;
420 } 423 }
421 } 424 }
422 425
426 block_w = drm_format_info_block_width(fb->format, 0);
427 block_h = drm_format_info_block_height(fb->format, 0);
428 if (fb->width % block_w || fb->height % block_h) {
429 DRM_DEBUG_KMS("Buffer width/height needs to be a multiple of tile sizes");
430 return -EINVAL;
431 }
432 if ((state->src_x >> 16) % block_w || (state->src_y >> 16) % block_h) {
433 DRM_DEBUG_KMS("Plane src_x/src_y needs to be a multiple of tile sizes");
434 return -EINVAL;
435 }
436
423 if ((state->crtc_w > mp->hwdev->max_line_size) || 437 if ((state->crtc_w > mp->hwdev->max_line_size) ||
424 (state->crtc_h > mp->hwdev->max_line_size) || 438 (state->crtc_h > mp->hwdev->max_line_size) ||
425 (state->crtc_w < mp->hwdev->min_line_size) || 439 (state->crtc_w < mp->hwdev->min_line_size) ||
@@ -492,10 +506,18 @@ static void malidp_de_set_plane_pitches(struct malidp_plane *mp,
492 num_strides = (mp->hwdev->hw->features & 506 num_strides = (mp->hwdev->hw->features &
493 MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2; 507 MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;
494 508
495 for (i = 0; i < num_strides; ++i) 509 /*
496 malidp_hw_write(mp->hwdev, pitches[i], 510 * The drm convention for pitch is that it needs to cover width * cpp,
511 * but our hardware wants the pitch/stride to cover all rows included
512 * in a tile.
513 */
514 for (i = 0; i < num_strides; ++i) {
515 unsigned int block_h = drm_format_info_block_height(mp->base.state->fb->format, i);
516
517 malidp_hw_write(mp->hwdev, pitches[i] * block_h,
497 mp->layer->base + 518 mp->layer->base +
498 mp->layer->stride_offset + i * 4); 519 mp->layer->stride_offset + i * 4);
520 }
499} 521}
500 522
501static const s16 523static const s16
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 9e34bce089d0..96f4082671fe 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -364,9 +364,7 @@ static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
364 364
365static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = { 365static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
366 .mode_valid = atmel_hlcdc_crtc_mode_valid, 366 .mode_valid = atmel_hlcdc_crtc_mode_valid,
367 .mode_set = drm_helper_crtc_mode_set,
368 .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb, 367 .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
369 .mode_set_base = drm_helper_crtc_mode_set_base,
370 .atomic_check = atmel_hlcdc_crtc_atomic_check, 368 .atomic_check = atmel_hlcdc_crtc_atomic_check,
371 .atomic_begin = atmel_hlcdc_crtc_atomic_begin, 369 .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
372 .atomic_flush = atmel_hlcdc_crtc_atomic_flush, 370 .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 843cac222e60..034a91112098 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -556,7 +556,6 @@ error:
556 556
557static const struct drm_mode_config_funcs mode_config_funcs = { 557static const struct drm_mode_config_funcs mode_config_funcs = {
558 .fb_create = atmel_hlcdc_fb_create, 558 .fb_create = atmel_hlcdc_fb_create,
559 .output_poll_changed = drm_fb_helper_output_poll_changed,
560 .atomic_check = drm_atomic_helper_check, 559 .atomic_check = drm_atomic_helper_check,
561 .atomic_commit = atmel_hlcdc_dc_atomic_commit, 560 .atomic_commit = atmel_hlcdc_dc_atomic_commit,
562}; 561};
@@ -658,8 +657,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
658 657
659 platform_set_drvdata(pdev, dev); 658 platform_set_drvdata(pdev, dev);
660 659
661 drm_fb_cma_fbdev_init(dev, 24, 0);
662
663 drm_kms_helper_poll_init(dev); 660 drm_kms_helper_poll_init(dev);
664 661
665 return 0; 662 return 0;
@@ -678,7 +675,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
678{ 675{
679 struct atmel_hlcdc_dc *dc = dev->dev_private; 676 struct atmel_hlcdc_dc *dc = dev->dev_private;
680 677
681 drm_fb_cma_fbdev_fini(dev);
682 flush_workqueue(dc->wq); 678 flush_workqueue(dc->wq);
683 drm_kms_helper_poll_fini(dev); 679 drm_kms_helper_poll_fini(dev);
684 drm_atomic_helper_shutdown(dev); 680 drm_atomic_helper_shutdown(dev);
@@ -727,7 +723,6 @@ static struct drm_driver atmel_hlcdc_dc_driver = {
727 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | 723 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
728 DRIVER_MODESET | DRIVER_PRIME | 724 DRIVER_MODESET | DRIVER_PRIME |
729 DRIVER_ATOMIC, 725 DRIVER_ATOMIC,
730 .lastclose = drm_fb_helper_lastclose,
731 .irq_handler = atmel_hlcdc_dc_irq_handler, 726 .irq_handler = atmel_hlcdc_dc_irq_handler,
732 .irq_preinstall = atmel_hlcdc_dc_irq_uninstall, 727 .irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
733 .irq_postinstall = atmel_hlcdc_dc_irq_postinstall, 728 .irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
@@ -763,19 +758,21 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
763 758
764 ret = atmel_hlcdc_dc_load(ddev); 759 ret = atmel_hlcdc_dc_load(ddev);
765 if (ret) 760 if (ret)
766 goto err_unref; 761 goto err_put;
767 762
768 ret = drm_dev_register(ddev, 0); 763 ret = drm_dev_register(ddev, 0);
769 if (ret) 764 if (ret)
770 goto err_unload; 765 goto err_unload;
771 766
767 drm_fbdev_generic_setup(ddev, 24);
768
772 return 0; 769 return 0;
773 770
774err_unload: 771err_unload:
775 atmel_hlcdc_dc_unload(ddev); 772 atmel_hlcdc_dc_unload(ddev);
776 773
777err_unref: 774err_put:
778 drm_dev_unref(ddev); 775 drm_dev_put(ddev);
779 776
780 return ret; 777 return ret;
781} 778}
@@ -786,7 +783,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
786 783
787 drm_dev_unregister(ddev); 784 drm_dev_unregister(ddev);
788 atmel_hlcdc_dc_unload(ddev); 785 atmel_hlcdc_dc_unload(ddev);
789 drm_dev_unref(ddev); 786 drm_dev_put(ddev);
790 787
791 return 0; 788 return 0;
792} 789}
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
index e7a69077e45a..577a8b917cb9 100644
--- a/drivers/gpu/drm/bochs/bochs.h
+++ b/drivers/gpu/drm/bochs/bochs.h
@@ -66,6 +66,7 @@ struct bochs_device {
66 u16 yres_virtual; 66 u16 yres_virtual;
67 u32 stride; 67 u32 stride;
68 u32 bpp; 68 u32 bpp;
69 struct edid *edid;
69 70
70 /* drm */ 71 /* drm */
71 struct drm_device *dev; 72 struct drm_device *dev;
@@ -126,6 +127,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
126 const struct drm_format_info *format); 127 const struct drm_format_info *format);
127void bochs_hw_setbase(struct bochs_device *bochs, 128void bochs_hw_setbase(struct bochs_device *bochs,
128 int x, int y, u64 addr); 129 int x, int y, u64 addr);
130int bochs_hw_load_edid(struct bochs_device *bochs);
129 131
130/* bochs_mm.c */ 132/* bochs_mm.c */
131int bochs_mm_init(struct bochs_device *bochs); 133int bochs_mm_init(struct bochs_device *bochs);
diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c
index cacff73a64ab..c90a0d492fd5 100644
--- a/drivers/gpu/drm/bochs/bochs_hw.c
+++ b/drivers/gpu/drm/bochs/bochs_hw.c
@@ -69,6 +69,35 @@ static void bochs_hw_set_little_endian(struct bochs_device *bochs)
69#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b) 69#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b)
70#endif 70#endif
71 71
72static int bochs_get_edid_block(void *data, u8 *buf,
73 unsigned int block, size_t len)
74{
75 struct bochs_device *bochs = data;
76 size_t i, start = block * EDID_LENGTH;
77
78 if (start + len > 0x400 /* vga register offset */)
79 return -1;
80
81 for (i = 0; i < len; i++) {
82 buf[i] = readb(bochs->mmio + start + i);
83 }
84 return 0;
85}
86
87int bochs_hw_load_edid(struct bochs_device *bochs)
88{
89 if (!bochs->mmio)
90 return -1;
91
92 kfree(bochs->edid);
93 bochs->edid = drm_do_get_edid(&bochs->connector,
94 bochs_get_edid_block, bochs);
95 if (bochs->edid == NULL)
96 return -1;
97
98 return 0;
99}
100
72int bochs_hw_init(struct drm_device *dev) 101int bochs_hw_init(struct drm_device *dev)
73{ 102{
74 struct bochs_device *bochs = dev->dev_private; 103 struct bochs_device *bochs = dev->dev_private;
@@ -164,6 +193,7 @@ void bochs_hw_fini(struct drm_device *dev)
164 if (bochs->fb_map) 193 if (bochs->fb_map)
165 iounmap(bochs->fb_map); 194 iounmap(bochs->fb_map);
166 pci_release_regions(dev->pdev); 195 pci_release_regions(dev->pdev);
196 kfree(bochs->edid);
167} 197}
168 198
169void bochs_hw_setmode(struct bochs_device *bochs, 199void bochs_hw_setmode(struct bochs_device *bochs,
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 9bc5b438aefd..f87c284dd93d 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -213,10 +213,17 @@ static void bochs_encoder_init(struct drm_device *dev)
213 213
214static int bochs_connector_get_modes(struct drm_connector *connector) 214static int bochs_connector_get_modes(struct drm_connector *connector)
215{ 215{
216 int count; 216 struct bochs_device *bochs =
217 container_of(connector, struct bochs_device, connector);
218 int count = 0;
219
220 if (bochs->edid)
221 count = drm_add_edid_modes(connector, bochs->edid);
217 222
218 count = drm_add_modes_noedid(connector, 8192, 8192); 223 if (!count) {
219 drm_set_preferred_mode(connector, defx, defy); 224 count = drm_add_modes_noedid(connector, 8192, 8192);
225 drm_set_preferred_mode(connector, defx, defy);
226 }
220 return count; 227 return count;
221} 228}
222 229
@@ -271,6 +278,13 @@ static void bochs_connector_init(struct drm_device *dev)
271 drm_connector_helper_add(connector, 278 drm_connector_helper_add(connector,
272 &bochs_connector_connector_helper_funcs); 279 &bochs_connector_connector_helper_funcs);
273 drm_connector_register(connector); 280 drm_connector_register(connector);
281
282 bochs_hw_load_edid(bochs);
283 if (bochs->edid) {
284 DRM_INFO("Found EDID data blob.\n");
285 drm_connector_attach_edid_property(connector);
286 drm_connector_update_edid_property(connector, bochs->edid);
287 }
274} 288}
275 289
276 290
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index a61c1ecb2bdc..e6ccf7fa92d4 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -414,7 +414,7 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
414 return ret; 414 return ret;
415 415
416 ret = drm_gem_handle_create(file, gobj, &handle); 416 ret = drm_gem_handle_create(file, gobj, &handle);
417 drm_gem_object_unreference_unlocked(gobj); 417 drm_gem_object_put_unlocked(gobj);
418 if (ret) 418 if (ret)
419 return ret; 419 return ret;
420 420
@@ -454,6 +454,6 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
454 bo = gem_to_bochs_bo(obj); 454 bo = gem_to_bochs_bo(obj);
455 *offset = bochs_bo_mmap_offset(bo); 455 *offset = bochs_bo_mmap_offset(bo);
456 456
457 drm_gem_object_unreference_unlocked(obj); 457 drm_gem_object_put_unlocked(obj);
458 return 0; 458 return 0;
459} 459}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 2f21d3b6850b..753e96129ab7 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1219,12 +1219,12 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
1219 * plat_data->attch return, that's why we record the connector 1219 * plat_data->attch return, that's why we record the connector
1220 * point after plat attached. 1220 * point after plat attached.
1221 */ 1221 */
1222 if (dp->plat_data->attach) { 1222 if (dp->plat_data->attach) {
1223 ret = dp->plat_data->attach(dp->plat_data, bridge, connector); 1223 ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
1224 if (ret) { 1224 if (ret) {
1225 DRM_ERROR("Failed at platform attch func\n"); 1225 DRM_ERROR("Failed at platform attach func\n");
1226 return ret; 1226 return ret;
1227 } 1227 }
1228 } 1228 }
1229 1229
1230 if (dp->plat_data->panel) { 1230 if (dp->plat_data->panel) {
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 5971976284bf..64c3cf027518 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1664,6 +1664,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
1664 case 0x131a: 1664 case 0x131a:
1665 case 0x132a: 1665 case 0x132a:
1666 case 0x201a: 1666 case 0x201a:
1667 case 0x212a:
1667 count = 1; 1668 count = 1;
1668 break; 1669 break;
1669 default: 1670 default:
@@ -1957,7 +1958,6 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
1957 1958
1958static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { 1959static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
1959 .get_modes = dw_hdmi_connector_get_modes, 1960 .get_modes = dw_hdmi_connector_get_modes,
1960 .best_encoder = drm_atomic_helper_best_encoder,
1961}; 1961};
1962 1962
1963static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) 1963static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
@@ -2205,7 +2205,9 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
2205 unsigned int i; 2205 unsigned int i;
2206 u8 phy_type; 2206 u8 phy_type;
2207 2207
2208 phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID); 2208 phy_type = hdmi->plat_data->phy_force_vendor ?
2209 DW_HDMI_PHY_VENDOR_PHY :
2210 hdmi_readb(hdmi, HDMI_CONFIG2_ID);
2209 2211
2210 if (phy_type == DW_HDMI_PHY_VENDOR_PHY) { 2212 if (phy_type == DW_HDMI_PHY_VENDOR_PHY) {
2211 /* Vendor PHYs require support from the glue layer. */ 2213 /* Vendor PHYs require support from the glue layer. */
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index fd7999642cf8..2f4b145b73af 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -230,10 +230,21 @@ struct dw_mipi_dsi {
230 u32 format; 230 u32 format;
231 unsigned long mode_flags; 231 unsigned long mode_flags;
232 232
233 struct dw_mipi_dsi *master; /* dual-dsi master ptr */
234 struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
235
233 const struct dw_mipi_dsi_plat_data *plat_data; 236 const struct dw_mipi_dsi_plat_data *plat_data;
234}; 237};
235 238
236/* 239/*
240 * Check if either a link to a master or slave is present
241 */
242static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi)
243{
244 return dsi->slave || dsi->master;
245}
246
247/*
237 * The controller should generate 2 frames before 248 * The controller should generate 2 frames before
238 * preparing the peripheral. 249 * preparing the peripheral.
239 */ 250 */
@@ -270,6 +281,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
270 struct mipi_dsi_device *device) 281 struct mipi_dsi_device *device)
271{ 282{
272 struct dw_mipi_dsi *dsi = host_to_dsi(host); 283 struct dw_mipi_dsi *dsi = host_to_dsi(host);
284 const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
273 struct drm_bridge *bridge; 285 struct drm_bridge *bridge;
274 struct drm_panel *panel; 286 struct drm_panel *panel;
275 int ret; 287 int ret;
@@ -300,6 +312,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
300 312
301 drm_bridge_add(&dsi->bridge); 313 drm_bridge_add(&dsi->bridge);
302 314
315 if (pdata->host_ops && pdata->host_ops->attach) {
316 ret = pdata->host_ops->attach(pdata->priv_data, device);
317 if (ret < 0)
318 return ret;
319 }
320
303 return 0; 321 return 0;
304} 322}
305 323
@@ -307,6 +325,14 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
307 struct mipi_dsi_device *device) 325 struct mipi_dsi_device *device)
308{ 326{
309 struct dw_mipi_dsi *dsi = host_to_dsi(host); 327 struct dw_mipi_dsi *dsi = host_to_dsi(host);
328 const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
329 int ret;
330
331 if (pdata->host_ops && pdata->host_ops->detach) {
332 ret = pdata->host_ops->detach(pdata->priv_data, device);
333 if (ret < 0)
334 return ret;
335 }
310 336
311 drm_of_panel_bridge_remove(host->dev->of_node, 1, 0); 337 drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
312 338
@@ -441,10 +467,17 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
441 } 467 }
442 468
443 dw_mipi_message_config(dsi, msg); 469 dw_mipi_message_config(dsi, msg);
470 if (dsi->slave)
471 dw_mipi_message_config(dsi->slave, msg);
444 472
445 ret = dw_mipi_dsi_write(dsi, &packet); 473 ret = dw_mipi_dsi_write(dsi, &packet);
446 if (ret) 474 if (ret)
447 return ret; 475 return ret;
476 if (dsi->slave) {
477 ret = dw_mipi_dsi_write(dsi->slave, &packet);
478 if (ret)
479 return ret;
480 }
448 481
449 if (msg->rx_buf && msg->rx_len) { 482 if (msg->rx_buf && msg->rx_len) {
450 ret = dw_mipi_dsi_read(dsi, msg); 483 ret = dw_mipi_dsi_read(dsi, msg);
@@ -583,7 +616,11 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
583 * DSI_VNPCR.NPSIZE... especially because this driver supports 616 * DSI_VNPCR.NPSIZE... especially because this driver supports
584 * non-burst video modes, see dw_mipi_dsi_video_mode_config()... 617 * non-burst video modes, see dw_mipi_dsi_video_mode_config()...
585 */ 618 */
586 dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay)); 619
620 dsi_write(dsi, DSI_VID_PKT_SIZE,
621 dw_mipi_is_dual_mode(dsi) ?
622 VID_PKT_SIZE(mode->hdisplay / 2) :
623 VID_PKT_SIZE(mode->hdisplay));
587} 624}
588 625
589static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) 626static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
@@ -755,24 +792,43 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
755 */ 792 */
756 dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); 793 dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
757 794
795 if (dsi->slave) {
796 dw_mipi_dsi_disable(dsi->slave);
797 clk_disable_unprepare(dsi->slave->pclk);
798 pm_runtime_put(dsi->slave->dev);
799 }
758 dw_mipi_dsi_disable(dsi); 800 dw_mipi_dsi_disable(dsi);
801
759 clk_disable_unprepare(dsi->pclk); 802 clk_disable_unprepare(dsi->pclk);
760 pm_runtime_put(dsi->dev); 803 pm_runtime_put(dsi->dev);
761} 804}
762 805
763static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, 806static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
764 struct drm_display_mode *mode, 807{
765 struct drm_display_mode *adjusted_mode) 808 /* this instance is the slave, so add the master's lanes */
809 if (dsi->master)
810 return dsi->master->lanes + dsi->lanes;
811
812 /* this instance is the master, so add the slave's lanes */
813 if (dsi->slave)
814 return dsi->lanes + dsi->slave->lanes;
815
816 /* single-dsi, so no other instance to consider */
817 return dsi->lanes;
818}
819
820static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
821 struct drm_display_mode *adjusted_mode)
766{ 822{
767 struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
768 const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; 823 const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
769 void *priv_data = dsi->plat_data->priv_data; 824 void *priv_data = dsi->plat_data->priv_data;
770 int ret; 825 int ret;
826 u32 lanes = dw_mipi_dsi_get_lanes(dsi);
771 827
772 clk_prepare_enable(dsi->pclk); 828 clk_prepare_enable(dsi->pclk);
773 829
774 ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags, 830 ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags,
775 dsi->lanes, dsi->format, &dsi->lane_mbps); 831 lanes, dsi->format, &dsi->lane_mbps);
776 if (ret) 832 if (ret)
777 DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n"); 833 DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");
778 834
@@ -804,12 +860,25 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
804 dw_mipi_dsi_set_mode(dsi, 0); 860 dw_mipi_dsi_set_mode(dsi, 0);
805} 861}
806 862
863static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
864 struct drm_display_mode *mode,
865 struct drm_display_mode *adjusted_mode)
866{
867 struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
868
869 dw_mipi_dsi_mode_set(dsi, adjusted_mode);
870 if (dsi->slave)
871 dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
872}
873
807static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) 874static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
808{ 875{
809 struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); 876 struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
810 877
811 /* Switch to video mode for panel-bridge enable & panel enable */ 878 /* Switch to video mode for panel-bridge enable & panel enable */
812 dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); 879 dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
880 if (dsi->slave)
881 dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
813} 882}
814 883
815static enum drm_mode_status 884static enum drm_mode_status
@@ -941,9 +1010,25 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
941 1010
942static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) 1011static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
943{ 1012{
1013 mipi_dsi_host_unregister(&dsi->dsi_host);
1014
944 pm_runtime_disable(dsi->dev); 1015 pm_runtime_disable(dsi->dev);
945} 1016}
946 1017
1018void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave)
1019{
1020 /* introduce controllers to each other */
1021 dsi->slave = slave;
1022 dsi->slave->master = dsi;
1023
1024 /* migrate settings for already attached displays */
1025 dsi->slave->lanes = dsi->lanes;
1026 dsi->slave->channel = dsi->channel;
1027 dsi->slave->format = dsi->format;
1028 dsi->slave->mode_flags = dsi->mode_flags;
1029}
1030EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave);
1031
947/* 1032/*
948 * Probe/remove API, used from platforms based on the DRM bridge API. 1033 * Probe/remove API, used from platforms based on the DRM bridge API.
949 */ 1034 */
@@ -957,8 +1042,6 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe);
957 1042
958void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) 1043void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
959{ 1044{
960 mipi_dsi_host_unregister(&dsi->dsi_host);
961
962 __dw_mipi_dsi_remove(dsi); 1045 __dw_mipi_dsi_remove(dsi);
963} 1046}
964EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove); 1047EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
@@ -966,31 +1049,22 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
966/* 1049/*
967 * Bind/unbind API, used from platforms based on the component framework. 1050 * Bind/unbind API, used from platforms based on the component framework.
968 */ 1051 */
969struct dw_mipi_dsi * 1052int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder)
970dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
971 const struct dw_mipi_dsi_plat_data *plat_data)
972{ 1053{
973 struct dw_mipi_dsi *dsi;
974 int ret; 1054 int ret;
975 1055
976 dsi = __dw_mipi_dsi_probe(pdev, plat_data);
977 if (IS_ERR(dsi))
978 return dsi;
979
980 ret = drm_bridge_attach(encoder, &dsi->bridge, NULL); 1056 ret = drm_bridge_attach(encoder, &dsi->bridge, NULL);
981 if (ret) { 1057 if (ret) {
982 dw_mipi_dsi_remove(dsi);
983 DRM_ERROR("Failed to initialize bridge with drm\n"); 1058 DRM_ERROR("Failed to initialize bridge with drm\n");
984 return ERR_PTR(ret); 1059 return ret;
985 } 1060 }
986 1061
987 return dsi; 1062 return ret;
988} 1063}
989EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); 1064EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind);
990 1065
991void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) 1066void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi)
992{ 1067{
993 __dw_mipi_dsi_remove(dsi);
994} 1068}
995EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); 1069EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
996 1070
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index d8b526b7932c..474b503a73a1 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -92,6 +92,17 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
92 } 92 }
93} 93}
94 94
95/*
96 * For connectors that support multiple encoders, either the
97 * .atomic_best_encoder() or .best_encoder() operation must be implemented.
98 */
99static struct drm_encoder *
100pick_single_encoder_for_connector(struct drm_connector *connector)
101{
102 WARN_ON(connector->encoder_ids[1]);
103 return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
104}
105
95static int handle_conflicting_encoders(struct drm_atomic_state *state, 106static int handle_conflicting_encoders(struct drm_atomic_state *state,
96 bool disable_conflicting_encoders) 107 bool disable_conflicting_encoders)
97{ 108{
@@ -119,7 +130,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,
119 else if (funcs->best_encoder) 130 else if (funcs->best_encoder)
120 new_encoder = funcs->best_encoder(connector); 131 new_encoder = funcs->best_encoder(connector);
121 else 132 else
122 new_encoder = drm_atomic_helper_best_encoder(connector); 133 new_encoder = pick_single_encoder_for_connector(connector);
123 134
124 if (new_encoder) { 135 if (new_encoder) {
125 if (encoder_mask & drm_encoder_mask(new_encoder)) { 136 if (encoder_mask & drm_encoder_mask(new_encoder)) {
@@ -336,7 +347,7 @@ update_connector_routing(struct drm_atomic_state *state,
336 else if (funcs->best_encoder) 347 else if (funcs->best_encoder)
337 new_encoder = funcs->best_encoder(connector); 348 new_encoder = funcs->best_encoder(connector);
338 else 349 else
339 new_encoder = drm_atomic_helper_best_encoder(connector); 350 new_encoder = pick_single_encoder_for_connector(connector);
340 351
341 if (!new_encoder) { 352 if (!new_encoder) {
342 DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n", 353 DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -3411,586 +3422,3 @@ fail:
3411 return ret; 3422 return ret;
3412} 3423}
3413EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); 3424EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
3414
3415/**
3416 * drm_atomic_helper_best_encoder - Helper for
3417 * &drm_connector_helper_funcs.best_encoder callback
3418 * @connector: Connector control structure
3419 *
3420 * This is a &drm_connector_helper_funcs.best_encoder callback helper for
3421 * connectors that support exactly 1 encoder, statically determined at driver
3422 * init time.
3423 */
3424struct drm_encoder *
3425drm_atomic_helper_best_encoder(struct drm_connector *connector)
3426{
3427 WARN_ON(connector->encoder_ids[1]);
3428 return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
3429}
3430EXPORT_SYMBOL(drm_atomic_helper_best_encoder);
3431
3432/**
3433 * DOC: atomic state reset and initialization
3434 *
3435 * Both the drm core and the atomic helpers assume that there is always the full
3436 * and correct atomic software state for all connectors, CRTCs and planes
3437 * available. Which is a bit a problem on driver load and also after system
3438 * suspend. One way to solve this is to have a hardware state read-out
3439 * infrastructure which reconstructs the full software state (e.g. the i915
3440 * driver).
3441 *
3442 * The simpler solution is to just reset the software state to everything off,
3443 * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
3444 * the atomic helpers provide default reset implementations for all hooks.
3445 *
3446 * On the upside the precise state tracking of atomic simplifies system suspend
3447 * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
3448 * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
3449 * For other drivers the building blocks are split out, see the documentation
3450 * for these functions.
3451 */
3452
3453/**
3454 * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
3455 * @crtc: drm CRTC
3456 *
3457 * Resets the atomic state for @crtc by freeing the state pointer (which might
3458 * be NULL, e.g. at driver load time) and allocating a new empty state object.
3459 */
3460void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
3461{
3462 if (crtc->state)
3463 __drm_atomic_helper_crtc_destroy_state(crtc->state);
3464
3465 kfree(crtc->state);
3466 crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
3467
3468 if (crtc->state)
3469 crtc->state->crtc = crtc;
3470}
3471EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
3472
3473/**
3474 * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
3475 * @crtc: CRTC object
3476 * @state: atomic CRTC state
3477 *
3478 * Copies atomic state from a CRTC's current state and resets inferred values.
3479 * This is useful for drivers that subclass the CRTC state.
3480 */
3481void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
3482 struct drm_crtc_state *state)
3483{
3484 memcpy(state, crtc->state, sizeof(*state));
3485
3486 if (state->mode_blob)
3487 drm_property_blob_get(state->mode_blob);
3488 if (state->degamma_lut)
3489 drm_property_blob_get(state->degamma_lut);
3490 if (state->ctm)
3491 drm_property_blob_get(state->ctm);
3492 if (state->gamma_lut)
3493 drm_property_blob_get(state->gamma_lut);
3494 state->mode_changed = false;
3495 state->active_changed = false;
3496 state->planes_changed = false;
3497 state->connectors_changed = false;
3498 state->color_mgmt_changed = false;
3499 state->zpos_changed = false;
3500 state->commit = NULL;
3501 state->event = NULL;
3502 state->pageflip_flags = 0;
3503}
3504EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
3505
3506/**
3507 * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
3508 * @crtc: drm CRTC
3509 *
3510 * Default CRTC state duplicate hook for drivers which don't have their own
3511 * subclassed CRTC state structure.
3512 */
3513struct drm_crtc_state *
3514drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
3515{
3516 struct drm_crtc_state *state;
3517
3518 if (WARN_ON(!crtc->state))
3519 return NULL;
3520
3521 state = kmalloc(sizeof(*state), GFP_KERNEL);
3522 if (state)
3523 __drm_atomic_helper_crtc_duplicate_state(crtc, state);
3524
3525 return state;
3526}
3527EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
3528
3529/**
3530 * __drm_atomic_helper_crtc_destroy_state - release CRTC state
3531 * @state: CRTC state object to release
3532 *
3533 * Releases all resources stored in the CRTC state without actually freeing
3534 * the memory of the CRTC state. This is useful for drivers that subclass the
3535 * CRTC state.
3536 */
3537void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
3538{
3539 if (state->commit) {
3540 /*
3541 * In the event that a non-blocking commit returns
3542 * -ERESTARTSYS before the commit_tail work is queued, we will
3543 * have an extra reference to the commit object. Release it, if
3544 * the event has not been consumed by the worker.
3545 *
3546 * state->event may be freed, so we can't directly look at
3547 * state->event->base.completion.
3548 */
3549 if (state->event && state->commit->abort_completion)
3550 drm_crtc_commit_put(state->commit);
3551
3552 kfree(state->commit->event);
3553 state->commit->event = NULL;
3554
3555 drm_crtc_commit_put(state->commit);
3556 }
3557
3558 drm_property_blob_put(state->mode_blob);
3559 drm_property_blob_put(state->degamma_lut);
3560 drm_property_blob_put(state->ctm);
3561 drm_property_blob_put(state->gamma_lut);
3562}
3563EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
3564
3565/**
3566 * drm_atomic_helper_crtc_destroy_state - default state destroy hook
3567 * @crtc: drm CRTC
3568 * @state: CRTC state object to release
3569 *
3570 * Default CRTC state destroy hook for drivers which don't have their own
3571 * subclassed CRTC state structure.
3572 */
3573void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
3574 struct drm_crtc_state *state)
3575{
3576 __drm_atomic_helper_crtc_destroy_state(state);
3577 kfree(state);
3578}
3579EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
3580
3581/**
3582 * __drm_atomic_helper_plane_reset - resets planes state to default values
3583 * @plane: plane object, must not be NULL
3584 * @state: atomic plane state, must not be NULL
3585 *
3586 * Initializes plane state to default. This is useful for drivers that subclass
3587 * the plane state.
3588 */
3589void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
3590 struct drm_plane_state *state)
3591{
3592 state->plane = plane;
3593 state->rotation = DRM_MODE_ROTATE_0;
3594
3595 state->alpha = DRM_BLEND_ALPHA_OPAQUE;
3596 state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
3597
3598 plane->state = state;
3599}
3600EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
3601
3602/**
3603 * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
3604 * @plane: drm plane
3605 *
3606 * Resets the atomic state for @plane by freeing the state pointer (which might
3607 * be NULL, e.g. at driver load time) and allocating a new empty state object.
3608 */
3609void drm_atomic_helper_plane_reset(struct drm_plane *plane)
3610{
3611 if (plane->state)
3612 __drm_atomic_helper_plane_destroy_state(plane->state);
3613
3614 kfree(plane->state);
3615 plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
3616 if (plane->state)
3617 __drm_atomic_helper_plane_reset(plane, plane->state);
3618}
3619EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
3620
3621/**
3622 * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
3623 * @plane: plane object
3624 * @state: atomic plane state
3625 *
3626 * Copies atomic state from a plane's current state. This is useful for
3627 * drivers that subclass the plane state.
3628 */
3629void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
3630 struct drm_plane_state *state)
3631{
3632 memcpy(state, plane->state, sizeof(*state));
3633
3634 if (state->fb)
3635 drm_framebuffer_get(state->fb);
3636
3637 state->fence = NULL;
3638 state->commit = NULL;
3639}
3640EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
3641
3642/**
3643 * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
3644 * @plane: drm plane
3645 *
3646 * Default plane state duplicate hook for drivers which don't have their own
3647 * subclassed plane state structure.
3648 */
3649struct drm_plane_state *
3650drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
3651{
3652 struct drm_plane_state *state;
3653
3654 if (WARN_ON(!plane->state))
3655 return NULL;
3656
3657 state = kmalloc(sizeof(*state), GFP_KERNEL);
3658 if (state)
3659 __drm_atomic_helper_plane_duplicate_state(plane, state);
3660
3661 return state;
3662}
3663EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
3664
3665/**
3666 * __drm_atomic_helper_plane_destroy_state - release plane state
3667 * @state: plane state object to release
3668 *
3669 * Releases all resources stored in the plane state without actually freeing
3670 * the memory of the plane state. This is useful for drivers that subclass the
3671 * plane state.
3672 */
3673void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
3674{
3675 if (state->fb)
3676 drm_framebuffer_put(state->fb);
3677
3678 if (state->fence)
3679 dma_fence_put(state->fence);
3680
3681 if (state->commit)
3682 drm_crtc_commit_put(state->commit);
3683}
3684EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
3685
3686/**
3687 * drm_atomic_helper_plane_destroy_state - default state destroy hook
3688 * @plane: drm plane
3689 * @state: plane state object to release
3690 *
3691 * Default plane state destroy hook for drivers which don't have their own
3692 * subclassed plane state structure.
3693 */
3694void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
3695 struct drm_plane_state *state)
3696{
3697 __drm_atomic_helper_plane_destroy_state(state);
3698 kfree(state);
3699}
3700EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
3701
3702/**
3703 * __drm_atomic_helper_connector_reset - reset state on connector
3704 * @connector: drm connector
3705 * @conn_state: connector state to assign
3706 *
3707 * Initializes the newly allocated @conn_state and assigns it to
3708 * the &drm_conector->state pointer of @connector, usually required when
3709 * initializing the drivers or when called from the &drm_connector_funcs.reset
3710 * hook.
3711 *
3712 * This is useful for drivers that subclass the connector state.
3713 */
3714void
3715__drm_atomic_helper_connector_reset(struct drm_connector *connector,
3716 struct drm_connector_state *conn_state)
3717{
3718 if (conn_state)
3719 conn_state->connector = connector;
3720
3721 connector->state = conn_state;
3722}
3723EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
3724
3725/**
3726 * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
3727 * @connector: drm connector
3728 *
3729 * Resets the atomic state for @connector by freeing the state pointer (which
3730 * might be NULL, e.g. at driver load time) and allocating a new empty state
3731 * object.
3732 */
3733void drm_atomic_helper_connector_reset(struct drm_connector *connector)
3734{
3735 struct drm_connector_state *conn_state =
3736 kzalloc(sizeof(*conn_state), GFP_KERNEL);
3737
3738 if (connector->state)
3739 __drm_atomic_helper_connector_destroy_state(connector->state);
3740
3741 kfree(connector->state);
3742 __drm_atomic_helper_connector_reset(connector, conn_state);
3743}
3744EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
3745
3746/**
3747 * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
3748 * @connector: connector object
3749 * @state: atomic connector state
3750 *
3751 * Copies atomic state from a connector's current state. This is useful for
3752 * drivers that subclass the connector state.
3753 */
3754void
3755__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
3756 struct drm_connector_state *state)
3757{
3758 memcpy(state, connector->state, sizeof(*state));
3759 if (state->crtc)
3760 drm_connector_get(connector);
3761 state->commit = NULL;
3762
3763 /* Don't copy over a writeback job, they are used only once */
3764 state->writeback_job = NULL;
3765}
3766EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
3767
3768/**
3769 * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
3770 * @connector: drm connector
3771 *
3772 * Default connector state duplicate hook for drivers which don't have their own
3773 * subclassed connector state structure.
3774 */
3775struct drm_connector_state *
3776drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
3777{
3778 struct drm_connector_state *state;
3779
3780 if (WARN_ON(!connector->state))
3781 return NULL;
3782
3783 state = kmalloc(sizeof(*state), GFP_KERNEL);
3784 if (state)
3785 __drm_atomic_helper_connector_duplicate_state(connector, state);
3786
3787 return state;
3788}
3789EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
3790
3791/**
3792 * drm_atomic_helper_duplicate_state - duplicate an atomic state object
3793 * @dev: DRM device
3794 * @ctx: lock acquisition context
3795 *
3796 * Makes a copy of the current atomic state by looping over all objects and
3797 * duplicating their respective states. This is used for example by suspend/
3798 * resume support code to save the state prior to suspend such that it can
3799 * be restored upon resume.
3800 *
3801 * Note that this treats atomic state as persistent between save and restore.
3802 * Drivers must make sure that this is possible and won't result in confusion
3803 * or erroneous behaviour.
3804 *
3805 * Note that if callers haven't already acquired all modeset locks this might
3806 * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
3807 *
3808 * Returns:
3809 * A pointer to the copy of the atomic state object on success or an
3810 * ERR_PTR()-encoded error code on failure.
3811 *
3812 * See also:
3813 * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
3814 */
3815struct drm_atomic_state *
3816drm_atomic_helper_duplicate_state(struct drm_device *dev,
3817 struct drm_modeset_acquire_ctx *ctx)
3818{
3819 struct drm_atomic_state *state;
3820 struct drm_connector *conn;
3821 struct drm_connector_list_iter conn_iter;
3822 struct drm_plane *plane;
3823 struct drm_crtc *crtc;
3824 int err = 0;
3825
3826 state = drm_atomic_state_alloc(dev);
3827 if (!state)
3828 return ERR_PTR(-ENOMEM);
3829
3830 state->acquire_ctx = ctx;
3831
3832 drm_for_each_crtc(crtc, dev) {
3833 struct drm_crtc_state *crtc_state;
3834
3835 crtc_state = drm_atomic_get_crtc_state(state, crtc);
3836 if (IS_ERR(crtc_state)) {
3837 err = PTR_ERR(crtc_state);
3838 goto free;
3839 }
3840 }
3841
3842 drm_for_each_plane(plane, dev) {
3843 struct drm_plane_state *plane_state;
3844
3845 plane_state = drm_atomic_get_plane_state(state, plane);
3846 if (IS_ERR(plane_state)) {
3847 err = PTR_ERR(plane_state);
3848 goto free;
3849 }
3850 }
3851
3852 drm_connector_list_iter_begin(dev, &conn_iter);
3853 drm_for_each_connector_iter(conn, &conn_iter) {
3854 struct drm_connector_state *conn_state;
3855
3856 conn_state = drm_atomic_get_connector_state(state, conn);
3857 if (IS_ERR(conn_state)) {
3858 err = PTR_ERR(conn_state);
3859 drm_connector_list_iter_end(&conn_iter);
3860 goto free;
3861 }
3862 }
3863 drm_connector_list_iter_end(&conn_iter);
3864
3865 /* clear the acquire context so that it isn't accidentally reused */
3866 state->acquire_ctx = NULL;
3867
3868free:
3869 if (err < 0) {
3870 drm_atomic_state_put(state);
3871 state = ERR_PTR(err);
3872 }
3873
3874 return state;
3875}
3876EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
3877
3878/**
3879 * __drm_atomic_helper_connector_destroy_state - release connector state
3880 * @state: connector state object to release
3881 *
3882 * Releases all resources stored in the connector state without actually
3883 * freeing the memory of the connector state. This is useful for drivers that
3884 * subclass the connector state.
3885 */
3886void
3887__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
3888{
3889 if (state->crtc)
3890 drm_connector_put(state->connector);
3891
3892 if (state->commit)
3893 drm_crtc_commit_put(state->commit);
3894}
3895EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
3896
3897/**
3898 * drm_atomic_helper_connector_destroy_state - default state destroy hook
3899 * @connector: drm connector
3900 * @state: connector state object to release
3901 *
3902 * Default connector state destroy hook for drivers which don't have their own
3903 * subclassed connector state structure.
3904 */
3905void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
3906 struct drm_connector_state *state)
3907{
3908 __drm_atomic_helper_connector_destroy_state(state);
3909 kfree(state);
3910}
3911EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
3912
3913/**
3914 * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
3915 * @crtc: CRTC object
3916 * @red: red correction table
3917 * @green: green correction table
3918 * @blue: green correction table
3919 * @size: size of the tables
3920 * @ctx: lock acquire context
3921 *
3922 * Implements support for legacy gamma correction table for drivers
3923 * that support color management through the DEGAMMA_LUT/GAMMA_LUT
3924 * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
3925 * how the atomic color management and gamma tables work.
3926 */
3927int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
3928 u16 *red, u16 *green, u16 *blue,
3929 uint32_t size,
3930 struct drm_modeset_acquire_ctx *ctx)
3931{
3932 struct drm_device *dev = crtc->dev;
3933 struct drm_atomic_state *state;
3934 struct drm_crtc_state *crtc_state;
3935 struct drm_property_blob *blob = NULL;
3936 struct drm_color_lut *blob_data;
3937 int i, ret = 0;
3938 bool replaced;
3939
3940 state = drm_atomic_state_alloc(crtc->dev);
3941 if (!state)
3942 return -ENOMEM;
3943
3944 blob = drm_property_create_blob(dev,
3945 sizeof(struct drm_color_lut) * size,
3946 NULL);
3947 if (IS_ERR(blob)) {
3948 ret = PTR_ERR(blob);
3949 blob = NULL;
3950 goto fail;
3951 }
3952
3953 /* Prepare GAMMA_LUT with the legacy values. */
3954 blob_data = blob->data;
3955 for (i = 0; i < size; i++) {
3956 blob_data[i].red = red[i];
3957 blob_data[i].green = green[i];
3958 blob_data[i].blue = blue[i];
3959 }
3960
3961 state->acquire_ctx = ctx;
3962 crtc_state = drm_atomic_get_crtc_state(state, crtc);
3963 if (IS_ERR(crtc_state)) {
3964 ret = PTR_ERR(crtc_state);
3965 goto fail;
3966 }
3967
3968 /* Reset DEGAMMA_LUT and CTM properties. */
3969 replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
3970 replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
3971 replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
3972 crtc_state->color_mgmt_changed |= replaced;
3973
3974 ret = drm_atomic_commit(state);
3975
3976fail:
3977 drm_atomic_state_put(state);
3978 drm_property_blob_put(blob);
3979 return ret;
3980}
3981EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
3982
3983/**
3984 * __drm_atomic_helper_private_duplicate_state - copy atomic private state
3985 * @obj: CRTC object
3986 * @state: new private object state
3987 *
3988 * Copies atomic state from a private objects's current state and resets inferred values.
3989 * This is useful for drivers that subclass the private state.
3990 */
3991void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
3992 struct drm_private_state *state)
3993{
3994 memcpy(state, obj->state, sizeof(*state));
3995}
3996EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
new file mode 100644
index 000000000000..3ba996069d69
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -0,0 +1,601 @@
1/*
2 * Copyright (C) 2018 Intel Corp.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors:
23 * Rob Clark <robdclark@gmail.com>
24 * Daniel Vetter <daniel.vetter@ffwll.ch>
25 */
26
27#include <drm/drm_atomic_state_helper.h>
28#include <drm/drm_crtc.h>
29#include <drm/drm_plane.h>
30#include <drm/drm_connector.h>
31#include <drm/drm_atomic.h>
32#include <drm/drm_device.h>
33
34#include <linux/slab.h>
35#include <linux/dma-fence.h>
36
37/**
38 * DOC: atomic state reset and initialization
39 *
40 * Both the drm core and the atomic helpers assume that there is always the full
41 * and correct atomic software state for all connectors, CRTCs and planes
42 * available. Which is a bit a problem on driver load and also after system
43 * suspend. One way to solve this is to have a hardware state read-out
44 * infrastructure which reconstructs the full software state (e.g. the i915
45 * driver).
46 *
47 * The simpler solution is to just reset the software state to everything off,
48 * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
49 * the atomic helpers provide default reset implementations for all hooks.
50 *
51 * On the upside the precise state tracking of atomic simplifies system suspend
52 * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
53 * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
54 * For other drivers the building blocks are split out, see the documentation
55 * for these functions.
56 */
57
58/**
59 * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
60 * @crtc: drm CRTC
61 *
62 * Resets the atomic state for @crtc by freeing the state pointer (which might
63 * be NULL, e.g. at driver load time) and allocating a new empty state object.
64 */
65void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
66{
67 if (crtc->state)
68 __drm_atomic_helper_crtc_destroy_state(crtc->state);
69
70 kfree(crtc->state);
71 crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
72
73 if (crtc->state)
74 crtc->state->crtc = crtc;
75}
76EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
77
78/**
79 * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
80 * @crtc: CRTC object
81 * @state: atomic CRTC state
82 *
83 * Copies atomic state from a CRTC's current state and resets inferred values.
84 * This is useful for drivers that subclass the CRTC state.
85 */
86void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
87 struct drm_crtc_state *state)
88{
89 memcpy(state, crtc->state, sizeof(*state));
90
91 if (state->mode_blob)
92 drm_property_blob_get(state->mode_blob);
93 if (state->degamma_lut)
94 drm_property_blob_get(state->degamma_lut);
95 if (state->ctm)
96 drm_property_blob_get(state->ctm);
97 if (state->gamma_lut)
98 drm_property_blob_get(state->gamma_lut);
99 state->mode_changed = false;
100 state->active_changed = false;
101 state->planes_changed = false;
102 state->connectors_changed = false;
103 state->color_mgmt_changed = false;
104 state->zpos_changed = false;
105 state->commit = NULL;
106 state->event = NULL;
107 state->pageflip_flags = 0;
108}
109EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
110
111/**
112 * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
113 * @crtc: drm CRTC
114 *
115 * Default CRTC state duplicate hook for drivers which don't have their own
116 * subclassed CRTC state structure.
117 */
118struct drm_crtc_state *
119drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
120{
121 struct drm_crtc_state *state;
122
123 if (WARN_ON(!crtc->state))
124 return NULL;
125
126 state = kmalloc(sizeof(*state), GFP_KERNEL);
127 if (state)
128 __drm_atomic_helper_crtc_duplicate_state(crtc, state);
129
130 return state;
131}
132EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
133
134/**
135 * __drm_atomic_helper_crtc_destroy_state - release CRTC state
136 * @state: CRTC state object to release
137 *
138 * Releases all resources stored in the CRTC state without actually freeing
139 * the memory of the CRTC state. This is useful for drivers that subclass the
140 * CRTC state.
141 */
142void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
143{
144 if (state->commit) {
145 /*
146 * In the event that a non-blocking commit returns
147 * -ERESTARTSYS before the commit_tail work is queued, we will
148 * have an extra reference to the commit object. Release it, if
149 * the event has not been consumed by the worker.
150 *
151 * state->event may be freed, so we can't directly look at
152 * state->event->base.completion.
153 */
154 if (state->event && state->commit->abort_completion)
155 drm_crtc_commit_put(state->commit);
156
157 kfree(state->commit->event);
158 state->commit->event = NULL;
159
160 drm_crtc_commit_put(state->commit);
161 }
162
163 drm_property_blob_put(state->mode_blob);
164 drm_property_blob_put(state->degamma_lut);
165 drm_property_blob_put(state->ctm);
166 drm_property_blob_put(state->gamma_lut);
167}
168EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
169
170/**
171 * drm_atomic_helper_crtc_destroy_state - default state destroy hook
172 * @crtc: drm CRTC
173 * @state: CRTC state object to release
174 *
175 * Default CRTC state destroy hook for drivers which don't have their own
176 * subclassed CRTC state structure.
177 */
178void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
179 struct drm_crtc_state *state)
180{
181 __drm_atomic_helper_crtc_destroy_state(state);
182 kfree(state);
183}
184EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
185
186/**
187 * __drm_atomic_helper_plane_reset - resets planes state to default values
188 * @plane: plane object, must not be NULL
189 * @state: atomic plane state, must not be NULL
190 *
191 * Initializes plane state to default. This is useful for drivers that subclass
192 * the plane state.
193 */
194void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
195 struct drm_plane_state *state)
196{
197 state->plane = plane;
198 state->rotation = DRM_MODE_ROTATE_0;
199
200 state->alpha = DRM_BLEND_ALPHA_OPAQUE;
201 state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
202
203 plane->state = state;
204}
205EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
206
207/**
208 * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
209 * @plane: drm plane
210 *
211 * Resets the atomic state for @plane by freeing the state pointer (which might
212 * be NULL, e.g. at driver load time) and allocating a new empty state object.
213 */
214void drm_atomic_helper_plane_reset(struct drm_plane *plane)
215{
216 if (plane->state)
217 __drm_atomic_helper_plane_destroy_state(plane->state);
218
219 kfree(plane->state);
220 plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
221 if (plane->state)
222 __drm_atomic_helper_plane_reset(plane, plane->state);
223}
224EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
225
226/**
227 * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
228 * @plane: plane object
229 * @state: atomic plane state
230 *
231 * Copies atomic state from a plane's current state. This is useful for
232 * drivers that subclass the plane state.
233 */
234void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
235 struct drm_plane_state *state)
236{
237 memcpy(state, plane->state, sizeof(*state));
238
239 if (state->fb)
240 drm_framebuffer_get(state->fb);
241
242 state->fence = NULL;
243 state->commit = NULL;
244}
245EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
246
247/**
248 * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
249 * @plane: drm plane
250 *
251 * Default plane state duplicate hook for drivers which don't have their own
252 * subclassed plane state structure.
253 */
254struct drm_plane_state *
255drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
256{
257 struct drm_plane_state *state;
258
259 if (WARN_ON(!plane->state))
260 return NULL;
261
262 state = kmalloc(sizeof(*state), GFP_KERNEL);
263 if (state)
264 __drm_atomic_helper_plane_duplicate_state(plane, state);
265
266 return state;
267}
268EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
269
270/**
271 * __drm_atomic_helper_plane_destroy_state - release plane state
272 * @state: plane state object to release
273 *
274 * Releases all resources stored in the plane state without actually freeing
275 * the memory of the plane state. This is useful for drivers that subclass the
276 * plane state.
277 */
278void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
279{
280 if (state->fb)
281 drm_framebuffer_put(state->fb);
282
283 if (state->fence)
284 dma_fence_put(state->fence);
285
286 if (state->commit)
287 drm_crtc_commit_put(state->commit);
288}
289EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
290
291/**
292 * drm_atomic_helper_plane_destroy_state - default state destroy hook
293 * @plane: drm plane
294 * @state: plane state object to release
295 *
296 * Default plane state destroy hook for drivers which don't have their own
297 * subclassed plane state structure.
298 */
299void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
300 struct drm_plane_state *state)
301{
302 __drm_atomic_helper_plane_destroy_state(state);
303 kfree(state);
304}
305EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
306
307/**
308 * __drm_atomic_helper_connector_reset - reset state on connector
309 * @connector: drm connector
310 * @conn_state: connector state to assign
311 *
312 * Initializes the newly allocated @conn_state and assigns it to
313 * the &drm_conector->state pointer of @connector, usually required when
314 * initializing the drivers or when called from the &drm_connector_funcs.reset
315 * hook.
316 *
317 * This is useful for drivers that subclass the connector state.
318 */
319void
320__drm_atomic_helper_connector_reset(struct drm_connector *connector,
321 struct drm_connector_state *conn_state)
322{
323 if (conn_state)
324 conn_state->connector = connector;
325
326 connector->state = conn_state;
327}
328EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
329
330/**
331 * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
332 * @connector: drm connector
333 *
334 * Resets the atomic state for @connector by freeing the state pointer (which
335 * might be NULL, e.g. at driver load time) and allocating a new empty state
336 * object.
337 */
338void drm_atomic_helper_connector_reset(struct drm_connector *connector)
339{
340 struct drm_connector_state *conn_state =
341 kzalloc(sizeof(*conn_state), GFP_KERNEL);
342
343 if (connector->state)
344 __drm_atomic_helper_connector_destroy_state(connector->state);
345
346 kfree(connector->state);
347 __drm_atomic_helper_connector_reset(connector, conn_state);
348}
349EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
350
351/**
352 * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
353 * @connector: connector object
354 * @state: atomic connector state
355 *
356 * Copies atomic state from a connector's current state. This is useful for
357 * drivers that subclass the connector state.
358 */
359void
360__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
361 struct drm_connector_state *state)
362{
363 memcpy(state, connector->state, sizeof(*state));
364 if (state->crtc)
365 drm_connector_get(connector);
366 state->commit = NULL;
367
368 /* Don't copy over a writeback job, they are used only once */
369 state->writeback_job = NULL;
370}
371EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
372
373/**
374 * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
375 * @connector: drm connector
376 *
377 * Default connector state duplicate hook for drivers which don't have their own
378 * subclassed connector state structure.
379 */
380struct drm_connector_state *
381drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
382{
383 struct drm_connector_state *state;
384
385 if (WARN_ON(!connector->state))
386 return NULL;
387
388 state = kmalloc(sizeof(*state), GFP_KERNEL);
389 if (state)
390 __drm_atomic_helper_connector_duplicate_state(connector, state);
391
392 return state;
393}
394EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
395
396/**
397 * drm_atomic_helper_duplicate_state - duplicate an atomic state object
398 * @dev: DRM device
399 * @ctx: lock acquisition context
400 *
401 * Makes a copy of the current atomic state by looping over all objects and
402 * duplicating their respective states. This is used for example by suspend/
403 * resume support code to save the state prior to suspend such that it can
404 * be restored upon resume.
405 *
406 * Note that this treats atomic state as persistent between save and restore.
407 * Drivers must make sure that this is possible and won't result in confusion
408 * or erroneous behaviour.
409 *
410 * Note that if callers haven't already acquired all modeset locks this might
411 * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
412 *
413 * Returns:
414 * A pointer to the copy of the atomic state object on success or an
415 * ERR_PTR()-encoded error code on failure.
416 *
417 * See also:
418 * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
419 */
420struct drm_atomic_state *
421drm_atomic_helper_duplicate_state(struct drm_device *dev,
422 struct drm_modeset_acquire_ctx *ctx)
423{
424 struct drm_atomic_state *state;
425 struct drm_connector *conn;
426 struct drm_connector_list_iter conn_iter;
427 struct drm_plane *plane;
428 struct drm_crtc *crtc;
429 int err = 0;
430
431 state = drm_atomic_state_alloc(dev);
432 if (!state)
433 return ERR_PTR(-ENOMEM);
434
435 state->acquire_ctx = ctx;
436
437 drm_for_each_crtc(crtc, dev) {
438 struct drm_crtc_state *crtc_state;
439
440 crtc_state = drm_atomic_get_crtc_state(state, crtc);
441 if (IS_ERR(crtc_state)) {
442 err = PTR_ERR(crtc_state);
443 goto free;
444 }
445 }
446
447 drm_for_each_plane(plane, dev) {
448 struct drm_plane_state *plane_state;
449
450 plane_state = drm_atomic_get_plane_state(state, plane);
451 if (IS_ERR(plane_state)) {
452 err = PTR_ERR(plane_state);
453 goto free;
454 }
455 }
456
457 drm_connector_list_iter_begin(dev, &conn_iter);
458 drm_for_each_connector_iter(conn, &conn_iter) {
459 struct drm_connector_state *conn_state;
460
461 conn_state = drm_atomic_get_connector_state(state, conn);
462 if (IS_ERR(conn_state)) {
463 err = PTR_ERR(conn_state);
464 drm_connector_list_iter_end(&conn_iter);
465 goto free;
466 }
467 }
468 drm_connector_list_iter_end(&conn_iter);
469
470 /* clear the acquire context so that it isn't accidentally reused */
471 state->acquire_ctx = NULL;
472
473free:
474 if (err < 0) {
475 drm_atomic_state_put(state);
476 state = ERR_PTR(err);
477 }
478
479 return state;
480}
481EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
482
483/**
484 * __drm_atomic_helper_connector_destroy_state - release connector state
485 * @state: connector state object to release
486 *
487 * Releases all resources stored in the connector state without actually
488 * freeing the memory of the connector state. This is useful for drivers that
489 * subclass the connector state.
490 */
491void
492__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
493{
494 if (state->crtc)
495 drm_connector_put(state->connector);
496
497 if (state->commit)
498 drm_crtc_commit_put(state->commit);
499}
500EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
501
502/**
503 * drm_atomic_helper_connector_destroy_state - default state destroy hook
504 * @connector: drm connector
505 * @state: connector state object to release
506 *
507 * Default connector state destroy hook for drivers which don't have their own
508 * subclassed connector state structure.
509 */
510void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
511 struct drm_connector_state *state)
512{
513 __drm_atomic_helper_connector_destroy_state(state);
514 kfree(state);
515}
516EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
517
518/**
519 * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
520 * @crtc: CRTC object
521 * @red: red correction table
522 * @green: green correction table
523 * @blue: green correction table
524 * @size: size of the tables
525 * @ctx: lock acquire context
526 *
527 * Implements support for legacy gamma correction table for drivers
528 * that support color management through the DEGAMMA_LUT/GAMMA_LUT
529 * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
530 * how the atomic color management and gamma tables work.
531 */
532int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
533 u16 *red, u16 *green, u16 *blue,
534 uint32_t size,
535 struct drm_modeset_acquire_ctx *ctx)
536{
537 struct drm_device *dev = crtc->dev;
538 struct drm_atomic_state *state;
539 struct drm_crtc_state *crtc_state;
540 struct drm_property_blob *blob = NULL;
541 struct drm_color_lut *blob_data;
542 int i, ret = 0;
543 bool replaced;
544
545 state = drm_atomic_state_alloc(crtc->dev);
546 if (!state)
547 return -ENOMEM;
548
549 blob = drm_property_create_blob(dev,
550 sizeof(struct drm_color_lut) * size,
551 NULL);
552 if (IS_ERR(blob)) {
553 ret = PTR_ERR(blob);
554 blob = NULL;
555 goto fail;
556 }
557
558 /* Prepare GAMMA_LUT with the legacy values. */
559 blob_data = blob->data;
560 for (i = 0; i < size; i++) {
561 blob_data[i].red = red[i];
562 blob_data[i].green = green[i];
563 blob_data[i].blue = blue[i];
564 }
565
566 state->acquire_ctx = ctx;
567 crtc_state = drm_atomic_get_crtc_state(state, crtc);
568 if (IS_ERR(crtc_state)) {
569 ret = PTR_ERR(crtc_state);
570 goto fail;
571 }
572
573 /* Reset DEGAMMA_LUT and CTM properties. */
574 replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
575 replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
576 replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
577 crtc_state->color_mgmt_changed |= replaced;
578
579 ret = drm_atomic_commit(state);
580
581fail:
582 drm_atomic_state_put(state);
583 drm_property_blob_put(blob);
584 return ret;
585}
586EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
587
588/**
589 * __drm_atomic_helper_private_duplicate_state - copy atomic private state
590 * @obj: CRTC object
591 * @state: new private object state
592 *
593 * Copies atomic state from a private objects's current state and resets inferred values.
594 * This is useful for drivers that subclass the private state.
595 */
596void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
597 struct drm_private_state *state)
598{
599 memcpy(state, obj->state, sizeof(*state));
600}
601EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 7412acaf3cde..d7d10cabb9bb 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -36,6 +36,8 @@
36#include <drm/drmP.h> 36#include <drm/drmP.h>
37#include "drm_legacy.h" 37#include "drm_legacy.h"
38 38
39#include <linux/nospec.h>
40
39static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, 41static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
40 struct drm_local_map *map) 42 struct drm_local_map *map)
41{ 43{
@@ -1417,6 +1419,7 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
1417 idx, dma->buf_count - 1); 1419 idx, dma->buf_count - 1);
1418 return -EINVAL; 1420 return -EINVAL;
1419 } 1421 }
1422 idx = array_index_nospec(idx, dma->buf_count);
1420 buf = dma->buflist[idx]; 1423 buf = dma->buflist[idx];
1421 if (buf->file_priv != file_priv) { 1424 if (buf->file_priv != file_priv) {
1422 DRM_ERROR("Process %d freeing buffer not owned\n", 1425 DRM_ERROR("Process %d freeing buffer not owned\n",
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4943cef178be..aa18b1d7d3e4 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -260,9 +260,7 @@ int drm_connector_init(struct drm_device *dev,
260 260
261 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && 261 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL &&
262 connector_type != DRM_MODE_CONNECTOR_WRITEBACK) 262 connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
263 drm_object_attach_property(&connector->base, 263 drm_connector_attach_edid_property(connector);
264 config->edid_property,
265 0);
266 264
267 drm_object_attach_property(&connector->base, 265 drm_object_attach_property(&connector->base,
268 config->dpms_property, 0); 266 config->dpms_property, 0);
@@ -295,6 +293,24 @@ out_put:
295EXPORT_SYMBOL(drm_connector_init); 293EXPORT_SYMBOL(drm_connector_init);
296 294
297/** 295/**
296 * drm_connector_attach_edid_property - attach edid property.
297 * @connector: the connector
298 *
299 * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a
300 * edid property attached by default. This function can be used to
301 * explicitly enable the edid property in these cases.
302 */
303void drm_connector_attach_edid_property(struct drm_connector *connector)
304{
305 struct drm_mode_config *config = &connector->dev->mode_config;
306
307 drm_object_attach_property(&connector->base,
308 config->edid_property,
309 0);
310}
311EXPORT_SYMBOL(drm_connector_attach_edid_property);
312
313/**
298 * drm_connector_attach_encoder - attach a connector to an encoder 314 * drm_connector_attach_encoder - attach a connector to an encoder
299 * @connector: connector to attach 315 * @connector: connector to attach
300 * @encoder: encoder to attach @connector to 316 * @encoder: encoder to attach @connector to
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ce75e9506e85..a3c81850e755 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -984,118 +984,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
984 drm_modeset_unlock_all(dev); 984 drm_modeset_unlock_all(dev);
985} 985}
986EXPORT_SYMBOL(drm_helper_resume_force_mode); 986EXPORT_SYMBOL(drm_helper_resume_force_mode);
987
988/**
989 * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
990 * @crtc: DRM CRTC
991 * @mode: DRM display mode which userspace requested
992 * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
993 * @x: x offset of the CRTC scanout area on the underlying framebuffer
994 * @y: y offset of the CRTC scanout area on the underlying framebuffer
995 * @old_fb: previous framebuffer
996 *
997 * This function implements a callback useable as the ->mode_set callback
998 * required by the CRTC helpers. Besides the atomic plane helper functions for
999 * the primary plane the driver must also provide the ->mode_set_nofb callback
1000 * to set up the CRTC.
1001 *
1002 * This is a transitional helper useful for converting drivers to the atomic
1003 * interfaces.
1004 */
1005int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
1006 struct drm_display_mode *adjusted_mode, int x, int y,
1007 struct drm_framebuffer *old_fb)
1008{
1009 struct drm_crtc_state *crtc_state;
1010 const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
1011 int ret;
1012
1013 if (crtc->funcs->atomic_duplicate_state)
1014 crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
1015 else {
1016 if (!crtc->state)
1017 drm_atomic_helper_crtc_reset(crtc);
1018
1019 crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
1020 }
1021
1022 if (!crtc_state)
1023 return -ENOMEM;
1024
1025 crtc_state->planes_changed = true;
1026 crtc_state->mode_changed = true;
1027 ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
1028 if (ret)
1029 goto out;
1030 drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
1031
1032 if (crtc_funcs->atomic_check) {
1033 ret = crtc_funcs->atomic_check(crtc, crtc_state);
1034 if (ret)
1035 goto out;
1036 }
1037
1038 swap(crtc->state, crtc_state);
1039
1040 crtc_funcs->mode_set_nofb(crtc);
1041
1042 ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
1043
1044out:
1045 if (crtc_state) {
1046 if (crtc->funcs->atomic_destroy_state)
1047 crtc->funcs->atomic_destroy_state(crtc, crtc_state);
1048 else
1049 drm_atomic_helper_crtc_destroy_state(crtc, crtc_state);
1050 }
1051
1052 return ret;
1053}
1054EXPORT_SYMBOL(drm_helper_crtc_mode_set);
1055
1056/**
1057 * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
1058 * @crtc: DRM CRTC
1059 * @x: x offset of the CRTC scanout area on the underlying framebuffer
1060 * @y: y offset of the CRTC scanout area on the underlying framebuffer
1061 * @old_fb: previous framebuffer
1062 *
1063 * This function implements a callback useable as the ->mode_set_base used
1064 * required by the CRTC helpers. The driver must provide the atomic plane helper
1065 * functions for the primary plane.
1066 *
1067 * This is a transitional helper useful for converting drivers to the atomic
1068 * interfaces.
1069 */
1070int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
1071 struct drm_framebuffer *old_fb)
1072{
1073 struct drm_plane_state *plane_state;
1074 struct drm_plane *plane = crtc->primary;
1075
1076 if (plane->funcs->atomic_duplicate_state)
1077 plane_state = plane->funcs->atomic_duplicate_state(plane);
1078 else {
1079 if (!plane->state)
1080 drm_atomic_helper_plane_reset(plane);
1081
1082 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
1083 }
1084 if (!plane_state)
1085 return -ENOMEM;
1086 plane_state->plane = plane;
1087
1088 plane_state->crtc = crtc;
1089 drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
1090 plane_state->crtc_x = 0;
1091 plane_state->crtc_y = 0;
1092 plane_state->crtc_h = crtc->mode.vdisplay;
1093 plane_state->crtc_w = crtc->mode.hdisplay;
1094 plane_state->src_x = x << 16;
1095 plane_state->src_y = y << 16;
1096 plane_state->src_h = crtc->mode.vdisplay << 16;
1097 plane_state->src_w = crtc->mode.hdisplay << 16;
1098
1099 return drm_plane_helper_commit(plane, plane_state, old_fb);
1100}
1101EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c
index 8a718f85079a..b15cee85b702 100644
--- a/drivers/gpu/drm/drm_dp_cec.c
+++ b/drivers/gpu/drm/drm_dp_cec.c
@@ -424,8 +424,6 @@ void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name,
424 aux->cec.parent = parent; 424 aux->cec.parent = parent;
425 INIT_DELAYED_WORK(&aux->cec.unregister_work, 425 INIT_DELAYED_WORK(&aux->cec.unregister_work,
426 drm_dp_cec_unregister_work); 426 drm_dp_cec_unregister_work);
427
428 drm_dp_cec_set_edid(aux, NULL);
429} 427}
430EXPORT_SYMBOL(drm_dp_cec_register_connector); 428EXPORT_SYMBOL(drm_dp_cec_register_connector);
431 429
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 0e0df398222d..529414556962 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -2572,9 +2572,16 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
2572EXPORT_SYMBOL(drm_dp_mst_get_edid); 2572EXPORT_SYMBOL(drm_dp_mst_get_edid);
2573 2573
2574/** 2574/**
2575 * drm_dp_find_vcpi_slots() - find slots for this PBN value 2575 * drm_dp_find_vcpi_slots() - Find VCPI slots for this PBN value
2576 * @mgr: manager to use 2576 * @mgr: manager to use
2577 * @pbn: payload bandwidth to convert into slots. 2577 * @pbn: payload bandwidth to convert into slots.
2578 *
2579 * Calculate the number of VCPI slots that will be required for the given PBN
2580 * value. This function is deprecated, and should not be used in atomic
2581 * drivers.
2582 *
2583 * RETURNS:
2584 * The total slots required for this port, or error.
2578 */ 2585 */
2579int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, 2586int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
2580 int pbn) 2587 int pbn)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 36e8e9cbec52..aa1cef794f9a 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -476,8 +476,6 @@ static void drm_fs_inode_free(struct inode *inode)
476 * The initial ref-count of the object is 1. Use drm_dev_get() and 476 * The initial ref-count of the object is 1. Use drm_dev_get() and
477 * drm_dev_put() to take and drop further ref-counts. 477 * drm_dev_put() to take and drop further ref-counts.
478 * 478 *
479 * Note that for purely virtual devices @parent can be NULL.
480 *
481 * Drivers that do not want to allocate their own device struct 479 * Drivers that do not want to allocate their own device struct
482 * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers 480 * embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
483 * that do embed &struct drm_device it must be placed first in the overall 481 * that do embed &struct drm_device it must be placed first in the overall
@@ -502,6 +500,8 @@ int drm_dev_init(struct drm_device *dev,
502 return -ENODEV; 500 return -ENODEV;
503 } 501 }
504 502
503 BUG_ON(!parent);
504
505 kref_init(&dev->ref); 505 kref_init(&dev->ref);
506 dev->dev = parent; 506 dev->dev = parent;
507 dev->driver = driver; 507 dev->driver = driver;
@@ -556,9 +556,7 @@ int drm_dev_init(struct drm_device *dev,
556 } 556 }
557 } 557 }
558 558
559 /* Use the parent device name as DRM device unique identifier, but fall 559 ret = drm_dev_set_unique(dev, dev_name(parent));
560 * back to the driver name for virtual devices like vgem. */
561 ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
562 if (ret) 560 if (ret)
563 goto err_setunique; 561 goto err_setunique;
564 562
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index fb0dfc62b1b6..5b516615881a 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -72,7 +72,9 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
72EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); 72EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
73 73
74/** 74/**
75 * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer 75 * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel
76 * formats where values are grouped in blocks this will get you the beginning of
77 * the block
76 * @fb: The framebuffer 78 * @fb: The framebuffer
77 * @state: Which state of drm plane 79 * @state: Which state of drm plane
78 * @plane: Which plane 80 * @plane: Which plane
@@ -87,6 +89,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
87 struct drm_gem_cma_object *obj; 89 struct drm_gem_cma_object *obj;
88 dma_addr_t paddr; 90 dma_addr_t paddr;
89 u8 h_div = 1, v_div = 1; 91 u8 h_div = 1, v_div = 1;
92 u32 block_w = drm_format_info_block_width(fb->format, plane);
93 u32 block_h = drm_format_info_block_height(fb->format, plane);
94 u32 block_size = fb->format->char_per_block[plane];
95 u32 sample_x;
96 u32 sample_y;
97 u32 block_start_y;
98 u32 num_hblocks;
90 99
91 obj = drm_fb_cma_get_gem_obj(fb, plane); 100 obj = drm_fb_cma_get_gem_obj(fb, plane);
92 if (!obj) 101 if (!obj)
@@ -99,8 +108,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
99 v_div = fb->format->vsub; 108 v_div = fb->format->vsub;
100 } 109 }
101 110
102 paddr += (fb->format->cpp[plane] * (state->src_x >> 16)) / h_div; 111 sample_x = (state->src_x >> 16) / h_div;
103 paddr += (fb->pitches[plane] * (state->src_y >> 16)) / v_div; 112 sample_y = (state->src_y >> 16) / v_div;
113 block_start_y = (sample_y / block_h) * block_h;
114 num_hblocks = sample_x / block_w;
115
116 paddr += fb->pitches[plane] * block_start_y;
117 paddr += block_size * num_hblocks;
104 118
105 return paddr; 119 return paddr;
106} 120}
@@ -124,10 +138,7 @@ int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
124 138
125 /* dev->fb_helper will indirectly point to fbdev_cma after this call */ 139 /* dev->fb_helper will indirectly point to fbdev_cma after this call */
126 fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count); 140 fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count);
127 if (IS_ERR(fbdev_cma)) 141 return PTR_ERR_OR_ZERO(fbdev_cma);
128 return PTR_ERR(fbdev_cma);
129
130 return 0;
131} 142}
132EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init); 143EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init);
133 144
@@ -226,21 +237,3 @@ void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
226 drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper); 237 drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
227} 238}
228EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event); 239EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
229
230/**
231 * drm_fbdev_cma_set_suspend_unlocked - wrapper around
232 * drm_fb_helper_set_suspend_unlocked
233 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
234 * @state: desired state, zero to resume, non-zero to suspend
235 *
236 * Calls drm_fb_helper_set_suspend, which is a wrapper around
237 * fb_set_suspend implemented by fbdev core.
238 */
239void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
240 bool state)
241{
242 if (fbdev_cma)
243 drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper,
244 state);
245}
246EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index a502f3e519fd..9a69ad7e9f3b 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1632,6 +1632,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
1632 if (var->pixclock != 0 || in_dbg_master()) 1632 if (var->pixclock != 0 || in_dbg_master())
1633 return -EINVAL; 1633 return -EINVAL;
1634 1634
1635 if ((drm_format_info_block_width(fb->format, 0) > 1) ||
1636 (drm_format_info_block_height(fb->format, 0) > 1))
1637 return -EINVAL;
1638
1635 /* 1639 /*
1636 * Changes struct fb_var_screeninfo are currently not pushed back 1640 * Changes struct fb_var_screeninfo are currently not pushed back
1637 * to KMS, hence fail if different settings are requested. 1641 * to KMS, hence fail if different settings are requested.
@@ -1949,6 +1953,8 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
1949{ 1953{
1950 struct drm_framebuffer *fb = fb_helper->fb; 1954 struct drm_framebuffer *fb = fb_helper->fb;
1951 1955
1956 WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) ||
1957 (drm_format_info_block_height(fb->format, 0) > 1));
1952 info->pseudo_palette = fb_helper->pseudo_palette; 1958 info->pseudo_palette = fb_helper->pseudo_palette;
1953 info->var.xres_virtual = fb->width; 1959 info->var.xres_virtual = fb->width;
1954 info->var.yres_virtual = fb->height; 1960 info->var.yres_virtual = fb->height;
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 8aaa5e86a979..f523948c82b1 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -103,8 +103,8 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
103 * 103 *
104 * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 104 * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
105 * Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config, 105 * Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
106 * and depending on the quirk_addfb_prefer_host_byte_order flag it returns 106 * and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
107 * little endian byte order or host byte order framebuffer formats. 107 * it returns little endian byte order or host byte order framebuffer formats.
108 */ 108 */
109uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, 109uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
110 uint32_t bpp, uint32_t depth) 110 uint32_t bpp, uint32_t depth)
@@ -225,6 +225,18 @@ const struct drm_format_info *__drm_format_info(u32 format)
225 { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, 225 { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
226 { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, 226 { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
227 { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true }, 227 { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
228 { .format = DRM_FORMAT_Y0L0, .depth = 0, .num_planes = 1,
229 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
230 .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
231 { .format = DRM_FORMAT_X0L0, .depth = 0, .num_planes = 1,
232 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
233 .hsub = 2, .vsub = 2, .is_yuv = true },
234 { .format = DRM_FORMAT_Y0L2, .depth = 0, .num_planes = 1,
235 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
236 .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
237 { .format = DRM_FORMAT_X0L2, .depth = 0, .num_planes = 1,
238 .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
239 .hsub = 2, .vsub = 2, .is_yuv = true },
228 }; 240 };
229 241
230 unsigned int i; 242 unsigned int i;
@@ -400,3 +412,65 @@ int drm_format_plane_height(int height, uint32_t format, int plane)
400 return height / info->vsub; 412 return height / info->vsub;
401} 413}
402EXPORT_SYMBOL(drm_format_plane_height); 414EXPORT_SYMBOL(drm_format_plane_height);
415
416/**
417 * drm_format_info_block_width - width in pixels of block.
418 * @info: pixel format info
419 * @plane: plane index
420 *
421 * Returns:
422 * The width in pixels of a block, depending on the plane index.
423 */
424unsigned int drm_format_info_block_width(const struct drm_format_info *info,
425 int plane)
426{
427 if (!info || plane < 0 || plane >= info->num_planes)
428 return 0;
429
430 if (!info->block_w[plane])
431 return 1;
432 return info->block_w[plane];
433}
434EXPORT_SYMBOL(drm_format_info_block_width);
435
436/**
437 * drm_format_info_block_height - height in pixels of a block
438 * @info: pixel format info
439 * @plane: plane index
440 *
441 * Returns:
442 * The height in pixels of a block, depending on the plane index.
443 */
444unsigned int drm_format_info_block_height(const struct drm_format_info *info,
445 int plane)
446{
447 if (!info || plane < 0 || plane >= info->num_planes)
448 return 0;
449
450 if (!info->block_h[plane])
451 return 1;
452 return info->block_h[plane];
453}
454EXPORT_SYMBOL(drm_format_info_block_height);
455
456/**
457 * drm_format_info_min_pitch - computes the minimum required pitch in bytes
458 * @info: pixel format info
459 * @plane: plane index
460 * @buffer_width: buffer width in pixels
461 *
462 * Returns:
463 * The minimum required pitch in bytes for a buffer by taking into consideration
464 * the pixel format information and the buffer width.
465 */
466uint64_t drm_format_info_min_pitch(const struct drm_format_info *info,
467 int plane, unsigned int buffer_width)
468{
469 if (!info || plane < 0 || plane >= info->num_planes)
470 return 0;
471
472 return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
473 drm_format_info_block_width(info, plane) *
474 drm_format_info_block_height(info, plane));
475}
476EXPORT_SYMBOL(drm_format_info_min_pitch);
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 3bf729d0aae5..fcaea8f50513 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -195,20 +195,26 @@ static int framebuffer_check(struct drm_device *dev,
195 for (i = 0; i < info->num_planes; i++) { 195 for (i = 0; i < info->num_planes; i++) {
196 unsigned int width = fb_plane_width(r->width, info, i); 196 unsigned int width = fb_plane_width(r->width, info, i);
197 unsigned int height = fb_plane_height(r->height, info, i); 197 unsigned int height = fb_plane_height(r->height, info, i);
198 unsigned int cpp = info->cpp[i]; 198 unsigned int block_size = info->char_per_block[i];
199 u64 min_pitch = drm_format_info_min_pitch(info, i, width);
200
201 if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
202 DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i);
203 return -EINVAL;
204 }
199 205
200 if (!r->handles[i]) { 206 if (!r->handles[i]) {
201 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 207 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
202 return -EINVAL; 208 return -EINVAL;
203 } 209 }
204 210
205 if ((uint64_t) width * cpp > UINT_MAX) 211 if (min_pitch > UINT_MAX)
206 return -ERANGE; 212 return -ERANGE;
207 213
208 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 214 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
209 return -ERANGE; 215 return -ERANGE;
210 216
211 if (r->pitches[i] < width * cpp) { 217 if (block_size && r->pitches[i] < min_pitch) {
212 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 218 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
213 return -EINVAL; 219 return -EINVAL;
214 } 220 }
@@ -317,6 +323,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
317 323
318 return fb; 324 return fb;
319} 325}
326EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_internal_framebuffer_create);
320 327
321/** 328/**
322 * drm_mode_addfb2 - add an FB to the graphics configuration 329 * drm_mode_addfb2 - add an FB to the graphics configuration
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index ded7a379ac35..acb466d25afc 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -171,7 +171,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
171 } 171 }
172 172
173 min_size = (height - 1) * mode_cmd->pitches[i] 173 min_size = (height - 1) * mode_cmd->pitches[i]
174 + width * info->cpp[i] 174 + drm_format_info_min_pitch(info, i, width)
175 + mode_cmd->offsets[i]; 175 + mode_cmd->offsets[i];
176 176
177 if (objs[i]->size < min_size) { 177 if (objs[i]->size < min_size) {
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index 24a177ea5417..3650d3c46718 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -39,7 +39,6 @@ struct drm_master *drm_lease_owner(struct drm_master *master)
39 master = master->lessor; 39 master = master->lessor;
40 return master; 40 return master;
41} 41}
42EXPORT_SYMBOL(drm_lease_owner);
43 42
44/** 43/**
45 * _drm_find_lessee - find lessee by id (idr_mutex held) 44 * _drm_find_lessee - find lessee by id (idr_mutex held)
@@ -117,7 +116,6 @@ bool _drm_lease_held(struct drm_file *file_priv, int id)
117 116
118 return _drm_lease_held_master(file_priv->master, id); 117 return _drm_lease_held_master(file_priv->master, id);
119} 118}
120EXPORT_SYMBOL(_drm_lease_held);
121 119
122/** 120/**
123 * drm_lease_held - check drm_mode_object lease status (idr_mutex not held) 121 * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
@@ -144,7 +142,6 @@ bool drm_lease_held(struct drm_file *file_priv, int id)
144 mutex_unlock(&master->dev->mode_config.idr_mutex); 142 mutex_unlock(&master->dev->mode_config.idr_mutex);
145 return ret; 143 return ret;
146} 144}
147EXPORT_SYMBOL(drm_lease_held);
148 145
149/** 146/**
150 * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held) 147 * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
@@ -184,7 +181,6 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
184 mutex_unlock(&master->dev->mode_config.idr_mutex); 181 mutex_unlock(&master->dev->mode_config.idr_mutex);
185 return crtcs_out; 182 return crtcs_out;
186} 183}
187EXPORT_SYMBOL(drm_lease_filter_crtcs);
188 184
189/* 185/*
190 * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held) 186 * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
@@ -195,7 +191,7 @@ EXPORT_SYMBOL(drm_lease_filter_crtcs);
195 * make sure all of the desired objects can be leased, atomically 191 * make sure all of the desired objects can be leased, atomically
196 * leasing them to the new drmmaster. 192 * leasing them to the new drmmaster.
197 * 193 *
198 * ERR_PTR(-EACCESS) some other master holds the title to any object 194 * ERR_PTR(-EACCES) some other master holds the title to any object
199 * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device 195 * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device
200 * ERR_PTR(-EBUSY) some other lessee holds title to this object 196 * ERR_PTR(-EBUSY) some other lessee holds title to this object
201 * ERR_PTR(-EEXIST) same object specified more than once in the provided list 197 * ERR_PTR(-EEXIST) same object specified more than once in the provided list
@@ -357,9 +353,9 @@ void drm_lease_revoke(struct drm_master *top)
357} 353}
358 354
359static int validate_lease(struct drm_device *dev, 355static int validate_lease(struct drm_device *dev,
360 struct drm_file *lessor_priv,
361 int object_count, 356 int object_count,
362 struct drm_mode_object **objects) 357 struct drm_mode_object **objects,
358 bool universal_planes)
363{ 359{
364 int o; 360 int o;
365 int has_crtc = -1; 361 int has_crtc = -1;
@@ -376,14 +372,14 @@ static int validate_lease(struct drm_device *dev,
376 if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1) 372 if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
377 has_connector = o; 373 has_connector = o;
378 374
379 if (lessor_priv->universal_planes) { 375 if (universal_planes) {
380 if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1) 376 if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
381 has_plane = o; 377 has_plane = o;
382 } 378 }
383 } 379 }
384 if (has_crtc == -1 || has_connector == -1) 380 if (has_crtc == -1 || has_connector == -1)
385 return -EINVAL; 381 return -EINVAL;
386 if (lessor_priv->universal_planes && has_plane == -1) 382 if (universal_planes && has_plane == -1)
387 return -EINVAL; 383 return -EINVAL;
388 return 0; 384 return 0;
389} 385}
@@ -397,6 +393,8 @@ static int fill_object_idr(struct drm_device *dev,
397 struct drm_mode_object **objects; 393 struct drm_mode_object **objects;
398 u32 o; 394 u32 o;
399 int ret; 395 int ret;
396 bool universal_planes = READ_ONCE(lessor_priv->universal_planes);
397
400 objects = kcalloc(object_count, sizeof(struct drm_mode_object *), 398 objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
401 GFP_KERNEL); 399 GFP_KERNEL);
402 if (!objects) 400 if (!objects)
@@ -419,14 +417,17 @@ static int fill_object_idr(struct drm_device *dev,
419 } 417 }
420 418
421 if (!drm_mode_object_lease_required(objects[o]->type)) { 419 if (!drm_mode_object_lease_required(objects[o]->type)) {
420 DRM_DEBUG_KMS("invalid object for lease\n");
422 ret = -EINVAL; 421 ret = -EINVAL;
423 goto out_free_objects; 422 goto out_free_objects;
424 } 423 }
425 } 424 }
426 425
427 ret = validate_lease(dev, lessor_priv, object_count, objects); 426 ret = validate_lease(dev, object_count, objects, universal_planes);
428 if (ret) 427 if (ret) {
428 DRM_DEBUG_LEASE("lease validation failed\n");
429 goto out_free_objects; 429 goto out_free_objects;
430 }
430 431
431 /* add their IDs to the lease request - taking into account 432 /* add their IDs to the lease request - taking into account
432 universal planes */ 433 universal planes */
@@ -449,7 +450,7 @@ static int fill_object_idr(struct drm_device *dev,
449 object_id, ret); 450 object_id, ret);
450 goto out_free_objects; 451 goto out_free_objects;
451 } 452 }
452 if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) { 453 if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
453 struct drm_crtc *crtc = obj_to_crtc(obj); 454 struct drm_crtc *crtc = obj_to_crtc(obj);
454 ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL); 455 ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
455 if (ret < 0) { 456 if (ret < 0) {
@@ -509,15 +510,21 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
509 return -EOPNOTSUPP; 510 return -EOPNOTSUPP;
510 511
511 /* Do not allow sub-leases */ 512 /* Do not allow sub-leases */
512 if (lessor->lessor) 513 if (lessor->lessor) {
514 DRM_DEBUG_LEASE("recursive leasing not allowed\n");
513 return -EINVAL; 515 return -EINVAL;
516 }
514 517
515 /* need some objects */ 518 /* need some objects */
516 if (cl->object_count == 0) 519 if (cl->object_count == 0) {
520 DRM_DEBUG_LEASE("no objects in lease\n");
517 return -EINVAL; 521 return -EINVAL;
522 }
518 523
519 if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) 524 if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
525 DRM_DEBUG_LEASE("invalid flags\n");
520 return -EINVAL; 526 return -EINVAL;
527 }
521 528
522 object_count = cl->object_count; 529 object_count = cl->object_count;
523 530
@@ -532,6 +539,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
532 object_count, object_ids); 539 object_count, object_ids);
533 kfree(object_ids); 540 kfree(object_ids);
534 if (ret) { 541 if (ret) {
542 DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret);
535 idr_destroy(&leases); 543 idr_destroy(&leases);
536 return ret; 544 return ret;
537 } 545 }
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index d69e4fc1ee77..40c4349cb939 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -51,7 +51,7 @@
51#endif 51#endif
52 52
53static void *agp_remap(unsigned long offset, unsigned long size, 53static void *agp_remap(unsigned long offset, unsigned long size,
54 struct drm_device * dev) 54 struct drm_device *dev)
55{ 55{
56 unsigned long i, num_pages = 56 unsigned long i, num_pages =
57 PAGE_ALIGN(size) / PAGE_SIZE; 57 PAGE_ALIGN(size) / PAGE_SIZE;
@@ -94,26 +94,26 @@ static void *agp_remap(unsigned long offset, unsigned long size,
94} 94}
95 95
96/** Wrapper around agp_free_memory() */ 96/** Wrapper around agp_free_memory() */
97void drm_free_agp(struct agp_memory * handle, int pages) 97void drm_free_agp(struct agp_memory *handle, int pages)
98{ 98{
99 agp_free_memory(handle); 99 agp_free_memory(handle);
100} 100}
101 101
102/** Wrapper around agp_bind_memory() */ 102/** Wrapper around agp_bind_memory() */
103int drm_bind_agp(struct agp_memory * handle, unsigned int start) 103int drm_bind_agp(struct agp_memory *handle, unsigned int start)
104{ 104{
105 return agp_bind_memory(handle, start); 105 return agp_bind_memory(handle, start);
106} 106}
107 107
108/** Wrapper around agp_unbind_memory() */ 108/** Wrapper around agp_unbind_memory() */
109int drm_unbind_agp(struct agp_memory * handle) 109int drm_unbind_agp(struct agp_memory *handle)
110{ 110{
111 return agp_unbind_memory(handle); 111 return agp_unbind_memory(handle);
112} 112}
113 113
114#else /* CONFIG_AGP */ 114#else /* CONFIG_AGP */
115static inline void *agp_remap(unsigned long offset, unsigned long size, 115static inline void *agp_remap(unsigned long offset, unsigned long size,
116 struct drm_device * dev) 116 struct drm_device *dev)
117{ 117{
118 return NULL; 118 return NULL;
119} 119}
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index be8b754eaf60..cd9bc0ce9be0 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -38,7 +38,8 @@ int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
38 int ret; 38 int ret;
39 39
40 mutex_lock(&dev->mode_config.idr_mutex); 40 mutex_lock(&dev->mode_config.idr_mutex);
41 ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 41 ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL,
42 1, 0, GFP_KERNEL);
42 if (ret >= 0) { 43 if (ret >= 0) {
43 /* 44 /*
44 * Set up the object linking under the protection of the idr 45 * Set up the object linking under the protection of the idr
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 02db9ac82d7a..24a750436559 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -716,8 +716,8 @@ int of_get_drm_display_mode(struct device_node *np,
716 if (bus_flags) 716 if (bus_flags)
717 drm_bus_flags_from_videomode(&vm, bus_flags); 717 drm_bus_flags_from_videomode(&vm, bus_flags);
718 718
719 pr_debug("%pOF: got %dx%d display mode from %s\n", 719 pr_debug("%pOF: got %dx%d display mode\n",
720 np, vm.hactive, vm.vactive, np->name); 720 np, vm.hactive, vm.vactive);
721 drm_mode_debug_printmodeline(dmode); 721 drm_mode_debug_printmodeline(dmode);
722 722
723 return 0; 723 return 0;
diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
index f1c24ab0ef09..9150fa385bba 100644
--- a/drivers/gpu/drm/drm_modeset_helper.c
+++ b/drivers/gpu/drm/drm_modeset_helper.c
@@ -146,6 +146,21 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
146 * Initialize a CRTC object with a default helper-provided primary plane and no 146 * Initialize a CRTC object with a default helper-provided primary plane and no
147 * cursor plane. 147 * cursor plane.
148 * 148 *
149 * Note that we make some assumptions about hardware limitations that may not be
150 * true for all hardware:
151 *
152 * 1. Primary plane cannot be repositioned.
153 * 2. Primary plane cannot be scaled.
154 * 3. Primary plane must cover the entire CRTC.
155 * 4. Subpixel positioning is not supported.
156 * 5. The primary plane must always be on if the CRTC is enabled.
157 *
158 * This is purely a backwards compatibility helper for old drivers. Drivers
159 * should instead implement their own primary plane. Atomic drivers must do so.
160 * Drivers with the above hardware restriction can look into using &struct
161 * drm_simple_display_pipe, which encapsulates the above limitations into a nice
162 * interface.
163 *
149 * Returns: 164 * Returns:
150 * Zero on success, error code on failure. 165 * Zero on success, error code on failure.
151 */ 166 */
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index ee4a5e1221f1..ab4e70e63f6e 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -59,6 +59,14 @@ static const struct drm_dmi_panel_orientation_data gpd_win = {
59 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, 59 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
60}; 60};
61 61
62static const struct drm_dmi_panel_orientation_data gpd_win2 = {
63 .width = 720,
64 .height = 1280,
65 .bios_dates = (const char * const []){
66 "12/07/2017", "05/24/2018", NULL },
67 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
68};
69
62static const struct drm_dmi_panel_orientation_data itworks_tw891 = { 70static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
63 .width = 800, 71 .width = 800,
64 .height = 1280, 72 .height = 1280,
@@ -106,6 +114,14 @@ static const struct dmi_system_id orientation_data[] = {
106 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), 114 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
107 }, 115 },
108 .driver_data = (void *)&gpd_win, 116 .driver_data = (void *)&gpd_win,
117 }, { /* GPD Win 2 (too generic strings, also match on bios date) */
118 .matches = {
119 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
120 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
121 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
122 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
123 },
124 .driver_data = (void *)&gpd_win2,
109 }, { /* I.T.Works TW891 */ 125 }, { /* I.T.Works TW891 */
110 .matches = { 126 .matches = {
111 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), 127 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 48f615d38931..a9d9df6c85ad 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -61,15 +61,14 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali
61 return NULL; 61 return NULL;
62 62
63 dmah->size = size; 63 dmah->size = size;
64 dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); 64 dmah->vaddr = dma_zalloc_coherent(&dev->pdev->dev, size, &dmah->busaddr,
65 GFP_KERNEL | __GFP_COMP);
65 66
66 if (dmah->vaddr == NULL) { 67 if (dmah->vaddr == NULL) {
67 kfree(dmah); 68 kfree(dmah);
68 return NULL; 69 return NULL;
69 } 70 }
70 71
71 memset(dmah->vaddr, 0, size);
72
73 /* XXX - Is virt_to_page() legal for consistent mem? */ 72 /* XXX - Is virt_to_page() legal for consistent mem? */
74 /* Reserve */ 73 /* Reserve */
75 for (addr = (unsigned long)dmah->vaddr, sz = size; 74 for (addr = (unsigned long)dmah->vaddr, sz = size;
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 1fa98bd12003..679455e36829 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -636,6 +636,29 @@ static int __setplane_check(struct drm_plane *plane,
636 return 0; 636 return 0;
637} 637}
638 638
639/**
640 * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination
641 * @dev: DRM device
642 * @format: pixel format (DRM_FORMAT_*)
643 * @modifier: data layout modifier
644 *
645 * Returns:
646 * Whether at least one plane supports the specified format and modifier combination.
647 */
648bool drm_any_plane_has_format(struct drm_device *dev,
649 u32 format, u64 modifier)
650{
651 struct drm_plane *plane;
652
653 drm_for_each_plane(plane, dev) {
654 if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
655 return true;
656 }
657
658 return false;
659}
660EXPORT_SYMBOL(drm_any_plane_has_format);
661
639/* 662/*
640 * __setplane_internal - setplane handler for internal callers 663 * __setplane_internal - setplane handler for internal callers
641 * 664 *
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index a393756b664e..0fff72dcd06d 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -42,11 +42,8 @@
42 * primary plane support on top of the normal CRTC configuration interface. 42 * primary plane support on top of the normal CRTC configuration interface.
43 * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary 43 * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
44 * plane together with the CRTC state this does not allow userspace to disable 44 * plane together with the CRTC state this does not allow userspace to disable
45 * the primary plane itself. To avoid too much duplicated code use 45 * the primary plane itself. The default primary plane only expose XRBG8888 and
46 * drm_plane_helper_check_update() which can be used to enforce the same 46 * ARGB8888 as valid pixel formats for the attached framebuffer.
47 * restrictions as primary planes had thus. The default primary plane only
48 * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
49 * framebuffer.
50 * 47 *
51 * Drivers are highly recommended to implement proper support for primary 48 * Drivers are highly recommended to implement proper support for primary
52 * planes, and newly merged drivers must not rely upon these transitional 49 * planes, and newly merged drivers must not rely upon these transitional
@@ -100,43 +97,17 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
100 return count; 97 return count;
101} 98}
102 99
103/** 100static int drm_plane_helper_check_update(struct drm_plane *plane,
104 * drm_plane_helper_check_update() - Check plane update for validity 101 struct drm_crtc *crtc,
105 * @plane: plane object to update 102 struct drm_framebuffer *fb,
106 * @crtc: owning CRTC of owning plane 103 struct drm_rect *src,
107 * @fb: framebuffer to flip onto plane 104 struct drm_rect *dst,
108 * @src: source coordinates in 16.16 fixed point 105 unsigned int rotation,
109 * @dst: integer destination coordinates 106 int min_scale,
110 * @rotation: plane rotation 107 int max_scale,
111 * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point 108 bool can_position,
112 * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point 109 bool can_update_disabled,
113 * @can_position: is it legal to position the plane such that it 110 bool *visible)
114 * doesn't cover the entire crtc? This will generally
115 * only be false for primary planes.
116 * @can_update_disabled: can the plane be updated while the crtc
117 * is disabled?
118 * @visible: output parameter indicating whether plane is still visible after
119 * clipping
120 *
121 * Checks that a desired plane update is valid. Drivers that provide
122 * their own plane handling rather than helper-provided implementations may
123 * still wish to call this function to avoid duplication of error checking
124 * code.
125 *
126 * RETURNS:
127 * Zero if update appears valid, error code on failure
128 */
129int drm_plane_helper_check_update(struct drm_plane *plane,
130 struct drm_crtc *crtc,
131 struct drm_framebuffer *fb,
132 struct drm_rect *src,
133 struct drm_rect *dst,
134 unsigned int rotation,
135 int min_scale,
136 int max_scale,
137 bool can_position,
138 bool can_update_disabled,
139 bool *visible)
140{ 111{
141 struct drm_plane_state plane_state = { 112 struct drm_plane_state plane_state = {
142 .plane = plane, 113 .plane = plane,
@@ -173,52 +144,14 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
173 144
174 return 0; 145 return 0;
175} 146}
176EXPORT_SYMBOL(drm_plane_helper_check_update);
177 147
178/** 148static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
179 * drm_primary_helper_update() - Helper for primary plane update 149 struct drm_framebuffer *fb,
180 * @plane: plane object to update 150 int crtc_x, int crtc_y,
181 * @crtc: owning CRTC of owning plane 151 unsigned int crtc_w, unsigned int crtc_h,
182 * @fb: framebuffer to flip onto plane 152 uint32_t src_x, uint32_t src_y,
183 * @crtc_x: x offset of primary plane on crtc 153 uint32_t src_w, uint32_t src_h,
184 * @crtc_y: y offset of primary plane on crtc 154 struct drm_modeset_acquire_ctx *ctx)
185 * @crtc_w: width of primary plane rectangle on crtc
186 * @crtc_h: height of primary plane rectangle on crtc
187 * @src_x: x offset of @fb for panning
188 * @src_y: y offset of @fb for panning
189 * @src_w: width of source rectangle in @fb
190 * @src_h: height of source rectangle in @fb
191 * @ctx: lock acquire context, not used here
192 *
193 * Provides a default plane update handler for primary planes. This is handler
194 * is called in response to a userspace SetPlane operation on the plane with a
195 * non-NULL framebuffer. We call the driver's modeset handler to update the
196 * framebuffer.
197 *
198 * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
199 * return an error.
200 *
201 * Note that we make some assumptions about hardware limitations that may not be
202 * true for all hardware --
203 *
204 * 1. Primary plane cannot be repositioned.
205 * 2. Primary plane cannot be scaled.
206 * 3. Primary plane must cover the entire CRTC.
207 * 4. Subpixel positioning is not supported.
208 *
209 * Drivers for hardware that don't have these restrictions can provide their
210 * own implementation rather than using this helper.
211 *
212 * RETURNS:
213 * Zero on success, error code on failure
214 */
215int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
216 struct drm_framebuffer *fb,
217 int crtc_x, int crtc_y,
218 unsigned int crtc_w, unsigned int crtc_h,
219 uint32_t src_x, uint32_t src_y,
220 uint32_t src_w, uint32_t src_h,
221 struct drm_modeset_acquire_ctx *ctx)
222{ 155{
223 struct drm_mode_set set = { 156 struct drm_mode_set set = {
224 .crtc = crtc, 157 .crtc = crtc,
@@ -285,35 +218,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
285 kfree(connector_list); 218 kfree(connector_list);
286 return ret; 219 return ret;
287} 220}
288EXPORT_SYMBOL(drm_primary_helper_update);
289 221
290/** 222static int drm_primary_helper_disable(struct drm_plane *plane,
291 * drm_primary_helper_disable() - Helper for primary plane disable 223 struct drm_modeset_acquire_ctx *ctx)
292 * @plane: plane to disable
293 * @ctx: lock acquire context, not used here
294 *
295 * Provides a default plane disable handler for primary planes. This is handler
296 * is called in response to a userspace SetPlane operation on the plane with a
297 * NULL framebuffer parameter. It unconditionally fails the disable call with
298 * -EINVAL the only way to disable the primary plane without driver support is
299 * to disable the entire CRTC. Which does not match the plane
300 * &drm_plane_funcs.disable_plane hook.
301 *
302 * Note that some hardware may be able to disable the primary plane without
303 * disabling the whole CRTC. Drivers for such hardware should provide their
304 * own disable handler that disables just the primary plane (and they'll likely
305 * need to provide their own update handler as well to properly re-enable a
306 * disabled primary plane).
307 *
308 * RETURNS:
309 * Unconditionally returns -EINVAL.
310 */
311int drm_primary_helper_disable(struct drm_plane *plane,
312 struct drm_modeset_acquire_ctx *ctx)
313{ 224{
314 return -EINVAL; 225 return -EINVAL;
315} 226}
316EXPORT_SYMBOL(drm_primary_helper_disable);
317 227
318/** 228/**
319 * drm_primary_helper_destroy() - Helper for primary plane destruction 229 * drm_primary_helper_destroy() - Helper for primary plane destruction
@@ -336,200 +246,3 @@ const struct drm_plane_funcs drm_primary_helper_funcs = {
336 .destroy = drm_primary_helper_destroy, 246 .destroy = drm_primary_helper_destroy,
337}; 247};
338EXPORT_SYMBOL(drm_primary_helper_funcs); 248EXPORT_SYMBOL(drm_primary_helper_funcs);
339
340int drm_plane_helper_commit(struct drm_plane *plane,
341 struct drm_plane_state *plane_state,
342 struct drm_framebuffer *old_fb)
343{
344 const struct drm_plane_helper_funcs *plane_funcs;
345 struct drm_crtc *crtc[2];
346 const struct drm_crtc_helper_funcs *crtc_funcs[2];
347 int i, ret = 0;
348
349 plane_funcs = plane->helper_private;
350
351 /* Since this is a transitional helper we can't assume that plane->state
352 * is always valid. Hence we need to use plane->crtc instead of
353 * plane->state->crtc as the old crtc. */
354 crtc[0] = plane->crtc;
355 crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
356
357 for (i = 0; i < 2; i++)
358 crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
359
360 if (plane_funcs->atomic_check) {
361 ret = plane_funcs->atomic_check(plane, plane_state);
362 if (ret)
363 goto out;
364 }
365
366 if (plane_funcs->prepare_fb && plane_state->fb != old_fb) {
367 ret = plane_funcs->prepare_fb(plane,
368 plane_state);
369 if (ret)
370 goto out;
371 }
372
373 /* Point of no return, commit sw state. */
374 swap(plane->state, plane_state);
375
376 for (i = 0; i < 2; i++) {
377 if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
378 crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
379 }
380
381 /*
382 * Drivers may optionally implement the ->atomic_disable callback, so
383 * special-case that here.
384 */
385 if (drm_atomic_plane_disabling(plane_state, plane->state) &&
386 plane_funcs->atomic_disable)
387 plane_funcs->atomic_disable(plane, plane_state);
388 else
389 plane_funcs->atomic_update(plane, plane_state);
390
391 for (i = 0; i < 2; i++) {
392 if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
393 crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
394 }
395
396 /*
397 * If we only moved the plane and didn't change fb's, there's no need to
398 * wait for vblank.
399 */
400 if (plane->state->fb == old_fb)
401 goto out;
402
403 for (i = 0; i < 2; i++) {
404 if (!crtc[i])
405 continue;
406
407 if (crtc[i]->cursor == plane)
408 continue;
409
410 /* There's no other way to figure out whether the crtc is running. */
411 ret = drm_crtc_vblank_get(crtc[i]);
412 if (ret == 0) {
413 drm_crtc_wait_one_vblank(crtc[i]);
414 drm_crtc_vblank_put(crtc[i]);
415 }
416
417 ret = 0;
418 }
419
420 if (plane_funcs->cleanup_fb)
421 plane_funcs->cleanup_fb(plane, plane_state);
422out:
423 if (plane->funcs->atomic_destroy_state)
424 plane->funcs->atomic_destroy_state(plane, plane_state);
425 else
426 drm_atomic_helper_plane_destroy_state(plane, plane_state);
427
428 return ret;
429}
430
431/**
432 * drm_plane_helper_update() - Transitional helper for plane update
433 * @plane: plane object to update
434 * @crtc: owning CRTC of owning plane
435 * @fb: framebuffer to flip onto plane
436 * @crtc_x: x offset of primary plane on crtc
437 * @crtc_y: y offset of primary plane on crtc
438 * @crtc_w: width of primary plane rectangle on crtc
439 * @crtc_h: height of primary plane rectangle on crtc
440 * @src_x: x offset of @fb for panning
441 * @src_y: y offset of @fb for panning
442 * @src_w: width of source rectangle in @fb
443 * @src_h: height of source rectangle in @fb
444 * @ctx: lock acquire context, not used here
445 *
446 * Provides a default plane update handler using the atomic plane update
447 * functions. It is fully left to the driver to check plane constraints and
448 * handle corner-cases like a fully occluded or otherwise invisible plane.
449 *
450 * This is useful for piecewise transitioning of a driver to the atomic helpers.
451 *
452 * RETURNS:
453 * Zero on success, error code on failure
454 */
455int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
456 struct drm_framebuffer *fb,
457 int crtc_x, int crtc_y,
458 unsigned int crtc_w, unsigned int crtc_h,
459 uint32_t src_x, uint32_t src_y,
460 uint32_t src_w, uint32_t src_h,
461 struct drm_modeset_acquire_ctx *ctx)
462{
463 struct drm_plane_state *plane_state;
464
465 if (plane->funcs->atomic_duplicate_state)
466 plane_state = plane->funcs->atomic_duplicate_state(plane);
467 else {
468 if (!plane->state)
469 drm_atomic_helper_plane_reset(plane);
470
471 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
472 }
473 if (!plane_state)
474 return -ENOMEM;
475 plane_state->plane = plane;
476
477 plane_state->crtc = crtc;
478 drm_atomic_set_fb_for_plane(plane_state, fb);
479 plane_state->crtc_x = crtc_x;
480 plane_state->crtc_y = crtc_y;
481 plane_state->crtc_h = crtc_h;
482 plane_state->crtc_w = crtc_w;
483 plane_state->src_x = src_x;
484 plane_state->src_y = src_y;
485 plane_state->src_h = src_h;
486 plane_state->src_w = src_w;
487
488 return drm_plane_helper_commit(plane, plane_state, plane->fb);
489}
490EXPORT_SYMBOL(drm_plane_helper_update);
491
492/**
493 * drm_plane_helper_disable() - Transitional helper for plane disable
494 * @plane: plane to disable
495 * @ctx: lock acquire context, not used here
496 *
497 * Provides a default plane disable handler using the atomic plane update
498 * functions. It is fully left to the driver to check plane constraints and
499 * handle corner-cases like a fully occluded or otherwise invisible plane.
500 *
501 * This is useful for piecewise transitioning of a driver to the atomic helpers.
502 *
503 * RETURNS:
504 * Zero on success, error code on failure
505 */
506int drm_plane_helper_disable(struct drm_plane *plane,
507 struct drm_modeset_acquire_ctx *ctx)
508{
509 struct drm_plane_state *plane_state;
510 struct drm_framebuffer *old_fb;
511
512 /* crtc helpers love to call disable functions for already disabled hw
513 * functions. So cope with that. */
514 if (!plane->crtc)
515 return 0;
516
517 if (plane->funcs->atomic_duplicate_state)
518 plane_state = plane->funcs->atomic_duplicate_state(plane);
519 else {
520 if (!plane->state)
521 drm_atomic_helper_plane_reset(plane);
522
523 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
524 }
525 if (!plane_state)
526 return -ENOMEM;
527 plane_state->plane = plane;
528
529 plane_state->crtc = NULL;
530 old_fb = plane_state->fb;
531 drm_atomic_set_fb_for_plane(plane_state, NULL);
532
533 return drm_plane_helper_commit(plane, plane_state, old_fb);
534}
535EXPORT_SYMBOL(drm_plane_helper_disable);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 3f0205fc0a1a..8d54d51a6b6b 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -434,34 +434,6 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
434EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); 434EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
435 435
436/** 436/**
437 * drm_gem_dmabuf_kmap - map implementation for GEM
438 * @dma_buf: buffer to be mapped
439 * @page_num: page number within the buffer
440 *
441 * Not implemented. This can be used as the &dma_buf_ops.map callback.
442 */
443void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
444{
445 return NULL;
446}
447EXPORT_SYMBOL(drm_gem_dmabuf_kmap);
448
449/**
450 * drm_gem_dmabuf_kunmap - unmap implementation for GEM
451 * @dma_buf: buffer to be unmapped
452 * @page_num: page number within the buffer
453 * @addr: virtual address of the buffer
454 *
455 * Not implemented. This can be used as the &dma_buf_ops.unmap callback.
456 */
457void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num,
458 void *addr)
459{
460
461}
462EXPORT_SYMBOL(drm_gem_dmabuf_kunmap);
463
464/**
465 * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM 437 * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM
466 * @dma_buf: buffer to be mapped 438 * @dma_buf: buffer to be mapped
467 * @vma: virtual address range 439 * @vma: virtual address range
@@ -489,8 +461,6 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
489 .map_dma_buf = drm_gem_map_dma_buf, 461 .map_dma_buf = drm_gem_map_dma_buf,
490 .unmap_dma_buf = drm_gem_unmap_dma_buf, 462 .unmap_dma_buf = drm_gem_unmap_dma_buf,
491 .release = drm_gem_dmabuf_release, 463 .release = drm_gem_dmabuf_release,
492 .map = drm_gem_dmabuf_kmap,
493 .unmap = drm_gem_dmabuf_kunmap,
494 .mmap = drm_gem_dmabuf_mmap, 464 .mmap = drm_gem_dmabuf_mmap,
495 .vmap = drm_gem_dmabuf_vmap, 465 .vmap = drm_gem_dmabuf_vmap,
496 .vunmap = drm_gem_dmabuf_vunmap, 466 .vunmap = drm_gem_dmabuf_vunmap,
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 51fa978f0d23..917812448d1b 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -190,6 +190,13 @@ static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
190 pipe->funcs->cleanup_fb(pipe, state); 190 pipe->funcs->cleanup_fb(pipe, state);
191} 191}
192 192
193static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
194 uint32_t format,
195 uint64_t modifier)
196{
197 return modifier == DRM_FORMAT_MOD_LINEAR;
198}
199
193static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { 200static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
194 .prepare_fb = drm_simple_kms_plane_prepare_fb, 201 .prepare_fb = drm_simple_kms_plane_prepare_fb,
195 .cleanup_fb = drm_simple_kms_plane_cleanup_fb, 202 .cleanup_fb = drm_simple_kms_plane_cleanup_fb,
@@ -204,6 +211,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
204 .reset = drm_atomic_helper_plane_reset, 211 .reset = drm_atomic_helper_plane_reset,
205 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 212 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
206 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 213 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
214 .format_mod_supported = drm_simple_kms_format_mod_supported,
207}; 215};
208 216
209/** 217/**
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 5c2091dbd230..da8175d9c6ff 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -56,6 +56,9 @@
56#include "drm_internal.h" 56#include "drm_internal.h"
57#include <drm/drm_syncobj.h> 57#include <drm/drm_syncobj.h>
58 58
59/* merge normal syncobj to timeline syncobj, the point interval is 1 */
60#define DRM_SYNCOBJ_BINARY_POINT 1
61
59struct drm_syncobj_stub_fence { 62struct drm_syncobj_stub_fence {
60 struct dma_fence base; 63 struct dma_fence base;
61 spinlock_t lock; 64 spinlock_t lock;
@@ -71,7 +74,29 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
71 .get_timeline_name = drm_syncobj_stub_fence_get_name, 74 .get_timeline_name = drm_syncobj_stub_fence_get_name,
72}; 75};
73 76
77struct drm_syncobj_signal_pt {
78 struct dma_fence_array *fence_array;
79 u64 value;
80 struct list_head list;
81};
82
83static DEFINE_SPINLOCK(signaled_fence_lock);
84static struct dma_fence signaled_fence;
74 85
86static struct dma_fence *drm_syncobj_get_stub_fence(void)
87{
88 spin_lock(&signaled_fence_lock);
89 if (!signaled_fence.ops) {
90 dma_fence_init(&signaled_fence,
91 &drm_syncobj_stub_fence_ops,
92 &signaled_fence_lock,
93 0, 0);
94 dma_fence_signal_locked(&signaled_fence);
95 }
96 spin_unlock(&signaled_fence_lock);
97
98 return dma_fence_get(&signaled_fence);
99}
75/** 100/**
76 * drm_syncobj_find - lookup and reference a sync object. 101 * drm_syncobj_find - lookup and reference a sync object.
77 * @file_private: drm file private pointer 102 * @file_private: drm file private pointer
@@ -98,6 +123,27 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
98} 123}
99EXPORT_SYMBOL(drm_syncobj_find); 124EXPORT_SYMBOL(drm_syncobj_find);
100 125
126static struct dma_fence *
127drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
128 uint64_t point)
129{
130 struct drm_syncobj_signal_pt *signal_pt;
131
132 if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
133 (point <= syncobj->timeline))
134 return drm_syncobj_get_stub_fence();
135
136 list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
137 if (point > signal_pt->value)
138 continue;
139 if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
140 (point != signal_pt->value))
141 continue;
142 return dma_fence_get(&signal_pt->fence_array->base);
143 }
144 return NULL;
145}
146
101static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj, 147static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
102 struct drm_syncobj_cb *cb, 148 struct drm_syncobj_cb *cb,
103 drm_syncobj_func_t func) 149 drm_syncobj_func_t func)
@@ -106,55 +152,158 @@ static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
106 list_add_tail(&cb->node, &syncobj->cb_list); 152 list_add_tail(&cb->node, &syncobj->cb_list);
107} 153}
108 154
109static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, 155static void drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
110 struct dma_fence **fence, 156 struct dma_fence **fence,
111 struct drm_syncobj_cb *cb, 157 struct drm_syncobj_cb *cb,
112 drm_syncobj_func_t func) 158 drm_syncobj_func_t func)
113{ 159{
114 int ret; 160 u64 pt_value = 0;
115 161
116 WARN_ON(*fence); 162 WARN_ON(*fence);
117 163
118 *fence = drm_syncobj_fence_get(syncobj); 164 if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
119 if (*fence) 165 /*BINARY syncobj always wait on last pt */
120 return 1; 166 pt_value = syncobj->signal_point;
121 167
122 spin_lock(&syncobj->lock); 168 if (pt_value == 0)
123 /* We've already tried once to get a fence and failed. Now that we 169 pt_value += DRM_SYNCOBJ_BINARY_POINT;
124 * have the lock, try one more time just to be sure we don't add a
125 * callback when a fence has already been set.
126 */
127 if (syncobj->fence) {
128 *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
129 lockdep_is_held(&syncobj->lock)));
130 ret = 1;
131 } else {
132 *fence = NULL;
133 drm_syncobj_add_callback_locked(syncobj, cb, func);
134 ret = 0;
135 } 170 }
136 spin_unlock(&syncobj->lock);
137 171
138 return ret; 172 mutex_lock(&syncobj->cb_mutex);
173 spin_lock(&syncobj->pt_lock);
174 *fence = drm_syncobj_find_signal_pt_for_point(syncobj, pt_value);
175 spin_unlock(&syncobj->pt_lock);
176 if (!*fence)
177 drm_syncobj_add_callback_locked(syncobj, cb, func);
178 mutex_unlock(&syncobj->cb_mutex);
139} 179}
140 180
141void drm_syncobj_add_callback(struct drm_syncobj *syncobj, 181static void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
142 struct drm_syncobj_cb *cb, 182 struct drm_syncobj_cb *cb)
143 drm_syncobj_func_t func)
144{ 183{
145 spin_lock(&syncobj->lock); 184 mutex_lock(&syncobj->cb_mutex);
146 drm_syncobj_add_callback_locked(syncobj, cb, func); 185 list_del_init(&cb->node);
147 spin_unlock(&syncobj->lock); 186 mutex_unlock(&syncobj->cb_mutex);
148} 187}
149 188
150void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, 189static void drm_syncobj_init(struct drm_syncobj *syncobj)
151 struct drm_syncobj_cb *cb)
152{ 190{
153 spin_lock(&syncobj->lock); 191 spin_lock(&syncobj->pt_lock);
154 list_del_init(&cb->node); 192 syncobj->timeline_context = dma_fence_context_alloc(1);
155 spin_unlock(&syncobj->lock); 193 syncobj->timeline = 0;
194 syncobj->signal_point = 0;
195 init_waitqueue_head(&syncobj->wq);
196
197 INIT_LIST_HEAD(&syncobj->signal_pt_list);
198 spin_unlock(&syncobj->pt_lock);
199}
200
201static void drm_syncobj_fini(struct drm_syncobj *syncobj)
202{
203 struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
204
205 spin_lock(&syncobj->pt_lock);
206 list_for_each_entry_safe(signal_pt, tmp,
207 &syncobj->signal_pt_list, list) {
208 list_del(&signal_pt->list);
209 dma_fence_put(&signal_pt->fence_array->base);
210 kfree(signal_pt);
211 }
212 spin_unlock(&syncobj->pt_lock);
213}
214
215static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
216 struct dma_fence *fence,
217 u64 point)
218{
219 struct drm_syncobj_signal_pt *signal_pt =
220 kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
221 struct drm_syncobj_signal_pt *tail_pt;
222 struct dma_fence **fences;
223 int num_fences = 0;
224 int ret = 0, i;
225
226 if (!signal_pt)
227 return -ENOMEM;
228 if (!fence)
229 goto out;
230
231 fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
232 if (!fences) {
233 ret = -ENOMEM;
234 goto out;
235 }
236 fences[num_fences++] = dma_fence_get(fence);
237 /* timeline syncobj must take this dependency */
238 if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
239 spin_lock(&syncobj->pt_lock);
240 if (!list_empty(&syncobj->signal_pt_list)) {
241 tail_pt = list_last_entry(&syncobj->signal_pt_list,
242 struct drm_syncobj_signal_pt, list);
243 fences[num_fences++] =
244 dma_fence_get(&tail_pt->fence_array->base);
245 }
246 spin_unlock(&syncobj->pt_lock);
247 }
248 signal_pt->fence_array = dma_fence_array_create(num_fences, fences,
249 syncobj->timeline_context,
250 point, false);
251 if (!signal_pt->fence_array) {
252 ret = -ENOMEM;
253 goto fail;
254 }
255
256 spin_lock(&syncobj->pt_lock);
257 if (syncobj->signal_point >= point) {
258 DRM_WARN("A later signal is ready!");
259 spin_unlock(&syncobj->pt_lock);
260 goto exist;
261 }
262 signal_pt->value = point;
263 list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
264 syncobj->signal_point = point;
265 spin_unlock(&syncobj->pt_lock);
266 wake_up_all(&syncobj->wq);
267
268 return 0;
269exist:
270 dma_fence_put(&signal_pt->fence_array->base);
271fail:
272 for (i = 0; i < num_fences; i++)
273 dma_fence_put(fences[i]);
274 kfree(fences);
275out:
276 kfree(signal_pt);
277 return ret;
156} 278}
157 279
280static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
281{
282 struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
283
284 spin_lock(&syncobj->pt_lock);
285 tail_pt = list_last_entry(&syncobj->signal_pt_list,
286 struct drm_syncobj_signal_pt,
287 list);
288 list_for_each_entry_safe(signal_pt, tmp,
289 &syncobj->signal_pt_list, list) {
290 if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
291 signal_pt == tail_pt)
292 continue;
293 if (dma_fence_is_signaled(&signal_pt->fence_array->base)) {
294 syncobj->timeline = signal_pt->value;
295 list_del(&signal_pt->list);
296 dma_fence_put(&signal_pt->fence_array->base);
297 kfree(signal_pt);
298 } else {
299 /*signal_pt is in order in list, from small to big, so
300 * the later must not be signal either */
301 break;
302 }
303 }
304
305 spin_unlock(&syncobj->pt_lock);
306}
158/** 307/**
159 * drm_syncobj_replace_fence - replace fence in a sync object. 308 * drm_syncobj_replace_fence - replace fence in a sync object.
160 * @syncobj: Sync object to replace fence in 309 * @syncobj: Sync object to replace fence in
@@ -167,28 +316,30 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
167 u64 point, 316 u64 point,
168 struct dma_fence *fence) 317 struct dma_fence *fence)
169{ 318{
170 struct dma_fence *old_fence; 319 u64 pt_value = point;
171 struct drm_syncobj_cb *cur, *tmp; 320
172 321 drm_syncobj_garbage_collection(syncobj);
173 if (fence) 322 if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
174 dma_fence_get(fence); 323 if (!fence) {
175 324 drm_syncobj_fini(syncobj);
176 spin_lock(&syncobj->lock); 325 drm_syncobj_init(syncobj);
177 326 return;
178 old_fence = rcu_dereference_protected(syncobj->fence, 327 }
179 lockdep_is_held(&syncobj->lock)); 328 pt_value = syncobj->signal_point +
180 rcu_assign_pointer(syncobj->fence, fence); 329 DRM_SYNCOBJ_BINARY_POINT;
330 }
331 drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
332 if (fence) {
333 struct drm_syncobj_cb *cur, *tmp;
334 LIST_HEAD(cb_list);
181 335
182 if (fence != old_fence) { 336 mutex_lock(&syncobj->cb_mutex);
183 list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) { 337 list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
184 list_del_init(&cur->node); 338 list_del_init(&cur->node);
185 cur->func(syncobj, cur); 339 cur->func(syncobj, cur);
186 } 340 }
341 mutex_unlock(&syncobj->cb_mutex);
187 } 342 }
188
189 spin_unlock(&syncobj->lock);
190
191 dma_fence_put(old_fence);
192} 343}
193EXPORT_SYMBOL(drm_syncobj_replace_fence); 344EXPORT_SYMBOL(drm_syncobj_replace_fence);
194 345
@@ -211,35 +362,89 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
211 return 0; 362 return 0;
212} 363}
213 364
365static int
366drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
367 struct dma_fence **fence)
368{
369 int ret = 0;
370
371 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
372 ret = wait_event_interruptible(syncobj->wq,
373 point <= syncobj->signal_point);
374 if (ret < 0)
375 return ret;
376 }
377 spin_lock(&syncobj->pt_lock);
378 *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
379 if (!*fence)
380 ret = -EINVAL;
381 spin_unlock(&syncobj->pt_lock);
382 return ret;
383}
384
385/**
386 * drm_syncobj_search_fence - lookup and reference the fence in a sync object or
387 * in a timeline point
388 * @syncobj: sync object pointer
389 * @point: timeline point
390 * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
391 * @fence: out parameter for the fence
392 *
393 * if flags is DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, the function will block
394 * here until specific timeline points is reached.
395 * if not, you need a submit thread and block in userspace until all future
396 * timeline points have materialized, only then you can submit to the kernel,
397 * otherwise, function will fail to return fence.
398 *
399 * Returns 0 on success or a negative error value on failure. On success @fence
400 * contains a reference to the fence, which must be released by calling
401 * dma_fence_put().
402 */
403int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
404 u64 flags, struct dma_fence **fence)
405{
406 u64 pt_value = point;
407
408 if (!syncobj)
409 return -ENOENT;
410
411 drm_syncobj_garbage_collection(syncobj);
412 if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
413 /*BINARY syncobj always wait on last pt */
414 pt_value = syncobj->signal_point;
415
416 if (pt_value == 0)
417 pt_value += DRM_SYNCOBJ_BINARY_POINT;
418 }
419 return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
420}
421EXPORT_SYMBOL(drm_syncobj_search_fence);
422
214/** 423/**
215 * drm_syncobj_find_fence - lookup and reference the fence in a sync object 424 * drm_syncobj_find_fence - lookup and reference the fence in a sync object
216 * @file_private: drm file private pointer 425 * @file_private: drm file private pointer
217 * @handle: sync object handle to lookup. 426 * @handle: sync object handle to lookup.
218 * @point: timeline point 427 * @point: timeline point
428 * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
219 * @fence: out parameter for the fence 429 * @fence: out parameter for the fence
220 * 430 *
221 * This is just a convenience function that combines drm_syncobj_find() and 431 * This is just a convenience function that combines drm_syncobj_find() and
222 * drm_syncobj_fence_get(). 432 * drm_syncobj_lookup_fence().
223 * 433 *
224 * Returns 0 on success or a negative error value on failure. On success @fence 434 * Returns 0 on success or a negative error value on failure. On success @fence
225 * contains a reference to the fence, which must be released by calling 435 * contains a reference to the fence, which must be released by calling
226 * dma_fence_put(). 436 * dma_fence_put().
227 */ 437 */
228int drm_syncobj_find_fence(struct drm_file *file_private, 438int drm_syncobj_find_fence(struct drm_file *file_private,
229 u32 handle, u64 point, 439 u32 handle, u64 point, u64 flags,
230 struct dma_fence **fence) 440 struct dma_fence **fence)
231{ 441{
232 struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle); 442 struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
233 int ret = 0; 443 int ret;
234
235 if (!syncobj)
236 return -ENOENT;
237 444
238 *fence = drm_syncobj_fence_get(syncobj); 445 ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
239 if (!*fence) { 446 if (syncobj)
240 ret = -EINVAL; 447 drm_syncobj_put(syncobj);
241 }
242 drm_syncobj_put(syncobj);
243 return ret; 448 return ret;
244} 449}
245EXPORT_SYMBOL(drm_syncobj_find_fence); 450EXPORT_SYMBOL(drm_syncobj_find_fence);
@@ -255,7 +460,7 @@ void drm_syncobj_free(struct kref *kref)
255 struct drm_syncobj *syncobj = container_of(kref, 460 struct drm_syncobj *syncobj = container_of(kref,
256 struct drm_syncobj, 461 struct drm_syncobj,
257 refcount); 462 refcount);
258 drm_syncobj_replace_fence(syncobj, 0, NULL); 463 drm_syncobj_fini(syncobj);
259 kfree(syncobj); 464 kfree(syncobj);
260} 465}
261EXPORT_SYMBOL(drm_syncobj_free); 466EXPORT_SYMBOL(drm_syncobj_free);
@@ -284,7 +489,13 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
284 489
285 kref_init(&syncobj->refcount); 490 kref_init(&syncobj->refcount);
286 INIT_LIST_HEAD(&syncobj->cb_list); 491 INIT_LIST_HEAD(&syncobj->cb_list);
287 spin_lock_init(&syncobj->lock); 492 spin_lock_init(&syncobj->pt_lock);
493 mutex_init(&syncobj->cb_mutex);
494 if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
495 syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
496 else
497 syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
498 drm_syncobj_init(syncobj);
288 499
289 if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) { 500 if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
290 ret = drm_syncobj_assign_null_handle(syncobj); 501 ret = drm_syncobj_assign_null_handle(syncobj);
@@ -497,7 +708,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
497 if (fd < 0) 708 if (fd < 0)
498 return fd; 709 return fd;
499 710
500 ret = drm_syncobj_find_fence(file_private, handle, 0, &fence); 711 ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
501 if (ret) 712 if (ret)
502 goto err_put_fd; 713 goto err_put_fd;
503 714
@@ -567,7 +778,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
567 return -EOPNOTSUPP; 778 return -EOPNOTSUPP;
568 779
569 /* no valid flags yet */ 780 /* no valid flags yet */
570 if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED) 781 if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
782 DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
571 return -EINVAL; 783 return -EINVAL;
572 784
573 return drm_syncobj_create_as_handle(file_private, 785 return drm_syncobj_create_as_handle(file_private,
@@ -660,9 +872,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
660 struct syncobj_wait_entry *wait = 872 struct syncobj_wait_entry *wait =
661 container_of(cb, struct syncobj_wait_entry, syncobj_cb); 873 container_of(cb, struct syncobj_wait_entry, syncobj_cb);
662 874
663 /* This happens inside the syncobj lock */ 875 drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
664 wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 876
665 lockdep_is_held(&syncobj->lock)));
666 wake_up_process(wait->task); 877 wake_up_process(wait->task);
667} 878}
668 879
@@ -688,7 +899,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
688 signaled_count = 0; 899 signaled_count = 0;
689 for (i = 0; i < count; ++i) { 900 for (i = 0; i < count; ++i) {
690 entries[i].task = current; 901 entries[i].task = current;
691 entries[i].fence = drm_syncobj_fence_get(syncobjs[i]); 902 drm_syncobj_search_fence(syncobjs[i], 0, 0,
903 &entries[i].fence);
692 if (!entries[i].fence) { 904 if (!entries[i].fence) {
693 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { 905 if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
694 continue; 906 continue;
@@ -953,12 +1165,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
953 if (ret < 0) 1165 if (ret < 0)
954 return ret; 1166 return ret;
955 1167
956 for (i = 0; i < args->count_handles; i++) 1168 for (i = 0; i < args->count_handles; i++) {
957 drm_syncobj_replace_fence(syncobjs[i], 0, NULL); 1169 drm_syncobj_fini(syncobjs[i]);
958 1170 drm_syncobj_init(syncobjs[i]);
1171 }
959 drm_syncobj_array_free(syncobjs, args->count_handles); 1172 drm_syncobj_array_free(syncobjs, args->count_handles);
960 1173
961 return 0; 1174 return ret;
962} 1175}
963 1176
964int 1177int
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 983e67f19e45..30875f8f2933 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -179,7 +179,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit)
179 struct reservation_object *robj = bo->obj->resv; 179 struct reservation_object *robj = bo->obj->resv;
180 180
181 if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) { 181 if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) {
182 ret = reservation_object_reserve_shared(robj); 182 ret = reservation_object_reserve_shared(robj, 1);
183 if (ret) 183 if (ret)
184 return ret; 184 return ret;
185 } 185 }
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
index 0e3752437e44..18afc94e4dff 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
@@ -17,6 +17,7 @@
17#include <drm/drm_atomic_helper.h> 17#include <drm/drm_atomic_helper.h>
18#include <drm/drm_crtc.h> 18#include <drm/drm_crtc.h>
19#include <drm/drm_crtc_helper.h> 19#include <drm/drm_crtc_helper.h>
20#include <video/videomode.h>
20 21
21#include "fsl_dcu_drm_crtc.h" 22#include "fsl_dcu_drm_crtc.h"
22#include "fsl_dcu_drm_drv.h" 23#include "fsl_dcu_drm_drv.h"
@@ -85,40 +86,34 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
85 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 86 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
86 struct drm_connector *con = &fsl_dev->connector.base; 87 struct drm_connector *con = &fsl_dev->connector.base;
87 struct drm_display_mode *mode = &crtc->state->mode; 88 struct drm_display_mode *mode = &crtc->state->mode;
88 unsigned int hbp, hfp, hsw, vbp, vfp, vsw, index, pol = 0; 89 unsigned int pol = 0;
90 struct videomode vm;
89 91
90 index = drm_crtc_index(crtc);
91 clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000); 92 clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000);
92 93
93 /* Configure timings: */ 94 drm_display_mode_to_videomode(mode, &vm);
94 hbp = mode->htotal - mode->hsync_end;
95 hfp = mode->hsync_start - mode->hdisplay;
96 hsw = mode->hsync_end - mode->hsync_start;
97 vbp = mode->vtotal - mode->vsync_end;
98 vfp = mode->vsync_start - mode->vdisplay;
99 vsw = mode->vsync_end - mode->vsync_start;
100 95
101 /* INV_PXCK as default (most display sample data on rising edge) */ 96 /* INV_PXCK as default (most display sample data on rising edge) */
102 if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)) 97 if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE))
103 pol |= DCU_SYN_POL_INV_PXCK; 98 pol |= DCU_SYN_POL_INV_PXCK;
104 99
105 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 100 if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
106 pol |= DCU_SYN_POL_INV_HS_LOW; 101 pol |= DCU_SYN_POL_INV_HS_LOW;
107 102
108 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 103 if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
109 pol |= DCU_SYN_POL_INV_VS_LOW; 104 pol |= DCU_SYN_POL_INV_VS_LOW;
110 105
111 regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, 106 regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
112 DCU_HSYN_PARA_BP(hbp) | 107 DCU_HSYN_PARA_BP(vm.hback_porch) |
113 DCU_HSYN_PARA_PW(hsw) | 108 DCU_HSYN_PARA_PW(vm.hsync_len) |
114 DCU_HSYN_PARA_FP(hfp)); 109 DCU_HSYN_PARA_FP(vm.hfront_porch));
115 regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, 110 regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
116 DCU_VSYN_PARA_BP(vbp) | 111 DCU_VSYN_PARA_BP(vm.vback_porch) |
117 DCU_VSYN_PARA_PW(vsw) | 112 DCU_VSYN_PARA_PW(vm.vsync_len) |
118 DCU_VSYN_PARA_FP(vfp)); 113 DCU_VSYN_PARA_FP(vm.vfront_porch));
119 regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, 114 regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
120 DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | 115 DCU_DISP_SIZE_DELTA_Y(vm.vactive) |
121 DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); 116 DCU_DISP_SIZE_DELTA_X(vm.hactive));
122 regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol); 117 regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol);
123 regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | 118 regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
124 DCU_BGND_G(0) | DCU_BGND_B(0)); 119 DCU_BGND_G(0) | DCU_BGND_B(0));
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index 0496be5212e1..ceddc3e29258 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -26,6 +26,7 @@
26#include <drm/drm_atomic_helper.h> 26#include <drm/drm_atomic_helper.h>
27#include <drm/drm_crtc_helper.h> 27#include <drm/drm_crtc_helper.h>
28#include <drm/drm_fb_cma_helper.h> 28#include <drm/drm_fb_cma_helper.h>
29#include <drm/drm_fb_helper.h>
29#include <drm/drm_gem_cma_helper.h> 30#include <drm/drm_gem_cma_helper.h>
30#include <drm/drm_modeset_helper.h> 31#include <drm/drm_modeset_helper.h>
31 32
@@ -89,20 +90,11 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
89 "Invalid legacyfb_depth. Defaulting to 24bpp\n"); 90 "Invalid legacyfb_depth. Defaulting to 24bpp\n");
90 legacyfb_depth = 24; 91 legacyfb_depth = 24;
91 } 92 }
92 fsl_dev->fbdev = drm_fbdev_cma_init(dev, legacyfb_depth, 1);
93 if (IS_ERR(fsl_dev->fbdev)) {
94 ret = PTR_ERR(fsl_dev->fbdev);
95 fsl_dev->fbdev = NULL;
96 goto done;
97 }
98 93
99 return 0; 94 return 0;
100done: 95done:
101 drm_kms_helper_poll_fini(dev); 96 drm_kms_helper_poll_fini(dev);
102 97
103 if (fsl_dev->fbdev)
104 drm_fbdev_cma_fini(fsl_dev->fbdev);
105
106 drm_mode_config_cleanup(dev); 98 drm_mode_config_cleanup(dev);
107 drm_irq_uninstall(dev); 99 drm_irq_uninstall(dev);
108 dev->dev_private = NULL; 100 dev->dev_private = NULL;
@@ -112,14 +104,9 @@ done:
112 104
113static void fsl_dcu_unload(struct drm_device *dev) 105static void fsl_dcu_unload(struct drm_device *dev)
114{ 106{
115 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
116
117 drm_atomic_helper_shutdown(dev); 107 drm_atomic_helper_shutdown(dev);
118 drm_kms_helper_poll_fini(dev); 108 drm_kms_helper_poll_fini(dev);
119 109
120 if (fsl_dev->fbdev)
121 drm_fbdev_cma_fini(fsl_dev->fbdev);
122
123 drm_mode_config_cleanup(dev); 110 drm_mode_config_cleanup(dev);
124 drm_irq_uninstall(dev); 111 drm_irq_uninstall(dev);
125 112
@@ -147,19 +134,11 @@ static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
147 return IRQ_HANDLED; 134 return IRQ_HANDLED;
148} 135}
149 136
150static void fsl_dcu_drm_lastclose(struct drm_device *dev)
151{
152 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
153
154 drm_fbdev_cma_restore_mode(fsl_dev->fbdev);
155}
156
157DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops); 137DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops);
158 138
159static struct drm_driver fsl_dcu_drm_driver = { 139static struct drm_driver fsl_dcu_drm_driver = {
160 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET 140 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
161 | DRIVER_PRIME | DRIVER_ATOMIC, 141 | DRIVER_PRIME | DRIVER_ATOMIC,
162 .lastclose = fsl_dcu_drm_lastclose,
163 .load = fsl_dcu_load, 142 .load = fsl_dcu_load,
164 .unload = fsl_dcu_unload, 143 .unload = fsl_dcu_unload,
165 .irq_handler = fsl_dcu_drm_irq, 144 .irq_handler = fsl_dcu_drm_irq,
@@ -355,6 +334,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
355 if (ret < 0) 334 if (ret < 0)
356 goto put; 335 goto put;
357 336
337 drm_fbdev_generic_setup(drm, legacyfb_depth);
338
358 return 0; 339 return 0;
359 340
360put: 341put:
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
index 93bfb98012d4..cb87bb74cb87 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
@@ -191,7 +191,6 @@ struct fsl_dcu_drm_device {
191 /*protects hardware register*/ 191 /*protects hardware register*/
192 spinlock_t irq_lock; 192 spinlock_t irq_lock;
193 struct drm_device *drm; 193 struct drm_device *drm;
194 struct drm_fbdev_cma *fbdev;
195 struct drm_crtc crtc; 194 struct drm_crtc crtc;
196 struct drm_encoder encoder; 195 struct drm_encoder encoder;
197 struct fsl_dcu_drm_connector connector; 196 struct fsl_dcu_drm_connector connector;
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 1aaccbe7e1de..1a1c04db6c80 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -2157,7 +2157,7 @@ await_fence_array(struct i915_execbuffer *eb,
2157 if (!(flags & I915_EXEC_FENCE_WAIT)) 2157 if (!(flags & I915_EXEC_FENCE_WAIT))
2158 continue; 2158 continue;
2159 2159
2160 fence = drm_syncobj_fence_get(syncobj); 2160 drm_syncobj_search_fence(syncobj, 0, 0, &fence);
2161 if (!fence) 2161 if (!fence)
2162 return -EINVAL; 2162 return -EINVAL;
2163 2163
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 31efc971a3a8..35fce4c88629 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -892,7 +892,7 @@ static void export_fence(struct i915_vma *vma,
892 reservation_object_lock(resv, NULL); 892 reservation_object_lock(resv, NULL);
893 if (flags & EXEC_OBJECT_WRITE) 893 if (flags & EXEC_OBJECT_WRITE)
894 reservation_object_add_excl_fence(resv, &rq->fence); 894 reservation_object_add_excl_fence(resv, &rq->fence);
895 else if (reservation_object_reserve_shared(resv) == 0) 895 else if (reservation_object_reserve_shared(resv, 1) == 0)
896 reservation_object_add_shared_fence(resv, &rq->fence); 896 reservation_object_add_shared_fence(resv, &rq->fence);
897 reservation_object_unlock(resv); 897 reservation_object_unlock(resv);
898} 898}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index a2dab0b6bde6..d7234e03fdb0 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -474,7 +474,8 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
474 const struct drm_display_mode *adjusted_mode = 474 const struct drm_display_mode *adjusted_mode =
475 &crtc_state->base.adjusted_mode; 475 &crtc_state->base.adjusted_mode;
476 struct drm_connector *connector = &intel_hdmi->attached_connector->base; 476 struct drm_connector *connector = &intel_hdmi->attached_connector->base;
477 bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; 477 bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported ||
478 connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
478 union hdmi_infoframe frame; 479 union hdmi_infoframe frame;
479 int ret; 480 int ret;
480 481
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index d3443125e661..348b5a198b9d 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -68,15 +68,7 @@
68 * - Powering Up HDMI controller and PHY 68 * - Powering Up HDMI controller and PHY
69 */ 69 */
70 70
71static void meson_fb_output_poll_changed(struct drm_device *dev)
72{
73 struct meson_drm *priv = dev->dev_private;
74
75 drm_fbdev_cma_hotplug_event(priv->fbdev);
76}
77
78static const struct drm_mode_config_funcs meson_mode_config_funcs = { 71static const struct drm_mode_config_funcs meson_mode_config_funcs = {
79 .output_poll_changed = meson_fb_output_poll_changed,
80 .atomic_check = drm_atomic_helper_check, 72 .atomic_check = drm_atomic_helper_check,
81 .atomic_commit = drm_atomic_helper_commit, 73 .atomic_commit = drm_atomic_helper_commit,
82 .fb_create = drm_gem_fb_create, 74 .fb_create = drm_gem_fb_create,
@@ -282,13 +274,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
282 274
283 drm_mode_config_reset(drm); 275 drm_mode_config_reset(drm);
284 276
285 priv->fbdev = drm_fbdev_cma_init(drm, 32,
286 drm->mode_config.num_connector);
287 if (IS_ERR(priv->fbdev)) {
288 ret = PTR_ERR(priv->fbdev);
289 goto free_drm;
290 }
291
292 drm_kms_helper_poll_init(drm); 277 drm_kms_helper_poll_init(drm);
293 278
294 platform_set_drvdata(pdev, priv); 279 platform_set_drvdata(pdev, priv);
@@ -297,6 +282,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
297 if (ret) 282 if (ret)
298 goto free_drm; 283 goto free_drm;
299 284
285 drm_fbdev_generic_setup(drm, 32);
286
300 return 0; 287 return 0;
301 288
302free_drm: 289free_drm:
@@ -313,11 +300,9 @@ static int meson_drv_bind(struct device *dev)
313static void meson_drv_unbind(struct device *dev) 300static void meson_drv_unbind(struct device *dev)
314{ 301{
315 struct drm_device *drm = dev_get_drvdata(dev); 302 struct drm_device *drm = dev_get_drvdata(dev);
316 struct meson_drm *priv = drm->dev_private;
317 303
318 drm_dev_unregister(drm); 304 drm_dev_unregister(drm);
319 drm_kms_helper_poll_fini(drm); 305 drm_kms_helper_poll_fini(drm);
320 drm_fbdev_cma_fini(priv->fbdev);
321 drm_mode_config_cleanup(drm); 306 drm_mode_config_cleanup(drm);
322 drm_dev_put(drm); 307 drm_dev_put(drm);
323 308
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 8450d6ac8c9b..aab96260da9f 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -33,7 +33,6 @@ struct meson_drm {
33 33
34 struct drm_device *drm; 34 struct drm_device *drm;
35 struct drm_crtc *crtc; 35 struct drm_crtc *crtc;
36 struct drm_fbdev_cma *fbdev;
37 struct drm_plane *primary_plane; 36 struct drm_plane *primary_plane;
38 37
39 /* Components Data */ 38 /* Components Data */
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 48b5304f460c..8edd80bb0428 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1222,10 +1222,7 @@ static int a5xx_crashdumper_init(struct msm_gpu *gpu,
1222 SZ_1M, MSM_BO_UNCACHED, gpu->aspace, 1222 SZ_1M, MSM_BO_UNCACHED, gpu->aspace,
1223 &dumper->bo, &dumper->iova); 1223 &dumper->bo, &dumper->iova);
1224 1224
1225 if (IS_ERR(dumper->ptr)) 1225 return PTR_ERR_OR_ZERO(dumper->ptr);
1226 return PTR_ERR(dumper->ptr);
1227
1228 return 0;
1229} 1226}
1230 1227
1231static void a5xx_crashdumper_free(struct msm_gpu *gpu, 1228static void a5xx_crashdumper_free(struct msm_gpu *gpu,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index f549daf30fe6..d77a8cb15404 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -1179,8 +1179,6 @@ static void dpu_plane_destroy(struct drm_plane *plane)
1179 1179
1180 mutex_destroy(&pdpu->lock); 1180 mutex_destroy(&pdpu->lock);
1181 1181
1182 drm_plane_helper_disable(plane, NULL);
1183
1184 /* this will destroy the states as well */ 1182 /* this will destroy the states as well */
1185 drm_plane_cleanup(plane); 1183 drm_plane_cleanup(plane);
1186 1184
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
index 79ff653d8081..7a499731ce93 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
@@ -68,7 +68,6 @@ static void mdp4_plane_destroy(struct drm_plane *plane)
68{ 68{
69 struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); 69 struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
70 70
71 drm_plane_helper_disable(plane, NULL);
72 drm_plane_cleanup(plane); 71 drm_plane_cleanup(plane);
73 72
74 kfree(mdp4_plane); 73 kfree(mdp4_plane);
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
index 7f42c3e68a53..310459541e48 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -46,7 +46,6 @@ static void mdp5_plane_destroy(struct drm_plane *plane)
46{ 46{
47 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); 47 struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
48 48
49 drm_plane_helper_disable(plane, NULL);
50 drm_plane_cleanup(plane); 49 drm_plane_cleanup(plane);
51 50
52 kfree(mdp5_plane); 51 kfree(mdp5_plane);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c79659ca5706..23670907a29d 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -579,7 +579,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
579 hdmi_cfg = (struct hdmi_platform_config *) 579 hdmi_cfg = (struct hdmi_platform_config *)
580 of_device_get_match_data(dev); 580 of_device_get_match_data(dev);
581 if (!hdmi_cfg) { 581 if (!hdmi_cfg) {
582 dev_err(dev, "unknown hdmi_cfg: %s\n", of_node->name); 582 dev_err(dev, "unknown hdmi_cfg: %pOFn\n", of_node);
583 return -ENXIO; 583 return -ENXIO;
584 } 584 }
585 585
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 4904d0d41409..5e758d95751a 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -312,6 +312,7 @@ static int msm_drm_uninit(struct device *dev)
312 if (fbdev && priv->fbdev) 312 if (fbdev && priv->fbdev)
313 msm_fbdev_free(ddev); 313 msm_fbdev_free(ddev);
314#endif 314#endif
315 drm_atomic_helper_shutdown(ddev);
315 drm_mode_config_cleanup(ddev); 316 drm_mode_config_cleanup(ddev);
316 317
317 pm_runtime_get_sync(dev); 318 pm_runtime_get_sync(dev);
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 7a7923e6220d..a90aedd6883a 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -241,7 +241,8 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
241 * strange place to call it. OTOH this is a 241 * strange place to call it. OTOH this is a
242 * convenient can-fail point to hook it in. 242 * convenient can-fail point to hook it in.
243 */ 243 */
244 ret = reservation_object_reserve_shared(msm_obj->resv); 244 ret = reservation_object_reserve_shared(msm_obj->resv,
245 1);
245 if (ret) 246 if (ret)
246 return ret; 247 return ret;
247 } 248 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 99be61ddeb75..d4964f3397a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -341,7 +341,7 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
341 int ret = 0, i; 341 int ret = 0, i;
342 342
343 if (!exclusive) { 343 if (!exclusive) {
344 ret = reservation_object_reserve_shared(resv); 344 ret = reservation_object_reserve_shared(resv, 1);
345 345
346 if (ret) 346 if (ret)
347 return ret; 347 return ret;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 6020c30a33b3..3f3537719beb 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -90,6 +90,18 @@ config DRM_PANEL_LG_LG4573
90 Say Y here if you want to enable support for LG4573 RGB panel. 90 Say Y here if you want to enable support for LG4573 RGB panel.
91 To compile this driver as a module, choose M here. 91 To compile this driver as a module, choose M here.
92 92
93config DRM_PANEL_OLIMEX_LCD_OLINUXINO
94 tristate "Olimex LCD-OLinuXino panel"
95 depends on OF
96 depends on I2C
97 depends on BACKLIGHT_CLASS_DEVICE
98 help
99 The panel is used with different sizes LCDs, from 480x272 to
100 1280x800, and 24 bit per pixel.
101
102 Say Y here if you want to enable support for Olimex Ltd.
103 LCD-OLinuXino panel.
104
93config DRM_PANEL_ORISETECH_OTM8009A 105config DRM_PANEL_ORISETECH_OTM8009A
94 tristate "Orise Technology otm8009a 480x800 dsi 2dl panel" 106 tristate "Orise Technology otm8009a 480x800 dsi 2dl panel"
95 depends on OF 107 depends on OF
@@ -126,6 +138,12 @@ config DRM_PANEL_RAYDIUM_RM68200
126 Say Y here if you want to enable support for Raydium RM68200 138 Say Y here if you want to enable support for Raydium RM68200
127 720x1280 DSI video mode panel. 139 720x1280 DSI video mode panel.
128 140
141config DRM_PANEL_SAMSUNG_S6D16D0
142 tristate "Samsung S6D16D0 DSI video mode panel"
143 depends on OF
144 depends on DRM_MIPI_DSI
145 select VIDEOMODE_HELPERS
146
129config DRM_PANEL_SAMSUNG_S6E3HA2 147config DRM_PANEL_SAMSUNG_S6E3HA2
130 tristate "Samsung S6E3HA2 DSI video mode panel" 148 tristate "Samsung S6E3HA2 DSI video mode panel"
131 depends on OF 149 depends on OF
@@ -186,4 +204,11 @@ config DRM_PANEL_SITRONIX_ST7789V
186 Say Y here if you want to enable support for the Sitronix 204 Say Y here if you want to enable support for the Sitronix
187 ST7789V controller for 240x320 LCD panels 205 ST7789V controller for 240x320 LCD panels
188 206
207config DRM_PANEL_TRULY_NT35597_WQXGA
208 tristate "Truly WQXGA"
209 depends on OF
210 depends on DRM_MIPI_DSI
211 help
212 Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
213 Video Mode panel
189endmenu 214endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 5ccaaa9d13af..4396658a7996 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -7,11 +7,13 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
7obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o 7obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
8obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o 8obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
9obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o 9obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
10obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
10obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o 11obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
11obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o 12obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
12obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o 13obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
13obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o 14obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
14obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o 15obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
16obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
15obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o 17obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
16obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o 18obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
17obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o 19obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
@@ -19,3 +21,4 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
19obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o 21obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
20obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o 22obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
21obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o 23obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
24obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c
index 72edb334d997..ca4ae45dd307 100644
--- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c
+++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c
@@ -506,8 +506,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi,
506 506
507static void innolux_panel_del(struct innolux_panel *innolux) 507static void innolux_panel_del(struct innolux_panel *innolux)
508{ 508{
509 if (innolux->base.dev) 509 drm_panel_remove(&innolux->base);
510 drm_panel_remove(&innolux->base);
511} 510}
512 511
513static int innolux_panel_probe(struct mipi_dsi_device *dsi) 512static int innolux_panel_probe(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
new file mode 100644
index 000000000000..5e8d4523e9ed
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
@@ -0,0 +1,330 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * LCD-OLinuXino support for panel driver
4 *
5 * Copyright (C) 2018 Olimex Ltd.
6 * Author: Stefan Mavrodiev <stefan@olimex.com>
7 */
8
9#include <linux/backlight.h>
10#include <linux/crc32.h>
11#include <linux/gpio/consumer.h>
12#include <linux/i2c.h>
13#include <linux/module.h>
14#include <linux/mutex.h>
15#include <linux/of.h>
16#include <linux/regulator/consumer.h>
17
18#include <drm/drm_modes.h>
19#include <drm/drm_panel.h>
20#include <drm/drmP.h>
21
22#include <video/videomode.h>
23#include <video/display_timing.h>
24
25#define LCD_OLINUXINO_HEADER_MAGIC 0x4F4CB727
26#define LCD_OLINUXINO_DATA_LEN 256
27
28struct lcd_olinuxino_mode {
29 u32 pixelclock;
30 u32 hactive;
31 u32 hfp;
32 u32 hbp;
33 u32 hpw;
34 u32 vactive;
35 u32 vfp;
36 u32 vbp;
37 u32 vpw;
38 u32 refresh;
39 u32 flags;
40};
41
42struct lcd_olinuxino_info {
43 char name[32];
44 u32 width_mm;
45 u32 height_mm;
46 u32 bpc;
47 u32 bus_format;
48 u32 bus_flag;
49} __attribute__((__packed__));
50
51struct lcd_olinuxino_eeprom {
52 u32 header;
53 u32 id;
54 char revision[4];
55 u32 serial;
56 struct lcd_olinuxino_info info;
57 u32 num_modes;
58 u8 reserved[180];
59 u32 checksum;
60} __attribute__((__packed__));
61
62struct lcd_olinuxino {
63 struct drm_panel panel;
64 struct device *dev;
65 struct i2c_client *client;
66 struct mutex mutex;
67
68 bool prepared;
69 bool enabled;
70
71 struct backlight_device *backlight;
72 struct regulator *supply;
73 struct gpio_desc *enable_gpio;
74
75 struct lcd_olinuxino_eeprom eeprom;
76};
77
78static inline struct lcd_olinuxino *to_lcd_olinuxino(struct drm_panel *panel)
79{
80 return container_of(panel, struct lcd_olinuxino, panel);
81}
82
83static int lcd_olinuxino_disable(struct drm_panel *panel)
84{
85 struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
86
87 if (!lcd->enabled)
88 return 0;
89
90 backlight_disable(lcd->backlight);
91
92 lcd->enabled = false;
93
94 return 0;
95}
96
97static int lcd_olinuxino_unprepare(struct drm_panel *panel)
98{
99 struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
100
101 if (!lcd->prepared)
102 return 0;
103
104 gpiod_set_value_cansleep(lcd->enable_gpio, 0);
105 regulator_disable(lcd->supply);
106
107 lcd->prepared = false;
108
109 return 0;
110}
111
112static int lcd_olinuxino_prepare(struct drm_panel *panel)
113{
114 struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
115 int ret;
116
117 if (lcd->prepared)
118 return 0;
119
120 ret = regulator_enable(lcd->supply);
121 if (ret < 0)
122 return ret;
123
124 gpiod_set_value_cansleep(lcd->enable_gpio, 1);
125 lcd->prepared = true;
126
127 return 0;
128}
129
130static int lcd_olinuxino_enable(struct drm_panel *panel)
131{
132 struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
133
134 if (lcd->enabled)
135 return 0;
136
137 backlight_enable(lcd->backlight);
138
139 lcd->enabled = true;
140
141 return 0;
142}
143
144static int lcd_olinuxino_get_modes(struct drm_panel *panel)
145{
146 struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
147 struct drm_connector *connector = lcd->panel.connector;
148 struct lcd_olinuxino_info *lcd_info = &lcd->eeprom.info;
149 struct drm_device *drm = lcd->panel.drm;
150 struct lcd_olinuxino_mode *lcd_mode;
151 struct drm_display_mode *mode;
152 u32 i, num = 0;
153
154 for (i = 0; i < lcd->eeprom.num_modes; i++) {
155 lcd_mode = (struct lcd_olinuxino_mode *)
156 &lcd->eeprom.reserved[i * sizeof(*lcd_mode)];
157
158 mode = drm_mode_create(drm);
159 if (!mode) {
160 dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
161 lcd_mode->hactive,
162 lcd_mode->vactive,
163 lcd_mode->refresh);
164 continue;
165 }
166
167 mode->clock = lcd_mode->pixelclock;
168 mode->hdisplay = lcd_mode->hactive;
169 mode->hsync_start = lcd_mode->hactive + lcd_mode->hfp;
170 mode->hsync_end = lcd_mode->hactive + lcd_mode->hfp +
171 lcd_mode->hpw;
172 mode->htotal = lcd_mode->hactive + lcd_mode->hfp +
173 lcd_mode->hpw + lcd_mode->hbp;
174 mode->vdisplay = lcd_mode->vactive;
175 mode->vsync_start = lcd_mode->vactive + lcd_mode->vfp;
176 mode->vsync_end = lcd_mode->vactive + lcd_mode->vfp +
177 lcd_mode->vpw;
178 mode->vtotal = lcd_mode->vactive + lcd_mode->vfp +
179 lcd_mode->vpw + lcd_mode->vbp;
180 mode->vrefresh = lcd_mode->refresh;
181
182 /* Always make the first mode preferred */
183 if (i == 0)
184 mode->type |= DRM_MODE_TYPE_PREFERRED;
185 mode->type |= DRM_MODE_TYPE_DRIVER;
186
187 drm_mode_set_name(mode);
188 drm_mode_probed_add(connector, mode);
189
190 num++;
191 }
192
193 memcpy(connector->display_info.name, lcd_info->name, 32);
194 connector->display_info.width_mm = lcd_info->width_mm;
195 connector->display_info.height_mm = lcd_info->height_mm;
196 connector->display_info.bpc = lcd_info->bpc;
197
198 if (lcd_info->bus_format)
199 drm_display_info_set_bus_formats(&connector->display_info,
200 &lcd_info->bus_format, 1);
201 connector->display_info.bus_flags = lcd_info->bus_flag;
202
203 return num;
204}
205
206static const struct drm_panel_funcs lcd_olinuxino_funcs = {
207 .disable = lcd_olinuxino_disable,
208 .unprepare = lcd_olinuxino_unprepare,
209 .prepare = lcd_olinuxino_prepare,
210 .enable = lcd_olinuxino_enable,
211 .get_modes = lcd_olinuxino_get_modes,
212};
213
214static int lcd_olinuxino_probe(struct i2c_client *client,
215 const struct i2c_device_id *id)
216{
217 struct device *dev = &client->dev;
218 struct lcd_olinuxino *lcd;
219 u32 checksum, i;
220 int ret = 0;
221
222 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
223 I2C_FUNC_SMBUS_READ_I2C_BLOCK))
224 return -ENODEV;
225
226 lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
227 if (!lcd)
228 return -ENOMEM;
229
230 i2c_set_clientdata(client, lcd);
231 lcd->dev = dev;
232 lcd->client = client;
233
234 mutex_init(&lcd->mutex);
235
236 /* Copy data into buffer */
237 for (i = 0; i < LCD_OLINUXINO_DATA_LEN; i += I2C_SMBUS_BLOCK_MAX) {
238 mutex_lock(&lcd->mutex);
239 ret = i2c_smbus_read_i2c_block_data(client,
240 i,
241 I2C_SMBUS_BLOCK_MAX,
242 (u8 *)&lcd->eeprom + i);
243 mutex_unlock(&lcd->mutex);
244 if (ret < 0) {
245 dev_err(dev, "error reading from device at %02x\n", i);
246 return ret;
247 }
248 }
249
250 /* Check configuration checksum */
251 checksum = ~crc32(~0, (u8 *)&lcd->eeprom, 252);
252 if (checksum != lcd->eeprom.checksum) {
253 dev_err(dev, "configuration checksum does not match!\n");
254 return -EINVAL;
255 }
256
257 /* Check magic header */
258 if (lcd->eeprom.header != LCD_OLINUXINO_HEADER_MAGIC) {
259 dev_err(dev, "magic header does not match\n");
260 return -EINVAL;
261 }
262
263 dev_info(dev, "Detected %s, Rev. %s, Serial: %08x\n",
264 lcd->eeprom.info.name,
265 lcd->eeprom.revision,
266 lcd->eeprom.serial);
267
268 /*
269 * The eeprom can hold up to 4 modes.
270 * If the stored value is bigger, overwrite it.
271 */
272 if (lcd->eeprom.num_modes > 4) {
273 dev_warn(dev, "invalid number of modes, falling back to 4\n");
274 lcd->eeprom.num_modes = 4;
275 }
276
277 lcd->enabled = false;
278 lcd->prepared = false;
279
280 lcd->supply = devm_regulator_get(dev, "power");
281 if (IS_ERR(lcd->supply))
282 return PTR_ERR(lcd->supply);
283
284 lcd->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
285 if (IS_ERR(lcd->enable_gpio))
286 return PTR_ERR(lcd->enable_gpio);
287
288 lcd->backlight = devm_of_find_backlight(dev);
289 if (IS_ERR(lcd->backlight))
290 return PTR_ERR(lcd->backlight);
291
292 drm_panel_init(&lcd->panel);
293 lcd->panel.dev = dev;
294 lcd->panel.funcs = &lcd_olinuxino_funcs;
295
296 return drm_panel_add(&lcd->panel);
297}
298
299static int lcd_olinuxino_remove(struct i2c_client *client)
300{
301 struct lcd_olinuxino *panel = i2c_get_clientdata(client);
302
303 drm_panel_remove(&panel->panel);
304
305 lcd_olinuxino_disable(&panel->panel);
306 lcd_olinuxino_unprepare(&panel->panel);
307
308 return 0;
309}
310
311static const struct of_device_id lcd_olinuxino_of_ids[] = {
312 { .compatible = "olimex,lcd-olinuxino" },
313 { }
314};
315MODULE_DEVICE_TABLE(of, lcd_olinuxino_of_ids);
316
317static struct i2c_driver lcd_olinuxino_driver = {
318 .driver = {
319 .name = "lcd_olinuxino",
320 .of_match_table = lcd_olinuxino_of_ids,
321 },
322 .probe = lcd_olinuxino_probe,
323 .remove = lcd_olinuxino_remove,
324};
325
326module_i2c_driver(lcd_olinuxino_driver);
327
328MODULE_AUTHOR("Stefan Mavrodiev <stefan@olimex.com>");
329MODULE_DESCRIPTION("LCD-OLinuXino driver");
330MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
new file mode 100644
index 000000000000..fa8bfa7c492d
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
@@ -0,0 +1,264 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * MIPI-DSI Samsung s6d16d0 panel driver. This is a 864x480
4 * AMOLED panel with a command-only DSI interface.
5 */
6
7#include <drm/drm_modes.h>
8#include <drm/drm_mipi_dsi.h>
9#include <drm/drm_panel.h>
10#include <drm/drm_print.h>
11
12#include <linux/gpio/consumer.h>
13#include <linux/regulator/consumer.h>
14#include <linux/delay.h>
15#include <linux/of_device.h>
16#include <linux/module.h>
17
18struct s6d16d0 {
19 struct device *dev;
20 struct drm_panel panel;
21 struct regulator *supply;
22 struct gpio_desc *reset_gpio;
23};
24
25/*
26 * The timings are not very helpful as the display is used in
27 * command mode.
28 */
29static const struct drm_display_mode samsung_s6d16d0_mode = {
30 /* HS clock, (htotal*vtotal*vrefresh)/1000 */
31 .clock = 420160,
32 .hdisplay = 864,
33 .hsync_start = 864 + 154,
34 .hsync_end = 864 + 154 + 16,
35 .htotal = 864 + 154 + 16 + 32,
36 .vdisplay = 480,
37 .vsync_start = 480 + 1,
38 .vsync_end = 480 + 1 + 1,
39 .vtotal = 480 + 1 + 1 + 1,
40 /*
41 * This depends on the clocking HS vs LP rate, this value
42 * is calculated as:
43 * vrefresh = (clock * 1000) / (htotal*vtotal)
44 */
45 .vrefresh = 816,
46 .width_mm = 84,
47 .height_mm = 48,
48};
49
50static inline struct s6d16d0 *panel_to_s6d16d0(struct drm_panel *panel)
51{
52 return container_of(panel, struct s6d16d0, panel);
53}
54
55static int s6d16d0_unprepare(struct drm_panel *panel)
56{
57 struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
58 struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
59 int ret;
60
61 /* Enter sleep mode */
62 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
63 if (ret) {
64 DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n",
65 ret);
66 return ret;
67 }
68
69 /* Assert RESET */
70 gpiod_set_value_cansleep(s6->reset_gpio, 1);
71 regulator_disable(s6->supply);
72
73 return 0;
74}
75
76static int s6d16d0_prepare(struct drm_panel *panel)
77{
78 struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
79 struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
80 int ret;
81
82 ret = regulator_enable(s6->supply);
83 if (ret) {
84 DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret);
85 return ret;
86 }
87
88 /* Assert RESET */
89 gpiod_set_value_cansleep(s6->reset_gpio, 1);
90 udelay(10);
91 /* De-assert RESET */
92 gpiod_set_value_cansleep(s6->reset_gpio, 0);
93 msleep(120);
94
95 /* Enabe tearing mode: send TE (tearing effect) at VBLANK */
96 ret = mipi_dsi_dcs_set_tear_on(dsi,
97 MIPI_DSI_DCS_TEAR_MODE_VBLANK);
98 if (ret) {
99 DRM_DEV_ERROR(s6->dev, "failed to enble vblank TE (%d)\n",
100 ret);
101 return ret;
102 }
103 /* Exit sleep mode and power on */
104 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
105 if (ret) {
106 DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n",
107 ret);
108 return ret;
109 }
110
111 return 0;
112}
113
114static int s6d16d0_enable(struct drm_panel *panel)
115{
116 struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
117 struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
118 int ret;
119
120 ret = mipi_dsi_dcs_set_display_on(dsi);
121 if (ret) {
122 DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n",
123 ret);
124 return ret;
125 }
126
127 return 0;
128}
129
130static int s6d16d0_disable(struct drm_panel *panel)
131{
132 struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
133 struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
134 int ret;
135
136 ret = mipi_dsi_dcs_set_display_off(dsi);
137 if (ret) {
138 DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n",
139 ret);
140 return ret;
141 }
142
143 return 0;
144}
145
146static int s6d16d0_get_modes(struct drm_panel *panel)
147{
148 struct drm_connector *connector = panel->connector;
149 struct drm_display_mode *mode;
150
151 strncpy(connector->display_info.name, "Samsung S6D16D0\0",
152 DRM_DISPLAY_INFO_LEN);
153
154 mode = drm_mode_duplicate(panel->drm, &samsung_s6d16d0_mode);
155 if (!mode) {
156 DRM_ERROR("bad mode or failed to add mode\n");
157 return -EINVAL;
158 }
159 drm_mode_set_name(mode);
160 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
161
162 connector->display_info.width_mm = mode->width_mm;
163 connector->display_info.height_mm = mode->height_mm;
164
165 drm_mode_probed_add(connector, mode);
166
167 return 1; /* Number of modes */
168}
169
170static const struct drm_panel_funcs s6d16d0_drm_funcs = {
171 .disable = s6d16d0_disable,
172 .unprepare = s6d16d0_unprepare,
173 .prepare = s6d16d0_prepare,
174 .enable = s6d16d0_enable,
175 .get_modes = s6d16d0_get_modes,
176};
177
178static int s6d16d0_probe(struct mipi_dsi_device *dsi)
179{
180 struct device *dev = &dsi->dev;
181 struct s6d16d0 *s6;
182 int ret;
183
184 s6 = devm_kzalloc(dev, sizeof(struct s6d16d0), GFP_KERNEL);
185 if (!s6)
186 return -ENOMEM;
187
188 mipi_dsi_set_drvdata(dsi, s6);
189 s6->dev = dev;
190
191 dsi->lanes = 2;
192 dsi->format = MIPI_DSI_FMT_RGB888;
193 dsi->hs_rate = 420160000;
194 dsi->lp_rate = 19200000;
195 /*
196 * This display uses command mode so no MIPI_DSI_MODE_VIDEO
197 * or MIPI_DSI_MODE_VIDEO_SYNC_PULSE
198 *
199 * As we only send commands we do not need to be continuously
200 * clocked.
201 */
202 dsi->mode_flags =
203 MIPI_DSI_CLOCK_NON_CONTINUOUS |
204 MIPI_DSI_MODE_EOT_PACKET;
205
206 s6->supply = devm_regulator_get(dev, "vdd1");
207 if (IS_ERR(s6->supply))
208 return PTR_ERR(s6->supply);
209
210 /* This asserts RESET by default */
211 s6->reset_gpio = devm_gpiod_get_optional(dev, "reset",
212 GPIOD_OUT_HIGH);
213 if (IS_ERR(s6->reset_gpio)) {
214 ret = PTR_ERR(s6->reset_gpio);
215 if (ret != -EPROBE_DEFER)
216 DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n",
217 ret);
218 return ret;
219 }
220
221 drm_panel_init(&s6->panel);
222 s6->panel.dev = dev;
223 s6->panel.funcs = &s6d16d0_drm_funcs;
224
225 ret = drm_panel_add(&s6->panel);
226 if (ret < 0)
227 return ret;
228
229 ret = mipi_dsi_attach(dsi);
230 if (ret < 0)
231 drm_panel_remove(&s6->panel);
232
233 return ret;
234}
235
236static int s6d16d0_remove(struct mipi_dsi_device *dsi)
237{
238 struct s6d16d0 *s6 = mipi_dsi_get_drvdata(dsi);
239
240 mipi_dsi_detach(dsi);
241 drm_panel_remove(&s6->panel);
242
243 return 0;
244}
245
246static const struct of_device_id s6d16d0_of_match[] = {
247 { .compatible = "samsung,s6d16d0" },
248 { }
249};
250MODULE_DEVICE_TABLE(of, s6d16d0_of_match);
251
252static struct mipi_dsi_driver s6d16d0_driver = {
253 .probe = s6d16d0_probe,
254 .remove = s6d16d0_remove,
255 .driver = {
256 .name = "panel-samsung-s6d16d0",
257 .of_match_table = s6d16d0_of_match,
258 },
259};
260module_mipi_dsi_driver(s6d16d0_driver);
261
262MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>");
263MODULE_DESCRIPTION("MIPI-DSI s6d16d0 Panel Driver");
264MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
index 75f925390551..2d99e28ff117 100644
--- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
+++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
@@ -1,12 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) 2017 NXP Semiconductors. 3 * Copyright (C) 2017 NXP Semiconductors.
3 * Author: Marco Franchi <marco.franchi@nxp.com> 4 * Author: Marco Franchi <marco.franchi@nxp.com>
4 * 5 *
5 * Based on Panel Simple driver by Thierry Reding <treding@nvidia.com> 6 * Based on Panel Simple driver by Thierry Reding <treding@nvidia.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
10 */ 7 */
11 8
12#include <linux/backlight.h> 9#include <linux/backlight.h>
@@ -366,6 +363,6 @@ static struct platform_driver seiko_panel_platform_driver = {
366}; 363};
367module_platform_driver(seiko_panel_platform_driver); 364module_platform_driver(seiko_panel_platform_driver);
368 365
369MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com"); 366MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com>");
370MODULE_DESCRIPTION("Seiko 43WVF1G panel driver"); 367MODULE_DESCRIPTION("Seiko 43WVF1G panel driver");
371MODULE_LICENSE("GPL v2"); 368MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index a04ffb3b2174..5fbee837b0db 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -782,16 +782,38 @@ static const struct panel_desc avic_tm070ddh03 = {
782 }, 782 },
783}; 783};
784 784
785static const struct drm_display_mode bananapi_s070wv20_ct16_mode = {
786 .clock = 30000,
787 .hdisplay = 800,
788 .hsync_start = 800 + 40,
789 .hsync_end = 800 + 40 + 48,
790 .htotal = 800 + 40 + 48 + 40,
791 .vdisplay = 480,
792 .vsync_start = 480 + 13,
793 .vsync_end = 480 + 13 + 3,
794 .vtotal = 480 + 13 + 3 + 29,
795};
796
797static const struct panel_desc bananapi_s070wv20_ct16 = {
798 .modes = &bananapi_s070wv20_ct16_mode,
799 .num_modes = 1,
800 .bpc = 6,
801 .size = {
802 .width = 154,
803 .height = 86,
804 },
805};
806
785static const struct drm_display_mode boe_hv070wsa_mode = { 807static const struct drm_display_mode boe_hv070wsa_mode = {
786 .clock = 40800, 808 .clock = 42105,
787 .hdisplay = 1024, 809 .hdisplay = 1024,
788 .hsync_start = 1024 + 90, 810 .hsync_start = 1024 + 30,
789 .hsync_end = 1024 + 90 + 90, 811 .hsync_end = 1024 + 30 + 30,
790 .htotal = 1024 + 90 + 90 + 90, 812 .htotal = 1024 + 30 + 30 + 30,
791 .vdisplay = 600, 813 .vdisplay = 600,
792 .vsync_start = 600 + 3, 814 .vsync_start = 600 + 10,
793 .vsync_end = 600 + 3 + 4, 815 .vsync_end = 600 + 10 + 10,
794 .vtotal = 600 + 3 + 4 + 3, 816 .vtotal = 600 + 10 + 10 + 10,
795 .vrefresh = 60, 817 .vrefresh = 60,
796}; 818};
797 819
@@ -846,6 +868,55 @@ static const struct panel_desc boe_nv101wxmn51 = {
846 }, 868 },
847}; 869};
848 870
871static const struct drm_display_mode cdtech_s043wq26h_ct7_mode = {
872 .clock = 9000,
873 .hdisplay = 480,
874 .hsync_start = 480 + 5,
875 .hsync_end = 480 + 5 + 5,
876 .htotal = 480 + 5 + 5 + 40,
877 .vdisplay = 272,
878 .vsync_start = 272 + 8,
879 .vsync_end = 272 + 8 + 8,
880 .vtotal = 272 + 8 + 8 + 8,
881 .vrefresh = 60,
882 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
883};
884
885static const struct panel_desc cdtech_s043wq26h_ct7 = {
886 .modes = &cdtech_s043wq26h_ct7_mode,
887 .num_modes = 1,
888 .bpc = 8,
889 .size = {
890 .width = 95,
891 .height = 54,
892 },
893 .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
894};
895
896static const struct drm_display_mode cdtech_s070wv95_ct16_mode = {
897 .clock = 35000,
898 .hdisplay = 800,
899 .hsync_start = 800 + 40,
900 .hsync_end = 800 + 40 + 40,
901 .htotal = 800 + 40 + 40 + 48,
902 .vdisplay = 480,
903 .vsync_start = 480 + 29,
904 .vsync_end = 480 + 29 + 13,
905 .vtotal = 480 + 29 + 13 + 3,
906 .vrefresh = 60,
907 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
908};
909
910static const struct panel_desc cdtech_s070wv95_ct16 = {
911 .modes = &cdtech_s070wv95_ct16_mode,
912 .num_modes = 1,
913 .bpc = 8,
914 .size = {
915 .width = 154,
916 .height = 85,
917 },
918};
919
849static const struct drm_display_mode chunghwa_claa070wp03xg_mode = { 920static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
850 .clock = 66770, 921 .clock = 66770,
851 .hdisplay = 800, 922 .hdisplay = 800,
@@ -971,6 +1042,36 @@ static const struct panel_desc dlc_dlc0700yzg_1 = {
971 .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 1042 .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
972}; 1043};
973 1044
1045static const struct display_timing dlc_dlc1010gig_timing = {
1046 .pixelclock = { 68900000, 71100000, 73400000 },
1047 .hactive = { 1280, 1280, 1280 },
1048 .hfront_porch = { 43, 53, 63 },
1049 .hback_porch = { 43, 53, 63 },
1050 .hsync_len = { 44, 54, 64 },
1051 .vactive = { 800, 800, 800 },
1052 .vfront_porch = { 5, 8, 11 },
1053 .vback_porch = { 5, 8, 11 },
1054 .vsync_len = { 5, 7, 11 },
1055 .flags = DISPLAY_FLAGS_DE_HIGH,
1056};
1057
1058static const struct panel_desc dlc_dlc1010gig = {
1059 .timings = &dlc_dlc1010gig_timing,
1060 .num_timings = 1,
1061 .bpc = 8,
1062 .size = {
1063 .width = 216,
1064 .height = 135,
1065 },
1066 .delay = {
1067 .prepare = 60,
1068 .enable = 150,
1069 .disable = 100,
1070 .unprepare = 60,
1071 },
1072 .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
1073};
1074
974static const struct drm_display_mode edt_et057090dhu_mode = { 1075static const struct drm_display_mode edt_et057090dhu_mode = {
975 .clock = 25175, 1076 .clock = 25175,
976 .hdisplay = 640, 1077 .hdisplay = 640,
@@ -2334,6 +2435,33 @@ static const struct panel_desc winstar_wf35ltiacd = {
2334 .bus_format = MEDIA_BUS_FMT_RGB888_1X24, 2435 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
2335}; 2436};
2336 2437
2438static const struct drm_display_mode arm_rtsm_mode[] = {
2439 {
2440 .clock = 65000,
2441 .hdisplay = 1024,
2442 .hsync_start = 1024 + 24,
2443 .hsync_end = 1024 + 24 + 136,
2444 .htotal = 1024 + 24 + 136 + 160,
2445 .vdisplay = 768,
2446 .vsync_start = 768 + 3,
2447 .vsync_end = 768 + 3 + 6,
2448 .vtotal = 768 + 3 + 6 + 29,
2449 .vrefresh = 60,
2450 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
2451 },
2452};
2453
2454static const struct panel_desc arm_rtsm = {
2455 .modes = arm_rtsm_mode,
2456 .num_modes = 1,
2457 .bpc = 8,
2458 .size = {
2459 .width = 400,
2460 .height = 300,
2461 },
2462 .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
2463};
2464
2337static const struct of_device_id platform_of_match[] = { 2465static const struct of_device_id platform_of_match[] = {
2338 { 2466 {
2339 .compatible = "ampire,am-480272h3tmqw-t01h", 2467 .compatible = "ampire,am-480272h3tmqw-t01h",
@@ -2342,6 +2470,9 @@ static const struct of_device_id platform_of_match[] = {
2342 .compatible = "ampire,am800480r3tmqwa1h", 2470 .compatible = "ampire,am800480r3tmqwa1h",
2343 .data = &ampire_am800480r3tmqwa1h, 2471 .data = &ampire_am800480r3tmqwa1h,
2344 }, { 2472 }, {
2473 .compatible = "arm,rtsm-display",
2474 .data = &arm_rtsm,
2475 }, {
2345 .compatible = "auo,b101aw03", 2476 .compatible = "auo,b101aw03",
2346 .data = &auo_b101aw03, 2477 .data = &auo_b101aw03,
2347 }, { 2478 }, {
@@ -2381,12 +2512,21 @@ static const struct of_device_id platform_of_match[] = {
2381 .compatible = "avic,tm070ddh03", 2512 .compatible = "avic,tm070ddh03",
2382 .data = &avic_tm070ddh03, 2513 .data = &avic_tm070ddh03,
2383 }, { 2514 }, {
2515 .compatible = "bananapi,s070wv20-ct16",
2516 .data = &bananapi_s070wv20_ct16,
2517 }, {
2384 .compatible = "boe,hv070wsa-100", 2518 .compatible = "boe,hv070wsa-100",
2385 .data = &boe_hv070wsa 2519 .data = &boe_hv070wsa
2386 }, { 2520 }, {
2387 .compatible = "boe,nv101wxmn51", 2521 .compatible = "boe,nv101wxmn51",
2388 .data = &boe_nv101wxmn51, 2522 .data = &boe_nv101wxmn51,
2389 }, { 2523 }, {
2524 .compatible = "cdtech,s043wq26h-ct7",
2525 .data = &cdtech_s043wq26h_ct7,
2526 }, {
2527 .compatible = "cdtech,s070wv95-ct16",
2528 .data = &cdtech_s070wv95_ct16,
2529 }, {
2390 .compatible = "chunghwa,claa070wp03xg", 2530 .compatible = "chunghwa,claa070wp03xg",
2391 .data = &chunghwa_claa070wp03xg, 2531 .data = &chunghwa_claa070wp03xg,
2392 }, { 2532 }, {
@@ -2402,6 +2542,9 @@ static const struct of_device_id platform_of_match[] = {
2402 .compatible = "dlc,dlc0700yzg-1", 2542 .compatible = "dlc,dlc0700yzg-1",
2403 .data = &dlc_dlc0700yzg_1, 2543 .data = &dlc_dlc0700yzg_1,
2404 }, { 2544 }, {
2545 .compatible = "dlc,dlc1010gig",
2546 .data = &dlc_dlc1010gig,
2547 }, {
2405 .compatible = "edt,et057090dhu", 2548 .compatible = "edt,et057090dhu",
2406 .data = &edt_et057090dhu, 2549 .data = &edt_et057090dhu,
2407 }, { 2550 }, {
diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c
new file mode 100644
index 000000000000..fc2a66c53db4
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -0,0 +1,675 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 */
5
6#include <drm/drmP.h>
7#include <drm/drm_panel.h>
8#include <drm/drm_mipi_dsi.h>
9
10#include <linux/gpio/consumer.h>
11#include <linux/of_device.h>
12#include <linux/of_graph.h>
13#include <linux/pinctrl/consumer.h>
14#include <linux/regulator/consumer.h>
15
16#include <video/mipi_display.h>
17
18static const char * const regulator_names[] = {
19 "vdda",
20 "vdispp",
21 "vdispn",
22};
23
24static unsigned long const regulator_enable_loads[] = {
25 62000,
26 100000,
27 100000,
28};
29
30static unsigned long const regulator_disable_loads[] = {
31 80,
32 100,
33 100,
34};
35
36struct cmd_set {
37 u8 commands[4];
38 u8 size;
39};
40
41struct nt35597_config {
42 u32 width_mm;
43 u32 height_mm;
44 const char *panel_name;
45 const struct cmd_set *panel_on_cmds;
46 u32 num_on_cmds;
47 const struct drm_display_mode *dm;
48};
49
50struct truly_nt35597 {
51 struct device *dev;
52 struct drm_panel panel;
53
54 struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
55
56 struct gpio_desc *reset_gpio;
57 struct gpio_desc *mode_gpio;
58
59 struct backlight_device *backlight;
60
61 struct mipi_dsi_device *dsi[2];
62
63 const struct nt35597_config *config;
64 bool prepared;
65 bool enabled;
66};
67
68static inline struct truly_nt35597 *panel_to_ctx(struct drm_panel *panel)
69{
70 return container_of(panel, struct truly_nt35597, panel);
71}
72
73static const struct cmd_set qcom_2k_panel_magic_cmds[] = {
74 /* CMD2_P0 */
75 { { 0xff, 0x20 }, 2 },
76 { { 0xfb, 0x01 }, 2 },
77 { { 0x00, 0x01 }, 2 },
78 { { 0x01, 0x55 }, 2 },
79 { { 0x02, 0x45 }, 2 },
80 { { 0x05, 0x40 }, 2 },
81 { { 0x06, 0x19 }, 2 },
82 { { 0x07, 0x1e }, 2 },
83 { { 0x0b, 0x73 }, 2 },
84 { { 0x0c, 0x73 }, 2 },
85 { { 0x0e, 0xb0 }, 2 },
86 { { 0x0f, 0xae }, 2 },
87 { { 0x11, 0xb8 }, 2 },
88 { { 0x13, 0x00 }, 2 },
89 { { 0x58, 0x80 }, 2 },
90 { { 0x59, 0x01 }, 2 },
91 { { 0x5a, 0x00 }, 2 },
92 { { 0x5b, 0x01 }, 2 },
93 { { 0x5c, 0x80 }, 2 },
94 { { 0x5d, 0x81 }, 2 },
95 { { 0x5e, 0x00 }, 2 },
96 { { 0x5f, 0x01 }, 2 },
97 { { 0x72, 0x11 }, 2 },
98 { { 0x68, 0x03 }, 2 },
99 /* CMD2_P4 */
100 { { 0xFF, 0x24 }, 2 },
101 { { 0xFB, 0x01 }, 2 },
102 { { 0x00, 0x1C }, 2 },
103 { { 0x01, 0x0B }, 2 },
104 { { 0x02, 0x0C }, 2 },
105 { { 0x03, 0x01 }, 2 },
106 { { 0x04, 0x0F }, 2 },
107 { { 0x05, 0x10 }, 2 },
108 { { 0x06, 0x10 }, 2 },
109 { { 0x07, 0x10 }, 2 },
110 { { 0x08, 0x89 }, 2 },
111 { { 0x09, 0x8A }, 2 },
112 { { 0x0A, 0x13 }, 2 },
113 { { 0x0B, 0x13 }, 2 },
114 { { 0x0C, 0x15 }, 2 },
115 { { 0x0D, 0x15 }, 2 },
116 { { 0x0E, 0x17 }, 2 },
117 { { 0x0F, 0x17 }, 2 },
118 { { 0x10, 0x1C }, 2 },
119 { { 0x11, 0x0B }, 2 },
120 { { 0x12, 0x0C }, 2 },
121 { { 0x13, 0x01 }, 2 },
122 { { 0x14, 0x0F }, 2 },
123 { { 0x15, 0x10 }, 2 },
124 { { 0x16, 0x10 }, 2 },
125 { { 0x17, 0x10 }, 2 },
126 { { 0x18, 0x89 }, 2 },
127 { { 0x19, 0x8A }, 2 },
128 { { 0x1A, 0x13 }, 2 },
129 { { 0x1B, 0x13 }, 2 },
130 { { 0x1C, 0x15 }, 2 },
131 { { 0x1D, 0x15 }, 2 },
132 { { 0x1E, 0x17 }, 2 },
133 { { 0x1F, 0x17 }, 2 },
134 /* STV */
135 { { 0x20, 0x40 }, 2 },
136 { { 0x21, 0x01 }, 2 },
137 { { 0x22, 0x00 }, 2 },
138 { { 0x23, 0x40 }, 2 },
139 { { 0x24, 0x40 }, 2 },
140 { { 0x25, 0x6D }, 2 },
141 { { 0x26, 0x40 }, 2 },
142 { { 0x27, 0x40 }, 2 },
143 /* Vend */
144 { { 0xE0, 0x00 }, 2 },
145 { { 0xDC, 0x21 }, 2 },
146 { { 0xDD, 0x22 }, 2 },
147 { { 0xDE, 0x07 }, 2 },
148 { { 0xDF, 0x07 }, 2 },
149 { { 0xE3, 0x6D }, 2 },
150 { { 0xE1, 0x07 }, 2 },
151 { { 0xE2, 0x07 }, 2 },
152 /* UD */
153 { { 0x29, 0xD8 }, 2 },
154 { { 0x2A, 0x2A }, 2 },
155 /* CLK */
156 { { 0x4B, 0x03 }, 2 },
157 { { 0x4C, 0x11 }, 2 },
158 { { 0x4D, 0x10 }, 2 },
159 { { 0x4E, 0x01 }, 2 },
160 { { 0x4F, 0x01 }, 2 },
161 { { 0x50, 0x10 }, 2 },
162 { { 0x51, 0x00 }, 2 },
163 { { 0x52, 0x80 }, 2 },
164 { { 0x53, 0x00 }, 2 },
165 { { 0x56, 0x00 }, 2 },
166 { { 0x54, 0x07 }, 2 },
167 { { 0x58, 0x07 }, 2 },
168 { { 0x55, 0x25 }, 2 },
169 /* Reset XDONB */
170 { { 0x5B, 0x43 }, 2 },
171 { { 0x5C, 0x00 }, 2 },
172 { { 0x5F, 0x73 }, 2 },
173 { { 0x60, 0x73 }, 2 },
174 { { 0x63, 0x22 }, 2 },
175 { { 0x64, 0x00 }, 2 },
176 { { 0x67, 0x08 }, 2 },
177 { { 0x68, 0x04 }, 2 },
178 /* Resolution:1440x2560 */
179 { { 0x72, 0x02 }, 2 },
180 /* mux */
181 { { 0x7A, 0x80 }, 2 },
182 { { 0x7B, 0x91 }, 2 },
183 { { 0x7C, 0xD8 }, 2 },
184 { { 0x7D, 0x60 }, 2 },
185 { { 0x7F, 0x15 }, 2 },
186 { { 0x75, 0x15 }, 2 },
187 /* ABOFF */
188 { { 0xB3, 0xC0 }, 2 },
189 { { 0xB4, 0x00 }, 2 },
190 { { 0xB5, 0x00 }, 2 },
191 /* Source EQ */
192 { { 0x78, 0x00 }, 2 },
193 { { 0x79, 0x00 }, 2 },
194 { { 0x80, 0x00 }, 2 },
195 { { 0x83, 0x00 }, 2 },
196 /* FP BP */
197 { { 0x93, 0x0A }, 2 },
198 { { 0x94, 0x0A }, 2 },
199 /* Inversion Type */
200 { { 0x8A, 0x00 }, 2 },
201 { { 0x9B, 0xFF }, 2 },
202 /* IMGSWAP =1 @PortSwap=1 */
203 { { 0x9D, 0xB0 }, 2 },
204 { { 0x9F, 0x63 }, 2 },
205 { { 0x98, 0x10 }, 2 },
206 /* FRM */
207 { { 0xEC, 0x00 }, 2 },
208 /* CMD1 */
209 { { 0xFF, 0x10 }, 2 },
210 /* VBP+VSA=,VFP = 10H */
211 { { 0x3B, 0x03, 0x0A, 0x0A }, 4 },
212 /* FTE on */
213 { { 0x35, 0x00 }, 2 },
214 /* EN_BK =1(auto black) */
215 { { 0xE5, 0x01 }, 2 },
216 /* CMD mode(10) VDO mode(03) */
217 { { 0xBB, 0x03 }, 2 },
218 /* Non Reload MTP */
219 { { 0xFB, 0x01 }, 2 },
220};
221
222static int truly_dcs_write(struct drm_panel *panel, u32 command)
223{
224 struct truly_nt35597 *ctx = panel_to_ctx(panel);
225 int i, ret;
226
227 for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
228 ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0);
229 if (ret < 0) {
230 DRM_DEV_ERROR(ctx->dev,
231 "cmd 0x%x failed for dsi = %d\n",
232 command, i);
233 }
234 }
235
236 return ret;
237}
238
239static int truly_dcs_write_buf(struct drm_panel *panel,
240 u32 size, const u8 *buf)
241{
242 struct truly_nt35597 *ctx = panel_to_ctx(panel);
243 int ret = 0;
244 int i;
245
246 for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
247 ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size);
248 if (ret < 0) {
249 DRM_DEV_ERROR(ctx->dev,
250 "failed to tx cmd [%d], err: %d\n", i, ret);
251 return ret;
252 }
253 }
254
255 return ret;
256}
257
258static int truly_35597_power_on(struct truly_nt35597 *ctx)
259{
260 int ret, i;
261
262 for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
263 ret = regulator_set_load(ctx->supplies[i].consumer,
264 regulator_enable_loads[i]);
265 if (ret)
266 return ret;
267 }
268
269 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
270 if (ret < 0)
271 return ret;
272
273 /*
274 * Reset sequence of truly panel requires the panel to be
275 * out of reset for 10ms, followed by being held in reset
276 * for 10ms and then out again
277 */
278 gpiod_set_value(ctx->reset_gpio, 0);
279 usleep_range(10000, 20000);
280 gpiod_set_value(ctx->reset_gpio, 1);
281 usleep_range(10000, 20000);
282 gpiod_set_value(ctx->reset_gpio, 0);
283
284 return 0;
285}
286
287static int truly_nt35597_power_off(struct truly_nt35597 *ctx)
288{
289 int ret = 0;
290 int i;
291
292 gpiod_set_value(ctx->reset_gpio, 1);
293
294 for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
295 ret = regulator_set_load(ctx->supplies[i].consumer,
296 regulator_disable_loads[i]);
297 if (ret) {
298 DRM_DEV_ERROR(ctx->dev,
299 "regulator_set_load failed %d\n", ret);
300 return ret;
301 }
302 }
303
304 ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
305 if (ret) {
306 DRM_DEV_ERROR(ctx->dev,
307 "regulator_bulk_disable failed %d\n", ret);
308 }
309 return ret;
310}
311
312static int truly_nt35597_disable(struct drm_panel *panel)
313{
314 struct truly_nt35597 *ctx = panel_to_ctx(panel);
315 int ret;
316
317 if (!ctx->enabled)
318 return 0;
319
320 if (ctx->backlight) {
321 ret = backlight_disable(ctx->backlight);
322 if (ret < 0)
323 DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n",
324 ret);
325 }
326
327 ctx->enabled = false;
328 return 0;
329}
330
331static int truly_nt35597_unprepare(struct drm_panel *panel)
332{
333 struct truly_nt35597 *ctx = panel_to_ctx(panel);
334 int ret = 0;
335
336 if (!ctx->prepared)
337 return 0;
338
339 ctx->dsi[0]->mode_flags = 0;
340 ctx->dsi[1]->mode_flags = 0;
341
342 ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF);
343 if (ret < 0) {
344 DRM_DEV_ERROR(ctx->dev,
345 "set_display_off cmd failed ret = %d\n",
346 ret);
347 }
348
349 /* 120ms delay required here as per DCS spec */
350 msleep(120);
351
352 ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE);
353 if (ret < 0) {
354 DRM_DEV_ERROR(ctx->dev,
355 "enter_sleep cmd failed ret = %d\n", ret);
356 }
357
358 ret = truly_nt35597_power_off(ctx);
359 if (ret < 0)
360 DRM_DEV_ERROR(ctx->dev, "power_off failed ret = %d\n", ret);
361
362 ctx->prepared = false;
363 return ret;
364}
365
366static int truly_nt35597_prepare(struct drm_panel *panel)
367{
368 struct truly_nt35597 *ctx = panel_to_ctx(panel);
369 int ret;
370 int i;
371 const struct cmd_set *panel_on_cmds;
372 const struct nt35597_config *config;
373 u32 num_cmds;
374
375 if (ctx->prepared)
376 return 0;
377
378 ret = truly_35597_power_on(ctx);
379 if (ret < 0)
380 return ret;
381
382 ctx->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
383 ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
384
385 config = ctx->config;
386 panel_on_cmds = config->panel_on_cmds;
387 num_cmds = config->num_on_cmds;
388
389 for (i = 0; i < num_cmds; i++) {
390 ret = truly_dcs_write_buf(panel,
391 panel_on_cmds[i].size,
392 panel_on_cmds[i].commands);
393 if (ret < 0) {
394 DRM_DEV_ERROR(ctx->dev,
395 "cmd set tx failed i = %d ret = %d\n",
396 i, ret);
397 goto power_off;
398 }
399 }
400
401 ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE);
402 if (ret < 0) {
403 DRM_DEV_ERROR(ctx->dev,
404 "exit_sleep_mode cmd failed ret = %d\n",
405 ret);
406 goto power_off;
407 }
408
409 /* Per DSI spec wait 120ms after sending exit sleep DCS command */
410 msleep(120);
411
412 ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON);
413 if (ret < 0) {
414 DRM_DEV_ERROR(ctx->dev,
415 "set_display_on cmd failed ret = %d\n", ret);
416 goto power_off;
417 }
418
419 /* Per DSI spec wait 120ms after sending set_display_on DCS command */
420 msleep(120);
421
422 ctx->prepared = true;
423
424 return 0;
425
426power_off:
427 if (truly_nt35597_power_off(ctx))
428 DRM_DEV_ERROR(ctx->dev, "power_off failed\n");
429 return ret;
430}
431
432static int truly_nt35597_enable(struct drm_panel *panel)
433{
434 struct truly_nt35597 *ctx = panel_to_ctx(panel);
435 int ret;
436
437 if (ctx->enabled)
438 return 0;
439
440 if (ctx->backlight) {
441 ret = backlight_enable(ctx->backlight);
442 if (ret < 0)
443 DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n",
444 ret);
445 }
446
447 ctx->enabled = true;
448
449 return 0;
450}
451
452static int truly_nt35597_get_modes(struct drm_panel *panel)
453{
454 struct drm_connector *connector = panel->connector;
455 struct truly_nt35597 *ctx = panel_to_ctx(panel);
456 struct drm_display_mode *mode;
457 const struct nt35597_config *config;
458
459 config = ctx->config;
460 mode = drm_mode_create(connector->dev);
461 if (!mode) {
462 DRM_DEV_ERROR(ctx->dev,
463 "failed to create a new display mode\n");
464 return 0;
465 }
466
467 connector->display_info.width_mm = config->width_mm;
468 connector->display_info.height_mm = config->height_mm;
469 drm_mode_copy(mode, config->dm);
470 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
471 drm_mode_probed_add(connector, mode);
472
473 return 1;
474}
475
476static const struct drm_panel_funcs truly_nt35597_drm_funcs = {
477 .disable = truly_nt35597_disable,
478 .unprepare = truly_nt35597_unprepare,
479 .prepare = truly_nt35597_prepare,
480 .enable = truly_nt35597_enable,
481 .get_modes = truly_nt35597_get_modes,
482};
483
484static int truly_nt35597_panel_add(struct truly_nt35597 *ctx)
485{
486 struct device *dev = ctx->dev;
487 int ret, i;
488 const struct nt35597_config *config;
489
490 config = ctx->config;
491 for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
492 ctx->supplies[i].supply = regulator_names[i];
493
494 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
495 ctx->supplies);
496 if (ret < 0)
497 return ret;
498
499 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
500 if (IS_ERR(ctx->reset_gpio)) {
501 DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
502 PTR_ERR(ctx->reset_gpio));
503 return PTR_ERR(ctx->reset_gpio);
504 }
505
506 ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW);
507 if (IS_ERR(ctx->mode_gpio)) {
508 DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n",
509 PTR_ERR(ctx->mode_gpio));
510 return PTR_ERR(ctx->mode_gpio);
511 }
512
513 /* dual port */
514 gpiod_set_value(ctx->mode_gpio, 0);
515
516 drm_panel_init(&ctx->panel);
517 ctx->panel.dev = dev;
518 ctx->panel.funcs = &truly_nt35597_drm_funcs;
519 drm_panel_add(&ctx->panel);
520
521 return 0;
522}
523
524static const struct drm_display_mode qcom_sdm845_mtp_2k_mode = {
525 .name = "1440x2560",
526 .clock = 268316,
527 .hdisplay = 1440,
528 .hsync_start = 1440 + 200,
529 .hsync_end = 1440 + 200 + 32,
530 .htotal = 1440 + 200 + 32 + 64,
531 .vdisplay = 2560,
532 .vsync_start = 2560 + 8,
533 .vsync_end = 2560 + 8 + 1,
534 .vtotal = 2560 + 8 + 1 + 7,
535 .vrefresh = 60,
536 .flags = 0,
537};
538
539static const struct nt35597_config nt35597_dir = {
540 .width_mm = 74,
541 .height_mm = 131,
542 .panel_name = "qcom_sdm845_mtp_2k_panel",
543 .dm = &qcom_sdm845_mtp_2k_mode,
544 .panel_on_cmds = qcom_2k_panel_magic_cmds,
545 .num_on_cmds = ARRAY_SIZE(qcom_2k_panel_magic_cmds),
546};
547
548static int truly_nt35597_probe(struct mipi_dsi_device *dsi)
549{
550 struct device *dev = &dsi->dev;
551 struct truly_nt35597 *ctx;
552 struct mipi_dsi_device *dsi1_device;
553 struct device_node *dsi1;
554 struct mipi_dsi_host *dsi1_host;
555 struct mipi_dsi_device *dsi_dev;
556 int ret = 0;
557 int i;
558
559 const struct mipi_dsi_device_info info = {
560 .type = "trulynt35597",
561 .channel = 0,
562 .node = NULL,
563 };
564
565 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
566
567 if (!ctx)
568 return -ENOMEM;
569
570 /*
571 * This device represents itself as one with two input ports which are
572 * fed by the output ports of the two DSI controllers . The DSI0 is
573 * the master controller and has most of the panel related info in its
574 * child node.
575 */
576
577 ctx->config = of_device_get_match_data(dev);
578
579 if (!ctx->config) {
580 dev_err(dev, "missing device configuration\n");
581 return -ENODEV;
582 }
583
584 dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
585 if (!dsi1) {
586 DRM_DEV_ERROR(dev,
587 "failed to get remote node for dsi1_device\n");
588 return -ENODEV;
589 }
590
591 dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
592 of_node_put(dsi1);
593 if (!dsi1_host) {
594 DRM_DEV_ERROR(dev, "failed to find dsi host\n");
595 return -EPROBE_DEFER;
596 }
597
598 /* register the second DSI device */
599 dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info);
600 if (IS_ERR(dsi1_device)) {
601 DRM_DEV_ERROR(dev, "failed to create dsi device\n");
602 return PTR_ERR(dsi1_device);
603 }
604
605 mipi_dsi_set_drvdata(dsi, ctx);
606
607 ctx->dev = dev;
608 ctx->dsi[0] = dsi;
609 ctx->dsi[1] = dsi1_device;
610
611 ret = truly_nt35597_panel_add(ctx);
612 if (ret) {
613 DRM_DEV_ERROR(dev, "failed to add panel\n");
614 goto err_panel_add;
615 }
616
617 for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
618 dsi_dev = ctx->dsi[i];
619 dsi_dev->lanes = 4;
620 dsi_dev->format = MIPI_DSI_FMT_RGB888;
621 dsi_dev->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
622 MIPI_DSI_CLOCK_NON_CONTINUOUS;
623 ret = mipi_dsi_attach(dsi_dev);
624 if (ret < 0) {
625 DRM_DEV_ERROR(dev,
626 "dsi attach failed i = %d\n", i);
627 goto err_dsi_attach;
628 }
629 }
630
631 return 0;
632
633err_dsi_attach:
634 drm_panel_remove(&ctx->panel);
635err_panel_add:
636 mipi_dsi_device_unregister(dsi1_device);
637 return ret;
638}
639
640static int truly_nt35597_remove(struct mipi_dsi_device *dsi)
641{
642 struct truly_nt35597 *ctx = mipi_dsi_get_drvdata(dsi);
643
644 if (ctx->dsi[0])
645 mipi_dsi_detach(ctx->dsi[0]);
646 if (ctx->dsi[1]) {
647 mipi_dsi_detach(ctx->dsi[1]);
648 mipi_dsi_device_unregister(ctx->dsi[1]);
649 }
650
651 drm_panel_remove(&ctx->panel);
652 return 0;
653}
654
655static const struct of_device_id truly_nt35597_of_match[] = {
656 {
657 .compatible = "truly,nt35597-2K-display",
658 .data = &nt35597_dir,
659 },
660 { }
661};
662MODULE_DEVICE_TABLE(of, truly_nt35597_of_match);
663
664static struct mipi_dsi_driver truly_nt35597_driver = {
665 .driver = {
666 .name = "panel-truly-nt35597",
667 .of_match_table = truly_nt35597_of_match,
668 },
669 .probe = truly_nt35597_probe,
670 .remove = truly_nt35597_remove,
671};
672module_mipi_dsi_driver(truly_nt35597_driver);
673
674MODULE_DESCRIPTION("Truly NT35597 DSI Panel Driver");
675MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 208af9f37914..dffc5093ff16 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -84,6 +84,7 @@ static int qxl_check_header(struct qxl_ring *ring)
84 int ret; 84 int ret;
85 struct qxl_ring_header *header = &(ring->ring->header); 85 struct qxl_ring_header *header = &(ring->ring->header);
86 unsigned long flags; 86 unsigned long flags;
87
87 spin_lock_irqsave(&ring->lock, flags); 88 spin_lock_irqsave(&ring->lock, flags);
88 ret = header->prod - header->cons < header->num_items; 89 ret = header->prod - header->cons < header->num_items;
89 if (ret == 0) 90 if (ret == 0)
@@ -97,6 +98,7 @@ int qxl_check_idle(struct qxl_ring *ring)
97 int ret; 98 int ret;
98 struct qxl_ring_header *header = &(ring->ring->header); 99 struct qxl_ring_header *header = &(ring->ring->header);
99 unsigned long flags; 100 unsigned long flags;
101
100 spin_lock_irqsave(&ring->lock, flags); 102 spin_lock_irqsave(&ring->lock, flags);
101 ret = header->prod == header->cons; 103 ret = header->prod == header->cons;
102 spin_unlock_irqrestore(&ring->lock, flags); 104 spin_unlock_irqrestore(&ring->lock, flags);
@@ -110,6 +112,7 @@ int qxl_ring_push(struct qxl_ring *ring,
110 uint8_t *elt; 112 uint8_t *elt;
111 int idx, ret; 113 int idx, ret;
112 unsigned long flags; 114 unsigned long flags;
115
113 spin_lock_irqsave(&ring->lock, flags); 116 spin_lock_irqsave(&ring->lock, flags);
114 if (header->prod - header->cons == header->num_items) { 117 if (header->prod - header->cons == header->num_items) {
115 header->notify_on_cons = header->cons + 1; 118 header->notify_on_cons = header->cons + 1;
@@ -156,6 +159,7 @@ static bool qxl_ring_pop(struct qxl_ring *ring,
156 volatile uint8_t *ring_elt; 159 volatile uint8_t *ring_elt;
157 int idx; 160 int idx;
158 unsigned long flags; 161 unsigned long flags;
162
159 spin_lock_irqsave(&ring->lock, flags); 163 spin_lock_irqsave(&ring->lock, flags);
160 if (header->cons == header->prod) { 164 if (header->cons == header->prod) {
161 header->notify_on_prod = header->cons + 1; 165 header->notify_on_prod = header->cons + 1;
@@ -365,7 +369,6 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev)
365 wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC); 369 wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC);
366} 370}
367 371
368
369void qxl_io_destroy_primary(struct qxl_device *qdev) 372void qxl_io_destroy_primary(struct qxl_device *qdev)
370{ 373{
371 wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); 374 wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
@@ -373,7 +376,7 @@ void qxl_io_destroy_primary(struct qxl_device *qdev)
373} 376}
374 377
375void qxl_io_create_primary(struct qxl_device *qdev, 378void qxl_io_create_primary(struct qxl_device *qdev,
376 unsigned offset, struct qxl_bo *bo) 379 unsigned int offset, struct qxl_bo *bo)
377{ 380{
378 struct qxl_surface_create *create; 381 struct qxl_surface_create *create;
379 382
diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c
index 15c84068d3fb..118422549828 100644
--- a/drivers/gpu/drm/qxl/qxl_debugfs.c
+++ b/drivers/gpu/drm/qxl/qxl_debugfs.c
@@ -34,7 +34,6 @@
34#include "qxl_drv.h" 34#include "qxl_drv.h"
35#include "qxl_object.h" 35#include "qxl_object.h"
36 36
37
38#if defined(CONFIG_DEBUG_FS) 37#if defined(CONFIG_DEBUG_FS)
39static int 38static int
40qxl_debugfs_irq_received(struct seq_file *m, void *data) 39qxl_debugfs_irq_received(struct seq_file *m, void *data)
@@ -102,9 +101,9 @@ qxl_debugfs_init(struct drm_minor *minor)
102 101
103int qxl_debugfs_add_files(struct qxl_device *qdev, 102int qxl_debugfs_add_files(struct qxl_device *qdev,
104 struct drm_info_list *files, 103 struct drm_info_list *files,
105 unsigned nfiles) 104 unsigned int nfiles)
106{ 105{
107 unsigned i; 106 unsigned int i;
108 107
109 for (i = 0; i < qdev->debugfs_count; i++) { 108 for (i = 0; i < qdev->debugfs_count; i++) {
110 if (qdev->debugfs[i].files == files) { 109 if (qdev->debugfs[i].files == files) {
diff --git a/drivers/gpu/drm/qxl/qxl_dev.h b/drivers/gpu/drm/qxl/qxl_dev.h
index 94c5aec71920..a0ee41632d7e 100644
--- a/drivers/gpu/drm/qxl/qxl_dev.h
+++ b/drivers/gpu/drm/qxl/qxl_dev.h
@@ -28,7 +28,6 @@
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*/ 29*/
30 30
31
32#ifndef H_QXL_DEV 31#ifndef H_QXL_DEV
33#define H_QXL_DEV 32#define H_QXL_DEV
34 33
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 87d16a0ce01e..2ce9a8dcec84 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -253,12 +253,13 @@ static struct mode_size {
253}; 253};
254 254
255static int qxl_add_common_modes(struct drm_connector *connector, 255static int qxl_add_common_modes(struct drm_connector *connector,
256 unsigned pwidth, 256 unsigned int pwidth,
257 unsigned pheight) 257 unsigned int pheight)
258{ 258{
259 struct drm_device *dev = connector->dev; 259 struct drm_device *dev = connector->dev;
260 struct drm_display_mode *mode = NULL; 260 struct drm_display_mode *mode = NULL;
261 int i; 261 int i;
262
262 for (i = 0; i < ARRAY_SIZE(common_modes); i++) { 263 for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
263 mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 264 mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h,
264 60, false, false, false); 265 60, false, false, false);
@@ -315,6 +316,7 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
315 oldcount = qdev->monitors_config->count; 316 oldcount = qdev->monitors_config->count;
316 if (crtc->state->active) { 317 if (crtc->state->active) {
317 struct drm_display_mode *mode = &crtc->mode; 318 struct drm_display_mode *mode = &crtc->mode;
319
318 head.width = mode->hdisplay; 320 head.width = mode->hdisplay;
319 head.height = mode->vdisplay; 321 head.height = mode->vdisplay;
320 head.x = crtc->x; 322 head.x = crtc->x;
@@ -391,9 +393,9 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
391 393
392static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, 394static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
393 struct drm_file *file_priv, 395 struct drm_file *file_priv,
394 unsigned flags, unsigned color, 396 unsigned int flags, unsigned int color,
395 struct drm_clip_rect *clips, 397 struct drm_clip_rect *clips,
396 unsigned num_clips) 398 unsigned int num_clips)
397{ 399{
398 /* TODO: vmwgfx where this was cribbed from had locking. Why? */ 400 /* TODO: vmwgfx where this was cribbed from had locking. Why? */
399 struct qxl_device *qdev = fb->dev->dev_private; 401 struct qxl_device *qdev = fb->dev->dev_private;
@@ -917,8 +919,8 @@ free_mem:
917 919
918static int qxl_conn_get_modes(struct drm_connector *connector) 920static int qxl_conn_get_modes(struct drm_connector *connector)
919{ 921{
920 unsigned pwidth = 1024; 922 unsigned int pwidth = 1024;
921 unsigned pheight = 768; 923 unsigned int pheight = 768;
922 int ret = 0; 924 int ret = 0;
923 925
924 ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight); 926 ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
@@ -938,8 +940,8 @@ static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
938 /* TODO: is this called for user defined modes? (xrandr --add-mode) 940 /* TODO: is this called for user defined modes? (xrandr --add-mode)
939 * TODO: check that the mode fits in the framebuffer */ 941 * TODO: check that the mode fits in the framebuffer */
940 942
941 if(qdev->monitors_config_width == mode->hdisplay && 943 if (qdev->monitors_config_width == mode->hdisplay &&
942 qdev->monitors_config_height == mode->vdisplay) 944 qdev->monitors_config_height == mode->vdisplay)
943 return MODE_OK; 945 return MODE_OK;
944 946
945 for (i = 0; i < ARRAY_SIZE(common_modes); i++) { 947 for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
@@ -958,7 +960,6 @@ static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector)
958 return &qxl_output->enc; 960 return &qxl_output->enc;
959} 961}
960 962
961
962static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = { 963static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = {
963}; 964};
964 965
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c
index cc5b32e749ce..c34e45662965 100644
--- a/drivers/gpu/drm/qxl/qxl_draw.c
+++ b/drivers/gpu/drm/qxl/qxl_draw.c
@@ -25,7 +25,7 @@
25 25
26static int alloc_clips(struct qxl_device *qdev, 26static int alloc_clips(struct qxl_device *qdev,
27 struct qxl_release *release, 27 struct qxl_release *release,
28 unsigned num_clips, 28 unsigned int num_clips,
29 struct qxl_bo **clips_bo) 29 struct qxl_bo **clips_bo)
30{ 30{
31 int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips; 31 int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
@@ -37,7 +37,7 @@ static int alloc_clips(struct qxl_device *qdev,
37 * the qxl_clip_rects. This is *not* the same as the memory allocated 37 * the qxl_clip_rects. This is *not* the same as the memory allocated
38 * on the device, it is offset to qxl_clip_rects.chunk.data */ 38 * on the device, it is offset to qxl_clip_rects.chunk.data */
39static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev, 39static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
40 unsigned num_clips, 40 unsigned int num_clips,
41 struct qxl_bo *clips_bo) 41 struct qxl_bo *clips_bo)
42{ 42{
43 struct qxl_clip_rects *dev_clips; 43 struct qxl_clip_rects *dev_clips;
@@ -168,6 +168,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
168 int ret; 168 int ret;
169 struct qxl_drm_image *dimage; 169 struct qxl_drm_image *dimage;
170 struct qxl_bo *palette_bo = NULL; 170 struct qxl_bo *palette_bo = NULL;
171
171 if (stride == 0) 172 if (stride == 0)
172 stride = depth * width / 8; 173 stride = depth * width / 8;
173 174
@@ -214,6 +215,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
214 215
215 if (depth == 1) { 216 if (depth == 1) {
216 void *ptr; 217 void *ptr;
218
217 ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image); 219 ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
218 220
219 ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0); 221 ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
@@ -264,9 +266,9 @@ out_free_drawable:
264void qxl_draw_dirty_fb(struct qxl_device *qdev, 266void qxl_draw_dirty_fb(struct qxl_device *qdev,
265 struct drm_framebuffer *fb, 267 struct drm_framebuffer *fb,
266 struct qxl_bo *bo, 268 struct qxl_bo *bo,
267 unsigned flags, unsigned color, 269 unsigned int flags, unsigned int color,
268 struct drm_clip_rect *clips, 270 struct drm_clip_rect *clips,
269 unsigned num_clips, int inc) 271 unsigned int num_clips, int inc)
270{ 272{
271 /* 273 /*
272 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should 274 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
@@ -340,7 +342,6 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
340 if (ret) 342 if (ret)
341 goto out_release_backoff; 343 goto out_release_backoff;
342 344
343
344 ret = qxl_image_init(qdev, release, dimage, surface_base, 345 ret = qxl_image_init(qdev, release, dimage, surface_base,
345 left, top, width, height, depth, stride); 346 left, top, width, height, depth, stride);
346 qxl_bo_kunmap(bo); 347 qxl_bo_kunmap(bo);
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 8ff70a7281a7..14d3fa855708 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -23,7 +23,6 @@
23 * Alon Levy 23 * Alon Levy
24 */ 24 */
25 25
26
27#ifndef QXL_DRV_H 26#ifndef QXL_DRV_H
28#define QXL_DRV_H 27#define QXL_DRV_H
29 28
@@ -83,16 +82,16 @@ struct qxl_bo {
83 struct ttm_placement placement; 82 struct ttm_placement placement;
84 struct ttm_buffer_object tbo; 83 struct ttm_buffer_object tbo;
85 struct ttm_bo_kmap_obj kmap; 84 struct ttm_bo_kmap_obj kmap;
86 unsigned pin_count; 85 unsigned int pin_count;
87 void *kptr; 86 void *kptr;
88 int type; 87 int type;
89 88
90 /* Constant after initialization */ 89 /* Constant after initialization */
91 struct drm_gem_object gem_base; 90 struct drm_gem_object gem_base;
92 bool is_primary; /* is this now a primary surface */ 91 unsigned int is_primary:1; /* is this now a primary surface */
93 bool is_dumb; 92 unsigned int is_dumb:1;
94 struct qxl_bo *shadow; 93 struct qxl_bo *shadow;
95 bool hw_surf_alloc; 94 unsigned int hw_surf_alloc:1;
96 struct qxl_surface surf; 95 struct qxl_surface surf;
97 uint32_t surface_id; 96 uint32_t surface_id;
98 struct qxl_release *surf_create; 97 struct qxl_release *surf_create;
@@ -129,11 +128,10 @@ struct qxl_output {
129struct qxl_mman { 128struct qxl_mman {
130 struct ttm_bo_global_ref bo_global_ref; 129 struct ttm_bo_global_ref bo_global_ref;
131 struct drm_global_reference mem_global_ref; 130 struct drm_global_reference mem_global_ref;
132 bool mem_global_referenced; 131 unsigned int mem_global_referenced:1;
133 struct ttm_bo_device bdev; 132 struct ttm_bo_device bdev;
134}; 133};
135 134
136
137struct qxl_memslot { 135struct qxl_memslot {
138 uint8_t generation; 136 uint8_t generation;
139 uint64_t start_phys_addr; 137 uint64_t start_phys_addr;
@@ -191,12 +189,12 @@ struct qxl_draw_fill {
191 */ 189 */
192struct qxl_debugfs { 190struct qxl_debugfs {
193 struct drm_info_list *files; 191 struct drm_info_list *files;
194 unsigned num_files; 192 unsigned int num_files;
195}; 193};
196 194
197int qxl_debugfs_add_files(struct qxl_device *rdev, 195int qxl_debugfs_add_files(struct qxl_device *rdev,
198 struct drm_info_list *files, 196 struct drm_info_list *files,
199 unsigned nfiles); 197 unsigned int nfiles);
200int qxl_debugfs_fence_init(struct qxl_device *rdev); 198int qxl_debugfs_fence_init(struct qxl_device *rdev);
201 199
202struct qxl_device; 200struct qxl_device;
@@ -231,7 +229,7 @@ struct qxl_device {
231 229
232 struct qxl_ram_header *ram_header; 230 struct qxl_ram_header *ram_header;
233 231
234 bool primary_created; 232 unsigned int primary_created:1;
235 233
236 struct qxl_memslot *mem_slots; 234 struct qxl_memslot *mem_slots;
237 uint8_t n_mem_slots; 235 uint8_t n_mem_slots;
@@ -254,7 +252,7 @@ struct qxl_device {
254 atomic_t irq_received_display; 252 atomic_t irq_received_display;
255 atomic_t irq_received_cursor; 253 atomic_t irq_received_cursor;
256 atomic_t irq_received_io_cmd; 254 atomic_t irq_received_io_cmd;
257 unsigned irq_received_error; 255 unsigned int irq_received_error;
258 wait_queue_head_t display_event; 256 wait_queue_head_t display_event;
259 wait_queue_head_t cursor_event; 257 wait_queue_head_t cursor_event;
260 wait_queue_head_t io_cmd_event; 258 wait_queue_head_t io_cmd_event;
@@ -262,7 +260,7 @@ struct qxl_device {
262 260
263 /* debugfs */ 261 /* debugfs */
264 struct qxl_debugfs debugfs[QXL_DEBUGFS_MAX_COMPONENTS]; 262 struct qxl_debugfs debugfs[QXL_DEBUGFS_MAX_COMPONENTS];
265 unsigned debugfs_count; 263 unsigned int debugfs_count;
266 264
267 struct mutex update_area_mutex; 265 struct mutex update_area_mutex;
268 266
@@ -372,7 +370,6 @@ int qxl_mode_dumb_mmap(struct drm_file *filp,
372 struct drm_device *dev, 370 struct drm_device *dev,
373 uint32_t handle, uint64_t *offset_p); 371 uint32_t handle, uint64_t *offset_p);
374 372
375
376/* qxl ttm */ 373/* qxl ttm */
377int qxl_ttm_init(struct qxl_device *qdev); 374int qxl_ttm_init(struct qxl_device *qdev);
378void qxl_ttm_fini(struct qxl_device *qdev); 375void qxl_ttm_fini(struct qxl_device *qdev);
@@ -398,7 +395,7 @@ void qxl_update_screen(struct qxl_device *qxl);
398/* qxl io operations (qxl_cmd.c) */ 395/* qxl io operations (qxl_cmd.c) */
399 396
400void qxl_io_create_primary(struct qxl_device *qdev, 397void qxl_io_create_primary(struct qxl_device *qdev,
401 unsigned offset, 398 unsigned int offset,
402 struct qxl_bo *bo); 399 struct qxl_bo *bo);
403void qxl_io_destroy_primary(struct qxl_device *qdev); 400void qxl_io_destroy_primary(struct qxl_device *qdev);
404void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id); 401void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
@@ -449,9 +446,9 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
449void qxl_draw_dirty_fb(struct qxl_device *qdev, 446void qxl_draw_dirty_fb(struct qxl_device *qdev,
450 struct drm_framebuffer *fb, 447 struct drm_framebuffer *fb,
451 struct qxl_bo *bo, 448 struct qxl_bo *bo,
452 unsigned flags, unsigned color, 449 unsigned int flags, unsigned int color,
453 struct drm_clip_rect *clips, 450 struct drm_clip_rect *clips,
454 unsigned num_clips, int inc); 451 unsigned int num_clips, int inc);
455 452
456void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec); 453void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec);
457 454
@@ -496,7 +493,7 @@ bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
496 493
497int qxl_debugfs_add_files(struct qxl_device *qdev, 494int qxl_debugfs_add_files(struct qxl_device *qdev,
498 struct drm_info_list *files, 495 struct drm_info_list *files,
499 unsigned nfiles); 496 unsigned int nfiles);
500 497
501int qxl_surface_id_alloc(struct qxl_device *qdev, 498int qxl_surface_id_alloc(struct qxl_device *qdev,
502 struct qxl_bo *surf); 499 struct qxl_bo *surf);
diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c
index c666b89eed5d..e3765739c396 100644
--- a/drivers/gpu/drm/qxl/qxl_dumb.c
+++ b/drivers/gpu/drm/qxl/qxl_dumb.c
@@ -38,6 +38,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
38 int r; 38 int r;
39 struct qxl_surface surf; 39 struct qxl_surface surf;
40 uint32_t pitch, format; 40 uint32_t pitch, format;
41
41 pitch = args->width * ((args->bpp + 1) / 8); 42 pitch = args->width * ((args->bpp + 1) / 8);
42 args->size = pitch * args->height; 43 args->size = pitch * args->height;
43 args->size = ALIGN(args->size, PAGE_SIZE); 44 args->size = ALIGN(args->size, PAGE_SIZE);
@@ -52,7 +53,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
52 default: 53 default:
53 return -EINVAL; 54 return -EINVAL;
54 } 55 }
55 56
56 surf.width = args->width; 57 surf.width = args->width;
57 surf.height = args->height; 58 surf.height = args->height;
58 surf.stride = pitch; 59 surf.stride = pitch;
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index 2294b7f14fdf..7e047c985ea6 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -134,9 +134,9 @@ out_unref:
134 */ 134 */
135static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb, 135static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
136 struct drm_file *file_priv, 136 struct drm_file *file_priv,
137 unsigned flags, unsigned color, 137 unsigned int flags, unsigned int color,
138 struct drm_clip_rect *clips, 138 struct drm_clip_rect *clips,
139 unsigned num_clips) 139 unsigned int num_clips)
140{ 140{
141 struct qxl_device *qdev = fb->dev->dev_private; 141 struct qxl_device *qdev = fb->dev->dev_private;
142 struct fb_info *info = qdev->fb_helper.fbdev; 142 struct fb_info *info = qdev->fb_helper.fbdev;
diff --git a/drivers/gpu/drm/qxl/qxl_image.c b/drivers/gpu/drm/qxl/qxl_image.c
index 7fbcc35e8ad3..43688ecdd8a0 100644
--- a/drivers/gpu/drm/qxl/qxl_image.c
+++ b/drivers/gpu/drm/qxl/qxl_image.c
@@ -136,6 +136,7 @@ qxl_image_init_helper(struct qxl_device *qdev,
136 int remain; 136 int remain;
137 int page; 137 int page;
138 int size; 138 int size;
139
139 if (stride == linesize && chunk_stride == stride) { 140 if (stride == linesize && chunk_stride == stride) {
140 remain = linesize * height; 141 remain = linesize * height;
141 page = 0; 142 page = 0;
@@ -162,7 +163,8 @@ qxl_image_init_helper(struct qxl_device *qdev,
162 page++; 163 page++;
163 } 164 }
164 } else { 165 } else {
165 unsigned page_base, page_offset, out_offset; 166 unsigned int page_base, page_offset, out_offset;
167
166 for (i = 0 ; i < height ; ++i) { 168 for (i = 0 ; i < height ; ++i) {
167 i_data = (void *)data + i * stride; 169 i_data = (void *)data + i * stride;
168 remain = linesize; 170 remain = linesize;
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 6cc9f3367fa0..6e828158bcb0 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -85,6 +85,7 @@ static void
85apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info) 85apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
86{ 86{
87 void *reloc_page; 87 void *reloc_page;
88
88 reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK); 89 reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
89 *(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev, 90 *(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
90 info->src_bo, 91 info->src_bo,
@@ -189,6 +190,7 @@ static int qxl_process_single_command(struct qxl_device *qdev,
189 190
190 { 191 {
191 struct qxl_drawable *draw = fb_cmd; 192 struct qxl_drawable *draw = fb_cmd;
193
192 draw->mm_time = qdev->rom->mm_clock; 194 draw->mm_time = qdev->rom->mm_clock;
193 } 195 }
194 196
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index e25c589d5f50..f6975d7c7d10 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -92,6 +92,7 @@ void qxl_reinit_memslots(struct qxl_device *qdev)
92static void qxl_gc_work(struct work_struct *work) 92static void qxl_gc_work(struct work_struct *work)
93{ 93{
94 struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work); 94 struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work);
95
95 qxl_garbage_collect(qdev); 96 qxl_garbage_collect(qdev);
96} 97}
97 98
@@ -284,7 +285,6 @@ int qxl_device_init(struct qxl_device *qdev,
284 (unsigned long)qdev->surfaceram_base, 285 (unsigned long)qdev->surfaceram_base,
285 (unsigned long)qdev->surfaceram_size); 286 (unsigned long)qdev->surfaceram_size);
286 287
287
288 INIT_WORK(&qdev->gc_work, qxl_gc_work); 288 INIT_WORK(&qdev->gc_work, qxl_gc_work);
289 289
290 return 0; 290 return 0;
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 6a30196e9d6c..f67a3c535afb 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -54,7 +54,7 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
54{ 54{
55 u32 c = 0; 55 u32 c = 0;
56 u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0; 56 u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0;
57 unsigned i; 57 unsigned int i;
58 58
59 qbo->placement.placement = qbo->placements; 59 qbo->placement.placement = qbo->placements;
60 qbo->placement.busy_placement = qbo->placements; 60 qbo->placement.busy_placement = qbo->placements;
@@ -74,7 +74,6 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
74 } 74 }
75} 75}
76 76
77
78int qxl_bo_create(struct qxl_device *qdev, 77int qxl_bo_create(struct qxl_device *qdev,
79 unsigned long size, bool kernel, bool pinned, u32 domain, 78 unsigned long size, bool kernel, bool pinned, u32 domain,
80 struct qxl_surface *surf, 79 struct qxl_surface *surf,
@@ -266,7 +265,6 @@ static int __qxl_bo_unpin(struct qxl_bo *bo)
266 return r; 265 return r;
267} 266}
268 267
269
270/* 268/*
271 * Reserve the BO before pinning the object. If the BO was reserved 269 * Reserve the BO before pinning the object. If the BO was reserved
272 * beforehand, use the internal version directly __qxl_bo_pin. 270 * beforehand, use the internal version directly __qxl_bo_pin.
@@ -335,6 +333,7 @@ void qxl_bo_fini(struct qxl_device *qdev)
335int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo) 333int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
336{ 334{
337 int ret; 335 int ret;
336
338 if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) { 337 if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) {
339 /* allocate a surface id for this surface now */ 338 /* allocate a surface id for this surface now */
340 ret = qxl_surface_id_alloc(qdev, bo); 339 ret = qxl_surface_id_alloc(qdev, bo);
diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h
index 0374fd93f4d6..b40fc9a10406 100644
--- a/drivers/gpu/drm/qxl/qxl_object.h
+++ b/drivers/gpu/drm/qxl/qxl_object.h
@@ -35,6 +35,7 @@ static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait)
35 if (unlikely(r != 0)) { 35 if (unlikely(r != 0)) {
36 if (r != -ERESTARTSYS) { 36 if (r != -ERESTARTSYS) {
37 struct drm_device *ddev = bo->gem_base.dev; 37 struct drm_device *ddev = bo->gem_base.dev;
38
38 dev_err(ddev->dev, "%p reserve failed\n", bo); 39 dev_err(ddev->dev, "%p reserve failed\n", bo);
39 } 40 }
40 return r; 41 return r;
@@ -71,6 +72,7 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
71 if (unlikely(r != 0)) { 72 if (unlikely(r != 0)) {
72 if (r != -ERESTARTSYS) { 73 if (r != -ERESTARTSYS) {
73 struct drm_device *ddev = bo->gem_base.dev; 74 struct drm_device *ddev = bo->gem_base.dev;
75
74 dev_err(ddev->dev, "%p reserve failed for wait\n", 76 dev_err(ddev->dev, "%p reserve failed for wait\n",
75 bo); 77 bo);
76 } 78 }
diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c
index 9f029dda1f07..a55dece118b2 100644
--- a/drivers/gpu/drm/qxl/qxl_prime.c
+++ b/drivers/gpu/drm/qxl/qxl_prime.c
@@ -38,7 +38,6 @@ void qxl_gem_prime_unpin(struct drm_gem_object *obj)
38 WARN_ONCE(1, "not implemented"); 38 WARN_ONCE(1, "not implemented");
39} 39}
40 40
41
42struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj) 41struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj)
43{ 42{
44 WARN_ONCE(1, "not implemented"); 43 WARN_ONCE(1, "not implemented");
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index e37f0097f744..3813ec198900 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -234,7 +234,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo)
234 return ret; 234 return ret;
235 } 235 }
236 236
237 ret = reservation_object_reserve_shared(bo->tbo.resv); 237 ret = reservation_object_reserve_shared(bo->tbo.resv, 1);
238 if (ret) 238 if (ret)
239 return ret; 239 return ret;
240 240
@@ -282,7 +282,6 @@ void qxl_release_backoff_reserve_list(struct qxl_release *release)
282 ttm_eu_backoff_reservation(&release->ticket, &release->bos); 282 ttm_eu_backoff_reservation(&release->ticket, &release->bos);
283} 283}
284 284
285
286int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, 285int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
287 enum qxl_surface_cmd_type surface_cmd_type, 286 enum qxl_surface_cmd_type surface_cmd_type,
288 struct qxl_release *create_rel, 287 struct qxl_release *create_rel,
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 86a1fb32f6db..559a10113837 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -174,7 +174,7 @@ static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
174 man->default_caching = TTM_PL_FLAG_CACHED; 174 man->default_caching = TTM_PL_FLAG_CACHED;
175 break; 175 break;
176 default: 176 default:
177 DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); 177 DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
178 return -EINVAL; 178 return -EINVAL;
179 } 179 }
180 return 0; 180 return 0;
@@ -331,7 +331,6 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
331 if (ret) 331 if (ret)
332 return ret; 332 return ret;
333 333
334
335 if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { 334 if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
336 qxl_move_null(bo, new_mem); 335 qxl_move_null(bo, new_mem);
337 return 0; 336 return 0;
@@ -401,11 +400,11 @@ int qxl_ttm_init(struct qxl_device *qdev)
401 return r; 400 return r;
402 } 401 }
403 DRM_INFO("qxl: %uM of VRAM memory size\n", 402 DRM_INFO("qxl: %uM of VRAM memory size\n",
404 (unsigned)qdev->vram_size / (1024 * 1024)); 403 (unsigned int)qdev->vram_size / (1024 * 1024));
405 DRM_INFO("qxl: %luM of IO pages memory ready (VRAM domain)\n", 404 DRM_INFO("qxl: %luM of IO pages memory ready (VRAM domain)\n",
406 ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024)); 405 ((unsigned int)num_io_pages * PAGE_SIZE) / (1024 * 1024));
407 DRM_INFO("qxl: %uM of Surface memory size\n", 406 DRM_INFO("qxl: %uM of Surface memory size\n",
408 (unsigned)qdev->surfaceram_size / (1024 * 1024)); 407 (unsigned int)qdev->surfaceram_size / (1024 * 1024));
409 return 0; 408 return 0;
410} 409}
411 410
@@ -418,7 +417,6 @@ void qxl_ttm_fini(struct qxl_device *qdev)
418 DRM_INFO("qxl: ttm finalized\n"); 417 DRM_INFO("qxl: ttm finalized\n");
419} 418}
420 419
421
422#define QXL_DEBUGFS_MEM_TYPES 2 420#define QXL_DEBUGFS_MEM_TYPES 2
423 421
424#if defined(CONFIG_DEBUG_FS) 422#if defined(CONFIG_DEBUG_FS)
@@ -443,7 +441,7 @@ int qxl_ttm_debugfs_init(struct qxl_device *qdev)
443#if defined(CONFIG_DEBUG_FS) 441#if defined(CONFIG_DEBUG_FS)
444 static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES]; 442 static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
445 static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32]; 443 static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32];
446 unsigned i; 444 unsigned int i;
447 445
448 for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) { 446 for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) {
449 if (i == 0) 447 if (i == 0)
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index 7f1a9c787bd1..fed11ece0de6 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -831,7 +831,7 @@ static int radeon_vm_update_ptes(struct radeon_device *rdev,
831 int r; 831 int r;
832 832
833 radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true); 833 radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true);
834 r = reservation_object_reserve_shared(pt->tbo.resv); 834 r = reservation_object_reserve_shared(pt->tbo.resv, 1);
835 if (r) 835 if (r)
836 return r; 836 return r;
837 837
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 084f58df4a8c..7015974c247a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -404,32 +404,15 @@ static struct drm_driver rcar_du_driver = {
404static int rcar_du_pm_suspend(struct device *dev) 404static int rcar_du_pm_suspend(struct device *dev)
405{ 405{
406 struct rcar_du_device *rcdu = dev_get_drvdata(dev); 406 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
407 struct drm_atomic_state *state;
408 407
409 drm_kms_helper_poll_disable(rcdu->ddev); 408 return drm_mode_config_helper_suspend(rcdu->ddev);
410 drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
411
412 state = drm_atomic_helper_suspend(rcdu->ddev);
413 if (IS_ERR(state)) {
414 drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
415 drm_kms_helper_poll_enable(rcdu->ddev);
416 return PTR_ERR(state);
417 }
418
419 rcdu->suspend_state = state;
420
421 return 0;
422} 409}
423 410
424static int rcar_du_pm_resume(struct device *dev) 411static int rcar_du_pm_resume(struct device *dev)
425{ 412{
426 struct rcar_du_device *rcdu = dev_get_drvdata(dev); 413 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
427 414
428 drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state); 415 return drm_mode_config_helper_resume(rcdu->ddev);
429 drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
430 drm_kms_helper_poll_enable(rcdu->ddev);
431
432 return 0;
433} 416}
434#endif 417#endif
435 418
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 143c037e2c0f..9f5563296c5a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -79,7 +79,6 @@ struct rcar_du_device {
79 79
80 struct drm_device *ddev; 80 struct drm_device *ddev;
81 struct drm_fbdev_cma *fbdev; 81 struct drm_fbdev_cma *fbdev;
82 struct drm_atomic_state *suspend_state;
83 82
84 struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS]; 83 struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
85 unsigned int num_crtcs; 84 unsigned int num_crtcs;
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 26438d45732b..1e75196f9659 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -7,7 +7,7 @@ config DRM_ROCKCHIP
7 select VIDEOMODE_HELPERS 7 select VIDEOMODE_HELPERS
8 select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP 8 select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
9 select DRM_DW_HDMI if ROCKCHIP_DW_HDMI 9 select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
10 select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI 10 select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
11 select DRM_RGB if ROCKCHIP_RGB 11 select DRM_RGB if ROCKCHIP_RGB
12 select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC 12 select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
13 help 13 help
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 868263ff0302..f6fc9d5dd0ad 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -11,7 +11,7 @@ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
11rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o 11rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
12rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o 12rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
13rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o 13rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
14rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o 14rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
15rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o 15rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
16rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o 16rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
17rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o 17rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
new file mode 100644
index 000000000000..7ee359bcee62
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -0,0 +1,1076 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:
5 * Chris Zhong <zyw@rock-chips.com>
6 * Nickey Yang <nickey.yang@rock-chips.com>
7 */
8
9#include <drm/drmP.h>
10#include <drm/drm_mipi_dsi.h>
11#include <drm/bridge/dw_mipi_dsi.h>
12#include <drm/drm_of.h>
13#include <linux/clk.h>
14#include <linux/iopoll.h>
15#include <linux/math64.h>
16#include <linux/mfd/syscon.h>
17#include <linux/module.h>
18#include <linux/of_device.h>
19#include <linux/pm_runtime.h>
20#include <linux/regmap.h>
21#include <video/mipi_display.h>
22
23#include "rockchip_drm_drv.h"
24#include "rockchip_drm_vop.h"
25
26#define DSI_PHY_RSTZ 0xa0
27#define PHY_DISFORCEPLL 0
28#define PHY_ENFORCEPLL BIT(3)
29#define PHY_DISABLECLK 0
30#define PHY_ENABLECLK BIT(2)
31#define PHY_RSTZ 0
32#define PHY_UNRSTZ BIT(1)
33#define PHY_SHUTDOWNZ 0
34#define PHY_UNSHUTDOWNZ BIT(0)
35
36#define DSI_PHY_IF_CFG 0xa4
37#define N_LANES(n) ((((n) - 1) & 0x3) << 0)
38#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8)
39
40#define DSI_PHY_STATUS 0xb0
41#define LOCK BIT(0)
42#define STOP_STATE_CLK_LANE BIT(2)
43
44#define DSI_PHY_TST_CTRL0 0xb4
45#define PHY_TESTCLK BIT(1)
46#define PHY_UNTESTCLK 0
47#define PHY_TESTCLR BIT(0)
48#define PHY_UNTESTCLR 0
49
50#define DSI_PHY_TST_CTRL1 0xb8
51#define PHY_TESTEN BIT(16)
52#define PHY_UNTESTEN 0
53#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
54#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
55
56#define DSI_INT_ST0 0xbc
57#define DSI_INT_ST1 0xc0
58#define DSI_INT_MSK0 0xc4
59#define DSI_INT_MSK1 0xc8
60
61#define PHY_STATUS_TIMEOUT_US 10000
62#define CMD_PKT_STATUS_TIMEOUT_US 20000
63
64#define BYPASS_VCO_RANGE BIT(7)
65#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
66#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
67#define VCO_IN_CAP_CON_LOW (0x1 << 1)
68#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
69#define REF_BIAS_CUR_SEL BIT(0)
70
71#define CP_CURRENT_3UA 0x1
72#define CP_CURRENT_4_5UA 0x2
73#define CP_CURRENT_7_5UA 0x6
74#define CP_CURRENT_6UA 0x9
75#define CP_CURRENT_12UA 0xb
76#define CP_CURRENT_SEL(val) ((val) & 0xf)
77#define CP_PROGRAM_EN BIT(7)
78
79#define LPF_RESISTORS_15_5KOHM 0x1
80#define LPF_RESISTORS_13KOHM 0x2
81#define LPF_RESISTORS_11_5KOHM 0x4
82#define LPF_RESISTORS_10_5KOHM 0x8
83#define LPF_RESISTORS_8KOHM 0x10
84#define LPF_PROGRAM_EN BIT(6)
85#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
86
87#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
88
89#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
90#define LOW_PROGRAM_EN 0
91#define HIGH_PROGRAM_EN BIT(7)
92#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
93#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
94#define PLL_LOOP_DIV_EN BIT(5)
95#define PLL_INPUT_DIV_EN BIT(4)
96
97#define POWER_CONTROL BIT(6)
98#define INTERNAL_REG_CURRENT BIT(3)
99#define BIAS_BLOCK_ON BIT(2)
100#define BANDGAP_ON BIT(0)
101
102#define TER_RESISTOR_HIGH BIT(7)
103#define TER_RESISTOR_LOW 0
104#define LEVEL_SHIFTERS_ON BIT(6)
105#define TER_CAL_DONE BIT(5)
106#define SETRD_MAX (0x7 << 2)
107#define POWER_MANAGE BIT(1)
108#define TER_RESISTORS_ON BIT(0)
109
110#define BIASEXTR_SEL(val) ((val) & 0x7)
111#define BANDGAP_SEL(val) ((val) & 0x7)
112#define TLP_PROGRAM_EN BIT(7)
113#define THS_PRE_PROGRAM_EN BIT(7)
114#define THS_ZERO_PROGRAM_EN BIT(6)
115
116#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
117#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
118#define PLL_LPF_AND_CP_CONTROL 0x12
119#define PLL_INPUT_DIVIDER_RATIO 0x17
120#define PLL_LOOP_DIVIDER_RATIO 0x18
121#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
122#define BANDGAP_AND_BIAS_CONTROL 0x20
123#define TERMINATION_RESISTER_CONTROL 0x21
124#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
125#define HS_RX_CONTROL_OF_LANE_0 0x44
126#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
127#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
128#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
129#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
130#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
131#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
132#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
133#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
134#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
135#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
136#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
137
138#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
139#define DW_MIPI_NEEDS_GRF_CLK BIT(1)
140
141#define RK3288_GRF_SOC_CON6 0x025c
142#define RK3288_DSI0_LCDC_SEL BIT(6)
143#define RK3288_DSI1_LCDC_SEL BIT(9)
144
145#define RK3399_GRF_SOC_CON20 0x6250
146#define RK3399_DSI0_LCDC_SEL BIT(0)
147#define RK3399_DSI1_LCDC_SEL BIT(4)
148
149#define RK3399_GRF_SOC_CON22 0x6258
150#define RK3399_DSI0_TURNREQUEST (0xf << 12)
151#define RK3399_DSI0_TURNDISABLE (0xf << 8)
152#define RK3399_DSI0_FORCETXSTOPMODE (0xf << 4)
153#define RK3399_DSI0_FORCERXMODE (0xf << 0)
154
155#define RK3399_GRF_SOC_CON23 0x625c
156#define RK3399_DSI1_TURNDISABLE (0xf << 12)
157#define RK3399_DSI1_FORCETXSTOPMODE (0xf << 8)
158#define RK3399_DSI1_FORCERXMODE (0xf << 4)
159#define RK3399_DSI1_ENABLE (0xf << 0)
160
161#define RK3399_GRF_SOC_CON24 0x6260
162#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
163#define RK3399_TXRX_ENABLECLK BIT(6)
164#define RK3399_TXRX_BASEDIR BIT(5)
165
166#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
167
168#define to_dsi(nm) container_of(nm, struct dw_mipi_dsi_rockchip, nm)
169
170enum {
171 BANDGAP_97_07,
172 BANDGAP_98_05,
173 BANDGAP_99_02,
174 BANDGAP_100_00,
175 BANDGAP_93_17,
176 BANDGAP_94_15,
177 BANDGAP_95_12,
178 BANDGAP_96_10,
179};
180
181enum {
182 BIASEXTR_87_1,
183 BIASEXTR_91_5,
184 BIASEXTR_95_9,
185 BIASEXTR_100,
186 BIASEXTR_105_94,
187 BIASEXTR_111_88,
188 BIASEXTR_118_8,
189 BIASEXTR_127_7,
190};
191
192struct rockchip_dw_dsi_chip_data {
193 u32 reg;
194
195 u32 lcdsel_grf_reg;
196 u32 lcdsel_big;
197 u32 lcdsel_lit;
198
199 u32 enable_grf_reg;
200 u32 enable;
201
202 u32 lanecfg1_grf_reg;
203 u32 lanecfg1;
204 u32 lanecfg2_grf_reg;
205 u32 lanecfg2;
206
207 unsigned int flags;
208 unsigned int max_data_lanes;
209};
210
211struct dw_mipi_dsi_rockchip {
212 struct device *dev;
213 struct drm_encoder encoder;
214 void __iomem *base;
215
216 struct regmap *grf_regmap;
217 struct clk *pllref_clk;
218 struct clk *grf_clk;
219 struct clk *phy_cfg_clk;
220
221 /* dual-channel */
222 bool is_slave;
223 struct dw_mipi_dsi_rockchip *slave;
224
225 unsigned int lane_mbps; /* per lane */
226 u16 input_div;
227 u16 feedback_div;
228 u32 format;
229
230 struct dw_mipi_dsi *dmd;
231 const struct rockchip_dw_dsi_chip_data *cdata;
232 struct dw_mipi_dsi_plat_data pdata;
233 int devcnt;
234};
235
236struct dphy_pll_parameter_map {
237 unsigned int max_mbps;
238 u8 hsfreqrange;
239 u8 icpctrl;
240 u8 lpfctrl;
241};
242
243/* The table is based on 27MHz DPHY pll reference clock. */
244static const struct dphy_pll_parameter_map dppa_map[] = {
245 { 89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
246 { 99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
247 { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
248 { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
249 { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
250 { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
251 { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
252 { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
253 { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
254 { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
255 { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
256 { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
257 { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
258 { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
259 { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
260 { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
261 { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
262 { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
263 { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
264 { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
265 { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
266 { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
267 { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
268 { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
269 { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
270 { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
271 { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
272 { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
273 { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
274 {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
275 {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
276 {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
277 {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
278 {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
279 {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
280 {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
281 {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
282 {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
283 {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }
284};
285
286static int max_mbps_to_parameter(unsigned int max_mbps)
287{
288 int i;
289
290 for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
291 if (dppa_map[i].max_mbps >= max_mbps)
292 return i;
293
294 return -EINVAL;
295}
296
297static inline void dsi_write(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 val)
298{
299 writel(val, dsi->base + reg);
300}
301
302static inline u32 dsi_read(struct dw_mipi_dsi_rockchip *dsi, u32 reg)
303{
304 return readl(dsi->base + reg);
305}
306
307static inline void dsi_set(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 mask)
308{
309 dsi_write(dsi, reg, dsi_read(dsi, reg) | mask);
310}
311
312static inline void dsi_update_bits(struct dw_mipi_dsi_rockchip *dsi, u32 reg,
313 u32 mask, u32 val)
314{
315 dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val);
316}
317
318static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi_rockchip *dsi,
319 u8 test_code,
320 u8 test_data)
321{
322 /*
323 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
324 * is latched internally as the current test code. Test data is
325 * programmed internally by rising edge on TESTCLK.
326 */
327 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
328
329 dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
330 PHY_TESTDIN(test_code));
331
332 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
333
334 dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
335 PHY_TESTDIN(test_data));
336
337 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
338}
339
340/**
341 * ns2bc - Nanoseconds to byte clock cycles
342 */
343static inline unsigned int ns2bc(struct dw_mipi_dsi_rockchip *dsi, int ns)
344{
345 return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
346}
347
348/**
349 * ns2ui - Nanoseconds to UI time periods
350 */
351static inline unsigned int ns2ui(struct dw_mipi_dsi_rockchip *dsi, int ns)
352{
353 return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
354}
355
356static int dw_mipi_dsi_phy_init(void *priv_data)
357{
358 struct dw_mipi_dsi_rockchip *dsi = priv_data;
359 int ret, i, vco;
360
361 /*
362 * Get vco from frequency(lane_mbps)
363 * vco frequency table
364 * 000 - between 80 and 200 MHz
365 * 001 - between 200 and 300 MHz
366 * 010 - between 300 and 500 MHz
367 * 011 - between 500 and 700 MHz
368 * 100 - between 700 and 900 MHz
369 * 101 - between 900 and 1100 MHz
370 * 110 - between 1100 and 1300 MHz
371 * 111 - between 1300 and 1500 MHz
372 */
373 vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
374
375 i = max_mbps_to_parameter(dsi->lane_mbps);
376 if (i < 0) {
377 DRM_DEV_ERROR(dsi->dev,
378 "failed to get parameter for %dmbps clock\n",
379 dsi->lane_mbps);
380 return i;
381 }
382
383 ret = clk_prepare_enable(dsi->phy_cfg_clk);
384 if (ret) {
385 DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
386 return ret;
387 }
388
389 dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
390 BYPASS_VCO_RANGE |
391 VCO_RANGE_CON_SEL(vco) |
392 VCO_IN_CAP_CON_LOW |
393 REF_BIAS_CUR_SEL);
394
395 dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
396 CP_CURRENT_SEL(dppa_map[i].icpctrl));
397 dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
398 CP_PROGRAM_EN | LPF_PROGRAM_EN |
399 LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
400
401 dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
402 HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
403
404 dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
405 INPUT_DIVIDER(dsi->input_div));
406 dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
407 LOOP_DIV_LOW_SEL(dsi->feedback_div) |
408 LOW_PROGRAM_EN);
409 /*
410 * We need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately
411 * to make the configured LSB effective according to IP simulation
412 * and lab test results.
413 * Only in this way can we get correct mipi phy pll frequency.
414 */
415 dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
416 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
417 dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
418 LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
419 HIGH_PROGRAM_EN);
420 dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
421 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
422
423 dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
424 LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
425 dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
426 HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
427
428 dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
429 POWER_CONTROL | INTERNAL_REG_CURRENT |
430 BIAS_BLOCK_ON | BANDGAP_ON);
431
432 dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
433 TER_RESISTOR_LOW | TER_CAL_DONE |
434 SETRD_MAX | TER_RESISTORS_ON);
435 dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
436 TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
437 SETRD_MAX | POWER_MANAGE |
438 TER_RESISTORS_ON);
439
440 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
441 TLP_PROGRAM_EN | ns2bc(dsi, 500));
442 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
443 THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
444 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
445 THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
446 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
447 THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
448 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
449 BIT(5) | ns2bc(dsi, 100));
450 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
451 BIT(5) | (ns2bc(dsi, 60) + 7));
452
453 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
454 TLP_PROGRAM_EN | ns2bc(dsi, 500));
455 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
456 THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 20));
457 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
458 THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
459 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
460 THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
461 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
462 BIT(5) | ns2bc(dsi, 100));
463
464 clk_disable_unprepare(dsi->phy_cfg_clk);
465
466 return ret;
467}
468
469static int
470dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
471 unsigned long mode_flags, u32 lanes, u32 format,
472 unsigned int *lane_mbps)
473{
474 struct dw_mipi_dsi_rockchip *dsi = priv_data;
475 int bpp;
476 unsigned long mpclk, tmp;
477 unsigned int target_mbps = 1000;
478 unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
479 unsigned long best_freq = 0;
480 unsigned long fvco_min, fvco_max, fin, fout;
481 unsigned int min_prediv, max_prediv;
482 unsigned int _prediv, uninitialized_var(best_prediv);
483 unsigned long _fbdiv, uninitialized_var(best_fbdiv);
484 unsigned long min_delta = ULONG_MAX;
485
486 dsi->format = format;
487 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
488 if (bpp < 0) {
489 DRM_DEV_ERROR(dsi->dev,
490 "failed to get bpp for pixel format %d\n",
491 dsi->format);
492 return bpp;
493 }
494
495 mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
496 if (mpclk) {
497 /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
498 tmp = mpclk * (bpp / lanes) * 10 / 8;
499 if (tmp < max_mbps)
500 target_mbps = tmp;
501 else
502 DRM_DEV_ERROR(dsi->dev,
503 "DPHY clock frequency is out of range\n");
504 }
505
506 fin = clk_get_rate(dsi->pllref_clk);
507 fout = target_mbps * USEC_PER_SEC;
508
509 /* constraint: 5Mhz <= Fref / N <= 40MHz */
510 min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
511 max_prediv = fin / (5 * USEC_PER_SEC);
512
513 /* constraint: 80MHz <= Fvco <= 1500Mhz */
514 fvco_min = 80 * USEC_PER_SEC;
515 fvco_max = 1500 * USEC_PER_SEC;
516
517 for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
518 u64 tmp;
519 u32 delta;
520 /* Fvco = Fref * M / N */
521 tmp = (u64)fout * _prediv;
522 do_div(tmp, fin);
523 _fbdiv = tmp;
524 /*
525 * Due to the use of a "by 2 pre-scaler," the range of the
526 * feedback multiplication value M is limited to even division
527 * numbers, and m must be greater than 6, not bigger than 512.
528 */
529 if (_fbdiv < 6 || _fbdiv > 512)
530 continue;
531
532 _fbdiv += _fbdiv % 2;
533
534 tmp = (u64)_fbdiv * fin;
535 do_div(tmp, _prediv);
536 if (tmp < fvco_min || tmp > fvco_max)
537 continue;
538
539 delta = abs(fout - tmp);
540 if (delta < min_delta) {
541 best_prediv = _prediv;
542 best_fbdiv = _fbdiv;
543 min_delta = delta;
544 best_freq = tmp;
545 }
546 }
547
548 if (best_freq) {
549 dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
550 *lane_mbps = dsi->lane_mbps;
551 dsi->input_div = best_prediv;
552 dsi->feedback_div = best_fbdiv;
553 } else {
554 DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
555 return -EINVAL;
556 }
557
558 return 0;
559}
560
561static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
562 .init = dw_mipi_dsi_phy_init,
563 .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
564};
565
566static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
567 int mux)
568{
569 if (dsi->cdata->lcdsel_grf_reg)
570 regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
571 mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
572
573 if (dsi->cdata->lanecfg1_grf_reg)
574 regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
575 dsi->cdata->lanecfg1);
576
577 if (dsi->cdata->lanecfg2_grf_reg)
578 regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg2_grf_reg,
579 dsi->cdata->lanecfg2);
580
581 if (dsi->cdata->enable_grf_reg)
582 regmap_write(dsi->grf_regmap, dsi->cdata->enable_grf_reg,
583 dsi->cdata->enable);
584}
585
586static int
587dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
588 struct drm_crtc_state *crtc_state,
589 struct drm_connector_state *conn_state)
590{
591 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
592 struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
593
594 switch (dsi->format) {
595 case MIPI_DSI_FMT_RGB888:
596 s->output_mode = ROCKCHIP_OUT_MODE_P888;
597 break;
598 case MIPI_DSI_FMT_RGB666:
599 s->output_mode = ROCKCHIP_OUT_MODE_P666;
600 break;
601 case MIPI_DSI_FMT_RGB565:
602 s->output_mode = ROCKCHIP_OUT_MODE_P565;
603 break;
604 default:
605 WARN_ON(1);
606 return -EINVAL;
607 }
608
609 s->output_type = DRM_MODE_CONNECTOR_DSI;
610 if (dsi->slave)
611 s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL;
612
613 return 0;
614}
615
616static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
617{
618 struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
619 int ret, mux;
620
621 mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node,
622 &dsi->encoder);
623 if (mux < 0)
624 return;
625
626 pm_runtime_get_sync(dsi->dev);
627 if (dsi->slave)
628 pm_runtime_get_sync(dsi->slave->dev);
629
630 /*
631 * For the RK3399, the clk of grf must be enabled before writing grf
632 * register. And for RK3288 or other soc, this grf_clk must be NULL,
633 * the clk_prepare_enable return true directly.
634 */
635 ret = clk_prepare_enable(dsi->grf_clk);
636 if (ret) {
637 DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
638 return;
639 }
640
641 dw_mipi_dsi_rockchip_config(dsi, mux);
642 if (dsi->slave)
643 dw_mipi_dsi_rockchip_config(dsi->slave, mux);
644
645 clk_disable_unprepare(dsi->grf_clk);
646}
647
648static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
649{
650 struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
651
652 if (dsi->slave)
653 pm_runtime_put(dsi->slave->dev);
654 pm_runtime_put(dsi->dev);
655}
656
657static const struct drm_encoder_helper_funcs
658dw_mipi_dsi_encoder_helper_funcs = {
659 .atomic_check = dw_mipi_dsi_encoder_atomic_check,
660 .enable = dw_mipi_dsi_encoder_enable,
661 .disable = dw_mipi_dsi_encoder_disable,
662};
663
664static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
665 .destroy = drm_encoder_cleanup,
666};
667
668static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
669 struct drm_device *drm_dev)
670{
671 struct drm_encoder *encoder = &dsi->encoder;
672 int ret;
673
674 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
675 dsi->dev->of_node);
676
677 ret = drm_encoder_init(drm_dev, encoder, &dw_mipi_dsi_encoder_funcs,
678 DRM_MODE_ENCODER_DSI, NULL);
679 if (ret) {
680 DRM_ERROR("Failed to initialize encoder with drm\n");
681 return ret;
682 }
683
684 drm_encoder_helper_add(encoder, &dw_mipi_dsi_encoder_helper_funcs);
685
686 return 0;
687}
688
689static struct device
690*dw_mipi_dsi_rockchip_find_second(struct dw_mipi_dsi_rockchip *dsi)
691{
692 const struct of_device_id *match;
693 struct device_node *node = NULL, *local;
694
695 match = of_match_device(dsi->dev->driver->of_match_table, dsi->dev);
696
697 local = of_graph_get_remote_node(dsi->dev->of_node, 1, 0);
698 if (!local)
699 return NULL;
700
701 while ((node = of_find_compatible_node(node, NULL,
702 match->compatible))) {
703 struct device_node *remote;
704
705 /* found ourself */
706 if (node == dsi->dev->of_node)
707 continue;
708
709 remote = of_graph_get_remote_node(node, 1, 0);
710 if (!remote)
711 continue;
712
713 /* same display device in port1-ep0 for both */
714 if (remote == local) {
715 struct dw_mipi_dsi_rockchip *dsi2;
716 struct platform_device *pdev;
717
718 pdev = of_find_device_by_node(node);
719
720 /*
721 * we have found the second, so will either return it
722 * or return with an error. In any case won't need the
723 * nodes anymore nor continue the loop.
724 */
725 of_node_put(remote);
726 of_node_put(node);
727 of_node_put(local);
728
729 if (!pdev)
730 return ERR_PTR(-EPROBE_DEFER);
731
732 dsi2 = platform_get_drvdata(pdev);
733 if (!dsi2) {
734 platform_device_put(pdev);
735 return ERR_PTR(-EPROBE_DEFER);
736 }
737
738 return &pdev->dev;
739 }
740
741 of_node_put(remote);
742 }
743
744 of_node_put(local);
745
746 return NULL;
747}
748
749static int dw_mipi_dsi_rockchip_bind(struct device *dev,
750 struct device *master,
751 void *data)
752{
753 struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
754 struct drm_device *drm_dev = data;
755 struct device *second;
756 bool master1, master2;
757 int ret;
758
759 second = dw_mipi_dsi_rockchip_find_second(dsi);
760 if (IS_ERR(second))
761 return PTR_ERR(second);
762
763 if (second) {
764 master1 = of_property_read_bool(dsi->dev->of_node,
765 "clock-master");
766 master2 = of_property_read_bool(second->of_node,
767 "clock-master");
768
769 if (master1 && master2) {
770 DRM_DEV_ERROR(dsi->dev, "only one clock-master allowed\n");
771 return -EINVAL;
772 }
773
774 if (!master1 && !master2) {
775 DRM_DEV_ERROR(dsi->dev, "no clock-master defined\n");
776 return -EINVAL;
777 }
778
779 /* we are the slave in dual-DSI */
780 if (!master1) {
781 dsi->is_slave = true;
782 return 0;
783 }
784
785 dsi->slave = dev_get_drvdata(second);
786 if (!dsi->slave) {
787 DRM_DEV_ERROR(dev, "could not get slaves data\n");
788 return -ENODEV;
789 }
790
791 dsi->slave->is_slave = true;
792 dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd);
793 put_device(second);
794 }
795
796 ret = clk_prepare_enable(dsi->pllref_clk);
797 if (ret) {
798 DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
799 return ret;
800 }
801
802 ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
803 if (ret) {
804 DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
805 return ret;
806 }
807
808 ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
809 if (ret) {
810 DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
811 return ret;
812 }
813
814 return 0;
815}
816
817static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
818 struct device *master,
819 void *data)
820{
821 struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
822
823 if (dsi->is_slave)
824 return;
825
826 dw_mipi_dsi_unbind(dsi->dmd);
827
828 clk_disable_unprepare(dsi->pllref_clk);
829}
830
831static const struct component_ops dw_mipi_dsi_rockchip_ops = {
832 .bind = dw_mipi_dsi_rockchip_bind,
833 .unbind = dw_mipi_dsi_rockchip_unbind,
834};
835
836static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
837 struct mipi_dsi_device *device)
838{
839 struct dw_mipi_dsi_rockchip *dsi = priv_data;
840 struct device *second;
841 int ret;
842
843 ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops);
844 if (ret) {
845 DRM_DEV_ERROR(dsi->dev, "Failed to register component: %d\n",
846 ret);
847 return ret;
848 }
849
850 second = dw_mipi_dsi_rockchip_find_second(dsi);
851 if (IS_ERR(second))
852 return PTR_ERR(second);
853 if (second) {
854 ret = component_add(second, &dw_mipi_dsi_rockchip_ops);
855 if (ret) {
856 DRM_DEV_ERROR(second,
857 "Failed to register component: %d\n",
858 ret);
859 return ret;
860 }
861 }
862
863 return 0;
864}
865
866static int dw_mipi_dsi_rockchip_host_detach(void *priv_data,
867 struct mipi_dsi_device *device)
868{
869 struct dw_mipi_dsi_rockchip *dsi = priv_data;
870 struct device *second;
871
872 second = dw_mipi_dsi_rockchip_find_second(dsi);
873 if (second && !IS_ERR(second))
874 component_del(second, &dw_mipi_dsi_rockchip_ops);
875
876 component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
877
878 return 0;
879}
880
881static const struct dw_mipi_dsi_host_ops dw_mipi_dsi_rockchip_host_ops = {
882 .attach = dw_mipi_dsi_rockchip_host_attach,
883 .detach = dw_mipi_dsi_rockchip_host_detach,
884};
885
886static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev)
887{
888 struct device *dev = &pdev->dev;
889 struct device_node *np = dev->of_node;
890 struct dw_mipi_dsi_rockchip *dsi;
891 struct resource *res;
892 const struct rockchip_dw_dsi_chip_data *cdata =
893 of_device_get_match_data(dev);
894 int ret, i;
895
896 dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
897 if (!dsi)
898 return -ENOMEM;
899
900 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
901 dsi->base = devm_ioremap_resource(dev, res);
902 if (IS_ERR(dsi->base)) {
903 DRM_DEV_ERROR(dev, "Unable to get dsi registers\n");
904 return PTR_ERR(dsi->base);
905 }
906
907 i = 0;
908 while (cdata[i].reg) {
909 if (cdata[i].reg == res->start) {
910 dsi->cdata = &cdata[i];
911 break;
912 }
913
914 i++;
915 }
916
917 if (!dsi->cdata) {
918 dev_err(dev, "no dsi-config for %s node\n", np->name);
919 return -EINVAL;
920 }
921
922 dsi->pllref_clk = devm_clk_get(dev, "ref");
923 if (IS_ERR(dsi->pllref_clk)) {
924 ret = PTR_ERR(dsi->pllref_clk);
925 DRM_DEV_ERROR(dev,
926 "Unable to get pll reference clock: %d\n", ret);
927 return ret;
928 }
929
930 if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
931 dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
932 if (IS_ERR(dsi->phy_cfg_clk)) {
933 ret = PTR_ERR(dsi->phy_cfg_clk);
934 DRM_DEV_ERROR(dev,
935 "Unable to get phy_cfg_clk: %d\n", ret);
936 return ret;
937 }
938 }
939
940 if (dsi->cdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
941 dsi->grf_clk = devm_clk_get(dev, "grf");
942 if (IS_ERR(dsi->grf_clk)) {
943 ret = PTR_ERR(dsi->grf_clk);
944 DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
945 return ret;
946 }
947 }
948
949 dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
950 if (IS_ERR(dsi->grf_regmap)) {
951 DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
952 return PTR_ERR(dsi->grf_regmap);
953 }
954
955 dsi->dev = dev;
956 dsi->pdata.base = dsi->base;
957 dsi->pdata.max_data_lanes = dsi->cdata->max_data_lanes;
958 dsi->pdata.phy_ops = &dw_mipi_dsi_rockchip_phy_ops;
959 dsi->pdata.host_ops = &dw_mipi_dsi_rockchip_host_ops;
960 dsi->pdata.priv_data = dsi;
961 platform_set_drvdata(pdev, dsi);
962
963 dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata);
964 if (IS_ERR(dsi->dmd)) {
965 ret = PTR_ERR(dsi->dmd);
966 if (ret != -EPROBE_DEFER)
967 DRM_DEV_ERROR(dev,
968 "Failed to probe dw_mipi_dsi: %d\n", ret);
969 goto err_clkdisable;
970 }
971
972 return 0;
973
974err_clkdisable:
975 clk_disable_unprepare(dsi->pllref_clk);
976 return ret;
977}
978
979static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
980{
981 struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
982
983 if (dsi->devcnt == 0)
984 component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
985
986 dw_mipi_dsi_remove(dsi->dmd);
987
988 return 0;
989}
990
991static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
992 {
993 .reg = 0xff960000,
994 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
995 .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI0_LCDC_SEL),
996 .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI0_LCDC_SEL, RK3288_DSI0_LCDC_SEL),
997
998 .max_data_lanes = 4,
999 },
1000 {
1001 .reg = 0xff964000,
1002 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
1003 .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI1_LCDC_SEL),
1004 .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI1_LCDC_SEL, RK3288_DSI1_LCDC_SEL),
1005
1006 .max_data_lanes = 4,
1007 },
1008 { /* sentinel */ }
1009};
1010
1011static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
1012 {
1013 .reg = 0xff960000,
1014 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
1015 .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI0_LCDC_SEL),
1016 .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI0_LCDC_SEL,
1017 RK3399_DSI0_LCDC_SEL),
1018
1019 .lanecfg1_grf_reg = RK3399_GRF_SOC_CON22,
1020 .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI0_TURNREQUEST |
1021 RK3399_DSI0_TURNDISABLE |
1022 RK3399_DSI0_FORCETXSTOPMODE |
1023 RK3399_DSI0_FORCERXMODE),
1024
1025 .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
1026 .max_data_lanes = 4,
1027 },
1028 {
1029 .reg = 0xff968000,
1030 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
1031 .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI1_LCDC_SEL),
1032 .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI1_LCDC_SEL,
1033 RK3399_DSI1_LCDC_SEL),
1034
1035 .lanecfg1_grf_reg = RK3399_GRF_SOC_CON23,
1036 .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI1_TURNDISABLE |
1037 RK3399_DSI1_FORCETXSTOPMODE |
1038 RK3399_DSI1_FORCERXMODE |
1039 RK3399_DSI1_ENABLE),
1040
1041 .lanecfg2_grf_reg = RK3399_GRF_SOC_CON24,
1042 .lanecfg2 = HIWORD_UPDATE(RK3399_TXRX_MASTERSLAVEZ |
1043 RK3399_TXRX_ENABLECLK,
1044 RK3399_TXRX_MASTERSLAVEZ |
1045 RK3399_TXRX_ENABLECLK |
1046 RK3399_TXRX_BASEDIR),
1047
1048 .enable_grf_reg = RK3399_GRF_SOC_CON23,
1049 .enable = HIWORD_UPDATE(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE),
1050
1051 .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
1052 .max_data_lanes = 4,
1053 },
1054 { /* sentinel */ }
1055};
1056
1057static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
1058 {
1059 .compatible = "rockchip,rk3288-mipi-dsi",
1060 .data = &rk3288_chip_data,
1061 }, {
1062 .compatible = "rockchip,rk3399-mipi-dsi",
1063 .data = &rk3399_chip_data,
1064 },
1065 { /* sentinel */ }
1066};
1067MODULE_DEVICE_TABLE(of, dw_mipi_dsi_rockchip_dt_ids);
1068
1069struct platform_driver dw_mipi_dsi_rockchip_driver = {
1070 .probe = dw_mipi_dsi_rockchip_probe,
1071 .remove = dw_mipi_dsi_rockchip_remove,
1072 .driver = {
1073 .of_match_table = dw_mipi_dsi_rockchip_dt_ids,
1074 .name = "dw-mipi-dsi-rockchip",
1075 },
1076};
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
deleted file mode 100644
index 662b6cb5d3f0..000000000000
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ /dev/null
@@ -1,1349 +0,0 @@
1/*
2 * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9#include <linux/clk.h>
10#include <linux/component.h>
11#include <linux/iopoll.h>
12#include <linux/math64.h>
13#include <linux/module.h>
14#include <linux/of_device.h>
15#include <linux/pm_runtime.h>
16#include <linux/regmap.h>
17#include <linux/reset.h>
18#include <linux/mfd/syscon.h>
19#include <drm/drm_atomic_helper.h>
20#include <drm/drm_crtc.h>
21#include <drm/drm_crtc_helper.h>
22#include <drm/drm_mipi_dsi.h>
23#include <drm/drm_of.h>
24#include <drm/drm_panel.h>
25#include <drm/drmP.h>
26#include <video/mipi_display.h>
27
28#include "rockchip_drm_drv.h"
29#include "rockchip_drm_vop.h"
30
31#define DRIVER_NAME "dw-mipi-dsi"
32
33#define RK3288_GRF_SOC_CON6 0x025c
34#define RK3288_DSI0_SEL_VOP_LIT BIT(6)
35#define RK3288_DSI1_SEL_VOP_LIT BIT(9)
36
37#define RK3399_GRF_SOC_CON20 0x6250
38#define RK3399_DSI0_SEL_VOP_LIT BIT(0)
39#define RK3399_DSI1_SEL_VOP_LIT BIT(4)
40
41/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
42#define RK3399_GRF_SOC_CON22 0x6258
43#define RK3399_GRF_DSI_MODE 0xffff0000
44
45#define DSI_VERSION 0x00
46#define DSI_PWR_UP 0x04
47#define RESET 0
48#define POWERUP BIT(0)
49
50#define DSI_CLKMGR_CFG 0x08
51#define TO_CLK_DIVIDSION(div) (((div) & 0xff) << 8)
52#define TX_ESC_CLK_DIVIDSION(div) (((div) & 0xff) << 0)
53
54#define DSI_DPI_VCID 0x0c
55#define DPI_VID(vid) (((vid) & 0x3) << 0)
56
57#define DSI_DPI_COLOR_CODING 0x10
58#define EN18_LOOSELY BIT(8)
59#define DPI_COLOR_CODING_16BIT_1 0x0
60#define DPI_COLOR_CODING_16BIT_2 0x1
61#define DPI_COLOR_CODING_16BIT_3 0x2
62#define DPI_COLOR_CODING_18BIT_1 0x3
63#define DPI_COLOR_CODING_18BIT_2 0x4
64#define DPI_COLOR_CODING_24BIT 0x5
65
66#define DSI_DPI_CFG_POL 0x14
67#define COLORM_ACTIVE_LOW BIT(4)
68#define SHUTD_ACTIVE_LOW BIT(3)
69#define HSYNC_ACTIVE_LOW BIT(2)
70#define VSYNC_ACTIVE_LOW BIT(1)
71#define DATAEN_ACTIVE_LOW BIT(0)
72
73#define DSI_DPI_LP_CMD_TIM 0x18
74#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16)
75#define INVACT_LPCMD_TIME(p) ((p) & 0xff)
76
77#define DSI_DBI_CFG 0x20
78#define DSI_DBI_CMDSIZE 0x28
79
80#define DSI_PCKHDL_CFG 0x2c
81#define EN_CRC_RX BIT(4)
82#define EN_ECC_RX BIT(3)
83#define EN_BTA BIT(2)
84#define EN_EOTP_RX BIT(1)
85#define EN_EOTP_TX BIT(0)
86
87#define DSI_MODE_CFG 0x34
88#define ENABLE_VIDEO_MODE 0
89#define ENABLE_CMD_MODE BIT(0)
90
91#define DSI_VID_MODE_CFG 0x38
92#define FRAME_BTA_ACK BIT(14)
93#define ENABLE_LOW_POWER (0x3f << 8)
94#define ENABLE_LOW_POWER_MASK (0x3f << 8)
95#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0
96#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1
97#define VID_MODE_TYPE_BURST 0x2
98#define VID_MODE_TYPE_MASK 0x3
99
100#define DSI_VID_PKT_SIZE 0x3c
101#define VID_PKT_SIZE(p) (((p) & 0x3fff) << 0)
102#define VID_PKT_MAX_SIZE 0x3fff
103
104#define DSI_VID_HSA_TIME 0x48
105#define DSI_VID_HBP_TIME 0x4c
106#define DSI_VID_HLINE_TIME 0x50
107#define DSI_VID_VSA_LINES 0x54
108#define DSI_VID_VBP_LINES 0x58
109#define DSI_VID_VFP_LINES 0x5c
110#define DSI_VID_VACTIVE_LINES 0x60
111#define DSI_CMD_MODE_CFG 0x68
112#define MAX_RD_PKT_SIZE_LP BIT(24)
113#define DCS_LW_TX_LP BIT(19)
114#define DCS_SR_0P_TX_LP BIT(18)
115#define DCS_SW_1P_TX_LP BIT(17)
116#define DCS_SW_0P_TX_LP BIT(16)
117#define GEN_LW_TX_LP BIT(14)
118#define GEN_SR_2P_TX_LP BIT(13)
119#define GEN_SR_1P_TX_LP BIT(12)
120#define GEN_SR_0P_TX_LP BIT(11)
121#define GEN_SW_2P_TX_LP BIT(10)
122#define GEN_SW_1P_TX_LP BIT(9)
123#define GEN_SW_0P_TX_LP BIT(8)
124#define EN_ACK_RQST BIT(1)
125#define EN_TEAR_FX BIT(0)
126
127#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \
128 DCS_LW_TX_LP | \
129 DCS_SR_0P_TX_LP | \
130 DCS_SW_1P_TX_LP | \
131 DCS_SW_0P_TX_LP | \
132 GEN_LW_TX_LP | \
133 GEN_SR_2P_TX_LP | \
134 GEN_SR_1P_TX_LP | \
135 GEN_SR_0P_TX_LP | \
136 GEN_SW_2P_TX_LP | \
137 GEN_SW_1P_TX_LP | \
138 GEN_SW_0P_TX_LP)
139
140#define DSI_GEN_HDR 0x6c
141#define GEN_HDATA(data) (((data) & 0xffff) << 8)
142#define GEN_HDATA_MASK (0xffff << 8)
143#define GEN_HTYPE(type) (((type) & 0xff) << 0)
144#define GEN_HTYPE_MASK 0xff
145
146#define DSI_GEN_PLD_DATA 0x70
147
148#define DSI_CMD_PKT_STATUS 0x74
149#define GEN_CMD_EMPTY BIT(0)
150#define GEN_CMD_FULL BIT(1)
151#define GEN_PLD_W_EMPTY BIT(2)
152#define GEN_PLD_W_FULL BIT(3)
153#define GEN_PLD_R_EMPTY BIT(4)
154#define GEN_PLD_R_FULL BIT(5)
155#define GEN_RD_CMD_BUSY BIT(6)
156
157#define DSI_TO_CNT_CFG 0x78
158#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16)
159#define LPRX_TO_CNT(p) ((p) & 0xffff)
160
161#define DSI_BTA_TO_CNT 0x8c
162#define DSI_LPCLK_CTRL 0x94
163#define AUTO_CLKLANE_CTRL BIT(1)
164#define PHY_TXREQUESTCLKHS BIT(0)
165
166#define DSI_PHY_TMR_LPCLK_CFG 0x98
167#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16)
168#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff)
169
170#define DSI_PHY_TMR_CFG 0x9c
171#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24)
172#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16)
173#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff)
174
175#define DSI_PHY_RSTZ 0xa0
176#define PHY_DISFORCEPLL 0
177#define PHY_ENFORCEPLL BIT(3)
178#define PHY_DISABLECLK 0
179#define PHY_ENABLECLK BIT(2)
180#define PHY_RSTZ 0
181#define PHY_UNRSTZ BIT(1)
182#define PHY_SHUTDOWNZ 0
183#define PHY_UNSHUTDOWNZ BIT(0)
184
185#define DSI_PHY_IF_CFG 0xa4
186#define N_LANES(n) ((((n) - 1) & 0x3) << 0)
187#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8)
188
189#define DSI_PHY_STATUS 0xb0
190#define LOCK BIT(0)
191#define STOP_STATE_CLK_LANE BIT(2)
192
193#define DSI_PHY_TST_CTRL0 0xb4
194#define PHY_TESTCLK BIT(1)
195#define PHY_UNTESTCLK 0
196#define PHY_TESTCLR BIT(0)
197#define PHY_UNTESTCLR 0
198
199#define DSI_PHY_TST_CTRL1 0xb8
200#define PHY_TESTEN BIT(16)
201#define PHY_UNTESTEN 0
202#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
203#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
204
205#define DSI_INT_ST0 0xbc
206#define DSI_INT_ST1 0xc0
207#define DSI_INT_MSK0 0xc4
208#define DSI_INT_MSK1 0xc8
209
210#define PHY_STATUS_TIMEOUT_US 10000
211#define CMD_PKT_STATUS_TIMEOUT_US 20000
212
213#define BYPASS_VCO_RANGE BIT(7)
214#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
215#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
216#define VCO_IN_CAP_CON_LOW (0x1 << 1)
217#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
218#define REF_BIAS_CUR_SEL BIT(0)
219
220#define CP_CURRENT_3MA BIT(3)
221#define CP_PROGRAM_EN BIT(7)
222#define LPF_PROGRAM_EN BIT(6)
223#define LPF_RESISTORS_20_KOHM 0
224
225#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
226
227#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
228#define LOW_PROGRAM_EN 0
229#define HIGH_PROGRAM_EN BIT(7)
230#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
231#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
232#define PLL_LOOP_DIV_EN BIT(5)
233#define PLL_INPUT_DIV_EN BIT(4)
234
235#define POWER_CONTROL BIT(6)
236#define INTERNAL_REG_CURRENT BIT(3)
237#define BIAS_BLOCK_ON BIT(2)
238#define BANDGAP_ON BIT(0)
239
240#define TER_RESISTOR_HIGH BIT(7)
241#define TER_RESISTOR_LOW 0
242#define LEVEL_SHIFTERS_ON BIT(6)
243#define TER_CAL_DONE BIT(5)
244#define SETRD_MAX (0x7 << 2)
245#define POWER_MANAGE BIT(1)
246#define TER_RESISTORS_ON BIT(0)
247
248#define BIASEXTR_SEL(val) ((val) & 0x7)
249#define BANDGAP_SEL(val) ((val) & 0x7)
250#define TLP_PROGRAM_EN BIT(7)
251#define THS_PRE_PROGRAM_EN BIT(7)
252#define THS_ZERO_PROGRAM_EN BIT(6)
253
254#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
255#define DW_MIPI_NEEDS_GRF_CLK BIT(1)
256
257enum {
258 BANDGAP_97_07,
259 BANDGAP_98_05,
260 BANDGAP_99_02,
261 BANDGAP_100_00,
262 BANDGAP_93_17,
263 BANDGAP_94_15,
264 BANDGAP_95_12,
265 BANDGAP_96_10,
266};
267
268enum {
269 BIASEXTR_87_1,
270 BIASEXTR_91_5,
271 BIASEXTR_95_9,
272 BIASEXTR_100,
273 BIASEXTR_105_94,
274 BIASEXTR_111_88,
275 BIASEXTR_118_8,
276 BIASEXTR_127_7,
277};
278
279struct dw_mipi_dsi_plat_data {
280 u32 dsi0_en_bit;
281 u32 dsi1_en_bit;
282 u32 grf_switch_reg;
283 u32 grf_dsi0_mode;
284 u32 grf_dsi0_mode_reg;
285 unsigned int flags;
286 unsigned int max_data_lanes;
287};
288
289struct dw_mipi_dsi {
290 struct drm_encoder encoder;
291 struct drm_connector connector;
292 struct mipi_dsi_host dsi_host;
293 struct drm_panel *panel;
294 struct device *dev;
295 struct regmap *grf_regmap;
296 void __iomem *base;
297
298 struct clk *grf_clk;
299 struct clk *pllref_clk;
300 struct clk *pclk;
301 struct clk *phy_cfg_clk;
302
303 int dpms_mode;
304 unsigned int lane_mbps; /* per lane */
305 u32 channel;
306 u32 lanes;
307 u32 format;
308 u16 input_div;
309 u16 feedback_div;
310 unsigned long mode_flags;
311
312 const struct dw_mipi_dsi_plat_data *pdata;
313};
314
315enum dw_mipi_dsi_mode {
316 DW_MIPI_DSI_CMD_MODE,
317 DW_MIPI_DSI_VID_MODE,
318};
319
320struct dphy_pll_testdin_map {
321 unsigned int max_mbps;
322 u8 testdin;
323};
324
325/* The table is based on 27MHz DPHY pll reference clock. */
326static const struct dphy_pll_testdin_map dptdin_map[] = {
327 { 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
328 { 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
329 { 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
330 { 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
331 { 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
332 { 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
333 { 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
334 {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
335 {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
336 {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
337};
338
339static int max_mbps_to_testdin(unsigned int max_mbps)
340{
341 int i;
342
343 for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
344 if (dptdin_map[i].max_mbps > max_mbps)
345 return dptdin_map[i].testdin;
346
347 return -EINVAL;
348}
349
350/*
351 * The controller should generate 2 frames before
352 * preparing the peripheral.
353 */
354static void dw_mipi_dsi_wait_for_two_frames(struct drm_display_mode *mode)
355{
356 int refresh, two_frames;
357
358 refresh = drm_mode_vrefresh(mode);
359 two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2;
360 msleep(two_frames);
361}
362
363static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host)
364{
365 return container_of(host, struct dw_mipi_dsi, dsi_host);
366}
367
368static inline struct dw_mipi_dsi *con_to_dsi(struct drm_connector *con)
369{
370 return container_of(con, struct dw_mipi_dsi, connector);
371}
372
373static inline struct dw_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
374{
375 return container_of(encoder, struct dw_mipi_dsi, encoder);
376}
377
378static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
379{
380 writel(val, dsi->base + reg);
381}
382
383static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
384{
385 return readl(dsi->base + reg);
386}
387
388static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code,
389 u8 test_data)
390{
391 /*
392 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
393 * is latched internally as the current test code. Test data is
394 * programmed internally by rising edge on TESTCLK.
395 */
396 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
397
398 dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
399 PHY_TESTDIN(test_code));
400
401 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
402
403 dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
404 PHY_TESTDIN(test_data));
405
406 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
407}
408
409/**
410 * ns2bc - Nanoseconds to byte clock cycles
411 */
412static inline unsigned int ns2bc(struct dw_mipi_dsi *dsi, int ns)
413{
414 return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
415}
416
417/**
418 * ns2ui - Nanoseconds to UI time periods
419 */
420static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
421{
422 return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
423}
424
425static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
426{
427 int ret, testdin, vco, val;
428
429 vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
430
431 testdin = max_mbps_to_testdin(dsi->lane_mbps);
432 if (testdin < 0) {
433 DRM_DEV_ERROR(dsi->dev,
434 "failed to get testdin for %dmbps lane clock\n",
435 dsi->lane_mbps);
436 return testdin;
437 }
438
439 /* Start by clearing PHY state */
440 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
441 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR);
442 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
443
444 ret = clk_prepare_enable(dsi->phy_cfg_clk);
445 if (ret) {
446 DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
447 return ret;
448 }
449
450 dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
451 VCO_RANGE_CON_SEL(vco) |
452 VCO_IN_CAP_CON_LOW |
453 REF_BIAS_CUR_SEL);
454
455 dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
456 dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
457 LPF_RESISTORS_20_KOHM);
458
459 dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
460
461 dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
462 dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
463 LOW_PROGRAM_EN);
464 dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
465 HIGH_PROGRAM_EN);
466 dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
467
468 dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
469 BIASEXTR_SEL(BIASEXTR_127_7));
470 dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
471 BANDGAP_SEL(BANDGAP_96_10));
472
473 dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
474 BIAS_BLOCK_ON | BANDGAP_ON);
475
476 dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
477 SETRD_MAX | TER_RESISTORS_ON);
478 dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
479 SETRD_MAX | POWER_MANAGE |
480 TER_RESISTORS_ON);
481
482 dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
483 dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
484 dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
485 dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
486 dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
487 dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
488
489 dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
490 dw_mipi_dsi_phy_write(dsi, 0x71,
491 THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
492 dw_mipi_dsi_phy_write(dsi, 0x72,
493 THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
494 dw_mipi_dsi_phy_write(dsi, 0x73,
495 THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
496 dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
497
498 dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
499 PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
500
501 ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
502 val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
503 if (ret < 0) {
504 DRM_DEV_ERROR(dsi->dev, "failed to wait for phy lock state\n");
505 goto phy_init_end;
506 }
507
508 ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
509 val, val & STOP_STATE_CLK_LANE, 1000,
510 PHY_STATUS_TIMEOUT_US);
511 if (ret < 0)
512 DRM_DEV_ERROR(dsi->dev,
513 "failed to wait for phy clk lane stop state\n");
514
515phy_init_end:
516 clk_disable_unprepare(dsi->phy_cfg_clk);
517
518 return ret;
519}
520
521static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
522 struct drm_display_mode *mode)
523{
524 unsigned int i, pre;
525 unsigned long mpclk, pllref, tmp;
526 unsigned int m = 1, n = 1, target_mbps = 1000;
527 unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
528 int bpp;
529
530 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
531 if (bpp < 0) {
532 DRM_DEV_ERROR(dsi->dev,
533 "failed to get bpp for pixel format %d\n",
534 dsi->format);
535 return bpp;
536 }
537
538 mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
539 if (mpclk) {
540 /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
541 tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
542 if (tmp < max_mbps)
543 target_mbps = tmp;
544 else
545 DRM_DEV_ERROR(dsi->dev,
546 "DPHY clock frequency is out of range\n");
547 }
548
549 pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
550 tmp = pllref;
551
552 /*
553 * The limits on the PLL divisor are:
554 *
555 * 5MHz <= (pllref / n) <= 40MHz
556 *
557 * we walk over these values in descreasing order so that if we hit
558 * an exact match for target_mbps it is more likely that "m" will be
559 * even.
560 *
561 * TODO: ensure that "m" is even after this loop.
562 */
563 for (i = pllref / 5; i > (pllref / 40); i--) {
564 pre = pllref / i;
565 if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
566 tmp = target_mbps % pre;
567 n = i;
568 m = target_mbps / pre;
569 }
570 if (tmp == 0)
571 break;
572 }
573
574 dsi->lane_mbps = pllref / n * m;
575 dsi->input_div = n;
576 dsi->feedback_div = m;
577
578 return 0;
579}
580
581static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
582 struct mipi_dsi_device *device)
583{
584 struct dw_mipi_dsi *dsi = host_to_dsi(host);
585
586 if (device->lanes > dsi->pdata->max_data_lanes) {
587 DRM_DEV_ERROR(dsi->dev,
588 "the number of data lanes(%u) is too many\n",
589 device->lanes);
590 return -EINVAL;
591 }
592
593 dsi->lanes = device->lanes;
594 dsi->channel = device->channel;
595 dsi->format = device->format;
596 dsi->mode_flags = device->mode_flags;
597 dsi->panel = of_drm_find_panel(device->dev.of_node);
598 if (!IS_ERR(dsi->panel))
599 return drm_panel_attach(dsi->panel, &dsi->connector);
600
601 return -EINVAL;
602}
603
604static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
605 struct mipi_dsi_device *device)
606{
607 struct dw_mipi_dsi *dsi = host_to_dsi(host);
608
609 drm_panel_detach(dsi->panel);
610
611 return 0;
612}
613
614static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
615 const struct mipi_dsi_msg *msg)
616{
617 bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;
618 u32 val = 0;
619
620 if (msg->flags & MIPI_DSI_MSG_REQ_ACK)
621 val |= EN_ACK_RQST;
622 if (lpm)
623 val |= CMD_MODE_ALL_LP;
624
625 dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS);
626 dsi_write(dsi, DSI_CMD_MODE_CFG, val);
627}
628
629static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
630{
631 int ret;
632 u32 val, mask;
633
634 ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
635 val, !(val & GEN_CMD_FULL), 1000,
636 CMD_PKT_STATUS_TIMEOUT_US);
637 if (ret < 0) {
638 DRM_DEV_ERROR(dsi->dev,
639 "failed to get available command FIFO\n");
640 return ret;
641 }
642
643 dsi_write(dsi, DSI_GEN_HDR, hdr_val);
644
645 mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
646 ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
647 val, (val & mask) == mask,
648 1000, CMD_PKT_STATUS_TIMEOUT_US);
649 if (ret < 0) {
650 DRM_DEV_ERROR(dsi->dev, "failed to write command FIFO\n");
651 return ret;
652 }
653
654 return 0;
655}
656
657static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
658 const struct mipi_dsi_msg *msg)
659{
660 const u8 *tx_buf = msg->tx_buf;
661 u16 data = 0;
662 u32 val;
663
664 if (msg->tx_len > 0)
665 data |= tx_buf[0];
666 if (msg->tx_len > 1)
667 data |= tx_buf[1] << 8;
668
669 if (msg->tx_len > 2) {
670 DRM_DEV_ERROR(dsi->dev,
671 "too long tx buf length %zu for short write\n",
672 msg->tx_len);
673 return -EINVAL;
674 }
675
676 val = GEN_HDATA(data) | GEN_HTYPE(msg->type);
677 return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
678}
679
680static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
681 const struct mipi_dsi_msg *msg)
682{
683 const u8 *tx_buf = msg->tx_buf;
684 int len = msg->tx_len, pld_data_bytes = sizeof(u32), ret;
685 u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
686 u32 remainder;
687 u32 val;
688
689 if (msg->tx_len < 3) {
690 DRM_DEV_ERROR(dsi->dev,
691 "wrong tx buf length %zu for long write\n",
692 msg->tx_len);
693 return -EINVAL;
694 }
695
696 while (DIV_ROUND_UP(len, pld_data_bytes)) {
697 if (len < pld_data_bytes) {
698 remainder = 0;
699 memcpy(&remainder, tx_buf, len);
700 dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
701 len = 0;
702 } else {
703 memcpy(&remainder, tx_buf, pld_data_bytes);
704 dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
705 tx_buf += pld_data_bytes;
706 len -= pld_data_bytes;
707 }
708
709 ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
710 val, !(val & GEN_PLD_W_FULL), 1000,
711 CMD_PKT_STATUS_TIMEOUT_US);
712 if (ret < 0) {
713 DRM_DEV_ERROR(dsi->dev,
714 "failed to get available write payload FIFO\n");
715 return ret;
716 }
717 }
718
719 return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val);
720}
721
722static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
723 const struct mipi_dsi_msg *msg)
724{
725 struct dw_mipi_dsi *dsi = host_to_dsi(host);
726 int ret;
727
728 dw_mipi_message_config(dsi, msg);
729
730 switch (msg->type) {
731 case MIPI_DSI_DCS_SHORT_WRITE:
732 case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
733 case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
734 ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
735 break;
736 case MIPI_DSI_DCS_LONG_WRITE:
737 ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
738 break;
739 default:
740 DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n",
741 msg->type);
742 ret = -EINVAL;
743 }
744
745 return ret;
746}
747
748static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
749 .attach = dw_mipi_dsi_host_attach,
750 .detach = dw_mipi_dsi_host_detach,
751 .transfer = dw_mipi_dsi_host_transfer,
752};
753
754static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
755{
756 u32 val;
757
758 val = ENABLE_LOW_POWER;
759
760 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
761 val |= VID_MODE_TYPE_BURST;
762 else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
763 val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES;
764 else
765 val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
766
767 dsi_write(dsi, DSI_VID_MODE_CFG, val);
768}
769
770static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
771 enum dw_mipi_dsi_mode mode)
772{
773 if (mode == DW_MIPI_DSI_CMD_MODE) {
774 dsi_write(dsi, DSI_PWR_UP, RESET);
775 dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
776 dsi_write(dsi, DSI_PWR_UP, POWERUP);
777 } else {
778 dsi_write(dsi, DSI_PWR_UP, RESET);
779 dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE);
780 dw_mipi_dsi_video_mode_config(dsi);
781 dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
782 dsi_write(dsi, DSI_PWR_UP, POWERUP);
783 }
784}
785
786static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
787{
788 dsi_write(dsi, DSI_PWR_UP, RESET);
789 dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
790}
791
792static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
793{
794 /*
795 * The maximum permitted escape clock is 20MHz and it is derived from
796 * lanebyteclk, which is running at "lane_mbps / 8". Thus we want:
797 *
798 * (lane_mbps >> 3) / esc_clk_division < 20
799 * which is:
800 * (lane_mbps >> 3) / 20 > esc_clk_division
801 */
802 u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1;
803
804 dsi_write(dsi, DSI_PWR_UP, RESET);
805 dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK
806 | PHY_RSTZ | PHY_SHUTDOWNZ);
807 dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) |
808 TX_ESC_CLK_DIVIDSION(esc_clk_division));
809}
810
811static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
812 struct drm_display_mode *mode)
813{
814 u32 val = 0, color = 0;
815
816 switch (dsi->format) {
817 case MIPI_DSI_FMT_RGB888:
818 color = DPI_COLOR_CODING_24BIT;
819 break;
820 case MIPI_DSI_FMT_RGB666:
821 color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY;
822 break;
823 case MIPI_DSI_FMT_RGB666_PACKED:
824 color = DPI_COLOR_CODING_18BIT_1;
825 break;
826 case MIPI_DSI_FMT_RGB565:
827 color = DPI_COLOR_CODING_16BIT_1;
828 break;
829 }
830
831 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
832 val |= VSYNC_ACTIVE_LOW;
833 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
834 val |= HSYNC_ACTIVE_LOW;
835
836 dsi_write(dsi, DSI_DPI_VCID, DPI_VID(dsi->channel));
837 dsi_write(dsi, DSI_DPI_COLOR_CODING, color);
838 dsi_write(dsi, DSI_DPI_CFG_POL, val);
839 dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4)
840 | INVACT_LPCMD_TIME(4));
841}
842
843static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
844{
845 dsi_write(dsi, DSI_PCKHDL_CFG, EN_CRC_RX | EN_ECC_RX | EN_BTA);
846}
847
848static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
849 struct drm_display_mode *mode)
850{
851 dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
852}
853
854static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
855{
856 dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
857 dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00);
858 dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
859}
860
861/* Get lane byte clock cycles. */
862static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
863 struct drm_display_mode *mode,
864 u32 hcomponent)
865{
866 u32 frac, lbcc;
867
868 lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
869
870 frac = lbcc % mode->clock;
871 lbcc = lbcc / mode->clock;
872 if (frac)
873 lbcc++;
874
875 return lbcc;
876}
877
878static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi,
879 struct drm_display_mode *mode)
880{
881 u32 htotal, hsa, hbp, lbcc;
882
883 htotal = mode->htotal;
884 hsa = mode->hsync_end - mode->hsync_start;
885 hbp = mode->htotal - mode->hsync_end;
886
887 lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, htotal);
888 dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc);
889
890 lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hsa);
891 dsi_write(dsi, DSI_VID_HSA_TIME, lbcc);
892
893 lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hbp);
894 dsi_write(dsi, DSI_VID_HBP_TIME, lbcc);
895}
896
897static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
898 struct drm_display_mode *mode)
899{
900 u32 vactive, vsa, vfp, vbp;
901
902 vactive = mode->vdisplay;
903 vsa = mode->vsync_end - mode->vsync_start;
904 vfp = mode->vsync_start - mode->vdisplay;
905 vbp = mode->vtotal - mode->vsync_end;
906
907 dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive);
908 dsi_write(dsi, DSI_VID_VSA_LINES, vsa);
909 dsi_write(dsi, DSI_VID_VFP_LINES, vfp);
910 dsi_write(dsi, DSI_VID_VBP_LINES, vbp);
911}
912
913static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
914{
915 dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40)
916 | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
917
918 dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40)
919 | PHY_CLKLP2HS_TIME(0x40));
920}
921
922static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
923{
924 dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) |
925 N_LANES(dsi->lanes));
926}
927
928static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
929{
930 dsi_read(dsi, DSI_INT_ST0);
931 dsi_read(dsi, DSI_INT_ST1);
932 dsi_write(dsi, DSI_INT_MSK0, 0);
933 dsi_write(dsi, DSI_INT_MSK1, 0);
934}
935
936static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
937{
938 struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
939
940 if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
941 return;
942
943 if (clk_prepare_enable(dsi->pclk)) {
944 DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
945 return;
946 }
947
948 drm_panel_disable(dsi->panel);
949
950 dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
951 drm_panel_unprepare(dsi->panel);
952
953 dw_mipi_dsi_disable(dsi);
954 pm_runtime_put(dsi->dev);
955 clk_disable_unprepare(dsi->pclk);
956 dsi->dpms_mode = DRM_MODE_DPMS_OFF;
957}
958
959static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
960{
961 struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
962 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
963 const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
964 int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
965 u32 val;
966 int ret;
967
968 ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
969 if (ret < 0)
970 return;
971
972 if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
973 return;
974
975 if (clk_prepare_enable(dsi->pclk)) {
976 DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
977 return;
978 }
979
980 pm_runtime_get_sync(dsi->dev);
981 dw_mipi_dsi_init(dsi);
982 dw_mipi_dsi_dpi_config(dsi, mode);
983 dw_mipi_dsi_packet_handler_config(dsi);
984 dw_mipi_dsi_video_mode_config(dsi);
985 dw_mipi_dsi_video_packet_config(dsi, mode);
986 dw_mipi_dsi_command_mode_config(dsi);
987 dw_mipi_dsi_line_timer_config(dsi, mode);
988 dw_mipi_dsi_vertical_timing_config(dsi, mode);
989 dw_mipi_dsi_dphy_timing_config(dsi);
990 dw_mipi_dsi_dphy_interface_config(dsi);
991 dw_mipi_dsi_clear_err(dsi);
992
993 /*
994 * For the RK3399, the clk of grf must be enabled before writing grf
995 * register. And for RK3288 or other soc, this grf_clk must be NULL,
996 * the clk_prepare_enable return true directly.
997 */
998 ret = clk_prepare_enable(dsi->grf_clk);
999 if (ret) {
1000 DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
1001 return;
1002 }
1003
1004 if (pdata->grf_dsi0_mode_reg)
1005 regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
1006 pdata->grf_dsi0_mode);
1007
1008 dw_mipi_dsi_phy_init(dsi);
1009 dw_mipi_dsi_wait_for_two_frames(mode);
1010
1011 dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
1012 if (drm_panel_prepare(dsi->panel))
1013 DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n");
1014
1015 dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
1016 drm_panel_enable(dsi->panel);
1017
1018 clk_disable_unprepare(dsi->pclk);
1019
1020 if (mux)
1021 val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
1022 else
1023 val = pdata->dsi0_en_bit << 16;
1024
1025 regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
1026 DRM_DEV_DEBUG(dsi->dev,
1027 "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
1028 dsi->dpms_mode = DRM_MODE_DPMS_ON;
1029
1030 clk_disable_unprepare(dsi->grf_clk);
1031}
1032
1033static int
1034dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
1035 struct drm_crtc_state *crtc_state,
1036 struct drm_connector_state *conn_state)
1037{
1038 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
1039 struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
1040
1041 switch (dsi->format) {
1042 case MIPI_DSI_FMT_RGB888:
1043 s->output_mode = ROCKCHIP_OUT_MODE_P888;
1044 break;
1045 case MIPI_DSI_FMT_RGB666:
1046 s->output_mode = ROCKCHIP_OUT_MODE_P666;
1047 break;
1048 case MIPI_DSI_FMT_RGB565:
1049 s->output_mode = ROCKCHIP_OUT_MODE_P565;
1050 break;
1051 default:
1052 WARN_ON(1);
1053 return -EINVAL;
1054 }
1055
1056 s->output_type = DRM_MODE_CONNECTOR_DSI;
1057
1058 return 0;
1059}
1060
1061static const struct drm_encoder_helper_funcs
1062dw_mipi_dsi_encoder_helper_funcs = {
1063 .enable = dw_mipi_dsi_encoder_enable,
1064 .disable = dw_mipi_dsi_encoder_disable,
1065 .atomic_check = dw_mipi_dsi_encoder_atomic_check,
1066};
1067
1068static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
1069 .destroy = drm_encoder_cleanup,
1070};
1071
1072static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
1073{
1074 struct dw_mipi_dsi *dsi = con_to_dsi(connector);
1075
1076 return drm_panel_get_modes(dsi->panel);
1077}
1078
1079static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
1080 .get_modes = dw_mipi_dsi_connector_get_modes,
1081};
1082
1083static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
1084{
1085 drm_connector_unregister(connector);
1086 drm_connector_cleanup(connector);
1087}
1088
1089static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
1090 .fill_modes = drm_helper_probe_single_connector_modes,
1091 .destroy = dw_mipi_dsi_drm_connector_destroy,
1092 .reset = drm_atomic_helper_connector_reset,
1093 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1094 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1095};
1096
1097static int dw_mipi_dsi_register(struct drm_device *drm,
1098 struct dw_mipi_dsi *dsi)
1099{
1100 struct drm_encoder *encoder = &dsi->encoder;
1101 struct drm_connector *connector = &dsi->connector;
1102 struct device *dev = dsi->dev;
1103 int ret;
1104
1105 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm,
1106 dev->of_node);
1107 /*
1108 * If we failed to find the CRTC(s) which this encoder is
1109 * supposed to be connected to, it's because the CRTC has
1110 * not been registered yet. Defer probing, and hope that
1111 * the required CRTC is added later.
1112 */
1113 if (encoder->possible_crtcs == 0)
1114 return -EPROBE_DEFER;
1115
1116 drm_encoder_helper_add(&dsi->encoder,
1117 &dw_mipi_dsi_encoder_helper_funcs);
1118 ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
1119 DRM_MODE_ENCODER_DSI, NULL);
1120 if (ret) {
1121 DRM_DEV_ERROR(dev, "Failed to initialize encoder with drm\n");
1122 return ret;
1123 }
1124
1125 drm_connector_helper_add(connector,
1126 &dw_mipi_dsi_connector_helper_funcs);
1127
1128 drm_connector_init(drm, &dsi->connector,
1129 &dw_mipi_dsi_atomic_connector_funcs,
1130 DRM_MODE_CONNECTOR_DSI);
1131
1132 drm_connector_attach_encoder(connector, encoder);
1133
1134 return 0;
1135}
1136
1137static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
1138{
1139 struct device_node *np = dsi->dev->of_node;
1140
1141 dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
1142 if (IS_ERR(dsi->grf_regmap)) {
1143 DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
1144 return PTR_ERR(dsi->grf_regmap);
1145 }
1146
1147 return 0;
1148}
1149
1150static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
1151 .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
1152 .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
1153 .grf_switch_reg = RK3288_GRF_SOC_CON6,
1154 .max_data_lanes = 4,
1155};
1156
1157static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
1158 .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT,
1159 .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT,
1160 .grf_switch_reg = RK3399_GRF_SOC_CON20,
1161 .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
1162 .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
1163 .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
1164 .max_data_lanes = 4,
1165};
1166
1167static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
1168 {
1169 .compatible = "rockchip,rk3288-mipi-dsi",
1170 .data = &rk3288_mipi_dsi_drv_data,
1171 }, {
1172 .compatible = "rockchip,rk3399-mipi-dsi",
1173 .data = &rk3399_mipi_dsi_drv_data,
1174 },
1175 { /* sentinel */ }
1176};
1177MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
1178
1179static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
1180 void *data)
1181{
1182 const struct of_device_id *of_id =
1183 of_match_device(dw_mipi_dsi_dt_ids, dev);
1184 const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
1185 struct platform_device *pdev = to_platform_device(dev);
1186 struct reset_control *apb_rst;
1187 struct drm_device *drm = data;
1188 struct dw_mipi_dsi *dsi;
1189 struct resource *res;
1190 int ret;
1191
1192 dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
1193 if (!dsi)
1194 return -ENOMEM;
1195
1196 dsi->dev = dev;
1197 dsi->pdata = pdata;
1198 dsi->dpms_mode = DRM_MODE_DPMS_OFF;
1199
1200 ret = rockchip_mipi_parse_dt(dsi);
1201 if (ret)
1202 return ret;
1203
1204 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1205 dsi->base = devm_ioremap_resource(dev, res);
1206 if (IS_ERR(dsi->base))
1207 return PTR_ERR(dsi->base);
1208
1209 dsi->pllref_clk = devm_clk_get(dev, "ref");
1210 if (IS_ERR(dsi->pllref_clk)) {
1211 ret = PTR_ERR(dsi->pllref_clk);
1212 DRM_DEV_ERROR(dev,
1213 "Unable to get pll reference clock: %d\n", ret);
1214 return ret;
1215 }
1216
1217 dsi->pclk = devm_clk_get(dev, "pclk");
1218 if (IS_ERR(dsi->pclk)) {
1219 ret = PTR_ERR(dsi->pclk);
1220 DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret);
1221 return ret;
1222 }
1223
1224 /*
1225 * Note that the reset was not defined in the initial device tree, so
1226 * we have to be prepared for it not being found.
1227 */
1228 apb_rst = devm_reset_control_get(dev, "apb");
1229 if (IS_ERR(apb_rst)) {
1230 ret = PTR_ERR(apb_rst);
1231 if (ret == -ENOENT) {
1232 apb_rst = NULL;
1233 } else {
1234 DRM_DEV_ERROR(dev,
1235 "Unable to get reset control: %d\n", ret);
1236 return ret;
1237 }
1238 }
1239
1240 if (apb_rst) {
1241 ret = clk_prepare_enable(dsi->pclk);
1242 if (ret) {
1243 DRM_DEV_ERROR(dev, "Failed to enable pclk\n");
1244 return ret;
1245 }
1246
1247 reset_control_assert(apb_rst);
1248 usleep_range(10, 20);
1249 reset_control_deassert(apb_rst);
1250
1251 clk_disable_unprepare(dsi->pclk);
1252 }
1253
1254 if (pdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
1255 dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
1256 if (IS_ERR(dsi->phy_cfg_clk)) {
1257 ret = PTR_ERR(dsi->phy_cfg_clk);
1258 DRM_DEV_ERROR(dev,
1259 "Unable to get phy_cfg_clk: %d\n", ret);
1260 return ret;
1261 }
1262 }
1263
1264 if (pdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
1265 dsi->grf_clk = devm_clk_get(dev, "grf");
1266 if (IS_ERR(dsi->grf_clk)) {
1267 ret = PTR_ERR(dsi->grf_clk);
1268 DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
1269 return ret;
1270 }
1271 }
1272
1273 ret = clk_prepare_enable(dsi->pllref_clk);
1274 if (ret) {
1275 DRM_DEV_ERROR(dev, "Failed to enable pllref_clk\n");
1276 return ret;
1277 }
1278
1279 ret = dw_mipi_dsi_register(drm, dsi);
1280 if (ret) {
1281 DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
1282 goto err_pllref;
1283 }
1284
1285 dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
1286 dsi->dsi_host.dev = dev;
1287 ret = mipi_dsi_host_register(&dsi->dsi_host);
1288 if (ret) {
1289 DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
1290 goto err_cleanup;
1291 }
1292
1293 if (!dsi->panel) {
1294 ret = -EPROBE_DEFER;
1295 goto err_mipi_dsi_host;
1296 }
1297
1298 dev_set_drvdata(dev, dsi);
1299 pm_runtime_enable(dev);
1300 return 0;
1301
1302err_mipi_dsi_host:
1303 mipi_dsi_host_unregister(&dsi->dsi_host);
1304err_cleanup:
1305 dsi->connector.funcs->destroy(&dsi->connector);
1306 dsi->encoder.funcs->destroy(&dsi->encoder);
1307err_pllref:
1308 clk_disable_unprepare(dsi->pllref_clk);
1309 return ret;
1310}
1311
1312static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
1313 void *data)
1314{
1315 struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
1316
1317 mipi_dsi_host_unregister(&dsi->dsi_host);
1318 pm_runtime_disable(dev);
1319
1320 dsi->connector.funcs->destroy(&dsi->connector);
1321 dsi->encoder.funcs->destroy(&dsi->encoder);
1322
1323 clk_disable_unprepare(dsi->pllref_clk);
1324}
1325
1326static const struct component_ops dw_mipi_dsi_ops = {
1327 .bind = dw_mipi_dsi_bind,
1328 .unbind = dw_mipi_dsi_unbind,
1329};
1330
1331static int dw_mipi_dsi_probe(struct platform_device *pdev)
1332{
1333 return component_add(&pdev->dev, &dw_mipi_dsi_ops);
1334}
1335
1336static int dw_mipi_dsi_remove(struct platform_device *pdev)
1337{
1338 component_del(&pdev->dev, &dw_mipi_dsi_ops);
1339 return 0;
1340}
1341
1342struct platform_driver dw_mipi_dsi_driver = {
1343 .probe = dw_mipi_dsi_probe,
1344 .remove = dw_mipi_dsi_remove,
1345 .driver = {
1346 .of_match_table = dw_mipi_dsi_dt_ids,
1347 .name = DRIVER_NAME,
1348 },
1349};
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 11309a2a4e43..89c63cfde5c8 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -11,6 +11,7 @@
11#include <linux/mfd/syscon.h> 11#include <linux/mfd/syscon.h>
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14#include <linux/phy/phy.h>
14#include <linux/regmap.h> 15#include <linux/regmap.h>
15 16
16#include <drm/drm_of.h> 17#include <drm/drm_of.h>
@@ -24,6 +25,24 @@
24 25
25#define RK3288_GRF_SOC_CON6 0x025C 26#define RK3288_GRF_SOC_CON6 0x025C
26#define RK3288_HDMI_LCDC_SEL BIT(4) 27#define RK3288_HDMI_LCDC_SEL BIT(4)
28#define RK3328_GRF_SOC_CON2 0x0408
29
30#define RK3328_HDMI_SDAIN_MSK BIT(11)
31#define RK3328_HDMI_SCLIN_MSK BIT(10)
32#define RK3328_HDMI_HPD_IOE BIT(2)
33#define RK3328_GRF_SOC_CON3 0x040c
34/* need to be unset if hdmi or i2c should control voltage */
35#define RK3328_HDMI_SDA5V_GRF BIT(15)
36#define RK3328_HDMI_SCL5V_GRF BIT(14)
37#define RK3328_HDMI_HPD5V_GRF BIT(13)
38#define RK3328_HDMI_CEC5V_GRF BIT(12)
39#define RK3328_GRF_SOC_CON4 0x0410
40#define RK3328_HDMI_HPD_SARADC BIT(13)
41#define RK3328_HDMI_CEC_5V BIT(11)
42#define RK3328_HDMI_SDA_5V BIT(10)
43#define RK3328_HDMI_SCL_5V BIT(9)
44#define RK3328_HDMI_HPD_5V BIT(8)
45
27#define RK3399_GRF_SOC_CON20 0x6250 46#define RK3399_GRF_SOC_CON20 0x6250
28#define RK3399_HDMI_LCDC_SEL BIT(6) 47#define RK3399_HDMI_LCDC_SEL BIT(6)
29 48
@@ -36,7 +55,7 @@
36 * @lcdsel_lit: reg value of selecting vop little for HDMI 55 * @lcdsel_lit: reg value of selecting vop little for HDMI
37 */ 56 */
38struct rockchip_hdmi_chip_data { 57struct rockchip_hdmi_chip_data {
39 u32 lcdsel_grf_reg; 58 int lcdsel_grf_reg;
40 u32 lcdsel_big; 59 u32 lcdsel_big;
41 u32 lcdsel_lit; 60 u32 lcdsel_lit;
42}; 61};
@@ -49,6 +68,7 @@ struct rockchip_hdmi {
49 struct clk *vpll_clk; 68 struct clk *vpll_clk;
50 struct clk *grf_clk; 69 struct clk *grf_clk;
51 struct dw_hdmi *hdmi; 70 struct dw_hdmi *hdmi;
71 struct phy *phy;
52}; 72};
53 73
54#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) 74#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
@@ -245,6 +265,9 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
245 u32 val; 265 u32 val;
246 int ret; 266 int ret;
247 267
268 if (hdmi->chip_data->lcdsel_grf_reg < 0)
269 return;
270
248 ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); 271 ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
249 if (ret) 272 if (ret)
250 val = hdmi->chip_data->lcdsel_lit; 273 val = hdmi->chip_data->lcdsel_lit;
@@ -287,6 +310,66 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun
287 .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, 310 .atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
288}; 311};
289 312
313static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
314 struct drm_display_mode *mode)
315{
316 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
317
318 return phy_power_on(hdmi->phy);
319}
320
321static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
322{
323 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
324
325 phy_power_off(hdmi->phy);
326}
327
328static enum drm_connector_status
329dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
330{
331 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
332 enum drm_connector_status status;
333
334 status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
335
336 if (status == connector_status_connected)
337 regmap_write(hdmi->regmap,
338 RK3328_GRF_SOC_CON4,
339 HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,
340 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));
341 else
342 regmap_write(hdmi->regmap,
343 RK3328_GRF_SOC_CON4,
344 HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |
345 RK3328_HDMI_SCL_5V));
346 return status;
347}
348
349static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
350{
351 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
352
353 dw_hdmi_phy_setup_hpd(dw_hdmi, data);
354
355 /* Enable and map pins to 3V grf-controlled io-voltage */
356 regmap_write(hdmi->regmap,
357 RK3328_GRF_SOC_CON4,
358 HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |
359 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |
360 RK3328_HDMI_HPD_5V));
361 regmap_write(hdmi->regmap,
362 RK3328_GRF_SOC_CON3,
363 HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |
364 RK3328_HDMI_HPD5V_GRF |
365 RK3328_HDMI_CEC5V_GRF));
366 regmap_write(hdmi->regmap,
367 RK3328_GRF_SOC_CON2,
368 HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,
369 RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |
370 RK3328_HDMI_HPD_IOE));
371}
372
290static struct rockchip_hdmi_chip_data rk3288_chip_data = { 373static struct rockchip_hdmi_chip_data rk3288_chip_data = {
291 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, 374 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
292 .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL), 375 .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
@@ -301,6 +384,29 @@ static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
301 .phy_data = &rk3288_chip_data, 384 .phy_data = &rk3288_chip_data,
302}; 385};
303 386
387static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
388 .init = dw_hdmi_rockchip_genphy_init,
389 .disable = dw_hdmi_rockchip_genphy_disable,
390 .read_hpd = dw_hdmi_rk3328_read_hpd,
391 .update_hpd = dw_hdmi_phy_update_hpd,
392 .setup_hpd = dw_hdmi_rk3328_setup_hpd,
393};
394
395static struct rockchip_hdmi_chip_data rk3328_chip_data = {
396 .lcdsel_grf_reg = -1,
397};
398
399static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
400 .mode_valid = dw_hdmi_rockchip_mode_valid,
401 .mpll_cfg = rockchip_mpll_cfg,
402 .cur_ctr = rockchip_cur_ctr,
403 .phy_config = rockchip_phy_config,
404 .phy_data = &rk3328_chip_data,
405 .phy_ops = &rk3328_hdmi_phy_ops,
406 .phy_name = "inno_dw_hdmi_phy2",
407 .phy_force_vendor = true,
408};
409
304static struct rockchip_hdmi_chip_data rk3399_chip_data = { 410static struct rockchip_hdmi_chip_data rk3399_chip_data = {
305 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, 411 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
306 .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), 412 .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
@@ -319,6 +425,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
319 { .compatible = "rockchip,rk3288-dw-hdmi", 425 { .compatible = "rockchip,rk3288-dw-hdmi",
320 .data = &rk3288_hdmi_drv_data 426 .data = &rk3288_hdmi_drv_data
321 }, 427 },
428 { .compatible = "rockchip,rk3328-dw-hdmi",
429 .data = &rk3328_hdmi_drv_data
430 },
322 { .compatible = "rockchip,rk3399-dw-hdmi", 431 { .compatible = "rockchip,rk3399-dw-hdmi",
323 .data = &rk3399_hdmi_drv_data 432 .data = &rk3399_hdmi_drv_data
324 }, 433 },
@@ -330,7 +439,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
330 void *data) 439 void *data)
331{ 440{
332 struct platform_device *pdev = to_platform_device(dev); 441 struct platform_device *pdev = to_platform_device(dev);
333 const struct dw_hdmi_plat_data *plat_data; 442 struct dw_hdmi_plat_data *plat_data;
334 const struct of_device_id *match; 443 const struct of_device_id *match;
335 struct drm_device *drm = data; 444 struct drm_device *drm = data;
336 struct drm_encoder *encoder; 445 struct drm_encoder *encoder;
@@ -345,9 +454,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
345 return -ENOMEM; 454 return -ENOMEM;
346 455
347 match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); 456 match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
348 plat_data = match->data; 457 plat_data = devm_kmemdup(&pdev->dev, match->data,
458 sizeof(*plat_data), GFP_KERNEL);
459 if (!plat_data)
460 return -ENOMEM;
461
349 hdmi->dev = &pdev->dev; 462 hdmi->dev = &pdev->dev;
350 hdmi->chip_data = plat_data->phy_data; 463 hdmi->chip_data = plat_data->phy_data;
464 plat_data->phy_data = hdmi;
351 encoder = &hdmi->encoder; 465 encoder = &hdmi->encoder;
352 466
353 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 467 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
@@ -373,6 +487,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
373 return ret; 487 return ret;
374 } 488 }
375 489
490 hdmi->phy = devm_phy_optional_get(dev, "hdmi");
491 if (IS_ERR(hdmi->phy)) {
492 ret = PTR_ERR(hdmi->phy);
493 if (ret != -EPROBE_DEFER)
494 DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
495 return ret;
496 }
497
376 drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); 498 drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
377 drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, 499 drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
378 DRM_MODE_ENCODER_TMDS, NULL); 500 DRM_MODE_ENCODER_TMDS, NULL);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 941f35233b1f..37f9a3b651ab 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -489,7 +489,7 @@ static int __init rockchip_drm_init(void)
489 ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); 489 ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
490 ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, 490 ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
491 CONFIG_ROCKCHIP_DW_HDMI); 491 CONFIG_ROCKCHIP_DW_HDMI);
492 ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver, 492 ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver,
493 CONFIG_ROCKCHIP_DW_MIPI_DSI); 493 CONFIG_ROCKCHIP_DW_MIPI_DSI);
494 ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); 494 ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
495 495
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 21a023a97bb8..ce48568ec8a0 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -37,6 +37,7 @@ struct rockchip_crtc_state {
37 int output_type; 37 int output_type;
38 int output_mode; 38 int output_mode;
39 int output_bpc; 39 int output_bpc;
40 int output_flags;
40}; 41};
41#define to_rockchip_crtc_state(s) \ 42#define to_rockchip_crtc_state(s) \
42 container_of(s, struct rockchip_crtc_state, base) 43 container_of(s, struct rockchip_crtc_state, base)
@@ -67,7 +68,7 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
67int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); 68int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
68extern struct platform_driver cdn_dp_driver; 69extern struct platform_driver cdn_dp_driver;
69extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; 70extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
70extern struct platform_driver dw_mipi_dsi_driver; 71extern struct platform_driver dw_mipi_dsi_rockchip_driver;
71extern struct platform_driver inno_hdmi_driver; 72extern struct platform_driver inno_hdmi_driver;
72extern struct platform_driver rockchip_dp_driver; 73extern struct platform_driver rockchip_dp_driver;
73extern struct platform_driver rockchip_lvds_driver; 74extern struct platform_driver rockchip_lvds_driver;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index 79d00d861a31..01ff3c858875 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -189,12 +189,14 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
189int rockchip_drm_psr_register(struct drm_encoder *encoder, 189int rockchip_drm_psr_register(struct drm_encoder *encoder,
190 int (*psr_set)(struct drm_encoder *, bool enable)) 190 int (*psr_set)(struct drm_encoder *, bool enable))
191{ 191{
192 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private; 192 struct rockchip_drm_private *drm_drv;
193 struct psr_drv *psr; 193 struct psr_drv *psr;
194 194
195 if (!encoder || !psr_set) 195 if (!encoder || !psr_set)
196 return -EINVAL; 196 return -EINVAL;
197 197
198 drm_drv = encoder->dev->dev_private;
199
198 psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL); 200 psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
199 if (!psr) 201 if (!psr)
200 return -ENOMEM; 202 return -ENOMEM;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 0c35a88e33dd..fb70fb486fbf 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -916,6 +916,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
916 pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? 916 pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
917 BIT(VSYNC_POSITIVE) : 0; 917 BIT(VSYNC_POSITIVE) : 0;
918 VOP_REG_SET(vop, output, pin_pol, pin_pol); 918 VOP_REG_SET(vop, output, pin_pol, pin_pol);
919 VOP_REG_SET(vop, output, mipi_dual_channel_en, 0);
919 920
920 switch (s->output_type) { 921 switch (s->output_type) {
921 case DRM_MODE_CONNECTOR_LVDS: 922 case DRM_MODE_CONNECTOR_LVDS:
@@ -933,6 +934,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
933 case DRM_MODE_CONNECTOR_DSI: 934 case DRM_MODE_CONNECTOR_DSI:
934 VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol); 935 VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
935 VOP_REG_SET(vop, output, mipi_en, 1); 936 VOP_REG_SET(vop, output, mipi_en, 1);
937 VOP_REG_SET(vop, output, mipi_dual_channel_en,
938 !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL));
936 break; 939 break;
937 case DRM_MODE_CONNECTOR_DisplayPort: 940 case DRM_MODE_CONNECTOR_DisplayPort:
938 pin_pol &= ~BIT(DCLK_INVERT); 941 pin_pol &= ~BIT(DCLK_INVERT);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index fd5765dfd637..0fe40e1983d9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -60,6 +60,7 @@ struct vop_output {
60 struct vop_reg edp_en; 60 struct vop_reg edp_en;
61 struct vop_reg hdmi_en; 61 struct vop_reg hdmi_en;
62 struct vop_reg mipi_en; 62 struct vop_reg mipi_en;
63 struct vop_reg mipi_dual_channel_en;
63 struct vop_reg rgb_en; 64 struct vop_reg rgb_en;
64}; 65};
65 66
@@ -214,6 +215,9 @@ struct vop_data {
214/* for use special outface */ 215/* for use special outface */
215#define ROCKCHIP_OUT_MODE_AAAA 15 216#define ROCKCHIP_OUT_MODE_AAAA 15
216 217
218/* output flags */
219#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
220
217enum alpha_mode { 221enum alpha_mode {
218 ALPHA_STRAIGHT, 222 ALPHA_STRAIGHT,
219 ALPHA_INVERSE, 223 ALPHA_INVERSE,
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index a6db3cd5544b..08fc40af52c8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -361,7 +361,11 @@ static const struct vop_win_data rk3188_vop_win_data[] = {
361}; 361};
362 362
363static const int rk3188_vop_intrs[] = { 363static const int rk3188_vop_intrs[] = {
364 0, 364 /*
365 * hs_start interrupt fires at frame-start, so serves
366 * the same purpose as dsp_hold in the driver.
367 */
368 DSP_HOLD_VALID_INTR,
365 FS_INTR, 369 FS_INTR,
366 LINE_FLAG_INTR, 370 LINE_FLAG_INTR,
367 BUS_ERROR_INTR, 371 BUS_ERROR_INTR,
@@ -630,6 +634,7 @@ static const struct vop_output rk3399_output = {
630 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), 634 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
631 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), 635 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
632 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), 636 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
637 .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
633}; 638};
634 639
635static const struct vop_data rk3399_vop_big = { 640static const struct vop_data rk3399_vop_big = {
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 9fc349fa18e9..383d8d6c5847 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1 +1,4 @@
1obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o 1test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
2 test-drm_format.o test-drm_framebuffer.o
3
4obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
diff --git a/drivers/gpu/drm/selftests/drm_helper_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 9771290ed228..92601defd8f6 100644
--- a/drivers/gpu/drm/selftests/drm_helper_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -7,3 +7,7 @@
7 * Tests are executed in order by igt/drm_selftests_helper 7 * Tests are executed in order by igt/drm_selftests_helper
8 */ 8 */
9selftest(check_plane_state, igt_check_plane_state) 9selftest(check_plane_state, igt_check_plane_state)
10selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
11selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
12selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
13selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/selftests/test-drm_format.c
new file mode 100644
index 000000000000..c5e212afa27a
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_format.c
@@ -0,0 +1,280 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Test cases for the drm_format functions
4 */
5
6#define pr_fmt(fmt) "drm_format: " fmt
7
8#include <linux/errno.h>
9#include <linux/kernel.h>
10
11#include <drm/drm_fourcc.h>
12
13#include "test-drm_modeset_common.h"
14
15int igt_check_drm_format_block_width(void *ignored)
16{
17 const struct drm_format_info *info = NULL;
18
19 /* Test invalid arguments */
20 FAIL_ON(drm_format_info_block_width(info, 0) != 0);
21 FAIL_ON(drm_format_info_block_width(info, -1) != 0);
22 FAIL_ON(drm_format_info_block_width(info, 1) != 0);
23
24 /* Test 1 plane format */
25 info = drm_format_info(DRM_FORMAT_XRGB4444);
26 FAIL_ON(!info);
27 FAIL_ON(drm_format_info_block_width(info, 0) != 1);
28 FAIL_ON(drm_format_info_block_width(info, 1) != 0);
29 FAIL_ON(drm_format_info_block_width(info, -1) != 0);
30
31 /* Test 2 planes format */
32 info = drm_format_info(DRM_FORMAT_NV12);
33 FAIL_ON(!info);
34 FAIL_ON(drm_format_info_block_width(info, 0) != 1);
35 FAIL_ON(drm_format_info_block_width(info, 1) != 1);
36 FAIL_ON(drm_format_info_block_width(info, 2) != 0);
37 FAIL_ON(drm_format_info_block_width(info, -1) != 0);
38
39 /* Test 3 planes format */
40 info = drm_format_info(DRM_FORMAT_YUV422);
41 FAIL_ON(!info);
42 FAIL_ON(drm_format_info_block_width(info, 0) != 1);
43 FAIL_ON(drm_format_info_block_width(info, 1) != 1);
44 FAIL_ON(drm_format_info_block_width(info, 2) != 1);
45 FAIL_ON(drm_format_info_block_width(info, 3) != 0);
46 FAIL_ON(drm_format_info_block_width(info, -1) != 0);
47
48 /* Test a tiled format */
49 info = drm_format_info(DRM_FORMAT_X0L0);
50 FAIL_ON(!info);
51 FAIL_ON(drm_format_info_block_width(info, 0) != 2);
52 FAIL_ON(drm_format_info_block_width(info, 1) != 0);
53 FAIL_ON(drm_format_info_block_width(info, -1) != 0);
54
55 return 0;
56}
57
58int igt_check_drm_format_block_height(void *ignored)
59{
60 const struct drm_format_info *info = NULL;
61
62 /* Test invalid arguments */
63 FAIL_ON(drm_format_info_block_height(info, 0) != 0);
64 FAIL_ON(drm_format_info_block_height(info, -1) != 0);
65 FAIL_ON(drm_format_info_block_height(info, 1) != 0);
66
67 /* Test 1 plane format */
68 info = drm_format_info(DRM_FORMAT_XRGB4444);
69 FAIL_ON(!info);
70 FAIL_ON(drm_format_info_block_height(info, 0) != 1);
71 FAIL_ON(drm_format_info_block_height(info, 1) != 0);
72 FAIL_ON(drm_format_info_block_height(info, -1) != 0);
73
74 /* Test 2 planes format */
75 info = drm_format_info(DRM_FORMAT_NV12);
76 FAIL_ON(!info);
77 FAIL_ON(drm_format_info_block_height(info, 0) != 1);
78 FAIL_ON(drm_format_info_block_height(info, 1) != 1);
79 FAIL_ON(drm_format_info_block_height(info, 2) != 0);
80 FAIL_ON(drm_format_info_block_height(info, -1) != 0);
81
82 /* Test 3 planes format */
83 info = drm_format_info(DRM_FORMAT_YUV422);
84 FAIL_ON(!info);
85 FAIL_ON(drm_format_info_block_height(info, 0) != 1);
86 FAIL_ON(drm_format_info_block_height(info, 1) != 1);
87 FAIL_ON(drm_format_info_block_height(info, 2) != 1);
88 FAIL_ON(drm_format_info_block_height(info, 3) != 0);
89 FAIL_ON(drm_format_info_block_height(info, -1) != 0);
90
91 /* Test a tiled format */
92 info = drm_format_info(DRM_FORMAT_X0L0);
93 FAIL_ON(!info);
94 FAIL_ON(drm_format_info_block_height(info, 0) != 2);
95 FAIL_ON(drm_format_info_block_height(info, 1) != 0);
96 FAIL_ON(drm_format_info_block_height(info, -1) != 0);
97
98 return 0;
99}
100
101int igt_check_drm_format_min_pitch(void *ignored)
102{
103 const struct drm_format_info *info = NULL;
104
105 /* Test invalid arguments */
106 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
107 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
108 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
109
110 /* Test 1 plane 8 bits per pixel format */
111 info = drm_format_info(DRM_FORMAT_RGB332);
112 FAIL_ON(!info);
113 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
114 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
115 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
116
117 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
118 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
119 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
120 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
121 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
122 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
123 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
124 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
125 (uint64_t)UINT_MAX);
126 FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
127 (uint64_t)(UINT_MAX - 1));
128
129 /* Test 1 plane 16 bits per pixel format */
130 info = drm_format_info(DRM_FORMAT_XRGB4444);
131 FAIL_ON(!info);
132 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
133 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
134 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
135
136 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
137 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
138 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
139 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
140 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
141 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
142 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
143 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
144 (uint64_t)UINT_MAX * 2);
145 FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
146 (uint64_t)(UINT_MAX - 1) * 2);
147
148 /* Test 1 plane 24 bits per pixel format */
149 info = drm_format_info(DRM_FORMAT_RGB888);
150 FAIL_ON(!info);
151 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
152 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
153 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
154
155 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 3);
156 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 6);
157 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1920);
158 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 3072);
159 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 5760);
160 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 12288);
161 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2013);
162 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
163 (uint64_t)UINT_MAX * 3);
164 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
165 (uint64_t)(UINT_MAX - 1) * 3);
166
167 /* Test 1 plane 32 bits per pixel format */
168 info = drm_format_info(DRM_FORMAT_ABGR8888);
169 FAIL_ON(!info);
170 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
171 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
172 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
173
174 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 4);
175 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 8);
176 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 2560);
177 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 4096);
178 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 7680);
179 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 16384);
180 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2684);
181 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
182 (uint64_t)UINT_MAX * 4);
183 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
184 (uint64_t)(UINT_MAX - 1) * 4);
185
186 /* Test 2 planes format */
187 info = drm_format_info(DRM_FORMAT_NV12);
188 FAIL_ON(!info);
189 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
190 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
191 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
192 FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
193
194 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
195 FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
196 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
197 FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
198 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
199 FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 640);
200 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
201 FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 1024);
202 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
203 FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 1920);
204 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
205 FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 4096);
206 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
207 FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 672);
208 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
209 (uint64_t)UINT_MAX);
210 FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
211 (uint64_t)UINT_MAX + 1);
212 FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
213 (uint64_t)(UINT_MAX - 1));
214 FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
215 (uint64_t)(UINT_MAX - 1));
216
217 /* Test 3 planes 8 bits per pixel format */
218 info = drm_format_info(DRM_FORMAT_YUV422);
219 FAIL_ON(!info);
220 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
221 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
222 FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
223 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
224 FAIL_ON(drm_format_info_min_pitch(info, 3, 0) != 0);
225
226 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
227 FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 1);
228 FAIL_ON(drm_format_info_min_pitch(info, 2, 1) != 1);
229 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
230 FAIL_ON(drm_format_info_min_pitch(info, 1, 2) != 2);
231 FAIL_ON(drm_format_info_min_pitch(info, 2, 2) != 2);
232 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
233 FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 320);
234 FAIL_ON(drm_format_info_min_pitch(info, 2, 320) != 320);
235 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
236 FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 512);
237 FAIL_ON(drm_format_info_min_pitch(info, 2, 512) != 512);
238 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
239 FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 960);
240 FAIL_ON(drm_format_info_min_pitch(info, 2, 960) != 960);
241 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
242 FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 2048);
243 FAIL_ON(drm_format_info_min_pitch(info, 2, 2048) != 2048);
244 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
245 FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 336);
246 FAIL_ON(drm_format_info_min_pitch(info, 2, 336) != 336);
247 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
248 (uint64_t)UINT_MAX);
249 FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
250 (uint64_t)UINT_MAX / 2 + 1);
251 FAIL_ON(drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
252 (uint64_t)UINT_MAX / 2 + 1);
253 FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
254 (uint64_t)(UINT_MAX - 1) / 2);
255 FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
256 (uint64_t)(UINT_MAX - 1) / 2);
257 FAIL_ON(drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
258 (uint64_t)(UINT_MAX - 1) / 2);
259
260 /* Test tiled format */
261 info = drm_format_info(DRM_FORMAT_X0L2);
262 FAIL_ON(!info);
263 FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
264 FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
265 FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
266
267 FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
268 FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
269 FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
270 FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
271 FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
272 FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
273 FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
274 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
275 (uint64_t)UINT_MAX * 2);
276 FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
277 (uint64_t)(UINT_MAX - 1) * 2);
278
279 return 0;
280}
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
new file mode 100644
index 000000000000..a04d02dacce2
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
@@ -0,0 +1,346 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Test cases for the drm_framebuffer functions
4 */
5
6#include <drm/drmP.h>
7#include "../drm_crtc_internal.h"
8
9#include "test-drm_modeset_common.h"
10
11#define MIN_WIDTH 4
12#define MAX_WIDTH 4096
13#define MIN_HEIGHT 4
14#define MAX_HEIGHT 4096
15
16struct drm_framebuffer_test {
17 int buffer_created;
18 struct drm_mode_fb_cmd2 cmd;
19 const char *name;
20};
21
22static struct drm_framebuffer_test createbuffer_tests[] = {
23{ .buffer_created = 1, .name = "ABGR8888 normal sizes",
24 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
25 .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
26 }
27},
28{ .buffer_created = 1, .name = "ABGR8888 max sizes",
29 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
30 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
31 }
32},
33{ .buffer_created = 1, .name = "ABGR8888 pitch greater than min required",
34 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
35 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH + 1, 0, 0 },
36 }
37},
38{ .buffer_created = 0, .name = "ABGR8888 pitch less than min required",
39 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
40 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH - 1, 0, 0 },
41 }
42},
43{ .buffer_created = 0, .name = "ABGR8888 Invalid width",
44 .cmd = { .width = MAX_WIDTH + 1, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
45 .handles = { 1, 0, 0 }, .pitches = { 4 * (MAX_WIDTH + 1), 0, 0 },
46 }
47},
48{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer handle",
49 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
50 .handles = { 0, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
51 }
52},
53{ .buffer_created = 0, .name = "No pixel format",
54 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = 0,
55 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
56 }
57},
58{ .buffer_created = 0, .name = "ABGR8888 Width 0",
59 .cmd = { .width = 0, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
60 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
61 }
62},
63{ .buffer_created = 0, .name = "ABGR8888 Height 0",
64 .cmd = { .width = MAX_WIDTH, .height = 0, .pixel_format = DRM_FORMAT_ABGR8888,
65 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
66 }
67},
68{ .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination",
69 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
70 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
71 }
72},
73{ .buffer_created = 1, .name = "ABGR8888 Large buffer offset",
74 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
75 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
76 }
77},
78{ .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
79 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
80 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
81 .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
82 }
83},
84{ .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier",
85 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
86 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
87 .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 },
88 }
89},
90{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
91 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
92 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
93 .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
94 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
95 }
96},
97{ .buffer_created = 1, .name = "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
98 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
99 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
100 .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
101 }
102},
103{ .buffer_created = 0, .name = "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
104 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
105 .handles = { 1, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
106 .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
107 }
108},
109{ .buffer_created = 1, .name = "NV12 Normal sizes",
110 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
111 .handles = { 1, 1, 0 }, .pitches = { 600, 600, 0 },
112 }
113},
114{ .buffer_created = 1, .name = "NV12 Max sizes",
115 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
116 .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
117 }
118},
119{ .buffer_created = 0, .name = "NV12 Invalid pitch",
120 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
121 .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH - 1, 0 },
122 }
123},
124{ .buffer_created = 0, .name = "NV12 Invalid modifier/misssing DRM_MODE_FB_MODIFIERS flag",
125 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
126 .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
127 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
128 }
129},
130{ .buffer_created = 0, .name = "NV12 different modifier per-plane",
131 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
132 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
133 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
134 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
135 }
136},
137{ .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
138 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
139 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
140 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
141 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
142 }
143},
144{ .buffer_created = 0, .name = "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
145 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
146 .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
147 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
148 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
149 }
150},
151{ .buffer_created = 0, .name = "NV12 Modifier for inexistent plane",
152 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
153 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
154 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
155 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE },
156 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
157 }
158},
159{ .buffer_created = 0, .name = "NV12 Handle for inexistent plane",
160 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
161 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
162 }
163},
164{ .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
165 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
166 .handles = { 1, 1, 1 }, .pitches = { 600, 600, 600 },
167 }
168},
169{ .buffer_created = 1, .name = "YVU420 Normal sizes",
170 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
171 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
172 .pitches = { 600, 300, 300 },
173 }
174},
175{ .buffer_created = 1, .name = "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
176 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
177 .handles = { 1, 1, 1 }, .pitches = { 600, 300, 300 },
178 }
179},
180{ .buffer_created = 1, .name = "YVU420 Max sizes",
181 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
182 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2),
183 DIV_ROUND_UP(MAX_WIDTH, 2) },
184 }
185},
186{ .buffer_created = 0, .name = "YVU420 Invalid pitch",
187 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
188 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) - 1,
189 DIV_ROUND_UP(MAX_WIDTH, 2) },
190 }
191},
192{ .buffer_created = 1, .name = "YVU420 Different pitches",
193 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
194 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1,
195 DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
196 }
197},
198{ .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches",
199 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
200 .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH + MAX_WIDTH * MAX_HEIGHT,
201 MAX_WIDTH + 2 * MAX_WIDTH * MAX_HEIGHT },
202 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
203 }
204},
205{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
206 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
207 .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
208 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
209 }
210},
211{ .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS",
212 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
213 .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
214 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
215 }
216},
217{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS",
218 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
219 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
220 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
221 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
222 }
223},
224{ .buffer_created = 1, .name = "YVU420 Valid modifier",
225 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
226 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
227 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE },
228 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
229 }
230},
231{ .buffer_created = 0, .name = "YVU420 Different modifiers per plane",
232 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
233 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
234 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR,
235 AFBC_FORMAT_MOD_SPARSE },
236 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
237 }
238},
239{ .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane",
240 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
241 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
242 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE,
243 AFBC_FORMAT_MOD_SPARSE },
244 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
245 }
246},
247{ .buffer_created = 1, .name = "X0L2 Normal sizes",
248 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_X0L2,
249 .handles = { 1, 0, 0 }, .pitches = { 1200, 0, 0 }
250 }
251},
252{ .buffer_created = 1, .name = "X0L2 Max sizes",
253 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
254 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH, 0, 0 }
255 }
256},
257{ .buffer_created = 0, .name = "X0L2 Invalid pitch",
258 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
259 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH - 1, 0, 0 }
260 }
261},
262{ .buffer_created = 1, .name = "X0L2 Pitch greater than minimum required",
263 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
264 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
265 }
266},
267{ .buffer_created = 0, .name = "X0L2 Handle for inexistent plane",
268 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
269 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
270 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
271 }
272},
273{ .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
274 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
275 .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 },
276 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
277 }
278},
279{ .buffer_created = 0, .name = "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
280 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
281 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
282 .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
283 }
284},
285{ .buffer_created = 1, .name = "X0L2 Valid modifier",
286 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
287 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
288 .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
289 }
290},
291{ .buffer_created = 0, .name = "X0L2 Modifier for inexistent plane",
292 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT,
293 .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 },
294 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
295 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
296 .flags = DRM_MODE_FB_MODIFIERS,
297 }
298},
299};
300
301static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
302 struct drm_file *file_priv,
303 const struct drm_mode_fb_cmd2 *mode_cmd)
304{
305 int *buffer_created = dev->dev_private;
306 *buffer_created = 1;
307 return ERR_PTR(-EINVAL);
308}
309
310static struct drm_mode_config_funcs mock_config_funcs = {
311 .fb_create = fb_create_mock,
312};
313
314static struct drm_device mock_drm_device = {
315 .mode_config = {
316 .min_width = MIN_WIDTH,
317 .max_width = MAX_WIDTH,
318 .min_height = MIN_HEIGHT,
319 .max_height = MAX_HEIGHT,
320 .allow_fb_modifiers = true,
321 .funcs = &mock_config_funcs,
322 },
323};
324
325static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
326{
327 int buffer_created = 0;
328 struct drm_framebuffer *fb;
329
330 mock_drm_device.dev_private = &buffer_created;
331 fb = drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
332 return buffer_created;
333}
334
335int igt_check_drm_framebuffer_create(void *ignored)
336{
337 int i = 0;
338
339 for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
340 FAIL(createbuffer_tests[i].buffer_created !=
341 execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
342 "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
343 }
344
345 return 0;
346}
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.c b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
new file mode 100644
index 000000000000..2a7f93774006
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
@@ -0,0 +1,32 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Common file for modeset selftests.
4 */
5
6#include <linux/module.h>
7
8#include "test-drm_modeset_common.h"
9
10#define TESTS "drm_modeset_selftests.h"
11#include "drm_selftest.h"
12
13#include "drm_selftest.c"
14
15static int __init test_drm_modeset_init(void)
16{
17 int err;
18
19 err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
20
21 return err > 0 ? 0 : err;
22}
23
24static void __exit test_drm_modeset_exit(void)
25{
26}
27
28module_init(test_drm_modeset_init);
29module_exit(test_drm_modeset_exit);
30
31MODULE_AUTHOR("Intel Corporation");
32MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
new file mode 100644
index 000000000000..d5df5bd51b05
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -0,0 +1,22 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3#ifndef __TEST_DRM_MODESET_COMMON_H__
4#define __TEST_DRM_MODESET_COMMON_H__
5
6#define FAIL(test, msg, ...) \
7 do { \
8 if (test) { \
9 pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
10 return -EINVAL; \
11 } \
12 } while (0)
13
14#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
15
16int igt_check_plane_state(void *ignored);
17int igt_check_drm_format_block_width(void *ignored);
18int igt_check_drm_format_block_height(void *ignored);
19int igt_check_drm_format_min_pitch(void *ignored);
20int igt_check_drm_framebuffer_create(void *ignored);
21
22#endif
diff --git a/drivers/gpu/drm/selftests/test-drm-helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
index a015712b43e8..0a9553f51796 100644
--- a/drivers/gpu/drm/selftests/test-drm-helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
@@ -1,27 +1,15 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Test cases for the drm_kms_helper functions 3 * Test cases for the drm_plane_helper functions
3 */ 4 */
4 5
5#define pr_fmt(fmt) "drm_kms_helper: " fmt 6#define pr_fmt(fmt) "drm_plane_helper: " fmt
6
7#include <linux/module.h>
8 7
9#include <drm/drm_atomic_helper.h> 8#include <drm/drm_atomic_helper.h>
10#include <drm/drm_plane_helper.h> 9#include <drm/drm_plane_helper.h>
11#include <drm/drm_modes.h> 10#include <drm/drm_modes.h>
12 11
13#define TESTS "drm_helper_selftests.h" 12#include "test-drm_modeset_common.h"
14#include "drm_selftest.h"
15
16#define FAIL(test, msg, ...) \
17 do { \
18 if (test) { \
19 pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
20 return -EINVAL; \
21 } \
22 } while (0)
23
24#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
25 13
26static void set_src(struct drm_plane_state *plane_state, 14static void set_src(struct drm_plane_state *plane_state,
27 unsigned src_x, unsigned src_y, 15 unsigned src_x, unsigned src_y,
@@ -85,7 +73,7 @@ static bool check_crtc_eq(struct drm_plane_state *plane_state,
85 return true; 73 return true;
86} 74}
87 75
88static int igt_check_plane_state(void *ignored) 76int igt_check_plane_state(void *ignored)
89{ 77{
90 int ret; 78 int ret;
91 79
@@ -229,19 +217,3 @@ static int igt_check_plane_state(void *ignored)
229 217
230 return 0; 218 return 0;
231} 219}
232
233#include "drm_selftest.c"
234
235static int __init test_drm_helper_init(void)
236{
237 int err;
238
239 err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
240
241 return err > 0 ? 0 : err;
242}
243
244module_init(test_drm_helper_init);
245
246MODULE_AUTHOR("Intel Corporation");
247MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 5824e6aca8f4..61c2379fba87 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -40,6 +40,8 @@ static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
40 DRM_DEBUG_DRIVER("\n"); 40 DRM_DEBUG_DRIVER("\n");
41 41
42 mixer->status = STI_MIXER_DISABLING; 42 mixer->status = STI_MIXER_DISABLING;
43
44 drm_crtc_wait_one_vblank(crtc);
43} 45}
44 46
45static int 47static int
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 57b870e1e696..bc908453ffb3 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -332,7 +332,6 @@ static void sti_cursor_destroy(struct drm_plane *drm_plane)
332{ 332{
333 DRM_DEBUG_DRIVER("\n"); 333 DRM_DEBUG_DRIVER("\n");
334 334
335 drm_plane_helper_disable(drm_plane, NULL);
336 drm_plane_cleanup(drm_plane); 335 drm_plane_cleanup(drm_plane);
337} 336}
338 337
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 6dced8abcf16..ac54e0f9caea 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -206,6 +206,8 @@ static void sti_cleanup(struct drm_device *ddev)
206 struct sti_private *private = ddev->dev_private; 206 struct sti_private *private = ddev->dev_private;
207 207
208 drm_kms_helper_poll_fini(ddev); 208 drm_kms_helper_poll_fini(ddev);
209 drm_atomic_helper_shutdown(ddev);
210 drm_mode_config_cleanup(ddev);
209 component_unbind_all(ddev->dev, ddev); 211 component_unbind_all(ddev->dev, ddev);
210 kfree(private); 212 kfree(private);
211 ddev->dev_private = NULL; 213 ddev->dev_private = NULL;
@@ -230,7 +232,7 @@ static int sti_bind(struct device *dev)
230 232
231 ret = drm_dev_register(ddev, 0); 233 ret = drm_dev_register(ddev, 0);
232 if (ret) 234 if (ret)
233 goto err_register; 235 goto err_cleanup;
234 236
235 drm_mode_config_reset(ddev); 237 drm_mode_config_reset(ddev);
236 238
@@ -238,8 +240,6 @@ static int sti_bind(struct device *dev)
238 240
239 return 0; 241 return 0;
240 242
241err_register:
242 drm_mode_config_cleanup(ddev);
243err_cleanup: 243err_cleanup:
244 sti_cleanup(ddev); 244 sti_cleanup(ddev);
245err_drm_dev_put: 245err_drm_dev_put:
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index c32de6cbf061..cff7b2b5ee9e 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -517,7 +517,7 @@ static void sti_gdp_init(struct sti_gdp *gdp)
517 /* Allocate all the nodes within a single memory page */ 517 /* Allocate all the nodes within a single memory page */
518 size = sizeof(struct sti_gdp_node) * 518 size = sizeof(struct sti_gdp_node) *
519 GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK; 519 GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
520 base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL | GFP_DMA); 520 base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL);
521 521
522 if (!base) { 522 if (!base) {
523 DRM_ERROR("Failed to allocate memory for GDP node\n"); 523 DRM_ERROR("Failed to allocate memory for GDP node\n");
@@ -883,7 +883,6 @@ static void sti_gdp_destroy(struct drm_plane *drm_plane)
883{ 883{
884 DRM_DEBUG_DRIVER("\n"); 884 DRM_DEBUG_DRIVER("\n");
885 885
886 drm_plane_helper_disable(drm_plane, NULL);
887 drm_plane_cleanup(drm_plane); 886 drm_plane_cleanup(drm_plane);
888} 887}
889 888
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 03ac3b4a4469..23565f52dd71 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1260,7 +1260,6 @@ static void sti_hqvdp_destroy(struct drm_plane *drm_plane)
1260{ 1260{
1261 DRM_DEBUG_DRIVER("\n"); 1261 DRM_DEBUG_DRIVER("\n");
1262 1262
1263 drm_plane_helper_disable(drm_plane, NULL);
1264 drm_plane_cleanup(drm_plane); 1263 drm_plane_cleanup(drm_plane);
1265} 1264}
1266 1265
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index f2021b23554d..8dec001b9d37 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -26,7 +26,6 @@
26 26
27static const struct drm_mode_config_funcs drv_mode_config_funcs = { 27static const struct drm_mode_config_funcs drv_mode_config_funcs = {
28 .fb_create = drm_gem_fb_create, 28 .fb_create = drm_gem_fb_create,
29 .output_poll_changed = drm_fb_helper_output_poll_changed,
30 .atomic_check = drm_atomic_helper_check, 29 .atomic_check = drm_atomic_helper_check,
31 .atomic_commit = drm_atomic_helper_commit, 30 .atomic_commit = drm_atomic_helper_commit,
32}; 31};
@@ -52,7 +51,6 @@ DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
52static struct drm_driver drv_driver = { 51static struct drm_driver drv_driver = {
53 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 52 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
54 DRIVER_ATOMIC, 53 DRIVER_ATOMIC,
55 .lastclose = drm_fb_helper_lastclose,
56 .name = "stm", 54 .name = "stm",
57 .desc = "STMicroelectronics SoC DRM", 55 .desc = "STMicroelectronics SoC DRM",
58 .date = "20170330", 56 .date = "20170330",
@@ -72,6 +70,8 @@ static struct drm_driver drv_driver = {
72 .gem_prime_vmap = drm_gem_cma_prime_vmap, 70 .gem_prime_vmap = drm_gem_cma_prime_vmap,
73 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 71 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
74 .gem_prime_mmap = drm_gem_cma_prime_mmap, 72 .gem_prime_mmap = drm_gem_cma_prime_mmap,
73 .get_scanout_position = ltdc_crtc_scanoutpos,
74 .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
75}; 75};
76 76
77static int drv_load(struct drm_device *ddev) 77static int drv_load(struct drm_device *ddev)
@@ -108,12 +108,6 @@ static int drv_load(struct drm_device *ddev)
108 drm_mode_config_reset(ddev); 108 drm_mode_config_reset(ddev);
109 drm_kms_helper_poll_init(ddev); 109 drm_kms_helper_poll_init(ddev);
110 110
111 if (ddev->mode_config.num_connector) {
112 ret = drm_fb_cma_fbdev_init(ddev, 16, 0);
113 if (ret)
114 DRM_DEBUG("Warning: fails to create fbdev\n");
115 }
116
117 platform_set_drvdata(pdev, ddev); 111 platform_set_drvdata(pdev, ddev);
118 112
119 return 0; 113 return 0;
@@ -126,7 +120,6 @@ static void drv_unload(struct drm_device *ddev)
126{ 120{
127 DRM_DEBUG("%s\n", __func__); 121 DRM_DEBUG("%s\n", __func__);
128 122
129 drm_fb_cma_fbdev_fini(ddev);
130 drm_kms_helper_poll_fini(ddev); 123 drm_kms_helper_poll_fini(ddev);
131 ltdc_unload(ddev); 124 ltdc_unload(ddev);
132 drm_mode_config_cleanup(ddev); 125 drm_mode_config_cleanup(ddev);
@@ -154,6 +147,8 @@ static int stm_drm_platform_probe(struct platform_device *pdev)
154 if (ret) 147 if (ret)
155 goto err_put; 148 goto err_put;
156 149
150 drm_fbdev_generic_setup(ddev, 16);
151
157 return 0; 152 return 0;
158 153
159err_put: 154err_put:
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 808d9fb627e9..61dd661aa0ac 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -148,6 +148,8 @@
148#define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */ 148#define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */
149#define IER_RRIE BIT(3) /* Register Reload Interrupt enable */ 149#define IER_RRIE BIT(3) /* Register Reload Interrupt enable */
150 150
151#define CPSR_CYPOS GENMASK(15, 0) /* Current Y position */
152
151#define ISR_LIF BIT(0) /* Line Interrupt Flag */ 153#define ISR_LIF BIT(0) /* Line Interrupt Flag */
152#define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */ 154#define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */
153#define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ 155#define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */
@@ -626,6 +628,49 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
626 reg_clear(ldev->regs, LTDC_IER, IER_LIE); 628 reg_clear(ldev->regs, LTDC_IER, IER_LIE);
627} 629}
628 630
631bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
632 bool in_vblank_irq, int *vpos, int *hpos,
633 ktime_t *stime, ktime_t *etime,
634 const struct drm_display_mode *mode)
635{
636 struct ltdc_device *ldev = ddev->dev_private;
637 int line, vactive_start, vactive_end, vtotal;
638
639 if (stime)
640 *stime = ktime_get();
641
642 /* The active area starts after vsync + front porch and ends
643 * at vsync + front porc + display size.
644 * The total height also include back porch.
645 * We have 3 possible cases to handle:
646 * - line < vactive_start: vpos = line - vactive_start and will be
647 * negative
648 * - vactive_start < line < vactive_end: vpos = line - vactive_start
649 * and will be positive
650 * - line > vactive_end: vpos = line - vtotal - vactive_start
651 * and will negative
652 *
653 * Computation for the two first cases are identical so we can
654 * simplify the code and only test if line > vactive_end
655 */
656 line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS;
657 vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP;
658 vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH;
659 vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH;
660
661 if (line > vactive_end)
662 *vpos = line - vtotal - vactive_start;
663 else
664 *vpos = line - vactive_start;
665
666 *hpos = 0;
667
668 if (etime)
669 *etime = ktime_get();
670
671 return true;
672}
673
629static const struct drm_crtc_funcs ltdc_crtc_funcs = { 674static const struct drm_crtc_funcs ltdc_crtc_funcs = {
630 .destroy = drm_crtc_cleanup, 675 .destroy = drm_crtc_cleanup,
631 .set_config = drm_atomic_helper_set_config, 676 .set_config = drm_atomic_helper_set_config,
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index d5afb8960867..e46f477a8494 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -38,6 +38,11 @@ struct ltdc_device {
38 struct fps_info plane_fpsi[LTDC_MAX_LAYER]; 38 struct fps_info plane_fpsi[LTDC_MAX_LAYER];
39}; 39};
40 40
41bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
42 bool in_vblank_irq, int *vpos, int *hpos,
43 ktime_t *stime, ktime_t *etime,
44 const struct drm_display_mode *mode);
45
41int ltdc_load(struct drm_device *ddev); 46int ltdc_load(struct drm_device *ddev);
42void ltdc_unload(struct drm_device *ddev); 47void ltdc_unload(struct drm_device *ddev);
43 48
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 1e41c3f5fd6d..ef773d36baf0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -34,7 +34,6 @@ static struct drm_driver sun4i_drv_driver = {
34 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, 34 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
35 35
36 /* Generic Operations */ 36 /* Generic Operations */
37 .lastclose = drm_fb_helper_lastclose,
38 .fops = &sun4i_drv_fops, 37 .fops = &sun4i_drv_fops,
39 .name = "sun4i-drm", 38 .name = "sun4i-drm",
40 .desc = "Allwinner sun4i Display Engine", 39 .desc = "Allwinner sun4i Display Engine",
@@ -105,12 +104,7 @@ static int sun4i_drv_bind(struct device *dev)
105 /* Remove early framebuffers (ie. simplefb) */ 104 /* Remove early framebuffers (ie. simplefb) */
106 drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false); 105 drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false);
107 106
108 /* Create our framebuffer */ 107 sun4i_framebuffer_init(drm);
109 ret = sun4i_framebuffer_init(drm);
110 if (ret) {
111 dev_err(drm->dev, "Couldn't create our framebuffer\n");
112 goto cleanup_mode_config;
113 }
114 108
115 /* Enable connectors polling */ 109 /* Enable connectors polling */
116 drm_kms_helper_poll_init(drm); 110 drm_kms_helper_poll_init(drm);
@@ -119,11 +113,12 @@ static int sun4i_drv_bind(struct device *dev)
119 if (ret) 113 if (ret)
120 goto finish_poll; 114 goto finish_poll;
121 115
116 drm_fbdev_generic_setup(drm, 32);
117
122 return 0; 118 return 0;
123 119
124finish_poll: 120finish_poll:
125 drm_kms_helper_poll_fini(drm); 121 drm_kms_helper_poll_fini(drm);
126 sun4i_framebuffer_free(drm);
127cleanup_mode_config: 122cleanup_mode_config:
128 drm_mode_config_cleanup(drm); 123 drm_mode_config_cleanup(drm);
129 of_reserved_mem_device_release(dev); 124 of_reserved_mem_device_release(dev);
@@ -138,7 +133,6 @@ static void sun4i_drv_unbind(struct device *dev)
138 133
139 drm_dev_unregister(drm); 134 drm_dev_unregister(drm);
140 drm_kms_helper_poll_fini(drm); 135 drm_kms_helper_poll_fini(drm);
141 sun4i_framebuffer_free(drm);
142 drm_mode_config_cleanup(drm); 136 drm_mode_config_cleanup(drm);
143 of_reserved_mem_device_release(dev); 137 of_reserved_mem_device_release(dev);
144 drm_dev_put(drm); 138 drm_dev_put(drm);
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 5f29850ef8ac..cb828028ae06 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -12,8 +12,6 @@
12 12
13#include <drm/drm_atomic.h> 13#include <drm/drm_atomic.h>
14#include <drm/drm_atomic_helper.h> 14#include <drm/drm_atomic_helper.h>
15#include <drm/drm_fb_helper.h>
16#include <drm/drm_fb_cma_helper.h>
17#include <drm/drm_gem_framebuffer_helper.h> 15#include <drm/drm_gem_framebuffer_helper.h>
18#include <drm/drmP.h> 16#include <drm/drmP.h>
19 17
@@ -37,7 +35,6 @@ static int sun4i_de_atomic_check(struct drm_device *dev,
37} 35}
38 36
39static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { 37static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
40 .output_poll_changed = drm_fb_helper_output_poll_changed,
41 .atomic_check = sun4i_de_atomic_check, 38 .atomic_check = sun4i_de_atomic_check,
42 .atomic_commit = drm_atomic_helper_commit, 39 .atomic_commit = drm_atomic_helper_commit,
43 .fb_create = drm_gem_fb_create, 40 .fb_create = drm_gem_fb_create,
@@ -47,7 +44,7 @@ static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
47 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, 44 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
48}; 45};
49 46
50int sun4i_framebuffer_init(struct drm_device *drm) 47void sun4i_framebuffer_init(struct drm_device *drm)
51{ 48{
52 drm_mode_config_reset(drm); 49 drm_mode_config_reset(drm);
53 50
@@ -56,11 +53,4 @@ int sun4i_framebuffer_init(struct drm_device *drm)
56 53
57 drm->mode_config.funcs = &sun4i_de_mode_config_funcs; 54 drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
58 drm->mode_config.helper_private = &sun4i_de_mode_config_helpers; 55 drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
59
60 return drm_fb_cma_fbdev_init(drm, 32, 0);
61}
62
63void sun4i_framebuffer_free(struct drm_device *drm)
64{
65 drm_fb_cma_fbdev_fini(drm);
66} 56}
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.h b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
index 7ef0aed8384c..6fe5bd8c4026 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
@@ -13,7 +13,6 @@
13#ifndef _SUN4I_FRAMEBUFFER_H_ 13#ifndef _SUN4I_FRAMEBUFFER_H_
14#define _SUN4I_FRAMEBUFFER_H_ 14#define _SUN4I_FRAMEBUFFER_H_
15 15
16int sun4i_framebuffer_init(struct drm_device *drm); 16void sun4i_framebuffer_init(struct drm_device *drm);
17void sun4i_framebuffer_free(struct drm_device *drm);
18 17
19#endif /* _SUN4I_FRAMEBUFFER_H_ */ 18#endif /* _SUN4I_FRAMEBUFFER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
index 3ecffa52c814..fb985ba1a176 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
@@ -35,7 +35,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate,
35{ 35{
36 unsigned long best_rate = 0; 36 unsigned long best_rate = 0;
37 u8 best_m = 0, m; 37 u8 best_m = 0, m;
38 bool is_double; 38 bool is_double = false;
39 39
40 for (m = div_offset ?: 1; m < (16 + div_offset); m++) { 40 for (m = div_offset ?: 1; m < (16 + div_offset); m++) {
41 u8 d; 41 u8 d;
@@ -52,7 +52,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate,
52 (rate - tmp_rate) < (rate - best_rate)) { 52 (rate - tmp_rate) < (rate - best_rate)) {
53 best_rate = tmp_rate; 53 best_rate = tmp_rate;
54 best_m = m; 54 best_m = m;
55 is_double = d; 55 is_double = (d == 2) ? true : false;
56 } 56 }
57 } 57 }
58 } 58 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index b14925b40ccf..e7608a72f26f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -34,6 +34,41 @@ static const u32 yvu2rgb[] = {
34 0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A, 34 0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A,
35}; 35};
36 36
37/*
38 * DE3 has a bit different CSC units. Factors are in two's complement format.
39 * First three factors in a row are multiplication factors which have 17 bits
40 * for fractional part. Fourth value in a row is comprised of two factors.
41 * Upper 16 bits represents difference, which is subtracted from the input
42 * value before multiplication and lower 16 bits represents constant, which
43 * is addes at the end.
44 *
45 * x' = c00 * (x + d0) + c01 * (y + d1) + c02 * (z + d2) + const0
46 * y' = c10 * (x + d0) + c11 * (y + d1) + c12 * (z + d2) + const1
47 * z' = c20 * (x + d0) + c21 * (y + d1) + c22 * (z + d2) + const2
48 *
49 * Please note that above formula is true only for Blender CSC. Other DE3 CSC
50 * units takes only positive value for difference. From what can be deducted
51 * from BSP driver code, those units probably automatically assume that
52 * difference has to be subtracted.
53 *
54 * Layout of factors in table:
55 * c00 c01 c02 [d0 const0]
56 * c10 c11 c12 [d1 const1]
57 * c20 c21 c22 [d2 const2]
58 */
59
60static const u32 yuv2rgb_de3[] = {
61 0x0002542a, 0x00000000, 0x0003312a, 0xffc00000,
62 0x0002542a, 0xffff376b, 0xfffe5fc3, 0xfe000000,
63 0x0002542a, 0x000408d3, 0x00000000, 0xfe000000,
64};
65
66static const u32 yvu2rgb_de3[] = {
67 0x0002542a, 0x0003312a, 0x00000000, 0xffc00000,
68 0x0002542a, 0xfffe5fc3, 0xffff376b, 0xfe000000,
69 0x0002542a, 0x00000000, 0x000408d3, 0xfe000000,
70};
71
37static void sun8i_csc_set_coefficients(struct regmap *map, u32 base, 72static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
38 enum sun8i_csc_mode mode) 73 enum sun8i_csc_mode mode)
39{ 74{
@@ -61,6 +96,28 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
61 } 96 }
62} 97}
63 98
99static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
100 enum sun8i_csc_mode mode)
101{
102 const u32 *table;
103 u32 base_reg;
104
105 switch (mode) {
106 case SUN8I_CSC_MODE_YUV2RGB:
107 table = yuv2rgb_de3;
108 break;
109 case SUN8I_CSC_MODE_YVU2RGB:
110 table = yvu2rgb_de3;
111 break;
112 default:
113 DRM_WARN("Wrong CSC mode specified.\n");
114 return;
115 }
116
117 base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0, 0);
118 regmap_bulk_write(map, base_reg, table, 12);
119}
120
64static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable) 121static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
65{ 122{
66 u32 val; 123 u32 val;
@@ -73,11 +130,32 @@ static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
73 regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val); 130 regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
74} 131}
75 132
133static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
134{
135 u32 val, mask;
136
137 mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
138
139 if (enable)
140 val = mask;
141 else
142 val = 0;
143
144 regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
145 mask, val);
146}
147
76void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer, 148void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
77 enum sun8i_csc_mode mode) 149 enum sun8i_csc_mode mode)
78{ 150{
79 u32 base; 151 u32 base;
80 152
153 if (mixer->cfg->is_de3) {
154 sun8i_de3_ccsc_set_coefficients(mixer->engine.regs,
155 layer, mode);
156 return;
157 }
158
81 base = ccsc_base[mixer->cfg->ccsc][layer]; 159 base = ccsc_base[mixer->cfg->ccsc][layer];
82 160
83 sun8i_csc_set_coefficients(mixer->engine.regs, base, mode); 161 sun8i_csc_set_coefficients(mixer->engine.regs, base, mode);
@@ -87,6 +165,11 @@ void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
87{ 165{
88 u32 base; 166 u32 base;
89 167
168 if (mixer->cfg->is_de3) {
169 sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable);
170 return;
171 }
172
90 base = ccsc_base[mixer->cfg->ccsc][layer]; 173 base = ccsc_base[mixer->cfg->ccsc][layer];
91 174
92 sun8i_csc_enable(mixer->engine.regs, base, enable); 175 sun8i_csc_enable(mixer->engine.regs, base, enable);
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
index ed2983770e9c..dc47720c99ba 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -5,6 +5,7 @@
5 5
6#include <linux/component.h> 6#include <linux/component.h>
7#include <linux/module.h> 7#include <linux/module.h>
8#include <linux/of_device.h>
8#include <linux/platform_device.h> 9#include <linux/platform_device.h>
9 10
10#include <drm/drm_of.h> 11#include <drm/drm_of.h>
@@ -20,7 +21,8 @@ static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
20{ 21{
21 struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder); 22 struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
22 23
23 clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000); 24 if (hdmi->quirks->set_rate)
25 clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
24} 26}
25 27
26static const struct drm_encoder_helper_funcs 28static const struct drm_encoder_helper_funcs
@@ -33,8 +35,8 @@ static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
33}; 35};
34 36
35static enum drm_mode_status 37static enum drm_mode_status
36sun8i_dw_hdmi_mode_valid(struct drm_connector *connector, 38sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector,
37 const struct drm_display_mode *mode) 39 const struct drm_display_mode *mode)
38{ 40{
39 if (mode->clock > 297000) 41 if (mode->clock > 297000)
40 return MODE_CLOCK_HIGH; 42 return MODE_CLOCK_HIGH;
@@ -42,6 +44,17 @@ sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
42 return MODE_OK; 44 return MODE_OK;
43} 45}
44 46
47static enum drm_mode_status
48sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector,
49 const struct drm_display_mode *mode)
50{
51 /* This is max for HDMI 2.0b (4K@60Hz) */
52 if (mode->clock > 594000)
53 return MODE_CLOCK_HIGH;
54
55 return MODE_OK;
56}
57
45static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node) 58static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node)
46{ 59{
47 return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) && 60 return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
@@ -102,6 +115,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
102 hdmi->dev = &pdev->dev; 115 hdmi->dev = &pdev->dev;
103 encoder = &hdmi->encoder; 116 encoder = &hdmi->encoder;
104 117
118 hdmi->quirks = of_device_get_match_data(dev);
119
105 encoder->possible_crtcs = 120 encoder->possible_crtcs =
106 sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node); 121 sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node);
107 /* 122 /*
@@ -168,10 +183,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
168 183
169 sun8i_hdmi_phy_init(hdmi->phy); 184 sun8i_hdmi_phy_init(hdmi->phy);
170 185
171 plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid; 186 plat_data->mode_valid = hdmi->quirks->mode_valid;
172 plat_data->phy_ops = sun8i_hdmi_phy_get_ops(); 187 sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
173 plat_data->phy_name = "sun8i_dw_hdmi_phy";
174 plat_data->phy_data = hdmi->phy;
175 188
176 platform_set_drvdata(pdev, hdmi); 189 platform_set_drvdata(pdev, hdmi);
177 190
@@ -230,8 +243,24 @@ static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
230 return 0; 243 return 0;
231} 244}
232 245
246static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = {
247 .mode_valid = sun8i_dw_hdmi_mode_valid_a83t,
248 .set_rate = true,
249};
250
251static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = {
252 .mode_valid = sun8i_dw_hdmi_mode_valid_h6,
253};
254
233static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { 255static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
234 { .compatible = "allwinner,sun8i-a83t-dw-hdmi" }, 256 {
257 .compatible = "allwinner,sun8i-a83t-dw-hdmi",
258 .data = &sun8i_a83t_quirks,
259 },
260 {
261 .compatible = "allwinner,sun50i-h6-dw-hdmi",
262 .data = &sun50i_h6_quirks,
263 },
235 { /* sentinel */ }, 264 { /* sentinel */ },
236}; 265};
237MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids); 266MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 7fdc1ecd2892..720c5aa8adc1 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -150,6 +150,10 @@ struct sun8i_hdmi_phy;
150struct sun8i_hdmi_phy_variant { 150struct sun8i_hdmi_phy_variant {
151 bool has_phy_clk; 151 bool has_phy_clk;
152 bool has_second_pll; 152 bool has_second_pll;
153 unsigned int is_custom_phy : 1;
154 const struct dw_hdmi_curr_ctrl *cur_ctr;
155 const struct dw_hdmi_mpll_config *mpll_cfg;
156 const struct dw_hdmi_phy_config *phy_cfg;
153 void (*phy_init)(struct sun8i_hdmi_phy *phy); 157 void (*phy_init)(struct sun8i_hdmi_phy *phy);
154 void (*phy_disable)(struct dw_hdmi *hdmi, 158 void (*phy_disable)(struct dw_hdmi *hdmi,
155 struct sun8i_hdmi_phy *phy); 159 struct sun8i_hdmi_phy *phy);
@@ -170,6 +174,12 @@ struct sun8i_hdmi_phy {
170 struct sun8i_hdmi_phy_variant *variant; 174 struct sun8i_hdmi_phy_variant *variant;
171}; 175};
172 176
177struct sun8i_dw_hdmi_quirks {
178 enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
179 const struct drm_display_mode *mode);
180 unsigned int set_rate : 1;
181};
182
173struct sun8i_dw_hdmi { 183struct sun8i_dw_hdmi {
174 struct clk *clk_tmds; 184 struct clk *clk_tmds;
175 struct device *dev; 185 struct device *dev;
@@ -178,6 +188,7 @@ struct sun8i_dw_hdmi {
178 struct sun8i_hdmi_phy *phy; 188 struct sun8i_hdmi_phy *phy;
179 struct dw_hdmi_plat_data plat_data; 189 struct dw_hdmi_plat_data plat_data;
180 struct regulator *regulator; 190 struct regulator *regulator;
191 const struct sun8i_dw_hdmi_quirks *quirks;
181 struct reset_control *rst_ctrl; 192 struct reset_control *rst_ctrl;
182}; 193};
183 194
@@ -191,7 +202,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
191void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi); 202void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
192 203
193void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); 204void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
194const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void); 205void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
206 struct dw_hdmi_plat_data *plat_data);
195 207
196int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev, 208int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
197 bool second_parent); 209 bool second_parent);
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 471993097ced..66ea3a902e36 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -14,6 +14,122 @@
14 */ 14 */
15#define I2C_ADDR 0x69 15#define I2C_ADDR 0x69
16 16
17static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
18 {
19 30666000, {
20 { 0x00b3, 0x0000 },
21 { 0x2153, 0x0000 },
22 { 0x40f3, 0x0000 },
23 },
24 }, {
25 36800000, {
26 { 0x00b3, 0x0000 },
27 { 0x2153, 0x0000 },
28 { 0x40a2, 0x0001 },
29 },
30 }, {
31 46000000, {
32 { 0x00b3, 0x0000 },
33 { 0x2142, 0x0001 },
34 { 0x40a2, 0x0001 },
35 },
36 }, {
37 61333000, {
38 { 0x0072, 0x0001 },
39 { 0x2142, 0x0001 },
40 { 0x40a2, 0x0001 },
41 },
42 }, {
43 73600000, {
44 { 0x0072, 0x0001 },
45 { 0x2142, 0x0001 },
46 { 0x4061, 0x0002 },
47 },
48 }, {
49 92000000, {
50 { 0x0072, 0x0001 },
51 { 0x2145, 0x0002 },
52 { 0x4061, 0x0002 },
53 },
54 }, {
55 122666000, {
56 { 0x0051, 0x0002 },
57 { 0x2145, 0x0002 },
58 { 0x4061, 0x0002 },
59 },
60 }, {
61 147200000, {
62 { 0x0051, 0x0002 },
63 { 0x2145, 0x0002 },
64 { 0x4064, 0x0003 },
65 },
66 }, {
67 184000000, {
68 { 0x0051, 0x0002 },
69 { 0x214c, 0x0003 },
70 { 0x4064, 0x0003 },
71 },
72 }, {
73 226666000, {
74 { 0x0040, 0x0003 },
75 { 0x214c, 0x0003 },
76 { 0x4064, 0x0003 },
77 },
78 }, {
79 272000000, {
80 { 0x0040, 0x0003 },
81 { 0x214c, 0x0003 },
82 { 0x5a64, 0x0003 },
83 },
84 }, {
85 340000000, {
86 { 0x0040, 0x0003 },
87 { 0x3b4c, 0x0003 },
88 { 0x5a64, 0x0003 },
89 },
90 }, {
91 594000000, {
92 { 0x1a40, 0x0003 },
93 { 0x3b4c, 0x0003 },
94 { 0x5a64, 0x0003 },
95 },
96 }, {
97 ~0UL, {
98 { 0x0000, 0x0000 },
99 { 0x0000, 0x0000 },
100 { 0x0000, 0x0000 },
101 },
102 }
103};
104
105static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = {
106 /* pixelclk bpp8 bpp10 bpp12 */
107 { 25175000, { 0x0000, 0x0000, 0x0000 }, },
108 { 27000000, { 0x0012, 0x0000, 0x0000 }, },
109 { 59400000, { 0x0008, 0x0008, 0x0008 }, },
110 { 72000000, { 0x0008, 0x0008, 0x001b }, },
111 { 74250000, { 0x0013, 0x0013, 0x0013 }, },
112 { 90000000, { 0x0008, 0x001a, 0x001b }, },
113 { 118800000, { 0x001b, 0x001a, 0x001b }, },
114 { 144000000, { 0x001b, 0x001a, 0x0034 }, },
115 { 180000000, { 0x001b, 0x0033, 0x0034 }, },
116 { 216000000, { 0x0036, 0x0033, 0x0034 }, },
117 { 237600000, { 0x0036, 0x0033, 0x001b }, },
118 { 288000000, { 0x0036, 0x001b, 0x001b }, },
119 { 297000000, { 0x0019, 0x001b, 0x0019 }, },
120 { 330000000, { 0x0036, 0x001b, 0x001b }, },
121 { 594000000, { 0x003f, 0x001b, 0x001b }, },
122 { ~0UL, { 0x0000, 0x0000, 0x0000 }, }
123};
124
125static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
126 /*pixelclk symbol term vlev*/
127 { 74250000, 0x8009, 0x0004, 0x0232},
128 { 148500000, 0x8029, 0x0004, 0x0273},
129 { 594000000, 0x8039, 0x0004, 0x014a},
130 { ~0UL, 0x0000, 0x0000, 0x0000}
131};
132
17static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi, 133static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
18 struct sun8i_hdmi_phy *phy, 134 struct sun8i_hdmi_phy *phy,
19 unsigned int clk_rate) 135 unsigned int clk_rate)
@@ -279,8 +395,31 @@ static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
279 .setup_hpd = &dw_hdmi_phy_setup_hpd, 395 .setup_hpd = &dw_hdmi_phy_setup_hpd,
280}; 396};
281 397
398static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy)
399{
400 /* enable read access to HDMI controller */
401 regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
402 SUN8I_HDMI_PHY_READ_EN_MAGIC);
403
404 /* unscramble register offsets */
405 regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
406 SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
407}
408
409static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy)
410{
411 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
412 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
413 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
414
415 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
416 0xffff0000, 0x80c00000);
417}
418
282static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) 419static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
283{ 420{
421 sun8i_hdmi_phy_unlock(phy);
422
284 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, 423 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
285 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK, 424 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
286 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK); 425 SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
@@ -298,6 +437,8 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
298{ 437{
299 unsigned int val; 438 unsigned int val;
300 439
440 sun8i_hdmi_phy_unlock(phy);
441
301 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0); 442 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
302 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 443 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
303 SUN8I_HDMI_PHY_ANA_CFG1_ENBI, 444 SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
@@ -372,20 +513,23 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
372 513
373void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) 514void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
374{ 515{
375 /* enable read access to HDMI controller */
376 regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
377 SUN8I_HDMI_PHY_READ_EN_MAGIC);
378
379 /* unscramble register offsets */
380 regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
381 SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
382
383 phy->variant->phy_init(phy); 516 phy->variant->phy_init(phy);
384} 517}
385 518
386const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void) 519void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
520 struct dw_hdmi_plat_data *plat_data)
387{ 521{
388 return &sun8i_hdmi_phy_ops; 522 struct sun8i_hdmi_phy_variant *variant = phy->variant;
523
524 if (variant->is_custom_phy) {
525 plat_data->phy_ops = &sun8i_hdmi_phy_ops;
526 plat_data->phy_name = "sun8i_dw_hdmi_phy";
527 plat_data->phy_data = phy;
528 } else {
529 plat_data->mpll_cfg = variant->mpll_cfg;
530 plat_data->cur_ctr = variant->cur_ctr;
531 plat_data->phy_config = variant->phy_cfg;
532 }
389} 533}
390 534
391static struct regmap_config sun8i_hdmi_phy_regmap_config = { 535static struct regmap_config sun8i_hdmi_phy_regmap_config = {
@@ -396,14 +540,8 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
396 .name = "phy" 540 .name = "phy"
397}; 541};
398 542
399static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
400 .has_phy_clk = true,
401 .phy_init = &sun8i_hdmi_phy_init_h3,
402 .phy_disable = &sun8i_hdmi_phy_disable_h3,
403 .phy_config = &sun8i_hdmi_phy_config_h3,
404};
405
406static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { 543static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
544 .is_custom_phy = true,
407 .phy_init = &sun8i_hdmi_phy_init_a83t, 545 .phy_init = &sun8i_hdmi_phy_init_a83t,
408 .phy_disable = &sun8i_hdmi_phy_disable_a83t, 546 .phy_disable = &sun8i_hdmi_phy_disable_a83t,
409 .phy_config = &sun8i_hdmi_phy_config_a83t, 547 .phy_config = &sun8i_hdmi_phy_config_a83t,
@@ -411,6 +549,7 @@ static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
411 549
412static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { 550static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
413 .has_phy_clk = true, 551 .has_phy_clk = true,
552 .is_custom_phy = true,
414 .phy_init = &sun8i_hdmi_phy_init_h3, 553 .phy_init = &sun8i_hdmi_phy_init_h3,
415 .phy_disable = &sun8i_hdmi_phy_disable_h3, 554 .phy_disable = &sun8i_hdmi_phy_disable_h3,
416 .phy_config = &sun8i_hdmi_phy_config_h3, 555 .phy_config = &sun8i_hdmi_phy_config_h3,
@@ -419,17 +558,29 @@ static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
419static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = { 558static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
420 .has_phy_clk = true, 559 .has_phy_clk = true,
421 .has_second_pll = true, 560 .has_second_pll = true,
561 .is_custom_phy = true,
562 .phy_init = &sun8i_hdmi_phy_init_h3,
563 .phy_disable = &sun8i_hdmi_phy_disable_h3,
564 .phy_config = &sun8i_hdmi_phy_config_h3,
565};
566
567static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
568 .has_phy_clk = true,
569 .is_custom_phy = true,
422 .phy_init = &sun8i_hdmi_phy_init_h3, 570 .phy_init = &sun8i_hdmi_phy_init_h3,
423 .phy_disable = &sun8i_hdmi_phy_disable_h3, 571 .phy_disable = &sun8i_hdmi_phy_disable_h3,
424 .phy_config = &sun8i_hdmi_phy_config_h3, 572 .phy_config = &sun8i_hdmi_phy_config_h3,
425}; 573};
426 574
575static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
576 .cur_ctr = sun50i_h6_cur_ctr,
577 .mpll_cfg = sun50i_h6_mpll_cfg,
578 .phy_cfg = sun50i_h6_phy_config,
579 .phy_init = &sun50i_hdmi_phy_init_h6,
580};
581
427static const struct of_device_id sun8i_hdmi_phy_of_table[] = { 582static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
428 { 583 {
429 .compatible = "allwinner,sun50i-a64-hdmi-phy",
430 .data = &sun50i_a64_hdmi_phy,
431 },
432 {
433 .compatible = "allwinner,sun8i-a83t-hdmi-phy", 584 .compatible = "allwinner,sun8i-a83t-hdmi-phy",
434 .data = &sun8i_a83t_hdmi_phy, 585 .data = &sun8i_a83t_hdmi_phy,
435 }, 586 },
@@ -441,6 +592,14 @@ static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
441 .compatible = "allwinner,sun8i-r40-hdmi-phy", 592 .compatible = "allwinner,sun8i-r40-hdmi-phy",
442 .data = &sun8i_r40_hdmi_phy, 593 .data = &sun8i_r40_hdmi_phy,
443 }, 594 },
595 {
596 .compatible = "allwinner,sun50i-a64-hdmi-phy",
597 .data = &sun50i_a64_hdmi_phy,
598 },
599 {
600 .compatible = "allwinner,sun50i-h6-hdmi-phy",
601 .data = &sun50i_h6_hdmi_phy,
602 },
444 { /* sentinel */ } 603 { /* sentinel */ }
445}; 604};
446 605
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 8b3d02b146b7..44a9ba7d8433 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -368,6 +368,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
368 struct sun8i_mixer *mixer; 368 struct sun8i_mixer *mixer;
369 struct resource *res; 369 struct resource *res;
370 void __iomem *regs; 370 void __iomem *regs;
371 unsigned int base;
371 int plane_cnt; 372 int plane_cnt;
372 int i, ret; 373 int i, ret;
373 374
@@ -456,33 +457,60 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
456 457
457 list_add_tail(&mixer->engine.list, &drv->engine_list); 458 list_add_tail(&mixer->engine.list, &drv->engine_list);
458 459
459 /* Reset the registers */ 460 base = sun8i_blender_base(mixer);
460 for (i = 0x0; i < 0x20000; i += 4) 461
461 regmap_write(mixer->engine.regs, i, 0); 462 /* Reset registers and disable unused sub-engines */
463 if (mixer->cfg->is_de3) {
464 for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
465 regmap_write(mixer->engine.regs, i, 0);
466
467 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
468 regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
469 regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
470 regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
471 regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
472 regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
473 regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
474 regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
475 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
476 regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
477 } else {
478 for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
479 regmap_write(mixer->engine.regs, i, 0);
480
481 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
482 regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
483 regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
484 regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
485 regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
486 regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
487 regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
488 }
462 489
463 /* Enable the mixer */ 490 /* Enable the mixer */
464 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL, 491 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
465 SUN8I_MIXER_GLOBAL_CTL_RT_EN); 492 SUN8I_MIXER_GLOBAL_CTL_RT_EN);
466 493
467 /* Set background color to black */ 494 /* Set background color to black */
468 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR, 495 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
469 SUN8I_MIXER_BLEND_COLOR_BLACK); 496 SUN8I_MIXER_BLEND_COLOR_BLACK);
470 497
471 /* 498 /*
472 * Set fill color of bottom plane to black. Generally not needed 499 * Set fill color of bottom plane to black. Generally not needed
473 * except when VI plane is at bottom (zpos = 0) and enabled. 500 * except when VI plane is at bottom (zpos = 0) and enabled.
474 */ 501 */
475 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL, 502 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
476 SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0)); 503 SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
477 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0), 504 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
478 SUN8I_MIXER_BLEND_COLOR_BLACK); 505 SUN8I_MIXER_BLEND_COLOR_BLACK);
479 506
480 plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num; 507 plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
481 for (i = 0; i < plane_cnt; i++) 508 for (i = 0; i < plane_cnt; i++)
482 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i), 509 regmap_write(mixer->engine.regs,
510 SUN8I_MIXER_BLEND_MODE(base, i),
483 SUN8I_MIXER_BLEND_MODE_DEF); 511 SUN8I_MIXER_BLEND_MODE_DEF);
484 512
485 regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL, 513 regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
486 SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); 514 SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
487 515
488 return 0; 516 return 0;
@@ -585,6 +613,15 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
585 .vi_num = 1, 613 .vi_num = 1,
586}; 614};
587 615
616static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
617 .ccsc = 0,
618 .is_de3 = true,
619 .mod_rate = 600000000,
620 .scaler_mask = 0xf,
621 .ui_num = 3,
622 .vi_num = 1,
623};
624
588static const struct of_device_id sun8i_mixer_of_table[] = { 625static const struct of_device_id sun8i_mixer_of_table[] = {
589 { 626 {
590 .compatible = "allwinner,sun8i-a83t-de2-mixer-0", 627 .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
@@ -618,6 +655,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
618 .compatible = "allwinner,sun50i-a64-de2-mixer-1", 655 .compatible = "allwinner,sun50i-a64-de2-mixer-1",
619 .data = &sun50i_a64_mixer1_cfg, 656 .data = &sun50i_a64_mixer1_cfg,
620 }, 657 },
658 {
659 .compatible = "allwinner,sun50i-h6-de3-mixer-0",
660 .data = &sun50i_h6_mixer0_cfg,
661 },
621 { } 662 { }
622}; 663};
623MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table); 664MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 406c42e752d7..913d14ce68b0 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -29,24 +29,41 @@
29 29
30#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0) 30#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0)
31 31
32#define SUN8I_MIXER_BLEND_PIPE_CTL 0x1000 32#define DE2_MIXER_UNIT_SIZE 0x6000
33#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0) 33#define DE3_MIXER_UNIT_SIZE 0x3000
34#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4) 34
35#define SUN8I_MIXER_BLEND_ATTR_COORD(x) (0x1004 + 0x10 * (x) + 0x8) 35#define DE2_BLD_BASE 0x1000
36#define SUN8I_MIXER_BLEND_ROUTE 0x1080 36#define DE2_CH_BASE 0x2000
37#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084 37#define DE2_CH_SIZE 0x1000
38#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088 38
39#define SUN8I_MIXER_BLEND_OUTSIZE 0x108c 39#define DE3_BLD_BASE 0x0800
40#define SUN8I_MIXER_BLEND_MODE(x) (0x1090 + 0x04 * (x)) 40#define DE3_CH_BASE 0x1000
41#define SUN8I_MIXER_BLEND_CK_CTL 0x10b0 41#define DE3_CH_SIZE 0x0800
42#define SUN8I_MIXER_BLEND_CK_CFG 0x10b4 42
43#define SUN8I_MIXER_BLEND_CK_MAX(x) (0x10c0 + 0x04 * (x)) 43#define SUN8I_MIXER_BLEND_PIPE_CTL(base) ((base) + 0)
44#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x)) 44#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, x) ((base) + 0x4 + 0x10 * (x))
45#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc 45#define SUN8I_MIXER_BLEND_ATTR_INSIZE(base, x) ((base) + 0x8 + 0x10 * (x))
46#define SUN8I_MIXER_BLEND_ATTR_COORD(base, x) ((base) + 0xc + 0x10 * (x))
47#define SUN8I_MIXER_BLEND_ROUTE(base) ((base) + 0x80)
48#define SUN8I_MIXER_BLEND_PREMULTIPLY(base) ((base) + 0x84)
49#define SUN8I_MIXER_BLEND_BKCOLOR(base) ((base) + 0x88)
50#define SUN8I_MIXER_BLEND_OUTSIZE(base) ((base) + 0x8c)
51#define SUN8I_MIXER_BLEND_MODE(base, x) ((base) + 0x90 + 0x04 * (x))
52#define SUN8I_MIXER_BLEND_CK_CTL(base) ((base) + 0xb0)
53#define SUN8I_MIXER_BLEND_CK_CFG(base) ((base) + 0xb4)
54#define SUN8I_MIXER_BLEND_CK_MAX(base, x) ((base) + 0xc0 + 0x04 * (x))
55#define SUN8I_MIXER_BLEND_CK_MIN(base, x) ((base) + 0xe0 + 0x04 * (x))
56#define SUN8I_MIXER_BLEND_OUTCTL(base) ((base) + 0xfc)
57#define SUN50I_MIXER_BLEND_CSC_CTL(base) ((base) + 0x100)
58#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x, y) \
59 ((base) + 0x110 + (layer) * 0x30 + (x) * 0x10 + 4 * (y))
60#define SUN50I_MIXER_BLEND_CSC_CONST(base, layer, i) \
61 ((base) + 0x110 + (layer) * 0x30 + (i) * 0x10 + 0x0c)
46 62
47#define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8) 63#define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8)
48#define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe) 64#define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe)
49#define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe) 65#define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe)
66
50/* colors are always in AARRGGBB format */ 67/* colors are always in AARRGGBB format */
51#define SUN8I_MIXER_BLEND_COLOR_BLACK 0xff000000 68#define SUN8I_MIXER_BLEND_COLOR_BLACK 0xff000000
52/* The following numbers are some still unknown magic numbers */ 69/* The following numbers are some still unknown magic numbers */
@@ -57,6 +74,9 @@
57 74
58#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1) 75#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
59 76
77#define SUN50I_MIXER_BLEND_CSC_CTL_EN(ch) BIT(ch)
78#define SUN50I_MIXER_BLEND_CSC_CONST_VAL(d, c) (((d) << 16) | ((c) & 0xffff))
79
60#define SUN8I_MIXER_FBFMT_ARGB8888 0 80#define SUN8I_MIXER_FBFMT_ARGB8888 0
61#define SUN8I_MIXER_FBFMT_ABGR8888 1 81#define SUN8I_MIXER_FBFMT_ABGR8888 1
62#define SUN8I_MIXER_FBFMT_RGBA8888 2 82#define SUN8I_MIXER_FBFMT_RGBA8888 2
@@ -95,8 +115,8 @@
95#define SUN8I_MIXER_FBFMT_YUV411 14 115#define SUN8I_MIXER_FBFMT_YUV411 14
96 116
97/* 117/*
98 * These sub-engines are still unknown now, the EN registers are here only to 118 * Sub-engines listed bellow are unused for now. The EN registers are here only
99 * be used to disable these sub-engines. 119 * to be used to disable these sub-engines.
100 */ 120 */
101#define SUN8I_MIXER_FCE_EN 0xa0000 121#define SUN8I_MIXER_FCE_EN 0xa0000
102#define SUN8I_MIXER_BWS_EN 0xa2000 122#define SUN8I_MIXER_BWS_EN 0xa2000
@@ -106,6 +126,17 @@
106#define SUN8I_MIXER_FCC_EN 0xaa000 126#define SUN8I_MIXER_FCC_EN 0xaa000
107#define SUN8I_MIXER_DCSC_EN 0xb0000 127#define SUN8I_MIXER_DCSC_EN 0xb0000
108 128
129#define SUN50I_MIXER_FCE_EN 0x70000
130#define SUN50I_MIXER_PEAK_EN 0x70800
131#define SUN50I_MIXER_LCTI_EN 0x71000
132#define SUN50I_MIXER_BLS_EN 0x71800
133#define SUN50I_MIXER_FCC_EN 0x72000
134#define SUN50I_MIXER_DNS_EN 0x80000
135#define SUN50I_MIXER_DRC_EN 0xa0000
136#define SUN50I_MIXER_FMT_EN 0xa8000
137#define SUN50I_MIXER_CDC0_EN 0xd0000
138#define SUN50I_MIXER_CDC1_EN 0xd8000
139
109struct de2_fmt_info { 140struct de2_fmt_info {
110 u32 drm_fmt; 141 u32 drm_fmt;
111 u32 de2_fmt; 142 u32 de2_fmt;
@@ -127,6 +158,7 @@ struct de2_fmt_info {
127 * are invalid. 158 * are invalid.
128 * @mod_rate: module clock rate that needs to be set in order to have 159 * @mod_rate: module clock rate that needs to be set in order to have
129 * a functional block. 160 * a functional block.
161 * @is_de3: true, if this is next gen display engine 3.0, false otherwise.
130 */ 162 */
131struct sun8i_mixer_cfg { 163struct sun8i_mixer_cfg {
132 int vi_num; 164 int vi_num;
@@ -134,6 +166,7 @@ struct sun8i_mixer_cfg {
134 int scaler_mask; 166 int scaler_mask;
135 int ccsc; 167 int ccsc;
136 unsigned long mod_rate; 168 unsigned long mod_rate;
169 unsigned int is_de3 : 1;
137}; 170};
138 171
139struct sun8i_mixer { 172struct sun8i_mixer {
@@ -153,5 +186,20 @@ engine_to_sun8i_mixer(struct sunxi_engine *engine)
153 return container_of(engine, struct sun8i_mixer, engine); 186 return container_of(engine, struct sun8i_mixer, engine);
154} 187}
155 188
189static inline u32
190sun8i_blender_base(struct sun8i_mixer *mixer)
191{
192 return mixer->cfg->is_de3 ? DE3_BLD_BASE : DE2_BLD_BASE;
193}
194
195static inline u32
196sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
197{
198 if (mixer->cfg->is_de3)
199 return DE3_CH_BASE + channel * DE3_CH_SIZE;
200 else
201 return DE2_CH_BASE + channel * DE2_CH_SIZE;
202}
203
156const struct de2_fmt_info *sun8i_mixer_format_info(u32 format); 204const struct de2_fmt_info *sun8i_mixer_format_info(u32 format);
157#endif /* _SUN8I_MIXER_H_ */ 205#endif /* _SUN8I_MIXER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
index 3040a79f298f..fc36e0c10a37 100644
--- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
@@ -9,11 +9,17 @@
9#include <linux/component.h> 9#include <linux/component.h>
10#include <linux/device.h> 10#include <linux/device.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/of_device.h>
12#include <linux/of_graph.h> 13#include <linux/of_graph.h>
13#include <linux/platform_device.h> 14#include <linux/platform_device.h>
14 15
15#include "sun8i_tcon_top.h" 16#include "sun8i_tcon_top.h"
16 17
18struct sun8i_tcon_top_quirks {
19 bool has_tcon_tv1;
20 bool has_dsi;
21};
22
17static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node) 23static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node)
18{ 24{
19 return !!of_match_node(sun8i_tcon_top_of_table, node); 25 return !!of_match_node(sun8i_tcon_top_of_table, node);
@@ -121,10 +127,13 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
121 struct platform_device *pdev = to_platform_device(dev); 127 struct platform_device *pdev = to_platform_device(dev);
122 struct clk_hw_onecell_data *clk_data; 128 struct clk_hw_onecell_data *clk_data;
123 struct sun8i_tcon_top *tcon_top; 129 struct sun8i_tcon_top *tcon_top;
130 const struct sun8i_tcon_top_quirks *quirks;
124 struct resource *res; 131 struct resource *res;
125 void __iomem *regs; 132 void __iomem *regs;
126 int ret, i; 133 int ret, i;
127 134
135 quirks = of_device_get_match_data(&pdev->dev);
136
128 tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL); 137 tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
129 if (!tcon_top) 138 if (!tcon_top)
130 return -ENOMEM; 139 return -ENOMEM;
@@ -168,6 +177,13 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
168 } 177 }
169 178
170 /* 179 /*
180 * At least on H6, some registers have some bits set by default
181 * which may cause issues. Clear them here.
182 */
183 writel(0, regs + TCON_TOP_PORT_SEL_REG);
184 writel(0, regs + TCON_TOP_GATE_SRC_REG);
185
186 /*
171 * TCON TOP has two muxes, which select parent clock for each TCON TV 187 * TCON TOP has two muxes, which select parent clock for each TCON TV
172 * channel clock. Parent could be either TCON TV or TVE clock. For now 188 * channel clock. Parent could be either TCON TV or TVE clock. For now
173 * we leave this fixed to TCON TV, since TVE driver for R40 is not yet 189 * we leave this fixed to TCON TV, since TVE driver for R40 is not yet
@@ -180,15 +196,17 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
180 &tcon_top->reg_lock, 196 &tcon_top->reg_lock,
181 TCON_TOP_TCON_TV0_GATE, 0); 197 TCON_TOP_TCON_TV0_GATE, 0);
182 198
183 clk_data->hws[CLK_TCON_TOP_TV1] = 199 if (quirks->has_tcon_tv1)
184 sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs, 200 clk_data->hws[CLK_TCON_TOP_TV1] =
185 &tcon_top->reg_lock, 201 sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs,
186 TCON_TOP_TCON_TV1_GATE, 1); 202 &tcon_top->reg_lock,
203 TCON_TOP_TCON_TV1_GATE, 1);
187 204
188 clk_data->hws[CLK_TCON_TOP_DSI] = 205 if (quirks->has_dsi)
189 sun8i_tcon_top_register_gate(dev, "dsi", regs, 206 clk_data->hws[CLK_TCON_TOP_DSI] =
190 &tcon_top->reg_lock, 207 sun8i_tcon_top_register_gate(dev, "dsi", regs,
191 TCON_TOP_TCON_DSI_GATE, 2); 208 &tcon_top->reg_lock,
209 TCON_TOP_TCON_DSI_GATE, 2);
192 210
193 for (i = 0; i < CLK_NUM; i++) 211 for (i = 0; i < CLK_NUM; i++)
194 if (IS_ERR(clk_data->hws[i])) { 212 if (IS_ERR(clk_data->hws[i])) {
@@ -250,9 +268,25 @@ static int sun8i_tcon_top_remove(struct platform_device *pdev)
250 return 0; 268 return 0;
251} 269}
252 270
271const struct sun8i_tcon_top_quirks sun8i_r40_tcon_top_quirks = {
272 .has_tcon_tv1 = true,
273 .has_dsi = true,
274};
275
276const struct sun8i_tcon_top_quirks sun50i_h6_tcon_top_quirks = {
277 /* Nothing special */
278};
279
253/* sun4i_drv uses this list to check if a device node is a TCON TOP */ 280/* sun4i_drv uses this list to check if a device node is a TCON TOP */
254const struct of_device_id sun8i_tcon_top_of_table[] = { 281const struct of_device_id sun8i_tcon_top_of_table[] = {
255 { .compatible = "allwinner,sun8i-r40-tcon-top" }, 282 {
283 .compatible = "allwinner,sun8i-r40-tcon-top",
284 .data = &sun8i_r40_tcon_top_quirks
285 },
286 {
287 .compatible = "allwinner,sun50i-h6-tcon-top",
288 .data = &sun50i_h6_tcon_top_quirks
289 },
256 { /* sentinel */ } 290 { /* sentinel */ }
257}; 291};
258MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table); 292MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 28c15c6ef1ef..e3fc8fa920fb 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -30,7 +30,10 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
30 int overlay, bool enable, unsigned int zpos, 30 int overlay, bool enable, unsigned int zpos,
31 unsigned int old_zpos) 31 unsigned int old_zpos)
32{ 32{
33 u32 val; 33 u32 val, bld_base, ch_base;
34
35 bld_base = sun8i_blender_base(mixer);
36 ch_base = sun8i_channel_base(mixer, channel);
34 37
35 DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n", 38 DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
36 enable ? "En" : "Dis", channel, overlay); 39 enable ? "En" : "Dis", channel, overlay);
@@ -41,17 +44,17 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
41 val = 0; 44 val = 0;
42 45
43 regmap_update_bits(mixer->engine.regs, 46 regmap_update_bits(mixer->engine.regs,
44 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay), 47 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
45 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); 48 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
46 49
47 if (!enable || zpos != old_zpos) { 50 if (!enable || zpos != old_zpos) {
48 regmap_update_bits(mixer->engine.regs, 51 regmap_update_bits(mixer->engine.regs,
49 SUN8I_MIXER_BLEND_PIPE_CTL, 52 SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
50 SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), 53 SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
51 0); 54 0);
52 55
53 regmap_update_bits(mixer->engine.regs, 56 regmap_update_bits(mixer->engine.regs,
54 SUN8I_MIXER_BLEND_ROUTE, 57 SUN8I_MIXER_BLEND_ROUTE(bld_base),
55 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), 58 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
56 0); 59 0);
57 } 60 }
@@ -60,12 +63,13 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
60 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); 63 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
61 64
62 regmap_update_bits(mixer->engine.regs, 65 regmap_update_bits(mixer->engine.regs,
63 SUN8I_MIXER_BLEND_PIPE_CTL, val, val); 66 SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
67 val, val);
64 68
65 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); 69 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
66 70
67 regmap_update_bits(mixer->engine.regs, 71 regmap_update_bits(mixer->engine.regs,
68 SUN8I_MIXER_BLEND_ROUTE, 72 SUN8I_MIXER_BLEND_ROUTE(bld_base),
69 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), 73 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
70 val); 74 val);
71 } 75 }
@@ -77,12 +81,16 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
77{ 81{
78 struct drm_plane_state *state = plane->state; 82 struct drm_plane_state *state = plane->state;
79 u32 src_w, src_h, dst_w, dst_h; 83 u32 src_w, src_h, dst_w, dst_h;
84 u32 bld_base, ch_base;
80 u32 outsize, insize; 85 u32 outsize, insize;
81 u32 hphase, vphase; 86 u32 hphase, vphase;
82 87
83 DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n", 88 DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
84 channel, overlay); 89 channel, overlay);
85 90
91 bld_base = sun8i_blender_base(mixer);
92 ch_base = sun8i_channel_base(mixer, channel);
93
86 src_w = drm_rect_width(&state->src) >> 16; 94 src_w = drm_rect_width(&state->src) >> 16;
87 src_h = drm_rect_height(&state->src) >> 16; 95 src_h = drm_rect_height(&state->src) >> 16;
88 dst_w = drm_rect_width(&state->dst); 96 dst_w = drm_rect_width(&state->dst);
@@ -103,8 +111,8 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
103 regmap_write(mixer->engine.regs, 111 regmap_write(mixer->engine.regs,
104 SUN8I_MIXER_GLOBAL_SIZE, 112 SUN8I_MIXER_GLOBAL_SIZE,
105 outsize); 113 outsize);
106 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE, 114 regmap_write(mixer->engine.regs,
107 outsize); 115 SUN8I_MIXER_BLEND_OUTSIZE(bld_base), outsize);
108 116
109 if (state->crtc) 117 if (state->crtc)
110 interlaced = state->crtc->state->adjusted_mode.flags 118 interlaced = state->crtc->state->adjusted_mode.flags
@@ -116,7 +124,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
116 val = 0; 124 val = 0;
117 125
118 regmap_update_bits(mixer->engine.regs, 126 regmap_update_bits(mixer->engine.regs,
119 SUN8I_MIXER_BLEND_OUTCTL, 127 SUN8I_MIXER_BLEND_OUTCTL(bld_base),
120 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, 128 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
121 val); 129 val);
122 130
@@ -129,10 +137,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
129 state->src.x1 >> 16, state->src.y1 >> 16); 137 state->src.x1 >> 16, state->src.y1 >> 16);
130 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); 138 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
131 regmap_write(mixer->engine.regs, 139 regmap_write(mixer->engine.regs,
132 SUN8I_MIXER_CHAN_UI_LAYER_SIZE(channel, overlay), 140 SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay),
133 insize); 141 insize);
134 regmap_write(mixer->engine.regs, 142 regmap_write(mixer->engine.regs,
135 SUN8I_MIXER_CHAN_UI_OVL_SIZE(channel), 143 SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base),
136 insize); 144 insize);
137 145
138 if (insize != outsize || hphase || vphase) { 146 if (insize != outsize || hphase || vphase) {
@@ -156,10 +164,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
156 state->dst.x1, state->dst.y1); 164 state->dst.x1, state->dst.y1);
157 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); 165 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
158 regmap_write(mixer->engine.regs, 166 regmap_write(mixer->engine.regs,
159 SUN8I_MIXER_BLEND_ATTR_COORD(zpos), 167 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
160 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); 168 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
161 regmap_write(mixer->engine.regs, 169 regmap_write(mixer->engine.regs,
162 SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), 170 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
163 outsize); 171 outsize);
164 172
165 return 0; 173 return 0;
@@ -170,7 +178,9 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
170{ 178{
171 struct drm_plane_state *state = plane->state; 179 struct drm_plane_state *state = plane->state;
172 const struct de2_fmt_info *fmt_info; 180 const struct de2_fmt_info *fmt_info;
173 u32 val; 181 u32 val, ch_base;
182
183 ch_base = sun8i_channel_base(mixer, channel);
174 184
175 fmt_info = sun8i_mixer_format_info(state->fb->format->format); 185 fmt_info = sun8i_mixer_format_info(state->fb->format->format);
176 if (!fmt_info || !fmt_info->rgb) { 186 if (!fmt_info || !fmt_info->rgb) {
@@ -180,7 +190,7 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
180 190
181 val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET; 191 val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
182 regmap_update_bits(mixer->engine.regs, 192 regmap_update_bits(mixer->engine.regs,
183 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay), 193 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
184 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val); 194 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
185 195
186 return 0; 196 return 0;
@@ -193,8 +203,11 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
193 struct drm_framebuffer *fb = state->fb; 203 struct drm_framebuffer *fb = state->fb;
194 struct drm_gem_cma_object *gem; 204 struct drm_gem_cma_object *gem;
195 dma_addr_t paddr; 205 dma_addr_t paddr;
206 u32 ch_base;
196 int bpp; 207 int bpp;
197 208
209 ch_base = sun8i_channel_base(mixer, channel);
210
198 /* Get the physical address of the buffer in memory */ 211 /* Get the physical address of the buffer in memory */
199 gem = drm_fb_cma_get_gem_obj(fb, 0); 212 gem = drm_fb_cma_get_gem_obj(fb, 0);
200 213
@@ -211,13 +224,13 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
211 /* Set the line width */ 224 /* Set the line width */
212 DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); 225 DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
213 regmap_write(mixer->engine.regs, 226 regmap_write(mixer->engine.regs,
214 SUN8I_MIXER_CHAN_UI_LAYER_PITCH(channel, overlay), 227 SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay),
215 fb->pitches[0]); 228 fb->pitches[0]);
216 229
217 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); 230 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
218 231
219 regmap_write(mixer->engine.regs, 232 regmap_write(mixer->engine.regs,
220 SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(channel, overlay), 233 SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay),
221 lower_32_bits(paddr)); 234 lower_32_bits(paddr));
222 235
223 return 0; 236 return 0;
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
index 123b15ea9918..f4389cf0ba20 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
@@ -18,23 +18,26 @@
18 18
19#include <drm/drm_plane.h> 19#include <drm/drm_plane.h>
20 20
21#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \ 21#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(base, layer) \
22 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0) 22 ((base) + 0x20 * (layer) + 0x0)
23#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \ 23#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(base, layer) \
24 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4) 24 ((base) + 0x20 * (layer) + 0x4)
25#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \ 25#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(base, layer) \
26 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8) 26 ((base) + 0x20 * (layer) + 0x8)
27#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \ 27#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(base, layer) \
28 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc) 28 ((base) + 0x20 * (layer) + 0xc)
29#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \ 29#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(base, layer) \
30 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10) 30 ((base) + 0x20 * (layer) + 0x10)
31#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \ 31#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(base, layer) \
32 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14) 32 ((base) + 0x20 * (layer) + 0x14)
33#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \ 33#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(base, layer) \
34 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18) 34 ((base) + 0x20 * (layer) + 0x18)
35#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80) 35#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(base) \
36#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84) 36 ((base) + 0x80)
37#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88) 37#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(base) \
38 ((base) + 0x84)
39#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(base) \
40 ((base) + 0x88)
38 41
39#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0) 42#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
40#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1) 43#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
index 6bb2aa164c8e..ae0806bccac7 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
@@ -10,6 +10,7 @@
10 */ 10 */
11 11
12#include "sun8i_ui_scaler.h" 12#include "sun8i_ui_scaler.h"
13#include "sun8i_vi_scaler.h"
13 14
14static const u32 lan2coefftab16[240] = { 15static const u32 lan2coefftab16[240] = {
15 0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb, 16 0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb,
@@ -88,6 +89,20 @@ static const u32 lan2coefftab16[240] = {
88 0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301, 89 0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
89}; 90};
90 91
92static u32 sun8i_ui_scaler_base(struct sun8i_mixer *mixer, int channel)
93{
94 int vi_num = mixer->cfg->vi_num;
95
96 if (mixer->cfg->is_de3)
97 return DE3_VI_SCALER_UNIT_BASE +
98 DE3_VI_SCALER_UNIT_SIZE * vi_num +
99 DE3_UI_SCALER_UNIT_SIZE * (channel - vi_num);
100 else
101 return DE2_VI_SCALER_UNIT_BASE +
102 DE2_VI_SCALER_UNIT_SIZE * vi_num +
103 DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num);
104}
105
91static int sun8i_ui_scaler_coef_index(unsigned int step) 106static int sun8i_ui_scaler_coef_index(unsigned int step)
92{ 107{
93 unsigned int scale, int_part, float_part; 108 unsigned int scale, int_part, float_part;
@@ -114,33 +129,35 @@ static int sun8i_ui_scaler_coef_index(unsigned int step)
114 129
115void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable) 130void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
116{ 131{
117 int vi_cnt = mixer->cfg->vi_num; 132 u32 val, base;
118 u32 val;
119 133
120 if (WARN_ON(layer < vi_cnt)) 134 if (WARN_ON(layer < mixer->cfg->vi_num))
121 return; 135 return;
122 136
137 base = sun8i_ui_scaler_base(mixer, layer);
138
123 if (enable) 139 if (enable)
124 val = SUN8I_SCALER_GSU_CTRL_EN | 140 val = SUN8I_SCALER_GSU_CTRL_EN |
125 SUN8I_SCALER_GSU_CTRL_COEFF_RDY; 141 SUN8I_SCALER_GSU_CTRL_COEFF_RDY;
126 else 142 else
127 val = 0; 143 val = 0;
128 144
129 regmap_write(mixer->engine.regs, 145 regmap_write(mixer->engine.regs, SUN8I_SCALER_GSU_CTRL(base), val);
130 SUN8I_SCALER_GSU_CTRL(vi_cnt, layer - vi_cnt), val);
131} 146}
132 147
133void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer, 148void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
134 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h, 149 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
135 u32 hscale, u32 vscale, u32 hphase, u32 vphase) 150 u32 hscale, u32 vscale, u32 hphase, u32 vphase)
136{ 151{
137 int vi_cnt = mixer->cfg->vi_num;
138 u32 insize, outsize; 152 u32 insize, outsize;
139 int i, offset; 153 int i, offset;
154 u32 base;
140 155
141 if (WARN_ON(layer < vi_cnt)) 156 if (WARN_ON(layer < mixer->cfg->vi_num))
142 return; 157 return;
143 158
159 base = sun8i_ui_scaler_base(mixer, layer);
160
144 hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16; 161 hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
145 vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16; 162 vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
146 hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16; 163 hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
@@ -149,24 +166,22 @@ void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
149 insize = SUN8I_UI_SCALER_SIZE(src_w, src_h); 166 insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
150 outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h); 167 outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
151 168
152 layer -= vi_cnt;
153
154 regmap_write(mixer->engine.regs, 169 regmap_write(mixer->engine.regs,
155 SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, layer), outsize); 170 SUN8I_SCALER_GSU_OUTSIZE(base), outsize);
156 regmap_write(mixer->engine.regs, 171 regmap_write(mixer->engine.regs,
157 SUN8I_SCALER_GSU_INSIZE(vi_cnt, layer), insize); 172 SUN8I_SCALER_GSU_INSIZE(base), insize);
158 regmap_write(mixer->engine.regs, 173 regmap_write(mixer->engine.regs,
159 SUN8I_SCALER_GSU_HSTEP(vi_cnt, layer), hscale); 174 SUN8I_SCALER_GSU_HSTEP(base), hscale);
160 regmap_write(mixer->engine.regs, 175 regmap_write(mixer->engine.regs,
161 SUN8I_SCALER_GSU_VSTEP(vi_cnt, layer), vscale); 176 SUN8I_SCALER_GSU_VSTEP(base), vscale);
162 regmap_write(mixer->engine.regs, 177 regmap_write(mixer->engine.regs,
163 SUN8I_SCALER_GSU_HPHASE(vi_cnt, layer), hphase); 178 SUN8I_SCALER_GSU_HPHASE(base), hphase);
164 regmap_write(mixer->engine.regs, 179 regmap_write(mixer->engine.regs,
165 SUN8I_SCALER_GSU_VPHASE(vi_cnt, layer), vphase); 180 SUN8I_SCALER_GSU_VPHASE(base), vphase);
166 offset = sun8i_ui_scaler_coef_index(hscale) * 181 offset = sun8i_ui_scaler_coef_index(hscale) *
167 SUN8I_UI_SCALER_COEFF_COUNT; 182 SUN8I_UI_SCALER_COEFF_COUNT;
168 for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++) 183 for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
169 regmap_write(mixer->engine.regs, 184 regmap_write(mixer->engine.regs,
170 SUN8I_SCALER_GSU_HCOEFF(vi_cnt, layer, i), 185 SUN8I_SCALER_GSU_HCOEFF(base, i),
171 lan2coefftab16[offset + i]); 186 lan2coefftab16[offset + i]);
172} 187}
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
index 86295be8be78..1ef4bd6f2718 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
@@ -11,6 +11,9 @@
11 11
12#include "sun8i_mixer.h" 12#include "sun8i_mixer.h"
13 13
14#define DE2_UI_SCALER_UNIT_SIZE 0x10000
15#define DE3_UI_SCALER_UNIT_SIZE 0x08000
16
14/* this two macros assumes 16 fractional bits which is standard in DRM */ 17/* this two macros assumes 16 fractional bits which is standard in DRM */
15#define SUN8I_UI_SCALER_SCALE_MIN 1 18#define SUN8I_UI_SCALER_SCALE_MIN 1
16#define SUN8I_UI_SCALER_SCALE_MAX ((1UL << 20) - 1) 19#define SUN8I_UI_SCALER_SCALE_MAX ((1UL << 20) - 1)
@@ -20,23 +23,14 @@
20#define SUN8I_UI_SCALER_COEFF_COUNT 16 23#define SUN8I_UI_SCALER_COEFF_COUNT 16
21#define SUN8I_UI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1)) 24#define SUN8I_UI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
22 25
23#define SUN8I_SCALER_GSU_CTRL(vi_cnt, ui_idx) \ 26#define SUN8I_SCALER_GSU_CTRL(base) ((base) + 0x0)
24 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x0) 27#define SUN8I_SCALER_GSU_OUTSIZE(base) ((base) + 0x40)
25#define SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, ui_idx) \ 28#define SUN8I_SCALER_GSU_INSIZE(base) ((base) + 0x80)
26 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x40) 29#define SUN8I_SCALER_GSU_HSTEP(base) ((base) + 0x88)
27#define SUN8I_SCALER_GSU_INSIZE(vi_cnt, ui_idx) \ 30#define SUN8I_SCALER_GSU_VSTEP(base) ((base) + 0x8c)
28 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x80) 31#define SUN8I_SCALER_GSU_HPHASE(base) ((base) + 0x90)
29#define SUN8I_SCALER_GSU_HSTEP(vi_cnt, ui_idx) \ 32#define SUN8I_SCALER_GSU_VPHASE(base) ((base) + 0x98)
30 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x88) 33#define SUN8I_SCALER_GSU_HCOEFF(base, index) ((base) + 0x200 + 0x4 * (index))
31#define SUN8I_SCALER_GSU_VSTEP(vi_cnt, ui_idx) \
32 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x8c)
33#define SUN8I_SCALER_GSU_HPHASE(vi_cnt, ui_idx) \
34 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x90)
35#define SUN8I_SCALER_GSU_VPHASE(vi_cnt, ui_idx) \
36 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x98)
37#define SUN8I_SCALER_GSU_HCOEFF(vi_cnt, ui_idx, index) \
38 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x200 + \
39 0x4 * (index))
40 34
41#define SUN8I_SCALER_GSU_CTRL_EN BIT(0) 35#define SUN8I_SCALER_GSU_CTRL_EN BIT(0)
42#define SUN8I_SCALER_GSU_CTRL_COEFF_RDY BIT(4) 36#define SUN8I_SCALER_GSU_CTRL_COEFF_RDY BIT(4)
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index f4fe97813f94..4249edfb47ed 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -24,7 +24,10 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
24 int overlay, bool enable, unsigned int zpos, 24 int overlay, bool enable, unsigned int zpos,
25 unsigned int old_zpos) 25 unsigned int old_zpos)
26{ 26{
27 u32 val; 27 u32 val, bld_base, ch_base;
28
29 bld_base = sun8i_blender_base(mixer);
30 ch_base = sun8i_channel_base(mixer, channel);
28 31
29 DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n", 32 DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
30 enable ? "En" : "Dis", channel, overlay); 33 enable ? "En" : "Dis", channel, overlay);
@@ -35,17 +38,17 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
35 val = 0; 38 val = 0;
36 39
37 regmap_update_bits(mixer->engine.regs, 40 regmap_update_bits(mixer->engine.regs,
38 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), 41 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
39 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val); 42 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
40 43
41 if (!enable || zpos != old_zpos) { 44 if (!enable || zpos != old_zpos) {
42 regmap_update_bits(mixer->engine.regs, 45 regmap_update_bits(mixer->engine.regs,
43 SUN8I_MIXER_BLEND_PIPE_CTL, 46 SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
44 SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), 47 SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
45 0); 48 0);
46 49
47 regmap_update_bits(mixer->engine.regs, 50 regmap_update_bits(mixer->engine.regs,
48 SUN8I_MIXER_BLEND_ROUTE, 51 SUN8I_MIXER_BLEND_ROUTE(bld_base),
49 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), 52 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
50 0); 53 0);
51 } 54 }
@@ -54,12 +57,13 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
54 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); 57 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
55 58
56 regmap_update_bits(mixer->engine.regs, 59 regmap_update_bits(mixer->engine.regs,
57 SUN8I_MIXER_BLEND_PIPE_CTL, val, val); 60 SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
61 val, val);
58 62
59 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); 63 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
60 64
61 regmap_update_bits(mixer->engine.regs, 65 regmap_update_bits(mixer->engine.regs,
62 SUN8I_MIXER_BLEND_ROUTE, 66 SUN8I_MIXER_BLEND_ROUTE(bld_base),
63 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), 67 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
64 val); 68 val);
65 } 69 }
@@ -72,6 +76,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
72 struct drm_plane_state *state = plane->state; 76 struct drm_plane_state *state = plane->state;
73 const struct drm_format_info *format = state->fb->format; 77 const struct drm_format_info *format = state->fb->format;
74 u32 src_w, src_h, dst_w, dst_h; 78 u32 src_w, src_h, dst_w, dst_h;
79 u32 bld_base, ch_base;
75 u32 outsize, insize; 80 u32 outsize, insize;
76 u32 hphase, vphase; 81 u32 hphase, vphase;
77 bool subsampled; 82 bool subsampled;
@@ -79,6 +84,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
79 DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n", 84 DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
80 channel, overlay); 85 channel, overlay);
81 86
87 bld_base = sun8i_blender_base(mixer);
88 ch_base = sun8i_channel_base(mixer, channel);
89
82 src_w = drm_rect_width(&state->src) >> 16; 90 src_w = drm_rect_width(&state->src) >> 16;
83 src_h = drm_rect_height(&state->src) >> 16; 91 src_h = drm_rect_height(&state->src) >> 16;
84 dst_w = drm_rect_width(&state->dst); 92 dst_w = drm_rect_width(&state->dst);
@@ -115,10 +123,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
115 (state->src.y1 >> 16) & ~(format->vsub - 1)); 123 (state->src.y1 >> 16) & ~(format->vsub - 1));
116 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h); 124 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
117 regmap_write(mixer->engine.regs, 125 regmap_write(mixer->engine.regs,
118 SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay), 126 SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
119 insize); 127 insize);
120 regmap_write(mixer->engine.regs, 128 regmap_write(mixer->engine.regs,
121 SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel), 129 SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
122 insize); 130 insize);
123 131
124 /* 132 /*
@@ -149,10 +157,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
149 state->dst.x1, state->dst.y1); 157 state->dst.x1, state->dst.y1);
150 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); 158 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
151 regmap_write(mixer->engine.regs, 159 regmap_write(mixer->engine.regs,
152 SUN8I_MIXER_BLEND_ATTR_COORD(zpos), 160 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
153 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); 161 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
154 regmap_write(mixer->engine.regs, 162 regmap_write(mixer->engine.regs,
155 SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), 163 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
156 outsize); 164 outsize);
157 165
158 return 0; 166 return 0;
@@ -163,7 +171,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
163{ 171{
164 struct drm_plane_state *state = plane->state; 172 struct drm_plane_state *state = plane->state;
165 const struct de2_fmt_info *fmt_info; 173 const struct de2_fmt_info *fmt_info;
166 u32 val; 174 u32 val, ch_base;
175
176 ch_base = sun8i_channel_base(mixer, channel);
167 177
168 fmt_info = sun8i_mixer_format_info(state->fb->format->format); 178 fmt_info = sun8i_mixer_format_info(state->fb->format->format);
169 if (!fmt_info) { 179 if (!fmt_info) {
@@ -173,7 +183,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
173 183
174 val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET; 184 val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
175 regmap_update_bits(mixer->engine.regs, 185 regmap_update_bits(mixer->engine.regs,
176 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), 186 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
177 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val); 187 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
178 188
179 if (fmt_info->csc != SUN8I_CSC_MODE_OFF) { 189 if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
@@ -189,9 +199,17 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
189 val = 0; 199 val = 0;
190 200
191 regmap_update_bits(mixer->engine.regs, 201 regmap_update_bits(mixer->engine.regs,
192 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), 202 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
193 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val); 203 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
194 204
205 /* It seems that YUV formats use global alpha setting. */
206 if (mixer->cfg->is_de3)
207 regmap_update_bits(mixer->engine.regs,
208 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
209 overlay),
210 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
211 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
212
195 return 0; 213 return 0;
196} 214}
197 215
@@ -204,8 +222,11 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
204 struct drm_gem_cma_object *gem; 222 struct drm_gem_cma_object *gem;
205 u32 dx, dy, src_x, src_y; 223 u32 dx, dy, src_x, src_y;
206 dma_addr_t paddr; 224 dma_addr_t paddr;
225 u32 ch_base;
207 int i; 226 int i;
208 227
228 ch_base = sun8i_channel_base(mixer, channel);
229
209 /* Adjust x and y to be dividable by subsampling factor */ 230 /* Adjust x and y to be dividable by subsampling factor */
210 src_x = (state->src.x1 >> 16) & ~(format->hsub - 1); 231 src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
211 src_y = (state->src.y1 >> 16) & ~(format->vsub - 1); 232 src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
@@ -235,17 +256,17 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
235 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n", 256 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
236 i + 1, fb->pitches[i]); 257 i + 1, fb->pitches[i]);
237 regmap_write(mixer->engine.regs, 258 regmap_write(mixer->engine.regs,
238 SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel, 259 SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
239 overlay, i), 260 overlay, i),
240 fb->pitches[i]); 261 fb->pitches[i]);
241 262
242 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n", 263 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
243 i + 1, &paddr); 264 i + 1, &paddr);
244 265
245 regmap_write(mixer->engine.regs, 266 regmap_write(mixer->engine.regs,
246 SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel, 267 SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
247 overlay, i), 268 overlay, i),
248 lower_32_bits(paddr)); 269 lower_32_bits(paddr));
249 } 270 }
250 271
251 return 0; 272 return 0;
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
index 6996627a0a76..8a5e6d01c85d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
@@ -12,23 +12,26 @@
12 12
13#include <drm/drm_plane.h> 13#include <drm/drm_plane.h>
14 14
15#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch, layer) \ 15#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(base, layer) \
16 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x0) 16 ((base) + 0x30 * (layer) + 0x0)
17#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch, layer) \ 17#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(base, layer) \
18 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x4) 18 ((base) + 0x30 * (layer) + 0x4)
19#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(ch, layer) \ 19#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(base, layer) \
20 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x8) 20 ((base) + 0x30 * (layer) + 0x8)
21#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch, layer, plane) \ 21#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(base, layer, plane) \
22 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0xc + 4 * (plane)) 22 ((base) + 0x30 * (layer) + 0xc + 4 * (plane))
23#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch, layer, plane) \ 23#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(base, layer, plane) \
24 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x18 + 4 * (plane)) 24 ((base) + 0x30 * (layer) + 0x18 + 4 * (plane))
25#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0xe8) 25#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(base) \
26 ((base) + 0xe8)
26 27
27#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN BIT(0) 28#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN BIT(0)
28/* RGB mode should be set for RGB formats and cleared for YCbCr */ 29/* RGB mode should be set for RGB formats and cleared for YCbCr */
29#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE BIT(15) 30#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE BIT(15)
30#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET 8 31#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET 8
31#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8) 32#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8)
33#define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
34#define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(x) ((x) << 24)
32 35
33struct sun8i_mixer; 36struct sun8i_mixer;
34 37
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index d3f1acb234b7..7ba75011adf9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -833,6 +833,16 @@ static const u32 bicubic4coefftab32[480] = {
833 0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c, 833 0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c,
834}; 834};
835 835
836static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
837{
838 if (mixer->cfg->is_de3)
839 return DE3_VI_SCALER_UNIT_BASE +
840 DE3_VI_SCALER_UNIT_SIZE * channel;
841 else
842 return DE2_VI_SCALER_UNIT_BASE +
843 DE2_VI_SCALER_UNIT_SIZE * channel;
844}
845
836static int sun8i_vi_scaler_coef_index(unsigned int step) 846static int sun8i_vi_scaler_coef_index(unsigned int step)
837{ 847{
838 unsigned int scale, int_part, float_part; 848 unsigned int scale, int_part, float_part;
@@ -857,7 +867,7 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
857 } 867 }
858} 868}
859 869
860static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer, 870static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
861 u32 hstep, u32 vstep, 871 u32 hstep, u32 vstep,
862 const struct drm_format_info *format) 872 const struct drm_format_info *format)
863{ 873{
@@ -877,29 +887,31 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
877 offset = sun8i_vi_scaler_coef_index(hstep) * 887 offset = sun8i_vi_scaler_coef_index(hstep) *
878 SUN8I_VI_SCALER_COEFF_COUNT; 888 SUN8I_VI_SCALER_COEFF_COUNT;
879 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) { 889 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
880 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(layer, i), 890 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
881 lan3coefftab32_left[offset + i]); 891 lan3coefftab32_left[offset + i]);
882 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(layer, i), 892 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
883 lan3coefftab32_right[offset + i]); 893 lan3coefftab32_right[offset + i]);
884 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(layer, i), 894 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
885 ch_left[offset + i]); 895 ch_left[offset + i]);
886 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(layer, i), 896 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
887 ch_right[offset + i]); 897 ch_right[offset + i]);
888 } 898 }
889 899
890 offset = sun8i_vi_scaler_coef_index(hstep) * 900 offset = sun8i_vi_scaler_coef_index(hstep) *
891 SUN8I_VI_SCALER_COEFF_COUNT; 901 SUN8I_VI_SCALER_COEFF_COUNT;
892 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) { 902 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
893 regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(layer, i), 903 regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
894 lan2coefftab32[offset + i]); 904 lan2coefftab32[offset + i]);
895 regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(layer, i), 905 regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
896 cy[offset + i]); 906 cy[offset + i]);
897 } 907 }
898} 908}
899 909
900void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable) 910void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
901{ 911{
902 u32 val; 912 u32 val, base;
913
914 base = sun8i_vi_scaler_base(mixer, layer);
903 915
904 if (enable) 916 if (enable)
905 val = SUN8I_SCALER_VSU_CTRL_EN | 917 val = SUN8I_SCALER_VSU_CTRL_EN |
@@ -907,7 +919,8 @@ void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
907 else 919 else
908 val = 0; 920 val = 0;
909 921
910 regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(layer), val); 922 regmap_write(mixer->engine.regs,
923 SUN8I_SCALER_VSU_CTRL(base), val);
911} 924}
912 925
913void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer, 926void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -917,6 +930,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
917{ 930{
918 u32 chphase, cvphase; 931 u32 chphase, cvphase;
919 u32 insize, outsize; 932 u32 insize, outsize;
933 u32 base;
934
935 base = sun8i_vi_scaler_base(mixer, layer);
920 936
921 hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16; 937 hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
922 vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16; 938 vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
@@ -940,32 +956,44 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
940 cvphase = vphase; 956 cvphase = vphase;
941 } 957 }
942 958
959 if (mixer->cfg->is_de3) {
960 u32 val;
961
962 if (format->hsub == 1 && format->vsub == 1)
963 val = SUN50I_SCALER_VSU_SCALE_MODE_UI;
964 else
965 val = SUN50I_SCALER_VSU_SCALE_MODE_NORMAL;
966
967 regmap_write(mixer->engine.regs,
968 SUN50I_SCALER_VSU_SCALE_MODE(base), val);
969 }
970
943 regmap_write(mixer->engine.regs, 971 regmap_write(mixer->engine.regs,
944 SUN8I_SCALER_VSU_OUTSIZE(layer), outsize); 972 SUN8I_SCALER_VSU_OUTSIZE(base), outsize);
945 regmap_write(mixer->engine.regs, 973 regmap_write(mixer->engine.regs,
946 SUN8I_SCALER_VSU_YINSIZE(layer), insize); 974 SUN8I_SCALER_VSU_YINSIZE(base), insize);
947 regmap_write(mixer->engine.regs, 975 regmap_write(mixer->engine.regs,
948 SUN8I_SCALER_VSU_YHSTEP(layer), hscale); 976 SUN8I_SCALER_VSU_YHSTEP(base), hscale);
949 regmap_write(mixer->engine.regs, 977 regmap_write(mixer->engine.regs,
950 SUN8I_SCALER_VSU_YVSTEP(layer), vscale); 978 SUN8I_SCALER_VSU_YVSTEP(base), vscale);
951 regmap_write(mixer->engine.regs, 979 regmap_write(mixer->engine.regs,
952 SUN8I_SCALER_VSU_YHPHASE(layer), hphase); 980 SUN8I_SCALER_VSU_YHPHASE(base), hphase);
953 regmap_write(mixer->engine.regs, 981 regmap_write(mixer->engine.regs,
954 SUN8I_SCALER_VSU_YVPHASE(layer), vphase); 982 SUN8I_SCALER_VSU_YVPHASE(base), vphase);
955 regmap_write(mixer->engine.regs, 983 regmap_write(mixer->engine.regs,
956 SUN8I_SCALER_VSU_CINSIZE(layer), 984 SUN8I_SCALER_VSU_CINSIZE(base),
957 SUN8I_VI_SCALER_SIZE(src_w / format->hsub, 985 SUN8I_VI_SCALER_SIZE(src_w / format->hsub,
958 src_h / format->vsub)); 986 src_h / format->vsub));
959 regmap_write(mixer->engine.regs, 987 regmap_write(mixer->engine.regs,
960 SUN8I_SCALER_VSU_CHSTEP(layer), 988 SUN8I_SCALER_VSU_CHSTEP(base),
961 hscale / format->hsub); 989 hscale / format->hsub);
962 regmap_write(mixer->engine.regs, 990 regmap_write(mixer->engine.regs,
963 SUN8I_SCALER_VSU_CVSTEP(layer), 991 SUN8I_SCALER_VSU_CVSTEP(base),
964 vscale / format->vsub); 992 vscale / format->vsub);
965 regmap_write(mixer->engine.regs, 993 regmap_write(mixer->engine.regs,
966 SUN8I_SCALER_VSU_CHPHASE(layer), chphase); 994 SUN8I_SCALER_VSU_CHPHASE(base), chphase);
967 regmap_write(mixer->engine.regs, 995 regmap_write(mixer->engine.regs,
968 SUN8I_SCALER_VSU_CVPHASE(layer), cvphase); 996 SUN8I_SCALER_VSU_CVPHASE(base), cvphase);
969 sun8i_vi_scaler_set_coeff(mixer->engine.regs, layer, 997 sun8i_vi_scaler_set_coeff(mixer->engine.regs, base,
970 hscale, vscale, format); 998 hscale, vscale, format);
971} 999}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index a595ab643a5a..68f6593b369a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -12,6 +12,12 @@
12#include <drm/drm_fourcc.h> 12#include <drm/drm_fourcc.h>
13#include "sun8i_mixer.h" 13#include "sun8i_mixer.h"
14 14
15#define DE2_VI_SCALER_UNIT_BASE 0x20000
16#define DE2_VI_SCALER_UNIT_SIZE 0x20000
17
18#define DE3_VI_SCALER_UNIT_BASE 0x20000
19#define DE3_VI_SCALER_UNIT_SIZE 0x08000
20
15/* this two macros assumes 16 fractional bits which is standard in DRM */ 21/* this two macros assumes 16 fractional bits which is standard in DRM */
16#define SUN8I_VI_SCALER_SCALE_MIN 1 22#define SUN8I_VI_SCALER_SCALE_MIN 1
17#define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1) 23#define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1)
@@ -21,34 +27,48 @@
21#define SUN8I_VI_SCALER_COEFF_COUNT 32 27#define SUN8I_VI_SCALER_COEFF_COUNT 32
22#define SUN8I_VI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1)) 28#define SUN8I_VI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
23 29
24#define SUN8I_SCALER_VSU_CTRL(ch) (0x20000 + 0x20000 * (ch) + 0x0) 30#define SUN8I_SCALER_VSU_CTRL(base) ((base) + 0x0)
25#define SUN8I_SCALER_VSU_OUTSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x40) 31#define SUN50I_SCALER_VSU_SCALE_MODE(base) ((base) + 0x10)
26#define SUN8I_SCALER_VSU_YINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x80) 32#define SUN50I_SCALER_VSU_DIR_THR(base) ((base) + 0x20)
27#define SUN8I_SCALER_VSU_YHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x88) 33#define SUN50I_SCALER_VSU_EDGE_THR(base) ((base) + 0x24)
28#define SUN8I_SCALER_VSU_YVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x8c) 34#define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)
29#define SUN8I_SCALER_VSU_YHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x90) 35#define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)
30#define SUN8I_SCALER_VSU_YVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x98) 36#define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)
31#define SUN8I_SCALER_VSU_CINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0xc0) 37#define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)
32#define SUN8I_SCALER_VSU_CHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xc8) 38#define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)
33#define SUN8I_SCALER_VSU_CVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xcc) 39#define SUN8I_SCALER_VSU_YVSTEP(base) ((base) + 0x8c)
34#define SUN8I_SCALER_VSU_CHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd0) 40#define SUN8I_SCALER_VSU_YHPHASE(base) ((base) + 0x90)
35#define SUN8I_SCALER_VSU_CVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd8) 41#define SUN8I_SCALER_VSU_YVPHASE(base) ((base) + 0x98)
36#define SUN8I_SCALER_VSU_YHCOEFF0(ch, i) \ 42#define SUN8I_SCALER_VSU_CINSIZE(base) ((base) + 0xc0)
37 (0x20000 + 0x20000 * (ch) + 0x200 + 0x4 * (i)) 43#define SUN8I_SCALER_VSU_CHSTEP(base) ((base) + 0xc8)
38#define SUN8I_SCALER_VSU_YHCOEFF1(ch, i) \ 44#define SUN8I_SCALER_VSU_CVSTEP(base) ((base) + 0xcc)
39 (0x20000 + 0x20000 * (ch) + 0x300 + 0x4 * (i)) 45#define SUN8I_SCALER_VSU_CHPHASE(base) ((base) + 0xd0)
40#define SUN8I_SCALER_VSU_YVCOEFF(ch, i) \ 46#define SUN8I_SCALER_VSU_CVPHASE(base) ((base) + 0xd8)
41 (0x20000 + 0x20000 * (ch) + 0x400 + 0x4 * (i)) 47#define SUN8I_SCALER_VSU_YHCOEFF0(base, i) ((base) + 0x200 + 0x4 * (i))
42#define SUN8I_SCALER_VSU_CHCOEFF0(ch, i) \ 48#define SUN8I_SCALER_VSU_YHCOEFF1(base, i) ((base) + 0x300 + 0x4 * (i))
43 (0x20000 + 0x20000 * (ch) + 0x600 + 0x4 * (i)) 49#define SUN8I_SCALER_VSU_YVCOEFF(base, i) ((base) + 0x400 + 0x4 * (i))
44#define SUN8I_SCALER_VSU_CHCOEFF1(ch, i) \ 50#define SUN8I_SCALER_VSU_CHCOEFF0(base, i) ((base) + 0x600 + 0x4 * (i))
45 (0x20000 + 0x20000 * (ch) + 0x700 + 0x4 * (i)) 51#define SUN8I_SCALER_VSU_CHCOEFF1(base, i) ((base) + 0x700 + 0x4 * (i))
46#define SUN8I_SCALER_VSU_CVCOEFF(ch, i) \ 52#define SUN8I_SCALER_VSU_CVCOEFF(base, i) ((base) + 0x800 + 0x4 * (i))
47 (0x20000 + 0x20000 * (ch) + 0x800 + 0x4 * (i))
48 53
49#define SUN8I_SCALER_VSU_CTRL_EN BIT(0) 54#define SUN8I_SCALER_VSU_CTRL_EN BIT(0)
50#define SUN8I_SCALER_VSU_CTRL_COEFF_RDY BIT(4) 55#define SUN8I_SCALER_VSU_CTRL_COEFF_RDY BIT(4)
51 56
57#define SUN50I_SCALER_VSU_SUB_ZERO_DIR_THR(x) (((x) << 24) & 0xFF)
58#define SUN50I_SCALER_VSU_ZERO_DIR_THR(x) (((x) << 16) & 0xFF)
59#define SUN50I_SCALER_VSU_HORZ_DIR_THR(x) (((x) << 8) & 0xFF)
60#define SUN50I_SCALER_VSU_VERT_DIR_THR(x) ((x) & 0xFF)
61
62#define SUN50I_SCALER_VSU_SCALE_MODE_UI 0
63#define SUN50I_SCALER_VSU_SCALE_MODE_NORMAL 1
64#define SUN50I_SCALER_VSU_SCALE_MODE_ED_SCALE 2
65
66#define SUN50I_SCALER_VSU_EDGE_SHIFT(x) (((x) << 16) & 0xF)
67#define SUN50I_SCALER_VSU_EDGE_OFFSET(x) ((x) & 0xFF)
68
69#define SUN50I_SCALER_VSU_ANGLE_SHIFT(x) (((x) << 16) & 0xF)
70#define SUN50I_SCALER_VSU_ANGLE_OFFSET(x) ((x) & 0xFF)
71
52void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable); 72void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
53void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer, 73void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
54 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h, 74 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 33e533268488..3dac08b24140 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -140,7 +140,6 @@ static int tilcdc_commit(struct drm_device *dev,
140 140
141static const struct drm_mode_config_funcs mode_config_funcs = { 141static const struct drm_mode_config_funcs mode_config_funcs = {
142 .fb_create = tilcdc_fb_create, 142 .fb_create = tilcdc_fb_create,
143 .output_poll_changed = drm_fb_helper_output_poll_changed,
144 .atomic_check = tilcdc_atomic_check, 143 .atomic_check = tilcdc_atomic_check,
145 .atomic_commit = tilcdc_commit, 144 .atomic_commit = tilcdc_commit,
146}; 145};
@@ -191,9 +190,6 @@ static void tilcdc_fini(struct drm_device *dev)
191 drm_dev_unregister(dev); 190 drm_dev_unregister(dev);
192 191
193 drm_kms_helper_poll_fini(dev); 192 drm_kms_helper_poll_fini(dev);
194
195 drm_fb_cma_fbdev_fini(dev);
196
197 drm_irq_uninstall(dev); 193 drm_irq_uninstall(dev);
198 drm_mode_config_cleanup(dev); 194 drm_mode_config_cleanup(dev);
199 tilcdc_remove_external_device(dev); 195 tilcdc_remove_external_device(dev);
@@ -396,16 +392,14 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
396 392
397 drm_mode_config_reset(ddev); 393 drm_mode_config_reset(ddev);
398 394
399 ret = drm_fb_cma_fbdev_init(ddev, bpp, 0);
400 if (ret)
401 goto init_failed;
402
403 drm_kms_helper_poll_init(ddev); 395 drm_kms_helper_poll_init(ddev);
404 396
405 ret = drm_dev_register(ddev, 0); 397 ret = drm_dev_register(ddev, 0);
406 if (ret) 398 if (ret)
407 goto init_failed; 399 goto init_failed;
408 400
401 drm_fbdev_generic_setup(ddev, bpp);
402
409 priv->is_registered = true; 403 priv->is_registered = true;
410 return 0; 404 return 0;
411 405
@@ -519,7 +513,6 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
519static struct drm_driver tilcdc_driver = { 513static struct drm_driver tilcdc_driver = {
520 .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | 514 .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
521 DRIVER_PRIME | DRIVER_ATOMIC), 515 DRIVER_PRIME | DRIVER_ATOMIC),
522 .lastclose = drm_fb_helper_lastclose,
523 .irq_handler = tilcdc_irq, 516 .irq_handler = tilcdc_irq,
524 .gem_free_object_unlocked = drm_gem_cma_free_object, 517 .gem_free_object_unlocked = drm_gem_cma_free_object,
525 .gem_print_info = drm_gem_cma_print_info, 518 .gem_print_info = drm_gem_cma_print_info,
diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
index 16f4b5c91f1b..2c408ac1a900 100644
--- a/drivers/gpu/drm/tinydrm/Kconfig
+++ b/drivers/gpu/drm/tinydrm/Kconfig
@@ -10,6 +10,17 @@ menuconfig DRM_TINYDRM
10config TINYDRM_MIPI_DBI 10config TINYDRM_MIPI_DBI
11 tristate 11 tristate
12 12
13config TINYDRM_HX8357D
14 tristate "DRM support for HX8357D display panels"
15 depends on DRM_TINYDRM && SPI
16 depends on BACKLIGHT_CLASS_DEVICE
17 select TINYDRM_MIPI_DBI
18 help
19 DRM driver for the following HX8357D panels:
20 * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5")
21
22 If M is selected the module will be called hx8357d.
23
13config TINYDRM_ILI9225 24config TINYDRM_ILI9225
14 tristate "DRM support for ILI9225 display panels" 25 tristate "DRM support for ILI9225 display panels"
15 depends on DRM_TINYDRM && SPI 26 depends on DRM_TINYDRM && SPI
diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile
index 14d99080665a..f823066f7743 100644
--- a/drivers/gpu/drm/tinydrm/Makefile
+++ b/drivers/gpu/drm/tinydrm/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM) += core/
4obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o 4obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o
5 5
6# Displays 6# Displays
7obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
7obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o 8obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o
8obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o 9obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o
9obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o 10obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 255341ee4eb9..9af51d982a33 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -146,6 +146,7 @@ static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
146 drm->dev_private = tdev; 146 drm->dev_private = tdev;
147 drm_mode_config_init(drm); 147 drm_mode_config_init(drm);
148 drm->mode_config.funcs = &tinydrm_mode_config_funcs; 148 drm->mode_config.funcs = &tinydrm_mode_config_funcs;
149 drm->mode_config.allow_fb_modifiers = true;
149 150
150 return 0; 151 return 0;
151} 152}
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
index 7e8e24d0b7a7..eacfc0ec8ff1 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
@@ -184,6 +184,10 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
184 struct drm_display_mode mode_copy; 184 struct drm_display_mode mode_copy;
185 struct drm_connector *connector; 185 struct drm_connector *connector;
186 int ret; 186 int ret;
187 static const uint64_t modifiers[] = {
188 DRM_FORMAT_MOD_LINEAR,
189 DRM_FORMAT_MOD_INVALID
190 };
187 191
188 drm_mode_copy(&mode_copy, mode); 192 drm_mode_copy(&mode_copy, mode);
189 ret = tinydrm_rotate_mode(&mode_copy, rotation); 193 ret = tinydrm_rotate_mode(&mode_copy, rotation);
@@ -202,6 +206,6 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
202 return PTR_ERR(connector); 206 return PTR_ERR(connector);
203 207
204 return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats, 208 return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
205 format_count, NULL, connector); 209 format_count, modifiers, connector);
206} 210}
207EXPORT_SYMBOL(tinydrm_display_pipe_init); 211EXPORT_SYMBOL(tinydrm_display_pipe_init);
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c
new file mode 100644
index 000000000000..c3e51c2baebc
--- /dev/null
+++ b/drivers/gpu/drm/tinydrm/hx8357d.c
@@ -0,0 +1,270 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * DRM driver for the HX8357D LCD controller
4 *
5 * Copyright 2018 Broadcom
6 * Copyright 2018 David Lechner <david@lechnology.com>
7 * Copyright 2016 Noralf Trønnes
8 * Copyright (C) 2015 Adafruit Industries
9 * Copyright (C) 2013 Christian Vogelgsang
10 */
11
12#include <linux/backlight.h>
13#include <linux/delay.h>
14#include <linux/gpio/consumer.h>
15#include <linux/module.h>
16#include <linux/property.h>
17#include <linux/spi/spi.h>
18
19#include <drm/drm_fb_helper.h>
20#include <drm/drm_gem_framebuffer_helper.h>
21#include <drm/drm_modeset_helper.h>
22#include <drm/tinydrm/mipi-dbi.h>
23#include <drm/tinydrm/tinydrm-helpers.h>
24#include <video/mipi_display.h>
25
26#define HX8357D_SETOSC 0xb0
27#define HX8357D_SETPOWER 0xb1
28#define HX8357D_SETRGB 0xb3
29#define HX8357D_SETCYC 0xb3
30#define HX8357D_SETCOM 0xb6
31#define HX8357D_SETEXTC 0xb9
32#define HX8357D_SETSTBA 0xc0
33#define HX8357D_SETPANEL 0xcc
34#define HX8357D_SETGAMMA 0xe0
35
36#define HX8357D_MADCTL_MY 0x80
37#define HX8357D_MADCTL_MX 0x40
38#define HX8357D_MADCTL_MV 0x20
39#define HX8357D_MADCTL_ML 0x10
40#define HX8357D_MADCTL_RGB 0x00
41#define HX8357D_MADCTL_BGR 0x08
42#define HX8357D_MADCTL_MH 0x04
43
44static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
45 struct drm_crtc_state *crtc_state,
46 struct drm_plane_state *plane_state)
47{
48 struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
49 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
50 u8 addr_mode;
51 int ret;
52
53 DRM_DEBUG_KMS("\n");
54
55 ret = mipi_dbi_poweron_conditional_reset(mipi);
56 if (ret < 0)
57 return;
58 if (ret == 1)
59 goto out_enable;
60
61 /* setextc */
62 mipi_dbi_command(mipi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
63 msleep(150);
64
65 /* setRGB which also enables SDO */
66 mipi_dbi_command(mipi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
67
68 /* -1.52V */
69 mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
70
71 /* Normal mode 70Hz, Idle mode 55 Hz */
72 mipi_dbi_command(mipi, HX8357D_SETOSC, 0x68);
73
74 /* Set Panel - BGR, Gate direction swapped */
75 mipi_dbi_command(mipi, HX8357D_SETPANEL, 0x05);
76
77 mipi_dbi_command(mipi, HX8357D_SETPOWER,
78 0x00, /* Not deep standby */
79 0x15, /* BT */
80 0x1C, /* VSPR */
81 0x1C, /* VSNR */
82 0x83, /* AP */
83 0xAA); /* FS */
84
85 mipi_dbi_command(mipi, HX8357D_SETSTBA,
86 0x50, /* OPON normal */
87 0x50, /* OPON idle */
88 0x01, /* STBA */
89 0x3C, /* STBA */
90 0x1E, /* STBA */
91 0x08); /* GEN */
92
93 mipi_dbi_command(mipi, HX8357D_SETCYC,
94 0x02, /* NW 0x02 */
95 0x40, /* RTN */
96 0x00, /* DIV */
97 0x2A, /* DUM */
98 0x2A, /* DUM */
99 0x0D, /* GDON */
100 0x78); /* GDOFF */
101
102 mipi_dbi_command(mipi, HX8357D_SETGAMMA,
103 0x02,
104 0x0A,
105 0x11,
106 0x1d,
107 0x23,
108 0x35,
109 0x41,
110 0x4b,
111 0x4b,
112 0x42,
113 0x3A,
114 0x27,
115 0x1B,
116 0x08,
117 0x09,
118 0x03,
119 0x02,
120 0x0A,
121 0x11,
122 0x1d,
123 0x23,
124 0x35,
125 0x41,
126 0x4b,
127 0x4b,
128 0x42,
129 0x3A,
130 0x27,
131 0x1B,
132 0x08,
133 0x09,
134 0x03,
135 0x00,
136 0x01);
137
138 /* 16 bit */
139 mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
140 MIPI_DCS_PIXEL_FMT_16BIT);
141
142 /* TE off */
143 mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
144
145 /* tear line */
146 mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
147
148 /* Exit Sleep */
149 mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
150 msleep(150);
151
152 /* display on */
153 mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
154 usleep_range(5000, 7000);
155
156out_enable:
157 switch (mipi->rotation) {
158 default:
159 addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
160 break;
161 case 90:
162 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
163 break;
164 case 180:
165 addr_mode = 0;
166 break;
167 case 270:
168 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
169 break;
170 }
171 mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
172 mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
173}
174
175static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
176 .enable = yx240qv29_enable,
177 .disable = mipi_dbi_pipe_disable,
178 .update = tinydrm_display_pipe_update,
179 .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
180};
181
182static const struct drm_display_mode yx350hv15_mode = {
183 TINYDRM_MODE(320, 480, 60, 75),
184};
185
186DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
187
188static struct drm_driver hx8357d_driver = {
189 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
190 .fops = &hx8357d_fops,
191 TINYDRM_GEM_DRIVER_OPS,
192 .debugfs_init = mipi_dbi_debugfs_init,
193 .name = "hx8357d",
194 .desc = "HX8357D",
195 .date = "20181023",
196 .major = 1,
197 .minor = 0,
198};
199
200static const struct of_device_id hx8357d_of_match[] = {
201 { .compatible = "adafruit,yx350hv15" },
202 { }
203};
204MODULE_DEVICE_TABLE(of, hx8357d_of_match);
205
206static const struct spi_device_id hx8357d_id[] = {
207 { "yx350hv15", 0 },
208 { }
209};
210MODULE_DEVICE_TABLE(spi, hx8357d_id);
211
212static int hx8357d_probe(struct spi_device *spi)
213{
214 struct device *dev = &spi->dev;
215 struct mipi_dbi *mipi;
216 struct gpio_desc *dc;
217 u32 rotation = 0;
218 int ret;
219
220 mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
221 if (!mipi)
222 return -ENOMEM;
223
224 dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
225 if (IS_ERR(dc)) {
226 DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
227 return PTR_ERR(dc);
228 }
229
230 mipi->backlight = devm_of_find_backlight(dev);
231 if (IS_ERR(mipi->backlight))
232 return PTR_ERR(mipi->backlight);
233
234 device_property_read_u32(dev, "rotation", &rotation);
235
236 ret = mipi_dbi_spi_init(spi, mipi, dc);
237 if (ret)
238 return ret;
239
240 ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs,
241 &hx8357d_driver, &yx350hv15_mode, rotation);
242 if (ret)
243 return ret;
244
245 spi_set_drvdata(spi, mipi);
246
247 return devm_tinydrm_register(&mipi->tinydrm);
248}
249
250static void hx8357d_shutdown(struct spi_device *spi)
251{
252 struct mipi_dbi *mipi = spi_get_drvdata(spi);
253
254 tinydrm_shutdown(&mipi->tinydrm);
255}
256
257static struct spi_driver hx8357d_spi_driver = {
258 .driver = {
259 .name = "hx8357d",
260 .of_match_table = hx8357d_of_match,
261 },
262 .id_table = hx8357d_id,
263 .probe = hx8357d_probe,
264 .shutdown = hx8357d_shutdown,
265};
266module_spi_driver(hx8357d_spi_driver);
267
268MODULE_DESCRIPTION("HX8357D DRM driver");
269MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
270MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c
index cb3441e51d5f..1bb870021f6e 100644
--- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
+++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
@@ -240,10 +240,10 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
240 240
241 mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS, 241 mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
242 (clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF, 242 (clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF,
243 (clip.x2 >> 8) & 0xFF, (clip.x2 - 1) & 0xFF); 243 ((clip.x2 - 1) >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
244 mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS, 244 mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
245 (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF, 245 (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
246 (clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF); 246 ((clip.y2 - 1) >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
247 247
248 ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr, 248 ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
249 (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2); 249 (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 26b889f86670..83b4657ffb10 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -872,7 +872,7 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
872 if (fence) { 872 if (fence) {
873 reservation_object_add_shared_fence(bo->resv, fence); 873 reservation_object_add_shared_fence(bo->resv, fence);
874 874
875 ret = reservation_object_reserve_shared(bo->resv); 875 ret = reservation_object_reserve_shared(bo->resv, 1);
876 if (unlikely(ret)) 876 if (unlikely(ret))
877 return ret; 877 return ret;
878 878
@@ -977,7 +977,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
977 bool has_erestartsys = false; 977 bool has_erestartsys = false;
978 int i, ret; 978 int i, ret;
979 979
980 ret = reservation_object_reserve_shared(bo->resv); 980 ret = reservation_object_reserve_shared(bo->resv, 1);
981 if (unlikely(ret)) 981 if (unlikely(ret))
982 return ret; 982 return ret;
983 983
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index e73ae0d22897..e493edb0d3e7 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -129,7 +129,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
129 if (!entry->shared) 129 if (!entry->shared)
130 continue; 130 continue;
131 131
132 ret = reservation_object_reserve_shared(bo->resv); 132 ret = reservation_object_reserve_shared(bo->resv, 1);
133 if (!ret) 133 if (!ret)
134 continue; 134 continue;
135 } 135 }
@@ -151,7 +151,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
151 } 151 }
152 152
153 if (!ret && entry->shared) 153 if (!ret && entry->shared)
154 ret = reservation_object_reserve_shared(bo->resv); 154 ret = reservation_object_reserve_shared(bo->resv, 1);
155 155
156 if (unlikely(ret != 0)) { 156 if (unlikely(ret != 0)) {
157 if (ret == -EINTR) 157 if (ret == -EINTR)
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index f455f095a146..1b014d92855b 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -350,15 +350,10 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
350 if (ret) 350 if (ret)
351 goto err; 351 goto err;
352 352
353 ret = drm_vblank_init(dev, 1);
354 if (ret)
355 goto err_fb;
356
357 drm_kms_helper_poll_init(dev); 353 drm_kms_helper_poll_init(dev);
358 354
359 return 0; 355 return 0;
360err_fb: 356
361 udl_fbdev_cleanup(dev);
362err: 357err:
363 if (udl->urbs.count) 358 if (udl->urbs.count)
364 udl_free_urb_list(dev); 359 udl_free_urb_list(dev);
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
index 4db62c545748..eb2b2d2f8553 100644
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
@@ -71,10 +71,13 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
71 V3D_READ(v3d_hub_reg_defs[i].reg)); 71 V3D_READ(v3d_hub_reg_defs[i].reg));
72 } 72 }
73 73
74 for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) { 74 if (v3d->ver < 41) {
75 seq_printf(m, "%s (0x%04x): 0x%08x\n", 75 for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
76 v3d_gca_reg_defs[i].name, v3d_gca_reg_defs[i].reg, 76 seq_printf(m, "%s (0x%04x): 0x%08x\n",
77 V3D_GCA_READ(v3d_gca_reg_defs[i].reg)); 77 v3d_gca_reg_defs[i].name,
78 v3d_gca_reg_defs[i].reg,
79 V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
80 }
78 } 81 }
79 82
80 for (core = 0; core < v3d->cores; core++) { 83 for (core = 0; core < v3d->cores; core++) {
@@ -176,9 +179,44 @@ static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
176 return 0; 179 return 0;
177} 180}
178 181
182static int v3d_measure_clock(struct seq_file *m, void *unused)
183{
184 struct drm_info_node *node = (struct drm_info_node *)m->private;
185 struct drm_device *dev = node->minor->dev;
186 struct v3d_dev *v3d = to_v3d_dev(dev);
187 uint32_t cycles;
188 int core = 0;
189 int measure_ms = 1000;
190
191 if (v3d->ver >= 40) {
192 V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
193 V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
194 V3D_PCTR_S0));
195 V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
196 V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
197 } else {
198 V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
199 V3D_PCTR_CYCLE_COUNT);
200 V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
201 V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
202 V3D_V3_PCTR_0_EN_ENABLE |
203 1);
204 }
205 msleep(measure_ms);
206 cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
207
208 seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
209 cycles,
210 cycles / (measure_ms * 1000),
211 (cycles / (measure_ms * 100)) % 10);
212
213 return 0;
214}
215
179static const struct drm_info_list v3d_debugfs_list[] = { 216static const struct drm_info_list v3d_debugfs_list[] = {
180 {"v3d_ident", v3d_v3d_debugfs_ident, 0}, 217 {"v3d_ident", v3d_v3d_debugfs_ident, 0},
181 {"v3d_regs", v3d_v3d_debugfs_regs, 0}, 218 {"v3d_regs", v3d_v3d_debugfs_regs, 0},
219 {"measure_clock", v3d_measure_clock, 0},
182 {"bo_stats", v3d_debugfs_bo_stats, 0}, 220 {"bo_stats", v3d_debugfs_bo_stats, 0},
183}; 221};
184 222
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index e6fed696ad86..cbe5be0c47eb 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -198,6 +198,11 @@ struct v3d_exec_info {
198 */ 198 */
199 struct dma_fence *bin_done_fence; 199 struct dma_fence *bin_done_fence;
200 200
201 /* Fence for when the scheduler considers the render to be
202 * done, for when the BOs reservations should be complete.
203 */
204 struct dma_fence *render_done_fence;
205
201 struct kref refcount; 206 struct kref refcount;
202 207
203 /* This is the array of BOs that were looked up at the start of exec. */ 208 /* This is the array of BOs that were looked up at the start of exec. */
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 70c54774400b..b88c96911453 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -209,7 +209,7 @@ v3d_flush_caches(struct v3d_dev *v3d)
209static void 209static void
210v3d_attach_object_fences(struct v3d_exec_info *exec) 210v3d_attach_object_fences(struct v3d_exec_info *exec)
211{ 211{
212 struct dma_fence *out_fence = &exec->render.base.s_fence->finished; 212 struct dma_fence *out_fence = exec->render_done_fence;
213 struct v3d_bo *bo; 213 struct v3d_bo *bo;
214 int i; 214 int i;
215 215
@@ -305,7 +305,7 @@ retry:
305 for (i = 0; i < exec->bo_count; i++) { 305 for (i = 0; i < exec->bo_count; i++) {
306 bo = to_v3d_bo(&exec->bo[i]->base); 306 bo = to_v3d_bo(&exec->bo[i]->base);
307 307
308 ret = reservation_object_reserve_shared(bo->resv); 308 ret = reservation_object_reserve_shared(bo->resv, 1);
309 if (ret) { 309 if (ret) {
310 v3d_unlock_bo_reservations(dev, exec, acquire_ctx); 310 v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
311 return ret; 311 return ret;
@@ -409,6 +409,7 @@ v3d_exec_cleanup(struct kref *ref)
409 dma_fence_put(exec->render.done_fence); 409 dma_fence_put(exec->render.done_fence);
410 410
411 dma_fence_put(exec->bin_done_fence); 411 dma_fence_put(exec->bin_done_fence);
412 dma_fence_put(exec->render_done_fence);
412 413
413 for (i = 0; i < exec->bo_count; i++) 414 for (i = 0; i < exec->bo_count; i++)
414 drm_gem_object_put_unlocked(&exec->bo[i]->base); 415 drm_gem_object_put_unlocked(&exec->bo[i]->base);
@@ -521,12 +522,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
521 kref_init(&exec->refcount); 522 kref_init(&exec->refcount);
522 523
523 ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl, 524 ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
524 0, &exec->bin.in_fence); 525 0, 0, &exec->bin.in_fence);
525 if (ret == -EINVAL) 526 if (ret == -EINVAL)
526 goto fail; 527 goto fail;
527 528
528 ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl, 529 ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
529 0, &exec->render.in_fence); 530 0, 0, &exec->render.in_fence);
530 if (ret == -EINVAL) 531 if (ret == -EINVAL)
531 goto fail; 532 goto fail;
532 533
@@ -572,6 +573,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
572 if (ret) 573 if (ret)
573 goto fail_unreserve; 574 goto fail_unreserve;
574 575
576 exec->render_done_fence =
577 dma_fence_get(&exec->render.base.s_fence->finished);
578
575 kref_get(&exec->refcount); /* put by scheduler job completion */ 579 kref_get(&exec->refcount); /* put by scheduler job completion */
576 drm_sched_entity_push_job(&exec->render.base, 580 drm_sched_entity_push_job(&exec->render.base,
577 &v3d_priv->sched_entity[V3D_RENDER]); 581 &v3d_priv->sched_entity[V3D_RENDER]);
@@ -585,7 +589,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
585 sync_out = drm_syncobj_find(file_priv, args->out_sync); 589 sync_out = drm_syncobj_find(file_priv, args->out_sync);
586 if (sync_out) { 590 if (sync_out) {
587 drm_syncobj_replace_fence(sync_out, 0, 591 drm_syncobj_replace_fence(sync_out, 0,
588 &exec->render.base.s_fence->finished); 592 exec->render_done_fence);
589 drm_syncobj_put(sync_out); 593 drm_syncobj_put(sync_out);
590 } 594 }
591 595
diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h
index 854046565989..c3a5e4e44f73 100644
--- a/drivers/gpu/drm/v3d/v3d_regs.h
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
@@ -267,6 +267,36 @@
267# define V3D_PTB_BXCF_RWORDERDISA BIT(1) 267# define V3D_PTB_BXCF_RWORDERDISA BIT(1)
268# define V3D_PTB_BXCF_CLIPDISA BIT(0) 268# define V3D_PTB_BXCF_CLIPDISA BIT(0)
269 269
270#define V3D_V3_PCTR_0_EN 0x00674
271#define V3D_V3_PCTR_0_EN_ENABLE BIT(31)
272#define V3D_V4_PCTR_0_EN 0x00650
273/* When a bit is set, resets the counter to 0. */
274#define V3D_V3_PCTR_0_CLR 0x00670
275#define V3D_V4_PCTR_0_CLR 0x00654
276#define V3D_PCTR_0_OVERFLOW 0x00658
277
278#define V3D_V3_PCTR_0_PCTRS0 0x00684
279#define V3D_V3_PCTR_0_PCTRS15 0x00660
280#define V3D_V3_PCTR_0_PCTRSX(x) (V3D_V3_PCTR_0_PCTRS0 + \
281 4 * (x))
282/* Each src reg muxes four counters each. */
283#define V3D_V4_PCTR_0_SRC_0_3 0x00660
284#define V3D_V4_PCTR_0_SRC_28_31 0x0067c
285# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
286# define V3D_PCTR_S0_SHIFT 0
287# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)
288# define V3D_PCTR_S1_SHIFT 8
289# define V3D_PCTR_S2_MASK V3D_MASK(22, 16)
290# define V3D_PCTR_S2_SHIFT 16
291# define V3D_PCTR_S3_MASK V3D_MASK(30, 24)
292# define V3D_PCTR_S3_SHIFT 24
293# define V3D_PCTR_CYCLE_COUNT 32
294
295/* Output values of the counters. */
296#define V3D_PCTR_0_PCTR0 0x00680
297#define V3D_PCTR_0_PCTR31 0x006fc
298#define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \
299 4 * (x))
270#define V3D_GMP_STATUS 0x00800 300#define V3D_GMP_STATUS 0x00800
271# define V3D_GMP_STATUS_GMPRST BIT(31) 301# define V3D_GMP_STATUS_GMPRST BIT(31)
272# define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24) 302# define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 1f1780ccdbdf..f6f5cd80c04d 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -33,6 +33,7 @@
33#include <linux/pm_runtime.h> 33#include <linux/pm_runtime.h>
34#include <drm/drm_fb_cma_helper.h> 34#include <drm/drm_fb_cma_helper.h>
35#include <drm/drm_fb_helper.h> 35#include <drm/drm_fb_helper.h>
36#include <drm/drm_atomic_helper.h>
36 37
37#include "uapi/drm/vc4_drm.h" 38#include "uapi/drm/vc4_drm.h"
38#include "vc4_drv.h" 39#include "vc4_drv.h"
@@ -308,6 +309,8 @@ static void vc4_drm_unbind(struct device *dev)
308 309
309 drm_dev_unregister(drm); 310 drm_dev_unregister(drm);
310 311
312 drm_atomic_helper_shutdown(drm);
313
311 drm_mode_config_cleanup(drm); 314 drm_mode_config_cleanup(drm);
312 315
313 drm_atomic_private_obj_fini(&vc4->ctm_manager); 316 drm_atomic_private_obj_fini(&vc4->ctm_manager);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 5b22e996af6c..41881ce4132d 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -635,7 +635,7 @@ retry:
635 for (i = 0; i < exec->bo_count; i++) { 635 for (i = 0; i < exec->bo_count; i++) {
636 bo = to_vc4_bo(&exec->bo[i]->base); 636 bo = to_vc4_bo(&exec->bo[i]->base);
637 637
638 ret = reservation_object_reserve_shared(bo->resv); 638 ret = reservation_object_reserve_shared(bo->resv, 1);
639 if (ret) { 639 if (ret) {
640 vc4_unlock_bo_reservations(dev, exec, acquire_ctx); 640 vc4_unlock_bo_reservations(dev, exec, acquire_ctx);
641 return ret; 641 return ret;
@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
1173 1173
1174 if (args->in_sync) { 1174 if (args->in_sync) {
1175 ret = drm_syncobj_find_fence(file_priv, args->in_sync, 1175 ret = drm_syncobj_find_fence(file_priv, args->in_sync,
1176 0, &in_fence); 1176 0, 0, &in_fence);
1177 if (ret) 1177 if (ret)
1178 goto fail; 1178 goto fail;
1179 1179
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 9dc3fcbd290b..98fae4daa08c 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -266,30 +266,59 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
266 u32 subpixel_src_mask = (1 << 16) - 1; 266 u32 subpixel_src_mask = (1 << 16) - 1;
267 u32 format = fb->format->format; 267 u32 format = fb->format->format;
268 int num_planes = fb->format->num_planes; 268 int num_planes = fb->format->num_planes;
269 u32 h_subsample = 1; 269 int min_scale = 1, max_scale = INT_MAX;
270 u32 v_subsample = 1; 270 struct drm_crtc_state *crtc_state;
271 int i; 271 u32 h_subsample, v_subsample;
272 int i, ret;
273
274 crtc_state = drm_atomic_get_existing_crtc_state(state->state,
275 state->crtc);
276 if (!crtc_state) {
277 DRM_DEBUG_KMS("Invalid crtc state\n");
278 return -EINVAL;
279 }
280
281 /* No configuring scaling on the cursor plane, since it gets
282 * non-vblank-synced updates, and scaling requires LBM changes which
283 * have to be vblank-synced.
284 */
285 if (plane->type == DRM_PLANE_TYPE_CURSOR) {
286 min_scale = DRM_PLANE_HELPER_NO_SCALING;
287 max_scale = DRM_PLANE_HELPER_NO_SCALING;
288 } else {
289 min_scale = 1;
290 max_scale = INT_MAX;
291 }
292
293 ret = drm_atomic_helper_check_plane_state(state, crtc_state,
294 min_scale, max_scale,
295 true, true);
296 if (ret)
297 return ret;
298
299 h_subsample = drm_format_horz_chroma_subsampling(format);
300 v_subsample = drm_format_vert_chroma_subsampling(format);
272 301
273 for (i = 0; i < num_planes; i++) 302 for (i = 0; i < num_planes; i++)
274 vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; 303 vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
275 304
276 /* We don't support subpixel source positioning for scaling. */ 305 /* We don't support subpixel source positioning for scaling. */
277 if ((state->src_x & subpixel_src_mask) || 306 if ((state->src.x1 & subpixel_src_mask) ||
278 (state->src_y & subpixel_src_mask) || 307 (state->src.x2 & subpixel_src_mask) ||
279 (state->src_w & subpixel_src_mask) || 308 (state->src.y1 & subpixel_src_mask) ||
280 (state->src_h & subpixel_src_mask)) { 309 (state->src.y2 & subpixel_src_mask)) {
281 return -EINVAL; 310 return -EINVAL;
282 } 311 }
283 312
284 vc4_state->src_x = state->src_x >> 16; 313 vc4_state->src_x = state->src.x1 >> 16;
285 vc4_state->src_y = state->src_y >> 16; 314 vc4_state->src_y = state->src.y1 >> 16;
286 vc4_state->src_w[0] = state->src_w >> 16; 315 vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
287 vc4_state->src_h[0] = state->src_h >> 16; 316 vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
288 317
289 vc4_state->crtc_x = state->crtc_x; 318 vc4_state->crtc_x = state->dst.x1;
290 vc4_state->crtc_y = state->crtc_y; 319 vc4_state->crtc_y = state->dst.y1;
291 vc4_state->crtc_w = state->crtc_w; 320 vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
292 vc4_state->crtc_h = state->crtc_h; 321 vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
293 322
294 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0], 323 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
295 vc4_state->crtc_w); 324 vc4_state->crtc_w);
@@ -302,8 +331,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
302 if (num_planes > 1) { 331 if (num_planes > 1) {
303 vc4_state->is_yuv = true; 332 vc4_state->is_yuv = true;
304 333
305 h_subsample = drm_format_horz_chroma_subsampling(format);
306 v_subsample = drm_format_vert_chroma_subsampling(format);
307 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample; 334 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
308 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample; 335 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
309 336
@@ -321,45 +348,11 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
321 if (vc4_state->is_unity) 348 if (vc4_state->is_unity)
322 vc4_state->x_scaling[0] = VC4_SCALING_PPF; 349 vc4_state->x_scaling[0] = VC4_SCALING_PPF;
323 } else { 350 } else {
351 vc4_state->is_yuv = false;
324 vc4_state->x_scaling[1] = VC4_SCALING_NONE; 352 vc4_state->x_scaling[1] = VC4_SCALING_NONE;
325 vc4_state->y_scaling[1] = VC4_SCALING_NONE; 353 vc4_state->y_scaling[1] = VC4_SCALING_NONE;
326 } 354 }
327 355
328 /* No configuring scaling on the cursor plane, since it gets
329 non-vblank-synced updates, and scaling requires requires
330 LBM changes which have to be vblank-synced.
331 */
332 if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
333 return -EINVAL;
334
335 /* Clamp the on-screen start x/y to 0. The hardware doesn't
336 * support negative y, and negative x wastes bandwidth.
337 */
338 if (vc4_state->crtc_x < 0) {
339 for (i = 0; i < num_planes; i++) {
340 u32 cpp = fb->format->cpp[i];
341 u32 subs = ((i == 0) ? 1 : h_subsample);
342
343 vc4_state->offsets[i] += (cpp *
344 (-vc4_state->crtc_x) / subs);
345 }
346 vc4_state->src_w[0] += vc4_state->crtc_x;
347 vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
348 vc4_state->crtc_x = 0;
349 }
350
351 if (vc4_state->crtc_y < 0) {
352 for (i = 0; i < num_planes; i++) {
353 u32 subs = ((i == 0) ? 1 : v_subsample);
354
355 vc4_state->offsets[i] += (fb->pitches[i] *
356 (-vc4_state->crtc_y) / subs);
357 }
358 vc4_state->src_h[0] += vc4_state->crtc_y;
359 vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
360 vc4_state->crtc_y = 0;
361 }
362
363 return 0; 356 return 0;
364} 357}
365 358
@@ -467,6 +460,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
467 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); 460 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
468 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); 461 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
469 int num_planes = drm_format_num_planes(format->drm); 462 int num_planes = drm_format_num_planes(format->drm);
463 u32 h_subsample, v_subsample;
470 bool mix_plane_alpha; 464 bool mix_plane_alpha;
471 bool covers_screen; 465 bool covers_screen;
472 u32 scl0, scl1, pitch0; 466 u32 scl0, scl1, pitch0;
@@ -512,26 +506,77 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
512 scl1 = vc4_get_scl_field(state, 0); 506 scl1 = vc4_get_scl_field(state, 0);
513 } 507 }
514 508
509 h_subsample = drm_format_horz_chroma_subsampling(format->drm);
510 v_subsample = drm_format_vert_chroma_subsampling(format->drm);
511
515 switch (base_format_mod) { 512 switch (base_format_mod) {
516 case DRM_FORMAT_MOD_LINEAR: 513 case DRM_FORMAT_MOD_LINEAR:
517 tiling = SCALER_CTL0_TILING_LINEAR; 514 tiling = SCALER_CTL0_TILING_LINEAR;
518 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); 515 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
516
517 /* Adjust the base pointer to the first pixel to be scanned
518 * out.
519 */
520 for (i = 0; i < num_planes; i++) {
521 vc4_state->offsets[i] += vc4_state->src_y /
522 (i ? v_subsample : 1) *
523 fb->pitches[i];
524 vc4_state->offsets[i] += vc4_state->src_x /
525 (i ? h_subsample : 1) *
526 fb->format->cpp[i];
527 }
528
519 break; 529 break;
520 530
521 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: { 531 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
522 /* For T-tiled, the FB pitch is "how many bytes from
523 * one row to the next, such that pitch * tile_h ==
524 * tile_size * tiles_per_row."
525 */
526 u32 tile_size_shift = 12; /* T tiles are 4kb */ 532 u32 tile_size_shift = 12; /* T tiles are 4kb */
533 /* Whole-tile offsets, mostly for setting the pitch. */
534 u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
527 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */ 535 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
536 u32 tile_w_mask = (1 << tile_w_shift) - 1;
537 /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
538 * the height (in pixels) of a 4k tile.
539 */
540 u32 tile_h_mask = (2 << tile_h_shift) - 1;
541 /* For T-tiled, the FB pitch is "how many bytes from one row to
542 * the next, such that
543 *
544 * pitch * tile_h == tile_size * tiles_per_row
545 */
528 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift); 546 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
547 u32 tiles_l = vc4_state->src_x >> tile_w_shift;
548 u32 tiles_r = tiles_w - tiles_l;
549 u32 tiles_t = vc4_state->src_y >> tile_h_shift;
550 /* Intra-tile offsets, which modify the base address (the
551 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
552 * base address).
553 */
554 u32 tile_y = (vc4_state->src_y >> 4) & 1;
555 u32 subtile_y = (vc4_state->src_y >> 2) & 3;
556 u32 utile_y = vc4_state->src_y & 3;
557 u32 x_off = vc4_state->src_x & tile_w_mask;
558 u32 y_off = vc4_state->src_y & tile_h_mask;
529 559
530 tiling = SCALER_CTL0_TILING_256B_OR_T; 560 tiling = SCALER_CTL0_TILING_256B_OR_T;
561 pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
562 VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
563 VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
564 VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
565 vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
566 vc4_state->offsets[0] += subtile_y << 8;
567 vc4_state->offsets[0] += utile_y << 4;
568
569 /* Rows of tiles alternate left-to-right and right-to-left. */
570 if (tiles_t & 1) {
571 pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
572 vc4_state->offsets[0] += (tiles_w - tiles_l) <<
573 tile_size_shift;
574 vc4_state->offsets[0] -= (1 + !tile_y) << 10;
575 } else {
576 vc4_state->offsets[0] += tiles_l << tile_size_shift;
577 vc4_state->offsets[0] += tile_y << 10;
578 }
531 579
532 pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
533 VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
534 VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
535 break; 580 break;
536 } 581 }
537 582
@@ -903,7 +948,6 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
903 948
904static void vc4_plane_destroy(struct drm_plane *plane) 949static void vc4_plane_destroy(struct drm_plane *plane)
905{ 950{
906 drm_plane_helper_disable(plane, NULL);
907 drm_plane_cleanup(plane); 951 drm_plane_cleanup(plane);
908} 952}
909 953
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index d6864fa4bd14..931088014272 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -1037,14 +1037,18 @@ enum hvs_pixel_format {
1037#define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0) 1037#define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0)
1038#define SCALER_TILE_HEIGHT_SHIFT 0 1038#define SCALER_TILE_HEIGHT_SHIFT 0
1039 1039
1040/* Common PITCH0 fields */
1041#define SCALER_PITCH0_SINK_PIX_MASK VC4_MASK(31, 26)
1042#define SCALER_PITCH0_SINK_PIX_SHIFT 26
1043
1040/* PITCH0 fields for T-tiled. */ 1044/* PITCH0 fields for T-tiled. */
1041#define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16) 1045#define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
1042#define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16 1046#define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
1043#define SCALER_PITCH0_TILE_LINE_DIR BIT(15) 1047#define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
1044#define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14) 1048#define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
1045/* Y offset within a tile. */ 1049/* Y offset within a tile. */
1046#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7) 1050#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 8)
1047#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7 1051#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 8
1048#define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0) 1052#define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
1049#define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0 1053#define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
1050 1054
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index ec6af8b920da..5930facd6d2d 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -431,7 +431,8 @@ static void vgem_release(struct drm_device *dev)
431} 431}
432 432
433static struct drm_driver vgem_driver = { 433static struct drm_driver vgem_driver = {
434 .driver_features = DRIVER_GEM | DRIVER_PRIME, 434 .driver_features = DRIVER_GEM | DRIVER_PRIME |
435 DRIVER_RENDER,
435 .release = vgem_release, 436 .release = vgem_release,
436 .open = vgem_open, 437 .open = vgem_open,
437 .postclose = vgem_postclose, 438 .postclose = vgem_postclose,
@@ -471,31 +472,31 @@ static int __init vgem_init(void)
471 if (!vgem_device) 472 if (!vgem_device)
472 return -ENOMEM; 473 return -ENOMEM;
473 474
474 ret = drm_dev_init(&vgem_device->drm, &vgem_driver, NULL);
475 if (ret)
476 goto out_free;
477
478 vgem_device->platform = 475 vgem_device->platform =
479 platform_device_register_simple("vgem", -1, NULL, 0); 476 platform_device_register_simple("vgem", -1, NULL, 0);
480 if (IS_ERR(vgem_device->platform)) { 477 if (IS_ERR(vgem_device->platform)) {
481 ret = PTR_ERR(vgem_device->platform); 478 ret = PTR_ERR(vgem_device->platform);
482 goto out_fini; 479 goto out_free;
483 } 480 }
484 481
485 dma_coerce_mask_and_coherent(&vgem_device->platform->dev, 482 dma_coerce_mask_and_coherent(&vgem_device->platform->dev,
486 DMA_BIT_MASK(64)); 483 DMA_BIT_MASK(64));
484 ret = drm_dev_init(&vgem_device->drm, &vgem_driver,
485 &vgem_device->platform->dev);
486 if (ret)
487 goto out_unregister;
487 488
488 /* Final step: expose the device/driver to userspace */ 489 /* Final step: expose the device/driver to userspace */
489 ret = drm_dev_register(&vgem_device->drm, 0); 490 ret = drm_dev_register(&vgem_device->drm, 0);
490 if (ret) 491 if (ret)
491 goto out_unregister; 492 goto out_fini;
492 493
493 return 0; 494 return 0;
494 495
495out_unregister:
496 platform_device_unregister(vgem_device->platform);
497out_fini: 496out_fini:
498 drm_dev_fini(&vgem_device->drm); 497 drm_dev_fini(&vgem_device->drm);
498out_unregister:
499 platform_device_unregister(vgem_device->platform);
499out_free: 500out_free:
500 kfree(vgem_device); 501 kfree(vgem_device);
501 return ret; 502 return ret;
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index e6ee71323a66..c1c420afe2dd 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -180,7 +180,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
180 reservation_object_lock(resv, NULL); 180 reservation_object_lock(resv, NULL);
181 if (arg->flags & VGEM_FENCE_WRITE) 181 if (arg->flags & VGEM_FENCE_WRITE)
182 reservation_object_add_excl_fence(resv, fence); 182 reservation_object_add_excl_fence(resv, fence);
183 else if ((ret = reservation_object_reserve_shared(resv)) == 0) 183 else if ((ret = reservation_object_reserve_shared(resv, 1)) == 0)
184 reservation_object_add_shared_fence(resv, fence); 184 reservation_object_add_shared_fence(resv, fence);
185 reservation_object_unlock(resv); 185 reservation_object_unlock(resv);
186 186
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
index 757ca28ab93e..0887e0b64b9c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
@@ -53,6 +53,37 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
53 0, 53 0,
54 "virtiodrmfb"); 54 "virtiodrmfb");
55 55
56 /*
57 * Normally the drm_dev_set_unique() call is done by core DRM.
58 * The following comment covers, why virtio cannot rely on it.
59 *
60 * Unlike the other virtual GPU drivers, virtio abstracts the
61 * underlying bus type by using struct virtio_device.
62 *
63 * Hence the dev_is_pci() check, used in core DRM, will fail
64 * and the unique returned will be the virtio_device "virtio0",
65 * while a "pci:..." one is required.
66 *
67 * A few other ideas were considered:
68 * - Extend the dev_is_pci() check [in drm_set_busid] to
69 * consider virtio.
70 * Seems like a bigger hack than what we have already.
71 *
72 * - Point drm_device::dev to the parent of the virtio_device
73 * Semantic changes:
74 * * Using the wrong device for i2c, framebuffer_alloc and
75 * prime import.
76 * Visual changes:
77 * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer,
78 * will print the wrong information.
79 *
80 * We could address the latter issues, by introducing
81 * drm_device::bus_dev, ... which would be used solely for this.
82 *
83 * So for the moment keep things as-is, with a bulky comment
84 * for the next person who feels like removing this
85 * drm_dev_set_unique() quirk.
86 */
56 snprintf(unique, sizeof(unique), "pci:%s", pname); 87 snprintf(unique, sizeof(unique), "pci:%s", pname);
57 ret = drm_dev_set_unique(dev, unique); 88 ret = drm_dev_set_unique(dev, unique);
58 if (ret) 89 if (ret)
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index d29f0c7c768c..6474e83cbf3d 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -65,6 +65,7 @@ struct virtio_gpu_object {
65 struct ttm_placement placement; 65 struct ttm_placement placement;
66 struct ttm_buffer_object tbo; 66 struct ttm_buffer_object tbo;
67 struct ttm_bo_kmap_obj kmap; 67 struct ttm_bo_kmap_obj kmap;
68 bool created;
68}; 69};
69#define gem_to_virtio_gpu_obj(gobj) \ 70#define gem_to_virtio_gpu_obj(gobj) \
70 container_of((gobj), struct virtio_gpu_object, gem_base) 71 container_of((gobj), struct virtio_gpu_object, gem_base)
@@ -190,8 +191,7 @@ struct virtio_gpu_device {
190 struct kmem_cache *vbufs; 191 struct kmem_cache *vbufs;
191 bool vqs_ready; 192 bool vqs_ready;
192 193
193 struct idr resource_idr; 194 struct ida resource_ida;
194 spinlock_t resource_idr_lock;
195 195
196 wait_queue_head_t resp_wq; 196 wait_queue_head_t resp_wq;
197 /* current display info */ 197 /* current display info */
@@ -200,8 +200,7 @@ struct virtio_gpu_device {
200 200
201 struct virtio_gpu_fence_driver fence_drv; 201 struct virtio_gpu_fence_driver fence_drv;
202 202
203 struct idr ctx_id_idr; 203 struct ida ctx_id_ida;
204 spinlock_t ctx_id_idr_lock;
205 204
206 bool has_virgl_3d; 205 bool has_virgl_3d;
207 206
@@ -259,11 +258,8 @@ int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *qfb,
259/* virtio vg */ 258/* virtio vg */
260int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev); 259int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev);
261void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev); 260void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev);
262void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
263 uint32_t *resid);
264void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id);
265void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev, 261void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
266 uint32_t resource_id, 262 struct virtio_gpu_object *bo,
267 uint32_t format, 263 uint32_t format,
268 uint32_t width, 264 uint32_t width,
269 uint32_t height); 265 uint32_t height);
@@ -285,7 +281,6 @@ void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
285 uint32_t x, uint32_t y); 281 uint32_t x, uint32_t y);
286int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, 282int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
287 struct virtio_gpu_object *obj, 283 struct virtio_gpu_object *obj,
288 uint32_t resource_id,
289 struct virtio_gpu_fence **fence); 284 struct virtio_gpu_fence **fence);
290void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev, 285void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
291 struct virtio_gpu_object *obj); 286 struct virtio_gpu_object *obj);
@@ -324,6 +319,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
324 struct virtio_gpu_fence **fence); 319 struct virtio_gpu_fence **fence);
325void 320void
326virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, 321virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
322 struct virtio_gpu_object *bo,
327 struct virtio_gpu_resource_create_3d *rc_3d, 323 struct virtio_gpu_resource_create_3d *rc_3d,
328 struct virtio_gpu_fence **fence); 324 struct virtio_gpu_fence **fence);
329void virtio_gpu_ctrl_ack(struct virtqueue *vq); 325void virtio_gpu_ctrl_ack(struct virtqueue *vq);
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index cea749f4ec39..fb1cc8b2f119 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -214,7 +214,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
214 struct drm_framebuffer *fb; 214 struct drm_framebuffer *fb;
215 struct drm_mode_fb_cmd2 mode_cmd = {}; 215 struct drm_mode_fb_cmd2 mode_cmd = {};
216 struct virtio_gpu_object *obj; 216 struct virtio_gpu_object *obj;
217 uint32_t resid, format, size; 217 uint32_t format, size;
218 int ret; 218 int ret;
219 219
220 mode_cmd.width = sizes->surface_width; 220 mode_cmd.width = sizes->surface_width;
@@ -231,8 +231,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
231 if (IS_ERR(obj)) 231 if (IS_ERR(obj))
232 return PTR_ERR(obj); 232 return PTR_ERR(obj);
233 233
234 virtio_gpu_resource_id_get(vgdev, &resid); 234 virtio_gpu_cmd_create_resource(vgdev, obj, format,
235 virtio_gpu_cmd_create_resource(vgdev, resid, format,
236 mode_cmd.width, mode_cmd.height); 235 mode_cmd.width, mode_cmd.height);
237 236
238 ret = virtio_gpu_object_kmap(obj); 237 ret = virtio_gpu_object_kmap(obj);
@@ -242,7 +241,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
242 } 241 }
243 242
244 /* attach the object to the resource */ 243 /* attach the object to the resource */
245 ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL); 244 ret = virtio_gpu_object_attach(vgdev, obj, NULL);
246 if (ret) 245 if (ret)
247 goto err_obj_attach; 246 goto err_obj_attach;
248 247
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 82c817f37cf7..f06586393974 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -87,7 +87,6 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
87 struct virtio_gpu_object *obj; 87 struct virtio_gpu_object *obj;
88 int ret; 88 int ret;
89 uint32_t pitch; 89 uint32_t pitch;
90 uint32_t resid;
91 uint32_t format; 90 uint32_t format;
92 91
93 if (args->bpp != 32) 92 if (args->bpp != 32)
@@ -103,13 +102,12 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
103 goto fail; 102 goto fail;
104 103
105 format = virtio_gpu_translate_format(DRM_FORMAT_HOST_XRGB8888); 104 format = virtio_gpu_translate_format(DRM_FORMAT_HOST_XRGB8888);
106 virtio_gpu_resource_id_get(vgdev, &resid); 105 obj = gem_to_virtio_gpu_obj(gobj);
107 virtio_gpu_cmd_create_resource(vgdev, resid, format, 106 virtio_gpu_cmd_create_resource(vgdev, obj, format,
108 args->width, args->height); 107 args->width, args->height);
109 108
110 /* attach the object to the resource */ 109 /* attach the object to the resource */
111 obj = gem_to_virtio_gpu_obj(gobj); 110 ret = virtio_gpu_object_attach(vgdev, obj, NULL);
112 ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL);
113 if (ret) 111 if (ret)
114 goto fail; 112 goto fail;
115 113
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index f16b875d6a46..bc5afa4f906e 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -217,7 +217,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
217 struct virtio_gpu_device *vgdev = dev->dev_private; 217 struct virtio_gpu_device *vgdev = dev->dev_private;
218 struct drm_virtgpu_resource_create *rc = data; 218 struct drm_virtgpu_resource_create *rc = data;
219 int ret; 219 int ret;
220 uint32_t res_id;
221 struct virtio_gpu_object *qobj; 220 struct virtio_gpu_object *qobj;
222 struct drm_gem_object *obj; 221 struct drm_gem_object *obj;
223 uint32_t handle = 0; 222 uint32_t handle = 0;
@@ -244,8 +243,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
244 INIT_LIST_HEAD(&validate_list); 243 INIT_LIST_HEAD(&validate_list);
245 memset(&mainbuf, 0, sizeof(struct ttm_validate_buffer)); 244 memset(&mainbuf, 0, sizeof(struct ttm_validate_buffer));
246 245
247 virtio_gpu_resource_id_get(vgdev, &res_id);
248
249 size = rc->size; 246 size = rc->size;
250 247
251 /* allocate a single page size object */ 248 /* allocate a single page size object */
@@ -253,17 +250,15 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
253 size = PAGE_SIZE; 250 size = PAGE_SIZE;
254 251
255 qobj = virtio_gpu_alloc_object(dev, size, false, false); 252 qobj = virtio_gpu_alloc_object(dev, size, false, false);
256 if (IS_ERR(qobj)) { 253 if (IS_ERR(qobj))
257 ret = PTR_ERR(qobj); 254 return PTR_ERR(qobj);
258 goto fail_id;
259 }
260 obj = &qobj->gem_base; 255 obj = &qobj->gem_base;
261 256
262 if (!vgdev->has_virgl_3d) { 257 if (!vgdev->has_virgl_3d) {
263 virtio_gpu_cmd_create_resource(vgdev, res_id, rc->format, 258 virtio_gpu_cmd_create_resource(vgdev, qobj, rc->format,
264 rc->width, rc->height); 259 rc->width, rc->height);
265 260
266 ret = virtio_gpu_object_attach(vgdev, qobj, res_id, NULL); 261 ret = virtio_gpu_object_attach(vgdev, qobj, NULL);
267 } else { 262 } else {
268 /* use a gem reference since unref list undoes them */ 263 /* use a gem reference since unref list undoes them */
269 drm_gem_object_get(&qobj->gem_base); 264 drm_gem_object_get(&qobj->gem_base);
@@ -276,7 +271,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
276 goto fail_unref; 271 goto fail_unref;
277 } 272 }
278 273
279 rc_3d.resource_id = cpu_to_le32(res_id); 274 rc_3d.resource_id = cpu_to_le32(qobj->hw_res_handle);
280 rc_3d.target = cpu_to_le32(rc->target); 275 rc_3d.target = cpu_to_le32(rc->target);
281 rc_3d.format = cpu_to_le32(rc->format); 276 rc_3d.format = cpu_to_le32(rc->format);
282 rc_3d.bind = cpu_to_le32(rc->bind); 277 rc_3d.bind = cpu_to_le32(rc->bind);
@@ -288,8 +283,8 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
288 rc_3d.nr_samples = cpu_to_le32(rc->nr_samples); 283 rc_3d.nr_samples = cpu_to_le32(rc->nr_samples);
289 rc_3d.flags = cpu_to_le32(rc->flags); 284 rc_3d.flags = cpu_to_le32(rc->flags);
290 285
291 virtio_gpu_cmd_resource_create_3d(vgdev, &rc_3d, NULL); 286 virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d, NULL);
292 ret = virtio_gpu_object_attach(vgdev, qobj, res_id, &fence); 287 ret = virtio_gpu_object_attach(vgdev, qobj, &fence);
293 if (ret) { 288 if (ret) {
294 ttm_eu_backoff_reservation(&ticket, &validate_list); 289 ttm_eu_backoff_reservation(&ticket, &validate_list);
295 goto fail_unref; 290 goto fail_unref;
@@ -297,8 +292,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
297 ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); 292 ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f);
298 } 293 }
299 294
300 qobj->hw_res_handle = res_id;
301
302 ret = drm_gem_handle_create(file_priv, obj, &handle); 295 ret = drm_gem_handle_create(file_priv, obj, &handle);
303 if (ret) { 296 if (ret) {
304 297
@@ -311,7 +304,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
311 } 304 }
312 drm_gem_object_put_unlocked(obj); 305 drm_gem_object_put_unlocked(obj);
313 306
314 rc->res_handle = res_id; /* similiar to a VM address */ 307 rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
315 rc->bo_handle = handle; 308 rc->bo_handle = handle;
316 309
317 if (vgdev->has_virgl_3d) { 310 if (vgdev->has_virgl_3d) {
@@ -326,8 +319,6 @@ fail_unref:
326 } 319 }
327//fail_obj: 320//fail_obj:
328// drm_gem_object_handle_unreference_unlocked(obj); 321// drm_gem_object_handle_unreference_unlocked(obj);
329fail_id:
330 virtio_gpu_resource_id_put(vgdev, res_id);
331 return ret; 322 return ret;
332} 323}
333 324
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 65060c08522d..bf609dcae224 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -52,39 +52,22 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
52 events_clear, &events_clear); 52 events_clear, &events_clear);
53} 53}
54 54
55static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev, 55static int virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
56 uint32_t *resid) 56 uint32_t nlen, const char *name)
57{ 57{
58 int handle; 58 int handle = ida_alloc_min(&vgdev->ctx_id_ida, 1, GFP_KERNEL);
59
60 idr_preload(GFP_KERNEL);
61 spin_lock(&vgdev->ctx_id_idr_lock);
62 handle = idr_alloc(&vgdev->ctx_id_idr, NULL, 1, 0, 0);
63 spin_unlock(&vgdev->ctx_id_idr_lock);
64 idr_preload_end();
65 *resid = handle;
66}
67 59
68static void virtio_gpu_ctx_id_put(struct virtio_gpu_device *vgdev, uint32_t id) 60 if (handle < 0)
69{ 61 return handle;
70 spin_lock(&vgdev->ctx_id_idr_lock); 62 virtio_gpu_cmd_context_create(vgdev, handle, nlen, name);
71 idr_remove(&vgdev->ctx_id_idr, id); 63 return handle;
72 spin_unlock(&vgdev->ctx_id_idr_lock);
73}
74
75static void virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
76 uint32_t nlen, const char *name,
77 uint32_t *ctx_id)
78{
79 virtio_gpu_ctx_id_get(vgdev, ctx_id);
80 virtio_gpu_cmd_context_create(vgdev, *ctx_id, nlen, name);
81} 64}
82 65
83static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev, 66static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev,
84 uint32_t ctx_id) 67 uint32_t ctx_id)
85{ 68{
86 virtio_gpu_cmd_context_destroy(vgdev, ctx_id); 69 virtio_gpu_cmd_context_destroy(vgdev, ctx_id);
87 virtio_gpu_ctx_id_put(vgdev, ctx_id); 70 ida_free(&vgdev->ctx_id_ida, ctx_id);
88} 71}
89 72
90static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, 73static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
@@ -151,10 +134,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
151 vgdev->dev = dev->dev; 134 vgdev->dev = dev->dev;
152 135
153 spin_lock_init(&vgdev->display_info_lock); 136 spin_lock_init(&vgdev->display_info_lock);
154 spin_lock_init(&vgdev->ctx_id_idr_lock); 137 ida_init(&vgdev->ctx_id_ida);
155 idr_init(&vgdev->ctx_id_idr); 138 ida_init(&vgdev->resource_ida);
156 spin_lock_init(&vgdev->resource_idr_lock);
157 idr_init(&vgdev->resource_idr);
158 init_waitqueue_head(&vgdev->resp_wq); 139 init_waitqueue_head(&vgdev->resp_wq);
159 virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func); 140 virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func);
160 virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func); 141 virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func);
@@ -271,7 +252,7 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
271{ 252{
272 struct virtio_gpu_device *vgdev = dev->dev_private; 253 struct virtio_gpu_device *vgdev = dev->dev_private;
273 struct virtio_gpu_fpriv *vfpriv; 254 struct virtio_gpu_fpriv *vfpriv;
274 uint32_t id; 255 int id;
275 char dbgname[TASK_COMM_LEN]; 256 char dbgname[TASK_COMM_LEN];
276 257
277 /* can't create contexts without 3d renderer */ 258 /* can't create contexts without 3d renderer */
@@ -284,7 +265,9 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
284 return -ENOMEM; 265 return -ENOMEM;
285 266
286 get_task_comm(dbgname, current); 267 get_task_comm(dbgname, current);
287 virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id); 268 id = virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname);
269 if (id < 0)
270 return id;
288 271
289 vfpriv->ctx_id = id; 272 vfpriv->ctx_id = id;
290 file->driver_priv = vfpriv; 273 file->driver_priv = vfpriv;
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index eca765537470..77eac4eb06b1 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -25,6 +25,18 @@
25 25
26#include "virtgpu_drv.h" 26#include "virtgpu_drv.h"
27 27
28static void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
29 uint32_t *resid)
30{
31 int handle = ida_alloc_min(&vgdev->resource_ida, 1, GFP_KERNEL);
32 *resid = handle;
33}
34
35static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
36{
37 ida_free(&vgdev->resource_ida, id);
38}
39
28static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) 40static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
29{ 41{
30 struct virtio_gpu_object *bo; 42 struct virtio_gpu_object *bo;
@@ -33,13 +45,14 @@ static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
33 bo = container_of(tbo, struct virtio_gpu_object, tbo); 45 bo = container_of(tbo, struct virtio_gpu_object, tbo);
34 vgdev = (struct virtio_gpu_device *)bo->gem_base.dev->dev_private; 46 vgdev = (struct virtio_gpu_device *)bo->gem_base.dev->dev_private;
35 47
36 if (bo->hw_res_handle) 48 if (bo->created)
37 virtio_gpu_cmd_unref_resource(vgdev, bo->hw_res_handle); 49 virtio_gpu_cmd_unref_resource(vgdev, bo->hw_res_handle);
38 if (bo->pages) 50 if (bo->pages)
39 virtio_gpu_object_free_sg_table(bo); 51 virtio_gpu_object_free_sg_table(bo);
40 if (bo->vmap) 52 if (bo->vmap)
41 virtio_gpu_object_kunmap(bo); 53 virtio_gpu_object_kunmap(bo);
42 drm_gem_object_release(&bo->gem_base); 54 drm_gem_object_release(&bo->gem_base);
55 virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
43 kfree(bo); 56 kfree(bo);
44} 57}
45 58
@@ -81,9 +94,11 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
81 bo = kzalloc(sizeof(struct virtio_gpu_object), GFP_KERNEL); 94 bo = kzalloc(sizeof(struct virtio_gpu_object), GFP_KERNEL);
82 if (bo == NULL) 95 if (bo == NULL)
83 return -ENOMEM; 96 return -ENOMEM;
97 virtio_gpu_resource_id_get(vgdev, &bo->hw_res_handle);
84 size = roundup(size, PAGE_SIZE); 98 size = roundup(size, PAGE_SIZE);
85 ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size); 99 ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size);
86 if (ret != 0) { 100 if (ret != 0) {
101 virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
87 kfree(bo); 102 kfree(bo);
88 return ret; 103 return ret;
89 } 104 }
diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c
index e3152d45c5f1..cd63dffa6d40 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ttm.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c
@@ -347,8 +347,7 @@ static void virtio_gpu_bo_move_notify(struct ttm_buffer_object *tbo,
347 347
348 } else if (new_mem->placement & TTM_PL_FLAG_TT) { 348 } else if (new_mem->placement & TTM_PL_FLAG_TT) {
349 if (bo->hw_res_handle) { 349 if (bo->hw_res_handle) {
350 virtio_gpu_object_attach(vgdev, bo, bo->hw_res_handle, 350 virtio_gpu_object_attach(vgdev, bo, NULL);
351 NULL);
352 } 351 }
353 } 352 }
354} 353}
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 4e2e037aed34..51bef1775e47 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -38,26 +38,6 @@
38 + MAX_INLINE_CMD_SIZE \ 38 + MAX_INLINE_CMD_SIZE \
39 + MAX_INLINE_RESP_SIZE) 39 + MAX_INLINE_RESP_SIZE)
40 40
41void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
42 uint32_t *resid)
43{
44 int handle;
45
46 idr_preload(GFP_KERNEL);
47 spin_lock(&vgdev->resource_idr_lock);
48 handle = idr_alloc(&vgdev->resource_idr, NULL, 1, 0, GFP_NOWAIT);
49 spin_unlock(&vgdev->resource_idr_lock);
50 idr_preload_end();
51 *resid = handle;
52}
53
54void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
55{
56 spin_lock(&vgdev->resource_idr_lock);
57 idr_remove(&vgdev->resource_idr, id);
58 spin_unlock(&vgdev->resource_idr_lock);
59}
60
61void virtio_gpu_ctrl_ack(struct virtqueue *vq) 41void virtio_gpu_ctrl_ack(struct virtqueue *vq)
62{ 42{
63 struct drm_device *dev = vq->vdev->priv; 43 struct drm_device *dev = vq->vdev->priv;
@@ -98,10 +78,9 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
98{ 78{
99 struct virtio_gpu_vbuffer *vbuf; 79 struct virtio_gpu_vbuffer *vbuf;
100 80
101 vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL); 81 vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL);
102 if (!vbuf) 82 if (!vbuf)
103 return ERR_PTR(-ENOMEM); 83 return ERR_PTR(-ENOMEM);
104 memset(vbuf, 0, VBUFFER_SIZE);
105 84
106 BUG_ON(size > MAX_INLINE_CMD_SIZE); 85 BUG_ON(size > MAX_INLINE_CMD_SIZE);
107 vbuf->buf = (void *)vbuf + sizeof(*vbuf); 86 vbuf->buf = (void *)vbuf + sizeof(*vbuf);
@@ -388,7 +367,7 @@ retry:
388 367
389/* create a basic resource */ 368/* create a basic resource */
390void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev, 369void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
391 uint32_t resource_id, 370 struct virtio_gpu_object *bo,
392 uint32_t format, 371 uint32_t format,
393 uint32_t width, 372 uint32_t width,
394 uint32_t height) 373 uint32_t height)
@@ -400,12 +379,13 @@ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
400 memset(cmd_p, 0, sizeof(*cmd_p)); 379 memset(cmd_p, 0, sizeof(*cmd_p));
401 380
402 cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D); 381 cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D);
403 cmd_p->resource_id = cpu_to_le32(resource_id); 382 cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle);
404 cmd_p->format = cpu_to_le32(format); 383 cmd_p->format = cpu_to_le32(format);
405 cmd_p->width = cpu_to_le32(width); 384 cmd_p->width = cpu_to_le32(width);
406 cmd_p->height = cpu_to_le32(height); 385 cmd_p->height = cpu_to_le32(height);
407 386
408 virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); 387 virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
388 bo->created = true;
409} 389}
410 390
411void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev, 391void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
@@ -772,6 +752,7 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev,
772 752
773void 753void
774virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, 754virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
755 struct virtio_gpu_object *bo,
775 struct virtio_gpu_resource_create_3d *rc_3d, 756 struct virtio_gpu_resource_create_3d *rc_3d,
776 struct virtio_gpu_fence **fence) 757 struct virtio_gpu_fence **fence)
777{ 758{
@@ -786,6 +767,7 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
786 cmd_p->hdr.flags = 0; 767 cmd_p->hdr.flags = 0;
787 768
788 virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); 769 virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
770 bo->created = true;
789} 771}
790 772
791void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, 773void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
@@ -861,7 +843,6 @@ void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
861 843
862int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, 844int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
863 struct virtio_gpu_object *obj, 845 struct virtio_gpu_object *obj,
864 uint32_t resource_id,
865 struct virtio_gpu_fence **fence) 846 struct virtio_gpu_fence **fence)
866{ 847{
867 bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev); 848 bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
@@ -869,6 +850,9 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
869 struct scatterlist *sg; 850 struct scatterlist *sg;
870 int si, nents; 851 int si, nents;
871 852
853 if (!obj->created)
854 return 0;
855
872 if (!obj->pages) { 856 if (!obj->pages) {
873 int ret; 857 int ret;
874 858
@@ -902,10 +886,9 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
902 ents[si].padding = 0; 886 ents[si].padding = 0;
903 } 887 }
904 888
905 virtio_gpu_cmd_resource_attach_backing(vgdev, resource_id, 889 virtio_gpu_cmd_resource_attach_backing(vgdev, obj->hw_res_handle,
906 ents, nents, 890 ents, nents,
907 fence); 891 fence);
908 obj->hw_res_handle = resource_id;
909 return 0; 892 return 0;
910} 893}
911 894
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 07cfde1b4132..a3d57e0f5ee5 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -108,17 +108,18 @@ static int __init vkms_init(void)
108 if (!vkms_device) 108 if (!vkms_device)
109 return -ENOMEM; 109 return -ENOMEM;
110 110
111 ret = drm_dev_init(&vkms_device->drm, &vkms_driver, NULL);
112 if (ret)
113 goto out_free;
114
115 vkms_device->platform = 111 vkms_device->platform =
116 platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); 112 platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
117 if (IS_ERR(vkms_device->platform)) { 113 if (IS_ERR(vkms_device->platform)) {
118 ret = PTR_ERR(vkms_device->platform); 114 ret = PTR_ERR(vkms_device->platform);
119 goto out_fini; 115 goto out_free;
120 } 116 }
121 117
118 ret = drm_dev_init(&vkms_device->drm, &vkms_driver,
119 &vkms_device->platform->dev);
120 if (ret)
121 goto out_unregister;
122
122 vkms_device->drm.irq_enabled = true; 123 vkms_device->drm.irq_enabled = true;
123 124
124 ret = drm_vblank_init(&vkms_device->drm, 1); 125 ret = drm_vblank_init(&vkms_device->drm, 1);
@@ -129,20 +130,20 @@ static int __init vkms_init(void)
129 130
130 ret = vkms_modeset_init(vkms_device); 131 ret = vkms_modeset_init(vkms_device);
131 if (ret) 132 if (ret)
132 goto out_unregister; 133 goto out_fini;
133 134
134 ret = drm_dev_register(&vkms_device->drm, 0); 135 ret = drm_dev_register(&vkms_device->drm, 0);
135 if (ret) 136 if (ret)
136 goto out_unregister; 137 goto out_fini;
137 138
138 return 0; 139 return 0;
139 140
140out_unregister:
141 platform_device_unregister(vkms_device->platform);
142
143out_fini: 141out_fini:
144 drm_dev_fini(&vkms_device->drm); 142 drm_dev_fini(&vkms_device->drm);
145 143
144out_unregister:
145 platform_device_unregister(vkms_device->platform);
146
146out_free: 147out_free:
147 kfree(vkms_device); 148 kfree(vkms_device);
148 return ret; 149 return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index dca04d4246ea..e6b11f6ae2e4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -493,24 +493,24 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
493 struct drm_plane_state *new_state) 493 struct drm_plane_state *new_state)
494{ 494{
495 int ret = 0; 495 int ret = 0;
496 struct drm_crtc_state *crtc_state = NULL;
496 struct vmw_surface *surface = NULL; 497 struct vmw_surface *surface = NULL;
497 struct drm_framebuffer *fb = new_state->fb; 498 struct drm_framebuffer *fb = new_state->fb;
498 499
499 struct drm_rect src = drm_plane_state_src(new_state); 500 if (new_state->crtc)
500 struct drm_rect dest = drm_plane_state_dest(new_state); 501 crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
502 new_state->crtc);
501 503
502 /* Turning off */ 504 ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,
503 if (!fb) 505 DRM_PLANE_HELPER_NO_SCALING,
506 DRM_PLANE_HELPER_NO_SCALING,
507 true, true);
508 if (ret)
504 return ret; 509 return ret;
505 510
506 ret = drm_plane_helper_check_update(plane, new_state->crtc, fb, 511 /* Turning off */
507 &src, &dest, 512 if (!fb)
508 DRM_MODE_ROTATE_0, 513 return 0;
509 DRM_PLANE_HELPER_NO_SCALING,
510 DRM_PLANE_HELPER_NO_SCALING,
511 true, true, &new_state->visible);
512 if (!ret)
513 return ret;
514 514
515 /* A lot of the code assumes this */ 515 /* A lot of the code assumes this */
516 if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { 516 if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 723578117191..4b5378495eea 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -274,7 +274,6 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
274 274
275static const struct 275static const struct
276drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { 276drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = {
277 .best_encoder = drm_atomic_helper_best_encoder,
278}; 277};
279 278
280/* 279/*
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 53316b1bda3d..333418dc259f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -389,7 +389,6 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = {
389 389
390static const struct 390static const struct
391drm_connector_helper_funcs vmw_sou_connector_helper_funcs = { 391drm_connector_helper_funcs vmw_sou_connector_helper_funcs = {
392 .best_encoder = drm_atomic_helper_best_encoder,
393}; 392};
394 393
395 394
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index e086565c1da6..c3e435f444c1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1054,7 +1054,6 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
1054 1054
1055static const struct 1055static const struct
1056drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { 1056drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
1057 .best_encoder = drm_atomic_helper_best_encoder,
1058}; 1057};
1059 1058
1060 1059
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index 11ef17c2d1c1..f5ea32ae8600 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -114,7 +114,7 @@ out_unbind:
114 component_unbind_all(dev, drm); 114 component_unbind_all(dev, drm);
115out_unregister: 115out_unregister:
116 dev_set_drvdata(dev, NULL); 116 dev_set_drvdata(dev, NULL);
117 drm_dev_unref(drm); 117 drm_dev_put(drm);
118 return ret; 118 return ret;
119} 119}
120 120
@@ -124,10 +124,11 @@ static void zx_drm_unbind(struct device *dev)
124 124
125 drm_dev_unregister(drm); 125 drm_dev_unregister(drm);
126 drm_kms_helper_poll_fini(drm); 126 drm_kms_helper_poll_fini(drm);
127 drm_atomic_helper_shutdown(drm);
127 drm_mode_config_cleanup(drm); 128 drm_mode_config_cleanup(drm);
128 component_unbind_all(dev, drm); 129 component_unbind_all(dev, drm);
129 dev_set_drvdata(dev, NULL); 130 dev_set_drvdata(dev, NULL);
130 drm_dev_unref(drm); 131 drm_dev_put(drm);
131} 132}
132 133
133static const struct component_master_ops zx_drm_master_ops = { 134static const struct component_master_ops zx_drm_master_ops = {
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
index ae8c53b4b261..83d236fd893c 100644
--- a/drivers/gpu/drm/zte/zx_plane.c
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -446,7 +446,6 @@ static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
446 446
447static void zx_plane_destroy(struct drm_plane *plane) 447static void zx_plane_destroy(struct drm_plane *plane)
448{ 448{
449 drm_plane_helper_disable(plane, NULL);
450 drm_plane_cleanup(plane); 449 drm_plane_cleanup(plane);
451} 450}
452 451
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index c61b04555779..dc8e039bfab5 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -676,7 +676,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
676 vga_arbiter_check_bridge_sharing(vgadev); 676 vga_arbiter_check_bridge_sharing(vgadev);
677 677
678 /* Add to the list */ 678 /* Add to the list */
679 list_add(&vgadev->list, &vga_list); 679 list_add_tail(&vgadev->list, &vga_list);
680 vga_count++; 680 vga_count++;
681 vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n", 681 vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n",
682 vga_iostate_to_str(vgadev->decodes), 682 vga_iostate_to_str(vgadev->decodes),
@@ -1408,6 +1408,18 @@ static void __init vga_arb_select_default_device(void)
1408 struct vga_device *vgadev; 1408 struct vga_device *vgadev;
1409 1409
1410#if defined(CONFIG_X86) || defined(CONFIG_IA64) 1410#if defined(CONFIG_X86) || defined(CONFIG_IA64)
1411 u64 base = screen_info.lfb_base;
1412 u64 size = screen_info.lfb_size;
1413 u64 limit;
1414 resource_size_t start, end;
1415 unsigned long flags;
1416 int i;
1417
1418 if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
1419 base |= (u64)screen_info.ext_lfb_base << 32;
1420
1421 limit = base + size;
1422
1411 list_for_each_entry(vgadev, &vga_list, list) { 1423 list_for_each_entry(vgadev, &vga_list, list) {
1412 struct device *dev = &vgadev->pdev->dev; 1424 struct device *dev = &vgadev->pdev->dev;
1413 /* 1425 /*
@@ -1418,11 +1430,6 @@ static void __init vga_arb_select_default_device(void)
1418 * Select the device owning the boot framebuffer if there is 1430 * Select the device owning the boot framebuffer if there is
1419 * one. 1431 * one.
1420 */ 1432 */
1421 resource_size_t start, end, limit;
1422 unsigned long flags;
1423 int i;
1424
1425 limit = screen_info.lfb_base + screen_info.lfb_size;
1426 1433
1427 /* Does firmware framebuffer belong to us? */ 1434 /* Does firmware framebuffer belong to us? */
1428 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 1435 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -1437,7 +1444,7 @@ static void __init vga_arb_select_default_device(void)
1437 if (!start || !end) 1444 if (!start || !end)
1438 continue; 1445 continue;
1439 1446
1440 if (screen_info.lfb_base < start || limit >= end) 1447 if (base < start || limit >= end)
1441 continue; 1448 continue;
1442 1449
1443 if (!vga_default_device()) 1450 if (!vga_default_device())