diff options
author | Dave Airlie <airlied@redhat.com> | 2018-11-18 19:40:00 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-11-18 19:40:33 -0500 |
commit | d7563c55ef9fc1fd2301b8708b3c1f53509d6745 (patch) | |
tree | d7c8ba37972ecab71b056356366e136d5f2527ec /drivers/gpu/drm | |
parent | 9ff01193a20d391e8dbce4403dd5ef87c7eaaca6 (diff) | |
parent | e7afb623b4fb82089c9a50c733c740522b8220bc (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/drm')
170 files changed, 6231 insertions, 3311 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 | ||
41 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | 42 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
42 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 43 | drm_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 | ||
3191 | static void dm_crtc_helper_disable(struct drm_crtc *crtc) | 3190 | static 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 | ||
3590 | static 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 | |||
3591 | static void amdgpu_dm_get_native_mode(struct drm_connector *connector) | 3595 | static 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 | ||
3723 | static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) | 3725 | static 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 @@ | |||
20 | struct arcpgu_drm_private { | 20 | struct 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, | |||
43 | int arc_pgu_setup_crtc(struct drm_device *dev); | 42 | int arc_pgu_setup_crtc(struct drm_device *dev); |
44 | int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np); | 43 | int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np); |
45 | int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np); | 44 | int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np); |
46 | struct 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 | ||
159 | static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = { | 159 | static 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 | ||
187 | static void arc_pgu_plane_destroy(struct drm_plane *plane) | 185 | static 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 | ||
28 | static 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 | |||
35 | static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { | 29 | static 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 | ||
52 | DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops); | 45 | DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops); |
53 | 46 | ||
54 | static 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 | |||
61 | static int arcpgu_load(struct drm_device *drm) | 47 | static 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 | ||
128 | static int arcpgu_unload(struct drm_device *drm) | 106 | static 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) | |||
167 | static struct drm_driver arcpgu_drm_driver = { | 140 | static 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 | ||
215 | err_unload: | 189 | err_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 | ||
82 | static const struct malidp_format_id malidp550_de_formats[] = { | 83 | static const struct malidp_format_id malidp550_de_formats[] = { |
83 | MALIDP_COMMON_FORMATS, | 84 | MALIDP_COMMON_FORMATS, |
84 | }; | 85 | }; |
85 | 86 | ||
87 | static 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 | |||
86 | static const struct malidp_layer malidp500_layers[] = { | 92 | static 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 | ||
501 | static const s16 | 523 | static 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 | ||
365 | static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = { | 365 | static 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 | ||
557 | static const struct drm_mode_config_funcs mode_config_funcs = { | 557 | static 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 | ||
774 | err_unload: | 771 | err_unload: |
775 | atmel_hlcdc_dc_unload(ddev); | 772 | atmel_hlcdc_dc_unload(ddev); |
776 | 773 | ||
777 | err_unref: | 774 | err_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); |
127 | void bochs_hw_setbase(struct bochs_device *bochs, | 128 | void bochs_hw_setbase(struct bochs_device *bochs, |
128 | int x, int y, u64 addr); | 129 | int x, int y, u64 addr); |
130 | int bochs_hw_load_edid(struct bochs_device *bochs); | ||
129 | 131 | ||
130 | /* bochs_mm.c */ | 132 | /* bochs_mm.c */ |
131 | int bochs_mm_init(struct bochs_device *bochs); | 133 | int 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 | ||
72 | static 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 | |||
87 | int 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 | |||
72 | int bochs_hw_init(struct drm_device *dev) | 101 | int 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 | ||
169 | void bochs_hw_setmode(struct bochs_device *bochs, | 199 | void 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 | ||
214 | static int bochs_connector_get_modes(struct drm_connector *connector) | 214 | static 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 | ||
1958 | static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { | 1959 | static 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 | ||
1963 | static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) | 1963 | static 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 | */ | ||
242 | static 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 | ||
589 | static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) | 626 | static 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 | ||
763 | static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, | 806 | static 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 | |||
820 | static 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 | ||
863 | static 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 | |||
807 | static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) | 874 | static 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 | ||
815 | static enum drm_mode_status | 884 | static enum drm_mode_status |
@@ -941,9 +1010,25 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, | |||
941 | 1010 | ||
942 | static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) | 1011 | static 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 | ||
1018 | void 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 | } | ||
1030 | EXPORT_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 | ||
958 | void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) | 1043 | void 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 | } |
964 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove); | 1047 | EXPORT_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 | */ |
969 | struct dw_mipi_dsi * | 1052 | int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder) |
970 | dw_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 | } |
989 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); | 1064 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); |
990 | 1065 | ||
991 | void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) | 1066 | void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) |
992 | { | 1067 | { |
993 | __dw_mipi_dsi_remove(dsi); | ||
994 | } | 1068 | } |
995 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); | 1069 | EXPORT_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 | */ | ||
99 | static struct drm_encoder * | ||
100 | pick_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 | |||
95 | static int handle_conflicting_encoders(struct drm_atomic_state *state, | 106 | static 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 | } |
3413 | EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); | 3424 | EXPORT_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 | */ | ||
3424 | struct drm_encoder * | ||
3425 | drm_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 | } | ||
3430 | EXPORT_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 | */ | ||
3460 | void 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 | } | ||
3471 | EXPORT_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 | */ | ||
3481 | void __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 | } | ||
3504 | EXPORT_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 | */ | ||
3513 | struct drm_crtc_state * | ||
3514 | drm_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 | } | ||
3527 | EXPORT_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 | */ | ||
3537 | void __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 | } | ||
3563 | EXPORT_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 | */ | ||
3573 | void 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 | } | ||
3579 | EXPORT_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 | */ | ||
3589 | void __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 | } | ||
3600 | EXPORT_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 | */ | ||
3609 | void 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 | } | ||
3619 | EXPORT_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 | */ | ||
3629 | void __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 | } | ||
3640 | EXPORT_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 | */ | ||
3649 | struct drm_plane_state * | ||
3650 | drm_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 | } | ||
3663 | EXPORT_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 | */ | ||
3673 | void __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 | } | ||
3684 | EXPORT_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 | */ | ||
3694 | void 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 | } | ||
3700 | EXPORT_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 | */ | ||
3714 | void | ||
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 | } | ||
3723 | EXPORT_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 | */ | ||
3733 | void 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 | } | ||
3744 | EXPORT_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 | */ | ||
3754 | void | ||
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 | } | ||
3766 | EXPORT_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 | */ | ||
3775 | struct drm_connector_state * | ||
3776 | drm_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 | } | ||
3789 | EXPORT_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 | */ | ||
3815 | struct drm_atomic_state * | ||
3816 | drm_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 | |||
3868 | free: | ||
3869 | if (err < 0) { | ||
3870 | drm_atomic_state_put(state); | ||
3871 | state = ERR_PTR(err); | ||
3872 | } | ||
3873 | |||
3874 | return state; | ||
3875 | } | ||
3876 | EXPORT_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 | */ | ||
3886 | void | ||
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 | } | ||
3895 | EXPORT_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 | */ | ||
3905 | void 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 | } | ||
3911 | EXPORT_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 | */ | ||
3927 | int 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 | |||
3976 | fail: | ||
3977 | drm_atomic_state_put(state); | ||
3978 | drm_property_blob_put(blob); | ||
3979 | return ret; | ||
3980 | } | ||
3981 | EXPORT_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 | */ | ||
3991 | void __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 | } | ||
3996 | EXPORT_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 | */ | ||
65 | void 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 | } | ||
76 | EXPORT_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 | */ | ||
86 | void __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 | } | ||
109 | EXPORT_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 | */ | ||
118 | struct drm_crtc_state * | ||
119 | drm_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 | } | ||
132 | EXPORT_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 | */ | ||
142 | void __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 | } | ||
168 | EXPORT_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 | */ | ||
178 | void 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 | } | ||
184 | EXPORT_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 | */ | ||
194 | void __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 | } | ||
205 | EXPORT_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 | */ | ||
214 | void 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 | } | ||
224 | EXPORT_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 | */ | ||
234 | void __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 | } | ||
245 | EXPORT_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 | */ | ||
254 | struct drm_plane_state * | ||
255 | drm_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 | } | ||
268 | EXPORT_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 | */ | ||
278 | void __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 | } | ||
289 | EXPORT_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 | */ | ||
299 | void 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 | } | ||
305 | EXPORT_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 | */ | ||
319 | void | ||
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 | } | ||
328 | EXPORT_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 | */ | ||
338 | void 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 | } | ||
349 | EXPORT_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 | */ | ||
359 | void | ||
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 | } | ||
371 | EXPORT_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 | */ | ||
380 | struct drm_connector_state * | ||
381 | drm_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 | } | ||
394 | EXPORT_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 | */ | ||
420 | struct drm_atomic_state * | ||
421 | drm_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 | |||
473 | free: | ||
474 | if (err < 0) { | ||
475 | drm_atomic_state_put(state); | ||
476 | state = ERR_PTR(err); | ||
477 | } | ||
478 | |||
479 | return state; | ||
480 | } | ||
481 | EXPORT_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 | */ | ||
491 | void | ||
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 | } | ||
500 | EXPORT_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 | */ | ||
510 | void 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 | } | ||
516 | EXPORT_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 | */ | ||
532 | int 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 | |||
581 | fail: | ||
582 | drm_atomic_state_put(state); | ||
583 | drm_property_blob_put(blob); | ||
584 | return ret; | ||
585 | } | ||
586 | EXPORT_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 | */ | ||
596 | void __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 | } | ||
601 | EXPORT_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 | |||
39 | static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, | 41 | static 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: | |||
295 | EXPORT_SYMBOL(drm_connector_init); | 293 | EXPORT_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 | */ | ||
303 | void 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 | } | ||
311 | EXPORT_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 | } |
986 | EXPORT_SYMBOL(drm_helper_resume_force_mode); | 986 | EXPORT_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 | */ | ||
1005 | int 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 | |||
1044 | out: | ||
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 | } | ||
1054 | EXPORT_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 | */ | ||
1070 | int 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 | } | ||
1101 | EXPORT_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 | } |
430 | EXPORT_SYMBOL(drm_dp_cec_register_connector); | 428 | EXPORT_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_ | |||
2572 | EXPORT_SYMBOL(drm_dp_mst_get_edid); | 2572 | EXPORT_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 | */ |
2579 | int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, | 2586 | int 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, | |||
72 | EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); | 72 | EXPORT_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 | } |
132 | EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init); | 143 | EXPORT_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 | } |
228 | EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event); | 239 | EXPORT_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 | */ | ||
239 | void 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 | } | ||
246 | EXPORT_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 | */ |
109 | uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, | 109 | uint32_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 | } |
402 | EXPORT_SYMBOL(drm_format_plane_height); | 414 | EXPORT_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 | */ | ||
424 | unsigned 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 | } | ||
434 | EXPORT_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 | */ | ||
444 | unsigned 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 | } | ||
454 | EXPORT_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 | */ | ||
466 | uint64_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 | } | ||
476 | EXPORT_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 | } |
326 | EXPORT_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 | } |
42 | EXPORT_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 | } |
120 | EXPORT_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 | } |
147 | EXPORT_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 | } |
187 | EXPORT_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 | ||
359 | static int validate_lease(struct drm_device *dev, | 355 | static 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 | ||
53 | static void *agp_remap(unsigned long offset, unsigned long size, | 53 | static 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() */ |
97 | void drm_free_agp(struct agp_memory * handle, int pages) | 97 | void 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() */ |
103 | int drm_bind_agp(struct agp_memory * handle, unsigned int start) | 103 | int 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() */ |
109 | int drm_unbind_agp(struct agp_memory * handle) | 109 | int 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 */ |
115 | static inline void *agp_remap(unsigned long offset, unsigned long size, | 115 | static 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 | ||
62 | static 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 | |||
62 | static const struct drm_dmi_panel_orientation_data itworks_tw891 = { | 70 | static 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 | */ | ||
648 | bool 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 | } | ||
660 | EXPORT_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 | /** | 100 | static 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 | */ | ||
129 | int 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 | } |
176 | EXPORT_SYMBOL(drm_plane_helper_check_update); | ||
177 | 147 | ||
178 | /** | 148 | static 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 | */ | ||
215 | int 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 | } |
288 | EXPORT_SYMBOL(drm_primary_helper_update); | ||
289 | 221 | ||
290 | /** | 222 | static 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 | */ | ||
311 | int 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 | } |
316 | EXPORT_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 | }; |
338 | EXPORT_SYMBOL(drm_primary_helper_funcs); | 248 | EXPORT_SYMBOL(drm_primary_helper_funcs); |
339 | |||
340 | int 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); | ||
422 | out: | ||
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 | */ | ||
455 | int 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 | } | ||
490 | EXPORT_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 | */ | ||
506 | int 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 | } | ||
535 | EXPORT_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) | |||
434 | EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); | 434 | EXPORT_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 | */ | ||
443 | void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) | ||
444 | { | ||
445 | return NULL; | ||
446 | } | ||
447 | EXPORT_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 | */ | ||
457 | void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, | ||
458 | void *addr) | ||
459 | { | ||
460 | |||
461 | } | ||
462 | EXPORT_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 | ||
193 | static 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 | |||
193 | static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { | 200 | static 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 | |||
59 | struct drm_syncobj_stub_fence { | 62 | struct 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 | ||
77 | struct drm_syncobj_signal_pt { | ||
78 | struct dma_fence_array *fence_array; | ||
79 | u64 value; | ||
80 | struct list_head list; | ||
81 | }; | ||
82 | |||
83 | static DEFINE_SPINLOCK(signaled_fence_lock); | ||
84 | static struct dma_fence signaled_fence; | ||
74 | 85 | ||
86 | static 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 | } |
99 | EXPORT_SYMBOL(drm_syncobj_find); | 124 | EXPORT_SYMBOL(drm_syncobj_find); |
100 | 125 | ||
126 | static struct dma_fence * | ||
127 | drm_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 | |||
101 | static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj, | 147 | static 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 | ||
109 | static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, | 155 | static 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 | ||
141 | void drm_syncobj_add_callback(struct drm_syncobj *syncobj, | 181 | static 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 | ||
150 | void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, | 189 | static 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 | |||
201 | static 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 | |||
215 | static 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; | ||
269 | exist: | ||
270 | dma_fence_put(&signal_pt->fence_array->base); | ||
271 | fail: | ||
272 | for (i = 0; i < num_fences; i++) | ||
273 | dma_fence_put(fences[i]); | ||
274 | kfree(fences); | ||
275 | out: | ||
276 | kfree(signal_pt); | ||
277 | return ret; | ||
156 | } | 278 | } |
157 | 279 | ||
280 | static 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 | } |
193 | EXPORT_SYMBOL(drm_syncobj_replace_fence); | 344 | EXPORT_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 | ||
365 | static int | ||
366 | drm_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 | */ | ||
403 | int 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 | } | ||
421 | EXPORT_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 | */ |
228 | int drm_syncobj_find_fence(struct drm_file *file_private, | 438 | int 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 | } |
245 | EXPORT_SYMBOL(drm_syncobj_find_fence); | 450 | EXPORT_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 | } |
261 | EXPORT_SYMBOL(drm_syncobj_free); | 466 | EXPORT_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 | ||
964 | int | 1177 | int |
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; |
100 | done: | 95 | done: |
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 | ||
113 | static void fsl_dcu_unload(struct drm_device *dev) | 105 | static 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 | ||
150 | static 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 | |||
157 | DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops); | 137 | DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops); |
158 | 138 | ||
159 | static struct drm_driver fsl_dcu_drm_driver = { | 139 | static 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 | ||
360 | put: | 341 | put: |
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 | ||
71 | static 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 | |||
78 | static const struct drm_mode_config_funcs meson_mode_config_funcs = { | 71 | static 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 | ||
302 | free_drm: | 289 | free_drm: |
@@ -313,11 +300,9 @@ static int meson_drv_bind(struct device *dev) | |||
313 | static void meson_drv_unbind(struct device *dev) | 300 | static 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 | ||
1231 | static void a5xx_crashdumper_free(struct msm_gpu *gpu, | 1228 | static 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 | ||
93 | config 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 | |||
93 | config DRM_PANEL_ORISETECH_OTM8009A | 105 | config 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 | ||
141 | config 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 | |||
129 | config DRM_PANEL_SAMSUNG_S6E3HA2 | 147 | config 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 | ||
207 | config 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 | ||
189 | endmenu | 214 | endmenu |
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 | |||
7 | obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o | 7 | obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o |
8 | obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o | 8 | obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o |
9 | obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o | 9 | obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o |
10 | obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o | ||
10 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o | 11 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o |
11 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o | 12 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o |
12 | obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o | 13 | obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o |
13 | obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o | 14 | obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o |
14 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o | 15 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o |
16 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o | ||
15 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o | 17 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o |
16 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o | 18 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o |
17 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o | 19 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o |
@@ -19,3 +21,4 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o | |||
19 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o | 21 | obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o |
20 | obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o | 22 | obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o |
21 | obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o | 23 | obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o |
24 | obj-$(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 | ||
507 | static void innolux_panel_del(struct innolux_panel *innolux) | 507 | static 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 | ||
513 | static int innolux_panel_probe(struct mipi_dsi_device *dsi) | 512 | static 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 | |||
28 | struct 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 | |||
42 | struct 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 | |||
51 | struct 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 | |||
62 | struct 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 | |||
78 | static inline struct lcd_olinuxino *to_lcd_olinuxino(struct drm_panel *panel) | ||
79 | { | ||
80 | return container_of(panel, struct lcd_olinuxino, panel); | ||
81 | } | ||
82 | |||
83 | static 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 | |||
97 | static 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 | |||
112 | static 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 | |||
130 | static 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 | |||
144 | static 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 | |||
206 | static 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 | |||
214 | static 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 | |||
299 | static 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 | |||
311 | static const struct of_device_id lcd_olinuxino_of_ids[] = { | ||
312 | { .compatible = "olimex,lcd-olinuxino" }, | ||
313 | { } | ||
314 | }; | ||
315 | MODULE_DEVICE_TABLE(of, lcd_olinuxino_of_ids); | ||
316 | |||
317 | static 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 | |||
326 | module_i2c_driver(lcd_olinuxino_driver); | ||
327 | |||
328 | MODULE_AUTHOR("Stefan Mavrodiev <stefan@olimex.com>"); | ||
329 | MODULE_DESCRIPTION("LCD-OLinuXino driver"); | ||
330 | MODULE_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 | |||
18 | struct 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 | */ | ||
29 | static 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 | |||
50 | static inline struct s6d16d0 *panel_to_s6d16d0(struct drm_panel *panel) | ||
51 | { | ||
52 | return container_of(panel, struct s6d16d0, panel); | ||
53 | } | ||
54 | |||
55 | static 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 | |||
76 | static 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 | |||
114 | static 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 | |||
130 | static 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 | |||
146 | static 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 | |||
170 | static 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 | |||
178 | static 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 | |||
236 | static 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 | |||
246 | static const struct of_device_id s6d16d0_of_match[] = { | ||
247 | { .compatible = "samsung,s6d16d0" }, | ||
248 | { } | ||
249 | }; | ||
250 | MODULE_DEVICE_TABLE(of, s6d16d0_of_match); | ||
251 | |||
252 | static 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 | }; | ||
260 | module_mipi_dsi_driver(s6d16d0_driver); | ||
261 | |||
262 | MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>"); | ||
263 | MODULE_DESCRIPTION("MIPI-DSI s6d16d0 Panel Driver"); | ||
264 | MODULE_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 | }; |
367 | module_platform_driver(seiko_panel_platform_driver); | 364 | module_platform_driver(seiko_panel_platform_driver); |
368 | 365 | ||
369 | MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com"); | 366 | MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com>"); |
370 | MODULE_DESCRIPTION("Seiko 43WVF1G panel driver"); | 367 | MODULE_DESCRIPTION("Seiko 43WVF1G panel driver"); |
371 | MODULE_LICENSE("GPL v2"); | 368 | MODULE_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 | ||
785 | static 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 | |||
797 | static 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 | |||
785 | static const struct drm_display_mode boe_hv070wsa_mode = { | 807 | static 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 | ||
871 | static 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 | |||
885 | static 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 | |||
896 | static 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 | |||
910 | static 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 | |||
849 | static const struct drm_display_mode chunghwa_claa070wp03xg_mode = { | 920 | static 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 | ||
1045 | static 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 | |||
1058 | static 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 | |||
974 | static const struct drm_display_mode edt_et057090dhu_mode = { | 1075 | static 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 | ||
2438 | static 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 | |||
2454 | static 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 | |||
2337 | static const struct of_device_id platform_of_match[] = { | 2465 | static 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 = &ire_am800480r3tmqwa1h, | 2471 | .data = &ire_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 | |||
18 | static const char * const regulator_names[] = { | ||
19 | "vdda", | ||
20 | "vdispp", | ||
21 | "vdispn", | ||
22 | }; | ||
23 | |||
24 | static unsigned long const regulator_enable_loads[] = { | ||
25 | 62000, | ||
26 | 100000, | ||
27 | 100000, | ||
28 | }; | ||
29 | |||
30 | static unsigned long const regulator_disable_loads[] = { | ||
31 | 80, | ||
32 | 100, | ||
33 | 100, | ||
34 | }; | ||
35 | |||
36 | struct cmd_set { | ||
37 | u8 commands[4]; | ||
38 | u8 size; | ||
39 | }; | ||
40 | |||
41 | struct 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 | |||
50 | struct 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 | |||
68 | static inline struct truly_nt35597 *panel_to_ctx(struct drm_panel *panel) | ||
69 | { | ||
70 | return container_of(panel, struct truly_nt35597, panel); | ||
71 | } | ||
72 | |||
73 | static 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 | |||
222 | static 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 | |||
239 | static 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 | |||
258 | static 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 | |||
287 | static 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 | |||
312 | static 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 | |||
331 | static 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 | |||
366 | static 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 | |||
426 | power_off: | ||
427 | if (truly_nt35597_power_off(ctx)) | ||
428 | DRM_DEV_ERROR(ctx->dev, "power_off failed\n"); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | static 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 | |||
452 | static 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 | |||
476 | static 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 | |||
484 | static 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 | |||
524 | static 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 | |||
539 | static 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 | |||
548 | static 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 | |||
633 | err_dsi_attach: | ||
634 | drm_panel_remove(&ctx->panel); | ||
635 | err_panel_add: | ||
636 | mipi_dsi_device_unregister(dsi1_device); | ||
637 | return ret; | ||
638 | } | ||
639 | |||
640 | static 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 | |||
655 | static const struct of_device_id truly_nt35597_of_match[] = { | ||
656 | { | ||
657 | .compatible = "truly,nt35597-2K-display", | ||
658 | .data = &nt35597_dir, | ||
659 | }, | ||
660 | { } | ||
661 | }; | ||
662 | MODULE_DEVICE_TABLE(of, truly_nt35597_of_match); | ||
663 | |||
664 | static 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 | }; | ||
672 | module_mipi_dsi_driver(truly_nt35597_driver); | ||
673 | |||
674 | MODULE_DESCRIPTION("Truly NT35597 DSI Panel Driver"); | ||
675 | MODULE_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 | |||
369 | void qxl_io_destroy_primary(struct qxl_device *qdev) | 372 | void 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 | ||
375 | void qxl_io_create_primary(struct qxl_device *qdev, | 378 | void 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) |
39 | static int | 38 | static int |
40 | qxl_debugfs_irq_received(struct seq_file *m, void *data) | 39 | qxl_debugfs_irq_received(struct seq_file *m, void *data) |
@@ -102,9 +101,9 @@ qxl_debugfs_init(struct drm_minor *minor) | |||
102 | 101 | ||
103 | int qxl_debugfs_add_files(struct qxl_device *qdev, | 102 | int 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 | ||
255 | static int qxl_add_common_modes(struct drm_connector *connector, | 255 | static 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 | ||
392 | static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, | 394 | static 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 | ||
918 | static int qxl_conn_get_modes(struct drm_connector *connector) | 920 | static 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 | |||
962 | static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = { | 963 | static 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 | ||
26 | static int alloc_clips(struct qxl_device *qdev, | 26 | static 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 */ |
39 | static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev, | 39 | static 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: | |||
264 | void qxl_draw_dirty_fb(struct qxl_device *qdev, | 266 | void 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 { | |||
129 | struct qxl_mman { | 128 | struct 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 | |||
137 | struct qxl_memslot { | 135 | struct 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 | */ |
192 | struct qxl_debugfs { | 190 | struct 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 | ||
197 | int qxl_debugfs_add_files(struct qxl_device *rdev, | 195 | int 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); |
200 | int qxl_debugfs_fence_init(struct qxl_device *rdev); | 198 | int qxl_debugfs_fence_init(struct qxl_device *rdev); |
201 | 199 | ||
202 | struct qxl_device; | 200 | struct 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 */ |
377 | int qxl_ttm_init(struct qxl_device *qdev); | 374 | int qxl_ttm_init(struct qxl_device *qdev); |
378 | void qxl_ttm_fini(struct qxl_device *qdev); | 375 | void 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 | ||
400 | void qxl_io_create_primary(struct qxl_device *qdev, | 397 | void 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); |
403 | void qxl_io_destroy_primary(struct qxl_device *qdev); | 400 | void qxl_io_destroy_primary(struct qxl_device *qdev); |
404 | void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id); | 401 | void 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, | |||
449 | void qxl_draw_dirty_fb(struct qxl_device *qdev, | 446 | void 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 | ||
456 | void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec); | 453 | void 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 | ||
497 | int qxl_debugfs_add_files(struct qxl_device *qdev, | 494 | int 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 | ||
501 | int qxl_surface_id_alloc(struct qxl_device *qdev, | 498 | int 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 | */ |
135 | static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb, | 135 | static 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 | |||
85 | apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info) | 85 | apply_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) | |||
92 | static void qxl_gc_work(struct work_struct *work) | 92 | static 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 | |||
78 | int qxl_bo_create(struct qxl_device *qdev, | 77 | int 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) | |||
335 | int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo) | 333 | int 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 | |||
42 | struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj) | 41 | struct 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 | |||
286 | int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, | 285 | int 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 = { | |||
404 | static int rcar_du_pm_suspend(struct device *dev) | 404 | static 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 | ||
424 | static int rcar_du_pm_resume(struct device *dev) | 411 | static 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 | |||
11 | rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o | 11 | rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o |
12 | rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o | 12 | rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o |
13 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o | 13 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o |
14 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o | 14 | rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o |
15 | rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o | 15 | rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o |
16 | rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o | 16 | rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o |
17 | rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o | 17 | rockchipdrm-$(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 | |||
170 | enum { | ||
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 | |||
181 | enum { | ||
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 | |||
192 | struct 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 | |||
211 | struct 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 | |||
236 | struct 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. */ | ||
244 | static 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 | |||
286 | static 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 | |||
297 | static inline void dsi_write(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 val) | ||
298 | { | ||
299 | writel(val, dsi->base + reg); | ||
300 | } | ||
301 | |||
302 | static inline u32 dsi_read(struct dw_mipi_dsi_rockchip *dsi, u32 reg) | ||
303 | { | ||
304 | return readl(dsi->base + reg); | ||
305 | } | ||
306 | |||
307 | static 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 | |||
312 | static 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 | |||
318 | static 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 | */ | ||
343 | static 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 | */ | ||
351 | static 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 | |||
356 | static 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 | |||
469 | static int | ||
470 | dw_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 | |||
561 | static 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 | |||
566 | static 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 | |||
586 | static int | ||
587 | dw_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 | |||
616 | static 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 | |||
648 | static 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 | |||
657 | static const struct drm_encoder_helper_funcs | ||
658 | dw_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 | |||
664 | static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = { | ||
665 | .destroy = drm_encoder_cleanup, | ||
666 | }; | ||
667 | |||
668 | static 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 | |||
689 | static 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 | |||
749 | static 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 | |||
817 | static 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 | |||
831 | static 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 | |||
836 | static 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 | |||
866 | static 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 | |||
881 | static 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 | |||
886 | static 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 | |||
974 | err_clkdisable: | ||
975 | clk_disable_unprepare(dsi->pllref_clk); | ||
976 | return ret; | ||
977 | } | ||
978 | |||
979 | static 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 | |||
991 | static 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 | |||
1011 | static 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 | |||
1057 | static 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 | }; | ||
1067 | MODULE_DEVICE_TABLE(of, dw_mipi_dsi_rockchip_dt_ids); | ||
1068 | |||
1069 | struct 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 | |||
257 | enum { | ||
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 | |||
268 | enum { | ||
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 | |||
279 | struct 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 | |||
289 | struct 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 | |||
315 | enum dw_mipi_dsi_mode { | ||
316 | DW_MIPI_DSI_CMD_MODE, | ||
317 | DW_MIPI_DSI_VID_MODE, | ||
318 | }; | ||
319 | |||
320 | struct 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. */ | ||
326 | static 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 | |||
339 | static 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 | */ | ||
354 | static 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 | |||
363 | static 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 | |||
368 | static 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 | |||
373 | static 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 | |||
378 | static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val) | ||
379 | { | ||
380 | writel(val, dsi->base + reg); | ||
381 | } | ||
382 | |||
383 | static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) | ||
384 | { | ||
385 | return readl(dsi->base + reg); | ||
386 | } | ||
387 | |||
388 | static 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 | */ | ||
412 | static 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 | */ | ||
420 | static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns) | ||
421 | { | ||
422 | return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000); | ||
423 | } | ||
424 | |||
425 | static 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 | |||
515 | phy_init_end: | ||
516 | clk_disable_unprepare(dsi->phy_cfg_clk); | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | static 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 | |||
581 | static 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 | |||
604 | static 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 | |||
614 | static 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 | |||
629 | static 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 | |||
657 | static 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 | |||
680 | static 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 | |||
722 | static 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 | |||
748 | static 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 | |||
754 | static 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 | |||
770 | static 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 | |||
786 | static 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 | |||
792 | static 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 | |||
811 | static 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 | |||
843 | static 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 | |||
848 | static 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 | |||
854 | static 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. */ | ||
862 | static 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 | |||
878 | static 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 | |||
897 | static 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 | |||
913 | static 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 | |||
922 | static 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 | |||
928 | static 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 | |||
936 | static 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 | |||
959 | static 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 | |||
1033 | static int | ||
1034 | dw_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 | |||
1061 | static const struct drm_encoder_helper_funcs | ||
1062 | dw_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 | |||
1068 | static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = { | ||
1069 | .destroy = drm_encoder_cleanup, | ||
1070 | }; | ||
1071 | |||
1072 | static 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 | |||
1079 | static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = { | ||
1080 | .get_modes = dw_mipi_dsi_connector_get_modes, | ||
1081 | }; | ||
1082 | |||
1083 | static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector) | ||
1084 | { | ||
1085 | drm_connector_unregister(connector); | ||
1086 | drm_connector_cleanup(connector); | ||
1087 | } | ||
1088 | |||
1089 | static 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 | |||
1097 | static 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 | |||
1137 | static 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 | |||
1150 | static 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 | |||
1157 | static 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 | |||
1167 | static 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 | }; | ||
1177 | MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids); | ||
1178 | |||
1179 | static 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 | |||
1302 | err_mipi_dsi_host: | ||
1303 | mipi_dsi_host_unregister(&dsi->dsi_host); | ||
1304 | err_cleanup: | ||
1305 | dsi->connector.funcs->destroy(&dsi->connector); | ||
1306 | dsi->encoder.funcs->destroy(&dsi->encoder); | ||
1307 | err_pllref: | ||
1308 | clk_disable_unprepare(dsi->pllref_clk); | ||
1309 | return ret; | ||
1310 | } | ||
1311 | |||
1312 | static 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 | |||
1326 | static const struct component_ops dw_mipi_dsi_ops = { | ||
1327 | .bind = dw_mipi_dsi_bind, | ||
1328 | .unbind = dw_mipi_dsi_unbind, | ||
1329 | }; | ||
1330 | |||
1331 | static int dw_mipi_dsi_probe(struct platform_device *pdev) | ||
1332 | { | ||
1333 | return component_add(&pdev->dev, &dw_mipi_dsi_ops); | ||
1334 | } | ||
1335 | |||
1336 | static int dw_mipi_dsi_remove(struct platform_device *pdev) | ||
1337 | { | ||
1338 | component_del(&pdev->dev, &dw_mipi_dsi_ops); | ||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | struct 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 | */ |
38 | struct rockchip_hdmi_chip_data { | 57 | struct 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 | ||
313 | static 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 | |||
321 | static 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 | |||
328 | static enum drm_connector_status | ||
329 | dw_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 | |||
349 | static 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 | |||
290 | static struct rockchip_hdmi_chip_data rk3288_chip_data = { | 373 | static 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 | ||
387 | static 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 | |||
395 | static struct rockchip_hdmi_chip_data rk3328_chip_data = { | ||
396 | .lcdsel_grf_reg = -1, | ||
397 | }; | ||
398 | |||
399 | static 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 | |||
304 | static struct rockchip_hdmi_chip_data rk3399_chip_data = { | 410 | static 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); | |||
67 | int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); | 68 | int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); |
68 | extern struct platform_driver cdn_dp_driver; | 69 | extern struct platform_driver cdn_dp_driver; |
69 | extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; | 70 | extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; |
70 | extern struct platform_driver dw_mipi_dsi_driver; | 71 | extern struct platform_driver dw_mipi_dsi_rockchip_driver; |
71 | extern struct platform_driver inno_hdmi_driver; | 72 | extern struct platform_driver inno_hdmi_driver; |
72 | extern struct platform_driver rockchip_dp_driver; | 73 | extern struct platform_driver rockchip_dp_driver; |
73 | extern struct platform_driver rockchip_lvds_driver; | 74 | extern 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); | |||
189 | int rockchip_drm_psr_register(struct drm_encoder *encoder, | 189 | int 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 | |||
217 | enum alpha_mode { | 221 | enum 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 | ||
363 | static const int rk3188_vop_intrs[] = { | 363 | static 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 | ||
635 | static const struct vop_data rk3399_vop_big = { | 640 | static 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 @@ | |||
1 | obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o | 1 | test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \ |
2 | test-drm_format.o test-drm_framebuffer.o | ||
3 | |||
4 | obj-$(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 | */ |
9 | selftest(check_plane_state, igt_check_plane_state) | 9 | selftest(check_plane_state, igt_check_plane_state) |
10 | selftest(check_drm_format_block_width, igt_check_drm_format_block_width) | ||
11 | selftest(check_drm_format_block_height, igt_check_drm_format_block_height) | ||
12 | selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch) | ||
13 | selftest(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 | |||
15 | int 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 | |||
58 | int 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 | |||
101 | int 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 | |||
16 | struct drm_framebuffer_test { | ||
17 | int buffer_created; | ||
18 | struct drm_mode_fb_cmd2 cmd; | ||
19 | const char *name; | ||
20 | }; | ||
21 | |||
22 | static 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 | |||
301 | static 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 | |||
310 | static struct drm_mode_config_funcs mock_config_funcs = { | ||
311 | .fb_create = fb_create_mock, | ||
312 | }; | ||
313 | |||
314 | static 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 | |||
325 | static 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 | |||
335 | int 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 | |||
15 | static 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 | |||
24 | static void __exit test_drm_modeset_exit(void) | ||
25 | { | ||
26 | } | ||
27 | |||
28 | module_init(test_drm_modeset_init); | ||
29 | module_exit(test_drm_modeset_exit); | ||
30 | |||
31 | MODULE_AUTHOR("Intel Corporation"); | ||
32 | MODULE_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 | |||
16 | int igt_check_plane_state(void *ignored); | ||
17 | int igt_check_drm_format_block_width(void *ignored); | ||
18 | int igt_check_drm_format_block_height(void *ignored); | ||
19 | int igt_check_drm_format_min_pitch(void *ignored); | ||
20 | int 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 | ||
26 | static void set_src(struct drm_plane_state *plane_state, | 14 | static 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 | ||
88 | static int igt_check_plane_state(void *ignored) | 76 | int 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 | |||
235 | static 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 | |||
244 | module_init(test_drm_helper_init); | ||
245 | |||
246 | MODULE_AUTHOR("Intel Corporation"); | ||
247 | MODULE_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 | ||
45 | static int | 47 | static 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 | ||
241 | err_register: | ||
242 | drm_mode_config_cleanup(ddev); | ||
243 | err_cleanup: | 243 | err_cleanup: |
244 | sti_cleanup(ddev); | 244 | sti_cleanup(ddev); |
245 | err_drm_dev_put: | 245 | err_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 | ||
27 | static const struct drm_mode_config_funcs drv_mode_config_funcs = { | 27 | static 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); | |||
52 | static struct drm_driver drv_driver = { | 51 | static 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 | ||
77 | static int drv_load(struct drm_device *ddev) | 77 | static 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 | ||
159 | err_put: | 154 | err_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 | ||
631 | bool 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 | |||
629 | static const struct drm_crtc_funcs ltdc_crtc_funcs = { | 674 | static 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 | ||
41 | bool 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 | |||
41 | int ltdc_load(struct drm_device *ddev); | 46 | int ltdc_load(struct drm_device *ddev); |
42 | void ltdc_unload(struct drm_device *ddev); | 47 | void 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 | ||
124 | finish_poll: | 120 | finish_poll: |
125 | drm_kms_helper_poll_fini(drm); | 121 | drm_kms_helper_poll_fini(drm); |
126 | sun4i_framebuffer_free(drm); | ||
127 | cleanup_mode_config: | 122 | cleanup_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 | ||
39 | static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { | 37 | static 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 | ||
50 | int sun4i_framebuffer_init(struct drm_device *drm) | 47 | void 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 | |||
63 | void 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 | ||
16 | int sun4i_framebuffer_init(struct drm_device *drm); | 16 | void sun4i_framebuffer_init(struct drm_device *drm); |
17 | void 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 | |||
60 | static const u32 yuv2rgb_de3[] = { | ||
61 | 0x0002542a, 0x00000000, 0x0003312a, 0xffc00000, | ||
62 | 0x0002542a, 0xffff376b, 0xfffe5fc3, 0xfe000000, | ||
63 | 0x0002542a, 0x000408d3, 0x00000000, 0xfe000000, | ||
64 | }; | ||
65 | |||
66 | static const u32 yvu2rgb_de3[] = { | ||
67 | 0x0002542a, 0x0003312a, 0x00000000, 0xffc00000, | ||
68 | 0x0002542a, 0xfffe5fc3, 0xffff376b, 0xfe000000, | ||
69 | 0x0002542a, 0x00000000, 0x000408d3, 0xfe000000, | ||
70 | }; | ||
71 | |||
37 | static void sun8i_csc_set_coefficients(struct regmap *map, u32 base, | 72 | static 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 | ||
99 | static 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 | |||
64 | static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable) | 121 | static 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 | ||
133 | static 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 | |||
76 | void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer, | 148 | void 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 | ||
26 | static const struct drm_encoder_helper_funcs | 28 | static 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 | ||
35 | static enum drm_mode_status | 37 | static enum drm_mode_status |
36 | sun8i_dw_hdmi_mode_valid(struct drm_connector *connector, | 38 | sun8i_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 | ||
47 | static enum drm_mode_status | ||
48 | sun8i_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 | |||
45 | static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node) | 58 | static 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 | ||
246 | static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = { | ||
247 | .mode_valid = sun8i_dw_hdmi_mode_valid_a83t, | ||
248 | .set_rate = true, | ||
249 | }; | ||
250 | |||
251 | static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = { | ||
252 | .mode_valid = sun8i_dw_hdmi_mode_valid_h6, | ||
253 | }; | ||
254 | |||
233 | static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { | 255 | static 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 | }; |
237 | MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids); | 266 | MODULE_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; | |||
150 | struct sun8i_hdmi_phy_variant { | 150 | struct 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 | ||
177 | struct 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 | |||
173 | struct sun8i_dw_hdmi { | 183 | struct 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); | |||
191 | void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi); | 202 | void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi); |
192 | 203 | ||
193 | void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); | 204 | void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); |
194 | const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void); | 205 | void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, |
206 | struct dw_hdmi_plat_data *plat_data); | ||
195 | 207 | ||
196 | int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev, | 208 | int 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 | ||
17 | static 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 | |||
105 | static 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 | |||
125 | static 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 | |||
17 | static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi, | 133 | static 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 | ||
398 | static 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 | |||
409 | static 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 | |||
282 | static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) | 419 | static 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 | ||
373 | void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) | 514 | void 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 | ||
386 | const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void) | 519 | void 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 | ||
391 | static struct regmap_config sun8i_hdmi_phy_regmap_config = { | 535 | static 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 | ||
399 | static 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 | |||
406 | static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { | 543 | static 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 | ||
412 | static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { | 550 | static 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 = { | |||
419 | static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = { | 558 | static 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 | |||
567 | static 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 | ||
575 | static 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 | |||
427 | static const struct of_device_id sun8i_hdmi_phy_of_table[] = { | 582 | static 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 | ||
616 | static 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 | |||
588 | static const struct of_device_id sun8i_mixer_of_table[] = { | 625 | static 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 | }; |
623 | MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table); | 664 | MODULE_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 | |||
109 | struct de2_fmt_info { | 140 | struct 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 | */ |
131 | struct sun8i_mixer_cfg { | 163 | struct 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 | ||
139 | struct sun8i_mixer { | 172 | struct 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 | ||
189 | static inline u32 | ||
190 | sun8i_blender_base(struct sun8i_mixer *mixer) | ||
191 | { | ||
192 | return mixer->cfg->is_de3 ? DE3_BLD_BASE : DE2_BLD_BASE; | ||
193 | } | ||
194 | |||
195 | static inline u32 | ||
196 | sun8i_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 | |||
156 | const struct de2_fmt_info *sun8i_mixer_format_info(u32 format); | 204 | const 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 | ||
18 | struct sun8i_tcon_top_quirks { | ||
19 | bool has_tcon_tv1; | ||
20 | bool has_dsi; | ||
21 | }; | ||
22 | |||
17 | static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node) | 23 | static 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 | ||
271 | const struct sun8i_tcon_top_quirks sun8i_r40_tcon_top_quirks = { | ||
272 | .has_tcon_tv1 = true, | ||
273 | .has_dsi = true, | ||
274 | }; | ||
275 | |||
276 | const 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 */ |
254 | const struct of_device_id sun8i_tcon_top_of_table[] = { | 281 | const 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 | }; |
258 | MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table); | 292 | MODULE_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 | ||
14 | static const u32 lan2coefftab16[240] = { | 15 | static 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 | ||
92 | static 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 | |||
91 | static int sun8i_ui_scaler_coef_index(unsigned int step) | 106 | static 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 | ||
115 | void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable) | 130 | void 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 | ||
133 | void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer, | 148 | void 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 | ||
33 | struct sun8i_mixer; | 36 | struct 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 | ||
836 | static 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 | |||
836 | static int sun8i_vi_scaler_coef_index(unsigned int step) | 846 | static 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 | ||
860 | static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer, | 870 | static 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 | ||
900 | void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable) | 910 | void 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 | ||
913 | void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer, | 926 | void 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 | |||
52 | void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable); | 72 | void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable); |
53 | void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer, | 73 | void 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 | ||
141 | static const struct drm_mode_config_funcs mode_config_funcs = { | 141 | static 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); | |||
519 | static struct drm_driver tilcdc_driver = { | 513 | static 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 | |||
10 | config TINYDRM_MIPI_DBI | 10 | config TINYDRM_MIPI_DBI |
11 | tristate | 11 | tristate |
12 | 12 | ||
13 | config 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 | |||
13 | config TINYDRM_ILI9225 | 24 | config 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/ | |||
4 | obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o | 4 | obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o |
5 | 5 | ||
6 | # Displays | 6 | # Displays |
7 | obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o | ||
7 | obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o | 8 | obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o |
8 | obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o | 9 | obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o |
9 | obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o | 10 | obj-$(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 | } |
207 | EXPORT_SYMBOL(tinydrm_display_pipe_init); | 211 | EXPORT_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 | |||
44 | static 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 | |||
156 | out_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 | |||
175 | static 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 | |||
182 | static const struct drm_display_mode yx350hv15_mode = { | ||
183 | TINYDRM_MODE(320, 480, 60, 75), | ||
184 | }; | ||
185 | |||
186 | DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops); | ||
187 | |||
188 | static 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 | |||
200 | static const struct of_device_id hx8357d_of_match[] = { | ||
201 | { .compatible = "adafruit,yx350hv15" }, | ||
202 | { } | ||
203 | }; | ||
204 | MODULE_DEVICE_TABLE(of, hx8357d_of_match); | ||
205 | |||
206 | static const struct spi_device_id hx8357d_id[] = { | ||
207 | { "yx350hv15", 0 }, | ||
208 | { } | ||
209 | }; | ||
210 | MODULE_DEVICE_TABLE(spi, hx8357d_id); | ||
211 | |||
212 | static 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 | |||
250 | static 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 | |||
257 | static 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 | }; | ||
266 | module_spi_driver(hx8357d_spi_driver); | ||
267 | |||
268 | MODULE_DESCRIPTION("HX8357D DRM driver"); | ||
269 | MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); | ||
270 | MODULE_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; |
360 | err_fb: | 356 | |
361 | udl_fbdev_cleanup(dev); | ||
362 | err: | 357 | err: |
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 | ||
182 | static 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 | |||
179 | static const struct drm_info_list v3d_debugfs_list[] = { | 216 | static 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) | |||
209 | static void | 209 | static void |
210 | v3d_attach_object_fences(struct v3d_exec_info *exec) | 210 | v3d_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 | ||
904 | static void vc4_plane_destroy(struct drm_plane *plane) | 949 | static 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 | ||
433 | static struct drm_driver vgem_driver = { | 433 | static 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 | ||
495 | out_unregister: | ||
496 | platform_device_unregister(vgem_device->platform); | ||
497 | out_fini: | 496 | out_fini: |
498 | drm_dev_fini(&vgem_device->drm); | 497 | drm_dev_fini(&vgem_device->drm); |
498 | out_unregister: | ||
499 | platform_device_unregister(vgem_device->platform); | ||
499 | out_free: | 500 | out_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 */ |
260 | int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev); | 259 | int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev); |
261 | void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev); | 260 | void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev); |
262 | void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev, | ||
263 | uint32_t *resid); | ||
264 | void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id); | ||
265 | void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev, | 261 | void 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); |
286 | int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, | 282 | int 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); |
290 | void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev, | 285 | void 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); |
325 | void | 320 | void |
326 | virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, | 321 | virtio_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); |
329 | void virtio_gpu_ctrl_ack(struct virtqueue *vq); | 325 | void 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); |
329 | fail_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 | ||
55 | static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev, | 55 | static 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 | ||
68 | static 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 | |||
75 | static 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 | ||
83 | static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev, | 66 | static 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 | ||
90 | static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, | 73 | static 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 | ||
28 | static 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 | |||
35 | static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id) | ||
36 | { | ||
37 | ida_free(&vgdev->resource_ida, id); | ||
38 | } | ||
39 | |||
28 | static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) | 40 | static 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 | ||
41 | void 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 | |||
54 | void 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 | |||
61 | void virtio_gpu_ctrl_ack(struct virtqueue *vq) | 41 | void 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 */ |
390 | void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev, | 369 | void 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 | ||
411 | void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev, | 391 | void 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 | ||
773 | void | 753 | void |
774 | virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, | 754 | virtio_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 | ||
791 | void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, | 773 | void 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 | ||
862 | int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, | 844 | int 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 | ||
140 | out_unregister: | ||
141 | platform_device_unregister(vkms_device->platform); | ||
142 | |||
143 | out_fini: | 141 | out_fini: |
144 | drm_dev_fini(&vkms_device->drm); | 142 | drm_dev_fini(&vkms_device->drm); |
145 | 143 | ||
144 | out_unregister: | ||
145 | platform_device_unregister(vkms_device->platform); | ||
146 | |||
146 | out_free: | 147 | out_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 | ||
275 | static const struct | 275 | static const struct |
276 | drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { | 276 | drm_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 | ||
390 | static const struct | 390 | static const struct |
391 | drm_connector_helper_funcs vmw_sou_connector_helper_funcs = { | 391 | drm_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 | ||
1055 | static const struct | 1055 | static const struct |
1056 | drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { | 1056 | drm_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); |
115 | out_unregister: | 115 | out_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 | ||
133 | static const struct component_master_ops zx_drm_master_ops = { | 134 | static 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 | ||
447 | static void zx_plane_destroy(struct drm_plane *plane) | 447 | static 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 | ||