aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-12-07 17:15:54 -0500
committerDave Airlie <airlied@redhat.com>2017-12-07 17:15:54 -0500
commit5c379b4f4fd0c97e7bd31b3523c7e5c2bdf4a9b6 (patch)
treea3cef7f73bf671f011599f3309ee8e6870d27b95
parent9c606cd4117a3c45e04a6616b1a0dbeb18eeee62 (diff)
parentbc29489f712079378081e43d5b1b7470ed70184d (diff)
Merge tag 'drm-misc-next-2017-12-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
UAPI Changes: - Add "panel orientation" property to DRM to indicate orientation of the panel vs the device's casing (Hans de Goede) Core Changes: - misc doc and bug fixes Driver Changes: - sun4i: Many improvements to the DE driver like multi-plane support and YUV formats (Jernej Skrabec) * tag 'drm-misc-next-2017-12-07' of git://anongit.freedesktop.org/drm/drm-misc: (50 commits) drm/sun4i: Fix uninitialized variables in vi layer drm/fb-helper: Fix potential NULL pointer dereference gpu: drm: stm: Adopt SPDX identifiers gpu: drm: sti: Adopt SPDX identifiers drm/fsl-dcu: Use drm_mode_config_helper_suspend/resume() drm/sun4i: Wire in DE2 YUV support drm/sun4i: Expand DE2 scaler lib with YUV support drm/sun4i: Add DE2 definitions for YUV formats drm/sun4i: Add DE2 CSC library drm/sun4i: Add CCSC property to DE2 configuration drm/sun4i: Add support for HW scaling to DE2 drm/sun4i: Add scaler configuration to DE2 mixers drm/sun4i: Add support for DE2 VI planes drm/sun4i: Reorganize UI layer code in DE2 drm/sun4i: Add support for all HW supported DE2 RGB formats drm/sun4i: Add multi plane support to DE2 driver drm/sun4i: Move interlace related code in DE2 drm/sun4i: Move channel size related code in DE2 drm/sun4i: Move line width setting in DE2 drm/sun4i: Use values calculated by atomic check ...
-rw-r--r--Documentation/devicetree/bindings/display/ilitek,ili9225.txt25
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--Documentation/gpu/drm-kms-helpers.rst3
-rw-r--r--Documentation/gpu/todo.rst14
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/gpu/drm/Kconfig5
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c24
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h1
-rw-r--r--drivers/gpu/drm/drm_connector.c73
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c94
-rw-r--r--drivers/gpu/drm/drm_modeset_helper.c76
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c (renamed from drivers/video/fbdev/core/fbcon_dmi_quirks.c)101
-rw-r--r--drivers/gpu/drm/drm_prime.c8
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c3
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c25
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c28
-rw-r--r--drivers/gpu/drm/sti/sti_awg_utils.c2
-rw-r--r--drivers/gpu/drm/sti/sti_awg_utils.h2
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c2
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.h2
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c2
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.h2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.h2
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c2
-rw-r--r--drivers/gpu/drm/sti/sti_drv.h2
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c2
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.h2
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.h2
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h2
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp_lut.h2
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c2
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.h2
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c2
-rw-r--r--drivers/gpu/drm/sti/sti_plane.h2
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c2
-rw-r--r--drivers/gpu/drm/sti/sti_vid.c2
-rw-r--r--drivers/gpu/drm/sti/sti_vid.h2
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.c2
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.h2
-rw-r--r--drivers/gpu/drm/stm/drv.c3
-rw-r--r--drivers/gpu/drm/stm/dw_mipi_dsi-stm.c3
-rw-r--r--drivers/gpu/drm/stm/ltdc.c3
-rw-r--r--drivers/gpu/drm/stm/ltdc.h3
-rw-r--r--drivers/gpu/drm/sun4i/Makefile4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c8
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.h2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.c93
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.h36
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_layer.c134
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_layer.h36
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c496
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.h123
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.c349
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.h63
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.c172
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.h49
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.c390
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.h51
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.c971
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.h58
-rw-r--r--drivers/gpu/drm/tinydrm/Kconfig10
-rw-r--r--drivers/gpu/drm/tinydrm/Makefile1
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-core.c67
-rw-r--r--drivers/gpu/drm/tinydrm/ili9225.c468
-rw-r--r--drivers/gpu/drm/tinydrm/mi0283qt.c7
-rw-r--r--drivers/gpu/drm/tinydrm/mipi-dbi.c24
-rw-r--r--drivers/video/fbdev/Kconfig1
-rw-r--r--drivers/video/fbdev/core/Makefile3
-rw-r--r--drivers/video/fbdev/core/fbcon.c22
-rw-r--r--drivers/video/fbdev/core/fbcon.h6
-rw-r--r--drivers/video/fbdev/core/fbsysfs.c1
-rw-r--r--drivers/video/fbdev/efifb.c21
-rw-r--r--include/drm/drm_connector.h40
-rw-r--r--include/drm/drm_fb_helper.h8
-rw-r--r--include/drm/drm_mode_config.h16
-rw-r--r--include/drm/drm_modeset_helper.h3
-rw-r--r--include/drm/drm_utils.h15
-rw-r--r--include/drm/tinydrm/mipi-dbi.h4
-rw-r--r--include/drm/tinydrm/tinydrm.h4
-rw-r--r--include/linux/fb.h5
89 files changed, 3661 insertions, 663 deletions
diff --git a/Documentation/devicetree/bindings/display/ilitek,ili9225.txt b/Documentation/devicetree/bindings/display/ilitek,ili9225.txt
new file mode 100644
index 000000000000..21607a541c33
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/ilitek,ili9225.txt
@@ -0,0 +1,25 @@
1Ilitek ILI9225 display panels
2
3This binding is for display panels using an Ilitek ILI9225 controller in SPI
4mode.
5
6Required properties:
7- compatible: "ilitek,ili9225-2.2in-176x220"
8- rs-gpios: Register select signal
9- reset-gpios: Reset pin
10
11The node for this driver must be a child node of a SPI controller, hence
12all mandatory properties described in ../spi/spi-bus.txt must be specified.
13
14Optional properties:
15- rotation: panel rotation in degrees counter clockwise (0,90,180,270)
16
17Example:
18 display@0{
19 compatible = "ilitek,ili9225-2.2in-176x220";
20 reg = <0>;
21 spi-max-frequency = <12000000>;
22 rs-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
23 reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
24 rotation = <270>;
25 };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 0994bdd82cd3..41cb1ff07150 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -154,6 +154,7 @@ i2se I2SE GmbH
154ibm International Business Machines (IBM) 154ibm International Business Machines (IBM)
155idt Integrated Device Technologies, Inc. 155idt Integrated Device Technologies, Inc.
156ifi Ingenieurburo Fur Ic-Technologie (I/F/I) 156ifi Ingenieurburo Fur Ic-Technologie (I/F/I)
157ilitek ILI Technology Corporation (ILITEK)
157img Imagination Technologies Ltd. 158img Imagination Technologies Ltd.
158infineon Infineon Technologies 159infineon Infineon Technologies
159inforce Inforce Computing 160inforce Inforce Computing
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 13dd237418cc..3ea622876b67 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -163,6 +163,9 @@ Panel Helper Reference
163.. kernel-doc:: drivers/gpu/drm/drm_panel.c 163.. kernel-doc:: drivers/gpu/drm/drm_panel.c
164 :export: 164 :export:
165 165
166.. kernel-doc:: drivers/gpu/drm/drm_panel_orientation_quirks.c
167 :export:
168
166Display Port Helper Functions Reference 169Display Port Helper Functions Reference
167======================================= 170=======================================
168 171
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 01eaa40dafc9..af614746d9c5 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -185,6 +185,15 @@ are better.
185 185
186Contact: Sean Paul, Maintainer of the driver you plan to convert 186Contact: Sean Paul, Maintainer of the driver you plan to convert
187 187
188Convert drivers to use simple modeset suspend/resume
189----------------------------------------------------
190
191Most drivers (except i915 and nouveau) that use
192drm_atomic_helper_suspend/resume() can probably be converted to use
193drm_mode_config_helper_suspend/resume().
194
195Contact: Maintainer of the driver you plan to convert
196
188Core refactorings 197Core refactorings
189================= 198=================
190 199
@@ -404,11 +413,6 @@ those drivers as simple as possible, so lots of room for refactoring:
404 a drm_device wrong. Doesn't matter, since everyone else gets it wrong 413 a drm_device wrong. Doesn't matter, since everyone else gets it wrong
405 too :-) 414 too :-)
406 415
407- With the fbdev pointer in dev->mode_config we could also make
408 suspend/resume helpers entirely generic, at least if we add a
409 dev->mode_config.suspend_state. We could even provide a generic pm_ops
410 structure with those.
411
412- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above. 416- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above.
413 417
414Contact: Noralf Trønnes, Daniel Vetter 418Contact: Noralf Trønnes, Daniel Vetter
diff --git a/MAINTAINERS b/MAINTAINERS
index 069ba63190b2..8110df7acfea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4461,6 +4461,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
4461S: Maintained 4461S: Maintained
4462F: drivers/gpu/drm/tve200/ 4462F: drivers/gpu/drm/tve200/
4463 4463
4464DRM DRIVER FOR ILITEK ILI9225 PANELS
4465M: David Lechner <david@lechnology.com>
4466S: Maintained
4467F: drivers/gpu/drm/tinydrm/ili9225.c
4468F: Documentation/devicetree/bindings/display/ili9225.txt
4469
4464DRM DRIVER FOR INTEL I810 VIDEO CARDS 4470DRM DRIVER FOR INTEL I810 VIDEO CARDS
4465S: Orphan / Obsolete 4471S: Orphan / Obsolete
4466F: drivers/gpu/drm/i810/ 4472F: drivers/gpu/drm/i810/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 4d9f21831741..d853989848d6 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -7,6 +7,7 @@
7menuconfig DRM 7menuconfig DRM
8 tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" 8 tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
9 depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA 9 depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
10 select DRM_PANEL_ORIENTATION_QUIRKS
10 select HDMI 11 select HDMI
11 select FB_CMDLINE 12 select FB_CMDLINE
12 select I2C 13 select I2C
@@ -26,6 +27,10 @@ config DRM_MIPI_DSI
26 bool 27 bool
27 depends on DRM 28 depends on DRM
28 29
30# Separate option because drm_panel_orientation_quirks.c is shared with fbdev
31config DRM_PANEL_ORIENTATION_QUIRKS
32 tristate
33
29config DRM_DP_AUX_CHARDEV 34config DRM_DP_AUX_CHARDEV
30 bool "DRM DP AUX Interface" 35 bool "DRM DP AUX Interface"
31 depends on DRM 36 depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e9500844333e..e5bf68b9c171 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_DRM_DEBUG_MM_SELFTEST) += selftests/
47 47
48obj-$(CONFIG_DRM) += drm.o 48obj-$(CONFIG_DRM) += drm.o
49obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o 49obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
50obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
50obj-$(CONFIG_DRM_ARM) += arm/ 51obj-$(CONFIG_DRM_ARM) += arm/
51obj-$(CONFIG_DRM_TTM) += ttm/ 52obj-$(CONFIG_DRM_TTM) += ttm/
52obj-$(CONFIG_DRM_TDFX) += tdfx/ 53obj-$(CONFIG_DRM_TDFX) += tdfx/
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 91f2b0191368..e080e31a8513 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -27,6 +27,7 @@
27#include <drm/drm_fb_cma_helper.h> 27#include <drm/drm_fb_cma_helper.h>
28#include <drm/drm_gem_cma_helper.h> 28#include <drm/drm_gem_cma_helper.h>
29#include <drm/drm_gem_framebuffer_helper.h> 29#include <drm/drm_gem_framebuffer_helper.h>
30#include <drm/drm_modeset_helper.h>
30#include <drm/drm_of.h> 31#include <drm/drm_of.h>
31 32
32#include "malidp_drv.h" 33#include "malidp_drv.h"
@@ -745,34 +746,15 @@ static int malidp_platform_remove(struct platform_device *pdev)
745static int __maybe_unused malidp_pm_suspend(struct device *dev) 746static int __maybe_unused malidp_pm_suspend(struct device *dev)
746{ 747{
747 struct drm_device *drm = dev_get_drvdata(dev); 748 struct drm_device *drm = dev_get_drvdata(dev);
748 struct malidp_drm *malidp = drm->dev_private;
749
750 drm_kms_helper_poll_disable(drm);
751 console_lock();
752 drm_fbdev_cma_set_suspend(malidp->fbdev, 1);
753 console_unlock();
754 malidp->pm_state = drm_atomic_helper_suspend(drm);
755 if (IS_ERR(malidp->pm_state)) {
756 console_lock();
757 drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
758 console_unlock();
759 drm_kms_helper_poll_enable(drm);
760 return PTR_ERR(malidp->pm_state);
761 }
762 749
763 return 0; 750 return drm_mode_config_helper_suspend(drm);
764} 751}
765 752
766static int __maybe_unused malidp_pm_resume(struct device *dev) 753static int __maybe_unused malidp_pm_resume(struct device *dev)
767{ 754{
768 struct drm_device *drm = dev_get_drvdata(dev); 755 struct drm_device *drm = dev_get_drvdata(dev);
769 struct malidp_drm *malidp = drm->dev_private;
770 756
771 drm_atomic_helper_resume(drm, malidp->pm_state); 757 drm_mode_config_helper_resume(drm);
772 console_lock();
773 drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
774 console_unlock();
775 drm_kms_helper_poll_enable(drm);
776 758
777 return 0; 759 return 0;
778} 760}
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index 2e2033140efc..70ed6aeccf05 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -24,7 +24,6 @@ struct malidp_drm {
24 struct drm_crtc crtc; 24 struct drm_crtc crtc;
25 wait_queue_head_t wq; 25 wait_queue_head_t wq;
26 atomic_t config_valid; 26 atomic_t config_valid;
27 struct drm_atomic_state *pm_state;
28 u32 core_id; 27 u32 core_id;
29}; 28};
30 29
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 25f4b2e9a44f..624edeb5c50d 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -24,6 +24,7 @@
24#include <drm/drm_connector.h> 24#include <drm/drm_connector.h>
25#include <drm/drm_edid.h> 25#include <drm/drm_edid.h>
26#include <drm/drm_encoder.h> 26#include <drm/drm_encoder.h>
27#include <drm/drm_utils.h>
27 28
28#include "drm_crtc_internal.h" 29#include "drm_crtc_internal.h"
29#include "drm_internal.h" 30#include "drm_internal.h"
@@ -212,6 +213,8 @@ int drm_connector_init(struct drm_device *dev,
212 mutex_init(&connector->mutex); 213 mutex_init(&connector->mutex);
213 connector->edid_blob_ptr = NULL; 214 connector->edid_blob_ptr = NULL;
214 connector->status = connector_status_unknown; 215 connector->status = connector_status_unknown;
216 connector->display_info.panel_orientation =
217 DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
215 218
216 drm_connector_get_cmdline_mode(connector); 219 drm_connector_get_cmdline_mode(connector);
217 220
@@ -668,6 +671,13 @@ static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
668 { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 671 { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
669}; 672};
670 673
674static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = {
675 { DRM_MODE_PANEL_ORIENTATION_NORMAL, "Normal" },
676 { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, "Upside Down" },
677 { DRM_MODE_PANEL_ORIENTATION_LEFT_UP, "Left Side Up" },
678 { DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, "Right Side Up" },
679};
680
671static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 681static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
672 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 682 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
673 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 683 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
@@ -776,6 +786,18 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
776 * 786 *
777 * CRTC_ID: 787 * CRTC_ID:
778 * Mode object ID of the &drm_crtc this connector should be connected to. 788 * Mode object ID of the &drm_crtc this connector should be connected to.
789 *
790 * Connectors for LCD panels may also have one standardized property:
791 *
792 * panel orientation:
793 * On some devices the LCD panel is mounted in the casing in such a way
794 * that the up/top side of the panel does not match with the top side of
795 * the device. Userspace can use this property to check for this.
796 * Note that input coordinates from touchscreens (input devices with
797 * INPUT_PROP_DIRECT) will still map 1:1 to the actual LCD panel
798 * coordinates, so if userspace rotates the picture to adjust for
799 * the orientation it must also apply the same transformation to the
800 * touchscreen input coordinates.
779 */ 801 */
780 802
781int drm_connector_create_standard_properties(struct drm_device *dev) 803int drm_connector_create_standard_properties(struct drm_device *dev)
@@ -1251,6 +1273,57 @@ void drm_mode_connector_set_link_status_property(struct drm_connector *connector
1251} 1273}
1252EXPORT_SYMBOL(drm_mode_connector_set_link_status_property); 1274EXPORT_SYMBOL(drm_mode_connector_set_link_status_property);
1253 1275
1276/**
1277 * drm_connector_init_panel_orientation_property -
1278 * initialize the connecters panel_orientation property
1279 * @connector: connector for which to init the panel-orientation property.
1280 * @width: width in pixels of the panel, used for panel quirk detection
1281 * @height: height in pixels of the panel, used for panel quirk detection
1282 *
1283 * This function should only be called for built-in panels, after setting
1284 * connector->display_info.panel_orientation first (if known).
1285 *
1286 * This function will check for platform specific (e.g. DMI based) quirks
1287 * overriding display_info.panel_orientation first, then if panel_orientation
1288 * is not DRM_MODE_PANEL_ORIENTATION_UNKNOWN it will attach the
1289 * "panel orientation" property to the connector.
1290 *
1291 * Returns:
1292 * Zero on success, negative errno on failure.
1293 */
1294int drm_connector_init_panel_orientation_property(
1295 struct drm_connector *connector, int width, int height)
1296{
1297 struct drm_device *dev = connector->dev;
1298 struct drm_display_info *info = &connector->display_info;
1299 struct drm_property *prop;
1300 int orientation_quirk;
1301
1302 orientation_quirk = drm_get_panel_orientation_quirk(width, height);
1303 if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
1304 info->panel_orientation = orientation_quirk;
1305
1306 if (info->panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
1307 return 0;
1308
1309 prop = dev->mode_config.panel_orientation_property;
1310 if (!prop) {
1311 prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1312 "panel orientation",
1313 drm_panel_orientation_enum_list,
1314 ARRAY_SIZE(drm_panel_orientation_enum_list));
1315 if (!prop)
1316 return -ENOMEM;
1317
1318 dev->mode_config.panel_orientation_property = prop;
1319 }
1320
1321 drm_object_attach_property(&connector->base, prop,
1322 info->panel_orientation);
1323 return 0;
1324}
1325EXPORT_SYMBOL(drm_connector_init_panel_orientation_property);
1326
1254int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 1327int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
1255 struct drm_property *property, 1328 struct drm_property *property,
1256 uint64_t value) 1329 uint64_t value)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 09919e8d67f9..04a3a5ce370a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -41,6 +41,7 @@
41#include <drm/drm_atomic.h> 41#include <drm/drm_atomic.h>
42#include <drm/drm_atomic_helper.h> 42#include <drm/drm_atomic_helper.h>
43 43
44#include "drm_crtc_internal.h"
44#include "drm_crtc_helper_internal.h" 45#include "drm_crtc_helper_internal.h"
45 46
46static bool drm_fbdev_emulation = true; 47static bool drm_fbdev_emulation = true;
@@ -177,7 +178,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
177 */ 178 */
178int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) 179int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
179{ 180{
180 struct drm_device *dev = fb_helper->dev; 181 struct drm_device *dev;
181 struct drm_connector *connector; 182 struct drm_connector *connector;
182 struct drm_connector_list_iter conn_iter; 183 struct drm_connector_list_iter conn_iter;
183 int i, ret = 0; 184 int i, ret = 0;
@@ -185,6 +186,8 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
185 if (!drm_fbdev_emulation || !fb_helper) 186 if (!drm_fbdev_emulation || !fb_helper)
186 return 0; 187 return 0;
187 188
189 dev = fb_helper->dev;
190
188 mutex_lock(&fb_helper->lock); 191 mutex_lock(&fb_helper->lock);
189 drm_connector_list_iter_begin(dev, &conn_iter); 192 drm_connector_list_iter_begin(dev, &conn_iter);
190 drm_for_each_connector_iter(connector, &conn_iter) { 193 drm_for_each_connector_iter(connector, &conn_iter) {
@@ -356,6 +359,7 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave);
356static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active) 359static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
357{ 360{
358 struct drm_device *dev = fb_helper->dev; 361 struct drm_device *dev = fb_helper->dev;
362 struct drm_plane_state *plane_state;
359 struct drm_plane *plane; 363 struct drm_plane *plane;
360 struct drm_atomic_state *state; 364 struct drm_atomic_state *state;
361 int i, ret; 365 int i, ret;
@@ -374,8 +378,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
374retry: 378retry:
375 plane_mask = 0; 379 plane_mask = 0;
376 drm_for_each_plane(plane, dev) { 380 drm_for_each_plane(plane, dev) {
377 struct drm_plane_state *plane_state;
378
379 plane_state = drm_atomic_get_plane_state(state, plane); 381 plane_state = drm_atomic_get_plane_state(state, plane);
380 if (IS_ERR(plane_state)) { 382 if (IS_ERR(plane_state)) {
381 ret = PTR_ERR(plane_state); 383 ret = PTR_ERR(plane_state);
@@ -398,6 +400,11 @@ retry:
398 400
399 for (i = 0; i < fb_helper->crtc_count; i++) { 401 for (i = 0; i < fb_helper->crtc_count; i++) {
400 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 402 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
403 struct drm_plane *primary = mode_set->crtc->primary;
404
405 /* Cannot fail as we've already gotten the plane state above */
406 plane_state = drm_atomic_get_new_plane_state(state, primary);
407 plane_state->rotation = fb_helper->crtc_info[i].rotation;
401 408
402 ret = __drm_atomic_helper_set_config(mode_set, state); 409 ret = __drm_atomic_helper_set_config(mode_set, state);
403 if (ret != 0) 410 if (ret != 0)
@@ -829,6 +836,7 @@ int drm_fb_helper_init(struct drm_device *dev,
829 if (!fb_helper->crtc_info[i].mode_set.connectors) 836 if (!fb_helper->crtc_info[i].mode_set.connectors)
830 goto out_free; 837 goto out_free;
831 fb_helper->crtc_info[i].mode_set.num_connectors = 0; 838 fb_helper->crtc_info[i].mode_set.num_connectors = 0;
839 fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
832 } 840 }
833 841
834 i = 0; 842 i = 0;
@@ -2357,6 +2365,62 @@ out:
2357 return best_score; 2365 return best_score;
2358} 2366}
2359 2367
2368/*
2369 * This function checks if rotation is necessary because of panel orientation
2370 * and if it is, if it is supported.
2371 * If rotation is necessary and supported, its gets set in fb_crtc.rotation.
2372 * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
2373 * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
2374 * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
2375 * the unsupported rotation.
2376 */
2377static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
2378 struct drm_fb_helper_crtc *fb_crtc,
2379 struct drm_connector *connector)
2380{
2381 struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
2382 uint64_t valid_mask = 0;
2383 int i, rotation;
2384
2385 fb_crtc->rotation = DRM_MODE_ROTATE_0;
2386
2387 switch (connector->display_info.panel_orientation) {
2388 case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
2389 rotation = DRM_MODE_ROTATE_180;
2390 break;
2391 case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
2392 rotation = DRM_MODE_ROTATE_90;
2393 break;
2394 case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
2395 rotation = DRM_MODE_ROTATE_270;
2396 break;
2397 default:
2398 rotation = DRM_MODE_ROTATE_0;
2399 }
2400
2401 /*
2402 * TODO: support 90 / 270 degree hardware rotation,
2403 * depending on the hardware this may require the framebuffer
2404 * to be in a specific tiling format.
2405 */
2406 if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) {
2407 fb_helper->sw_rotations |= rotation;
2408 return;
2409 }
2410
2411 for (i = 0; i < plane->rotation_property->num_values; i++)
2412 valid_mask |= (1ULL << plane->rotation_property->values[i]);
2413
2414 if (!(rotation & valid_mask)) {
2415 fb_helper->sw_rotations |= rotation;
2416 return;
2417 }
2418
2419 fb_crtc->rotation = rotation;
2420 /* Rotating in hardware, fbcon should not rotate */
2421 fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
2422}
2423
2360static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, 2424static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
2361 u32 width, u32 height) 2425 u32 width, u32 height)
2362{ 2426{
@@ -2416,6 +2480,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
2416 drm_fb_helper_modeset_release(fb_helper, 2480 drm_fb_helper_modeset_release(fb_helper,
2417 &fb_helper->crtc_info[i].mode_set); 2481 &fb_helper->crtc_info[i].mode_set);
2418 2482
2483 fb_helper->sw_rotations = 0;
2419 drm_fb_helper_for_each_connector(fb_helper, i) { 2484 drm_fb_helper_for_each_connector(fb_helper, i) {
2420 struct drm_display_mode *mode = modes[i]; 2485 struct drm_display_mode *mode = modes[i];
2421 struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; 2486 struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
@@ -2435,6 +2500,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
2435 modeset->mode = drm_mode_duplicate(dev, 2500 modeset->mode = drm_mode_duplicate(dev,
2436 fb_crtc->desired_mode); 2501 fb_crtc->desired_mode);
2437 drm_connector_get(connector); 2502 drm_connector_get(connector);
2503 drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
2438 modeset->connectors[modeset->num_connectors++] = connector; 2504 modeset->connectors[modeset->num_connectors++] = connector;
2439 modeset->x = offset->x; 2505 modeset->x = offset->x;
2440 modeset->y = offset->y; 2506 modeset->y = offset->y;
@@ -2476,6 +2542,28 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
2476 } 2542 }
2477 } 2543 }
2478 mutex_unlock(&fb_helper->dev->mode_config.mutex); 2544 mutex_unlock(&fb_helper->dev->mode_config.mutex);
2545
2546 switch (fb_helper->sw_rotations) {
2547 case DRM_MODE_ROTATE_0:
2548 info->fbcon_rotate_hint = FB_ROTATE_UR;
2549 break;
2550 case DRM_MODE_ROTATE_90:
2551 info->fbcon_rotate_hint = FB_ROTATE_CCW;
2552 break;
2553 case DRM_MODE_ROTATE_180:
2554 info->fbcon_rotate_hint = FB_ROTATE_UD;
2555 break;
2556 case DRM_MODE_ROTATE_270:
2557 info->fbcon_rotate_hint = FB_ROTATE_CW;
2558 break;
2559 default:
2560 /*
2561 * Multiple bits are set / multiple rotations requested
2562 * fbcon cannot handle separate rotation settings per
2563 * output, so fallback to unrotated.
2564 */
2565 info->fbcon_rotate_hint = FB_ROTATE_UR;
2566 }
2479} 2567}
2480 2568
2481/* Note: Drops fb_helper->lock before returning. */ 2569/* Note: Drops fb_helper->lock before returning. */
diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
index 9cb1eede0b4d..f1c24ab0ef09 100644
--- a/drivers/gpu/drm/drm_modeset_helper.c
+++ b/drivers/gpu/drm/drm_modeset_helper.c
@@ -20,6 +20,9 @@
20 * OF THIS SOFTWARE. 20 * OF THIS SOFTWARE.
21 */ 21 */
22 22
23#include <drm/drm_atomic_helper.h>
24#include <drm/drm_crtc_helper.h>
25#include <drm/drm_fb_helper.h>
23#include <drm/drm_modeset_helper.h> 26#include <drm/drm_modeset_helper.h>
24#include <drm/drm_plane_helper.h> 27#include <drm/drm_plane_helper.h>
25 28
@@ -156,3 +159,76 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
156 NULL); 159 NULL);
157} 160}
158EXPORT_SYMBOL(drm_crtc_init); 161EXPORT_SYMBOL(drm_crtc_init);
162
163/**
164 * drm_mode_config_helper_suspend - Modeset suspend helper
165 * @dev: DRM device
166 *
167 * This helper function takes care of suspending the modeset side. It disables
168 * output polling if initialized, suspends fbdev if used and finally calls
169 * drm_atomic_helper_suspend().
170 * If suspending fails, fbdev and polling is re-enabled.
171 *
172 * Returns:
173 * Zero on success, negative error code on error.
174 *
175 * See also:
176 * drm_kms_helper_poll_disable() and drm_fb_helper_set_suspend_unlocked().
177 */
178int drm_mode_config_helper_suspend(struct drm_device *dev)
179{
180 struct drm_atomic_state *state;
181
182 if (!dev)
183 return 0;
184
185 drm_kms_helper_poll_disable(dev);
186 drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1);
187 state = drm_atomic_helper_suspend(dev);
188 if (IS_ERR(state)) {
189 drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
190 drm_kms_helper_poll_enable(dev);
191 return PTR_ERR(state);
192 }
193
194 dev->mode_config.suspend_state = state;
195
196 return 0;
197}
198EXPORT_SYMBOL(drm_mode_config_helper_suspend);
199
200/**
201 * drm_mode_config_helper_resume - Modeset resume helper
202 * @dev: DRM device
203 *
204 * This helper function takes care of resuming the modeset side. It calls
205 * drm_atomic_helper_resume(), resumes fbdev if used and enables output polling
206 * if initiaized.
207 *
208 * Returns:
209 * Zero on success, negative error code on error.
210 *
211 * See also:
212 * drm_fb_helper_set_suspend_unlocked() and drm_kms_helper_poll_enable().
213 */
214int drm_mode_config_helper_resume(struct drm_device *dev)
215{
216 int ret;
217
218 if (!dev)
219 return 0;
220
221 if (WARN_ON(!dev->mode_config.suspend_state))
222 return -EINVAL;
223
224 ret = drm_atomic_helper_resume(dev, dev->mode_config.suspend_state);
225 if (ret)
226 DRM_ERROR("Failed to resume (%d)\n", ret);
227 dev->mode_config.suspend_state = NULL;
228
229 drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
230 drm_kms_helper_poll_enable(dev);
231
232 return ret;
233}
234EXPORT_SYMBOL(drm_mode_config_helper_resume);
diff --git a/drivers/video/fbdev/core/fbcon_dmi_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index 6904e47d1e51..901a4e9a87a3 100644
--- a/drivers/video/fbdev/core/fbcon_dmi_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -1,17 +1,17 @@
1/* SPDX-License-Identifier: MIT */
1/* 2/*
2 * fbcon_dmi_quirks.c -- DMI based quirk detection for fbcon 3 * drm_panel_orientation_quirks.c -- Quirks for non-normal panel orientation
3 * 4 *
4 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> 5 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
5 * 6 *
6 * This file is subject to the terms and conditions of the GNU General Public 7 * Note the quirks in this file are shared with fbdev/efifb and as such
7 * License. See the file COPYING in the main directory of this archive for 8 * must not depend on other drm code.
8 * more details.
9 */ 9 */
10 10
11#include <linux/dmi.h> 11#include <linux/dmi.h>
12#include <linux/fb.h> 12#include <drm/drm_connector.h>
13#include <linux/kernel.h> 13
14#include "fbcon.h" 14#ifdef CONFIG_DMI
15 15
16/* 16/*
17 * Some x86 clamshell design devices use portrait tablet screens and a display 17 * Some x86 clamshell design devices use portrait tablet screens and a display
@@ -21,56 +21,56 @@
21 * and a list of known BIOS dates to avoid false positives. 21 * and a list of known BIOS dates to avoid false positives.
22 */ 22 */
23 23
24struct fbcon_dmi_rotate_data { 24struct drm_dmi_panel_orientation_data {
25 int width; 25 int width;
26 int height; 26 int height;
27 const char * const *bios_dates; 27 const char * const *bios_dates;
28 int rotate; 28 int orientation;
29}; 29};
30 30
31static const struct fbcon_dmi_rotate_data rotate_data_asus_t100ha = { 31static const struct drm_dmi_panel_orientation_data asus_t100ha = {
32 .width = 800, 32 .width = 800,
33 .height = 1280, 33 .height = 1280,
34 .rotate = FB_ROTATE_CCW, 34 .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
35}; 35};
36 36
37static const struct fbcon_dmi_rotate_data rotate_data_gpd_pocket = { 37static const struct drm_dmi_panel_orientation_data gpd_pocket = {
38 .width = 1200, 38 .width = 1200,
39 .height = 1920, 39 .height = 1920,
40 .bios_dates = (const char * const []){ "05/26/2017", "06/28/2017", 40 .bios_dates = (const char * const []){ "05/26/2017", "06/28/2017",
41 "07/05/2017", "08/07/2017", NULL }, 41 "07/05/2017", "08/07/2017", NULL },
42 .rotate = FB_ROTATE_CW, 42 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
43}; 43};
44 44
45static const struct fbcon_dmi_rotate_data rotate_data_gpd_win = { 45static const struct drm_dmi_panel_orientation_data gpd_win = {
46 .width = 720, 46 .width = 720,
47 .height = 1280, 47 .height = 1280,
48 .bios_dates = (const char * const []){ 48 .bios_dates = (const char * const []){
49 "10/25/2016", "11/18/2016", "12/23/2016", "12/26/2016", 49 "10/25/2016", "11/18/2016", "12/23/2016", "12/26/2016",
50 "02/21/2017", "03/20/2017", "05/25/2017", NULL }, 50 "02/21/2017", "03/20/2017", "05/25/2017", NULL },
51 .rotate = FB_ROTATE_CW, 51 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
52}; 52};
53 53
54static const struct fbcon_dmi_rotate_data rotate_data_itworks_tw891 = { 54static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
55 .width = 800, 55 .width = 800,
56 .height = 1280, 56 .height = 1280,
57 .bios_dates = (const char * const []){ "10/16/2015", NULL }, 57 .bios_dates = (const char * const []){ "10/16/2015", NULL },
58 .rotate = FB_ROTATE_CW, 58 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
59}; 59};
60 60
61static const struct fbcon_dmi_rotate_data rotate_data_vios_lth17 = { 61static const struct drm_dmi_panel_orientation_data vios_lth17 = {
62 .width = 800, 62 .width = 800,
63 .height = 1280, 63 .height = 1280,
64 .rotate = FB_ROTATE_CW, 64 .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
65}; 65};
66 66
67static const struct dmi_system_id rotate_data[] = { 67static const struct dmi_system_id orientation_data[] = {
68 { /* Asus T100HA */ 68 { /* Asus T100HA */
69 .matches = { 69 .matches = {
70 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 70 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
71 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"), 71 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
72 }, 72 },
73 .driver_data = (void *)&rotate_data_asus_t100ha, 73 .driver_data = (void *)&asus_t100ha,
74 }, { /* 74 }, { /*
75 * GPD Pocket, note that the the DMI data is less generic then 75 * GPD Pocket, note that the the DMI data is less generic then
76 * it seems, devices with a board-vendor of "AMI Corporation" 76 * it seems, devices with a board-vendor of "AMI Corporation"
@@ -83,7 +83,7 @@ static const struct dmi_system_id rotate_data[] = {
83 DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), 83 DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
84 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), 84 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
85 }, 85 },
86 .driver_data = (void *)&rotate_data_gpd_pocket, 86 .driver_data = (void *)&gpd_pocket,
87 }, { /* GPD Win (same note on DMI match as GPD Pocket) */ 87 }, { /* GPD Win (same note on DMI match as GPD Pocket) */
88 .matches = { 88 .matches = {
89 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 89 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
@@ -91,7 +91,7 @@ static const struct dmi_system_id rotate_data[] = {
91 DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), 91 DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
92 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), 92 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
93 }, 93 },
94 .driver_data = (void *)&rotate_data_gpd_win, 94 .driver_data = (void *)&gpd_win,
95 }, { /* I.T.Works TW891 */ 95 }, { /* I.T.Works TW891 */
96 .matches = { 96 .matches = {
97 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), 97 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
@@ -99,37 +99,54 @@ static const struct dmi_system_id rotate_data[] = {
99 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), 99 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
100 DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"), 100 DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"),
101 }, 101 },
102 .driver_data = (void *)&rotate_data_itworks_tw891, 102 .driver_data = (void *)&itworks_tw891,
103 }, { /* VIOS LTH17 */ 103 }, { /* VIOS LTH17 */
104 .matches = { 104 .matches = {
105 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS"), 105 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS"),
106 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"), 106 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"),
107 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "VIOS"),
108 DMI_EXACT_MATCH(DMI_BOARD_NAME, "LTH17"),
109 }, 107 },
110 .driver_data = (void *)&rotate_data_vios_lth17, 108 .driver_data = (void *)&vios_lth17,
111 }, 109 },
112 {} 110 {}
113}; 111};
114 112
115int fbcon_platform_get_rotate(struct fb_info *info) 113/**
114 * drm_get_panel_orientation_quirk - Check for panel orientation quirks
115 * @width: width in pixels of the panel
116 * @height: height in pixels of the panel
117 *
118 * This function checks for platform specific (e.g. DMI based) quirks
119 * providing info on panel_orientation for systems where this cannot be
120 * probed from the hard-/firm-ware. To avoid false-positive this function
121 * takes the panel resolution as argument and checks that against the
122 * resolution expected by the quirk-table entry.
123 *
124 * Note this function is also used outside of the drm-subsys, by for example
125 * the efifb code. Because of this this function gets compiled into its own
126 * kernel-module when built as a module.
127 *
128 * Returns:
129 * A DRM_MODE_PANEL_ORIENTATION_* value if there is a quirk for this system,
130 * or DRM_MODE_PANEL_ORIENTATION_UNKNOWN if there is no quirk.
131 */
132int drm_get_panel_orientation_quirk(int width, int height)
116{ 133{
117 const struct dmi_system_id *match; 134 const struct dmi_system_id *match;
118 const struct fbcon_dmi_rotate_data *data; 135 const struct drm_dmi_panel_orientation_data *data;
119 const char *bios_date; 136 const char *bios_date;
120 int i; 137 int i;
121 138
122 for (match = dmi_first_match(rotate_data); 139 for (match = dmi_first_match(orientation_data);
123 match; 140 match;
124 match = dmi_first_match(match + 1)) { 141 match = dmi_first_match(match + 1)) {
125 data = match->driver_data; 142 data = match->driver_data;
126 143
127 if (data->width != info->var.xres || 144 if (data->width != width ||
128 data->height != info->var.yres) 145 data->height != height)
129 continue; 146 continue;
130 147
131 if (!data->bios_dates) 148 if (!data->bios_dates)
132 return data->rotate; 149 return data->orientation;
133 150
134 bios_date = dmi_get_system_info(DMI_BIOS_DATE); 151 bios_date = dmi_get_system_info(DMI_BIOS_DATE);
135 if (!bios_date) 152 if (!bios_date)
@@ -137,9 +154,21 @@ int fbcon_platform_get_rotate(struct fb_info *info)
137 154
138 for (i = 0; data->bios_dates[i]; i++) { 155 for (i = 0; data->bios_dates[i]; i++) {
139 if (!strcmp(data->bios_dates[i], bios_date)) 156 if (!strcmp(data->bios_dates[i], bios_date))
140 return data->rotate; 157 return data->orientation;
141 } 158 }
142 } 159 }
143 160
144 return FB_ROTATE_UR; 161 return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
145} 162}
163EXPORT_SYMBOL(drm_get_panel_orientation_quirk);
164
165#else
166
167/* There are no quirks for non x86 devices yet */
168int drm_get_panel_orientation_quirk(int width, int height)
169{
170 return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
171}
172EXPORT_SYMBOL(drm_get_panel_orientation_quirk);
173
174#endif
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 8de93a226c24..9a17725b0f7a 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -218,8 +218,9 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf,
218 sgt = prime_attach->sgt; 218 sgt = prime_attach->sgt;
219 if (sgt) { 219 if (sgt) {
220 if (prime_attach->dir != DMA_NONE) 220 if (prime_attach->dir != DMA_NONE)
221 dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, 221 dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents,
222 prime_attach->dir); 222 prime_attach->dir,
223 DMA_ATTR_SKIP_CPU_SYNC);
223 sg_free_table(sgt); 224 sg_free_table(sgt);
224 } 225 }
225 226
@@ -277,7 +278,8 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
277 sgt = obj->dev->driver->gem_prime_get_sg_table(obj); 278 sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
278 279
279 if (!IS_ERR(sgt)) { 280 if (!IS_ERR(sgt)) {
280 if (!dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir)) { 281 if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
282 DMA_ATTR_SKIP_CPU_SYNC)) {
281 sg_free_table(sgt); 283 sg_free_table(sgt);
282 kfree(sgt); 284 kfree(sgt);
283 sgt = ERR_PTR(-ENOMEM); 285 sgt = ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 6dc2dde5b672..555fbe54d6e2 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -216,8 +216,7 @@ enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector,
216 * suspend/resume. 216 * suspend/resume.
217 * 217 *
218 * Drivers can call this helper from their device resume implementation. It is 218 * Drivers can call this helper from their device resume implementation. It is
219 * an error to call this when the output polling support has not yet been set 219 * not an error to call this even when output polling isn't enabled.
220 * up.
221 * 220 *
222 * Note that calls to enable and disable polling must be strictly ordered, which 221 * Note that calls to enable and disable polling must be strictly ordered, which
223 * is automatically the case when they're only call from suspend/resume 222 * is automatically the case when they're only call from suspend/resume
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 faf17b83b910..80232321a244 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -27,6 +27,7 @@
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_gem_cma_helper.h> 29#include <drm/drm_gem_cma_helper.h>
30#include <drm/drm_modeset_helper.h>
30 31
31#include "fsl_dcu_drm_crtc.h" 32#include "fsl_dcu_drm_crtc.h"
32#include "fsl_dcu_drm_drv.h" 33#include "fsl_dcu_drm_drv.h"
@@ -188,26 +189,17 @@ static struct drm_driver fsl_dcu_drm_driver = {
188static int fsl_dcu_drm_pm_suspend(struct device *dev) 189static int fsl_dcu_drm_pm_suspend(struct device *dev)
189{ 190{
190 struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); 191 struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
192 int ret;
191 193
192 if (!fsl_dev) 194 if (!fsl_dev)
193 return 0; 195 return 0;
194 196
195 disable_irq(fsl_dev->irq); 197 disable_irq(fsl_dev->irq);
196 drm_kms_helper_poll_disable(fsl_dev->drm);
197
198 console_lock();
199 drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 1);
200 console_unlock();
201
202 fsl_dev->state = drm_atomic_helper_suspend(fsl_dev->drm);
203 if (IS_ERR(fsl_dev->state)) {
204 console_lock();
205 drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 0);
206 console_unlock();
207 198
208 drm_kms_helper_poll_enable(fsl_dev->drm); 199 ret = drm_mode_config_helper_suspend(fsl_dev->drm);
200 if (ret) {
209 enable_irq(fsl_dev->irq); 201 enable_irq(fsl_dev->irq);
210 return PTR_ERR(fsl_dev->state); 202 return ret;
211 } 203 }
212 204
213 clk_disable_unprepare(fsl_dev->clk); 205 clk_disable_unprepare(fsl_dev->clk);
@@ -233,13 +225,8 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
233 fsl_tcon_bypass_enable(fsl_dev->tcon); 225 fsl_tcon_bypass_enable(fsl_dev->tcon);
234 fsl_dcu_drm_init_planes(fsl_dev->drm); 226 fsl_dcu_drm_init_planes(fsl_dev->drm);
235 enable_irq(fsl_dev->irq); 227 enable_irq(fsl_dev->irq);
236 drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state);
237
238 console_lock();
239 drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 0);
240 console_unlock();
241 228
242 drm_kms_helper_poll_enable(fsl_dev->drm); 229 drm_mode_config_helper_resume(fsl_dev->drm);
243 230
244 return 0; 231 return 0;
245} 232}
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 da9bfd432ca6..93bfb98012d4 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
@@ -196,7 +196,6 @@ struct fsl_dcu_drm_device {
196 struct drm_encoder encoder; 196 struct drm_encoder encoder;
197 struct fsl_dcu_drm_connector connector; 197 struct fsl_dcu_drm_connector connector;
198 const struct fsl_dcu_soc_data *soc; 198 const struct fsl_dcu_soc_data *soc;
199 struct drm_atomic_state *state;
200}; 199};
201 200
202int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev); 201int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index f09474b0c4d3..1b60df3c14a0 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -1666,6 +1666,27 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
1666 .atomic_duplicate_state = intel_digital_connector_duplicate_state, 1666 .atomic_duplicate_state = intel_digital_connector_duplicate_state,
1667}; 1667};
1668 1668
1669static int intel_dsi_get_panel_orientation(struct intel_connector *connector)
1670{
1671 struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
1672 int orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
1673 enum plane plane;
1674 u32 val;
1675
1676 if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
1677 if (connector->encoder->crtc_mask == BIT(PIPE_B))
1678 plane = PLANE_B;
1679 else
1680 plane = PLANE_A;
1681
1682 val = I915_READ(DSPCNTR(plane));
1683 if (val & DISPPLANE_ROTATE_180)
1684 orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
1685 }
1686
1687 return orientation;
1688}
1689
1669static void intel_dsi_add_properties(struct intel_connector *connector) 1690static void intel_dsi_add_properties(struct intel_connector *connector)
1670{ 1691{
1671 struct drm_i915_private *dev_priv = to_i915(connector->base.dev); 1692 struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
@@ -1681,6 +1702,13 @@ static void intel_dsi_add_properties(struct intel_connector *connector)
1681 allowed_scalers); 1702 allowed_scalers);
1682 1703
1683 connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; 1704 connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
1705
1706 connector->base.display_info.panel_orientation =
1707 intel_dsi_get_panel_orientation(connector);
1708 drm_connector_init_panel_orientation_property(
1709 &connector->base,
1710 connector->panel.fixed_mode->hdisplay,
1711 connector->panel.fixed_mode->vdisplay);
1684 } 1712 }
1685} 1713}
1686 1714
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c
index 2da7d6866d5d..7c5a7830b6e8 100644
--- a/drivers/gpu/drm/sti/sti_awg_utils.c
+++ b/drivers/gpu/drm/sti/sti_awg_utils.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include "sti_awg_utils.h" 7#include "sti_awg_utils.h"
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.h b/drivers/gpu/drm/sti/sti_awg_utils.h
index 45d599bd570a..258a568f050b 100644
--- a/drivers/gpu/drm/sti/sti_awg_utils.h
+++ b/drivers/gpu/drm/sti/sti_awg_utils.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_AWG_UTILS_H_ 7#ifndef _STI_AWG_UTILS_H_
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index 6e4bf68262db..021b8fcaa0b9 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#include <linux/component.h> 9#include <linux/component.h>
diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h
index 2952a2d25a52..ac4bb3834810 100644
--- a/drivers/gpu/drm/sti/sti_compositor.h
+++ b/drivers/gpu/drm/sti/sti_compositor.h
@@ -1,9 +1,9 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#ifndef _STI_COMPOSITOR_H_ 9#ifndef _STI_COMPOSITOR_H_
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index e8a4d48e985a..21e50d7b1f86 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#include <linux/clk.h> 9#include <linux/clk.h>
diff --git a/drivers/gpu/drm/sti/sti_crtc.h b/drivers/gpu/drm/sti/sti_crtc.h
index 3f2d89a3634d..d87c488212d6 100644
--- a/drivers/gpu/drm/sti/sti_crtc.h
+++ b/drivers/gpu/drm/sti/sti_crtc.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_CRTC_H_ 7#ifndef _STI_CRTC_H_
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index b709ebbec095..df0a282b9615 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Vincent Abriou <vincent.abriou@st.com> 4 * Authors: Vincent Abriou <vincent.abriou@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#include <linux/seq_file.h> 9#include <linux/seq_file.h>
diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h
index 2ee5c10e8b33..067feda5226c 100644
--- a/drivers/gpu/drm/sti/sti_cursor.h
+++ b/drivers/gpu/drm/sti/sti_cursor.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2013 3 * Copyright (C) STMicroelectronics SA 2013
3 * Authors: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Authors: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_CURSOR_H_ 7#ifndef _STI_CURSOR_H_
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 9e9343101738..88d1dc6408af 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include <drm/drmP.h> 7#include <drm/drmP.h>
diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h
index 6502ed2d3351..abc49b43566e 100644
--- a/drivers/gpu/drm/sti/sti_drv.h
+++ b/drivers/gpu/drm/sti/sti_drv.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_DRV_H_ 7#ifndef _STI_DRV_H_
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index 83314aee65cb..a5979cd25cc7 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include <linux/clk.h> 7#include <linux/clk.h>
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index b65eea4f2c97..9b2c47051b51 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8#include <linux/seq_file.h> 8#include <linux/seq_file.h>
9 9
diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h
index 73947a4a8004..d3e8ebfe2e66 100644
--- a/drivers/gpu/drm/sti/sti_gdp.h
+++ b/drivers/gpu/drm/sti/sti_gdp.h
@@ -1,9 +1,9 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#ifndef _STI_GDP_H_ 9#ifndef _STI_GDP_H_
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index cf65e32b5090..67bbdb49fffc 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. 4 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include <linux/clk.h> 7#include <linux/clk.h>
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 4ea1cc1c032e..58f431102512 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include <linux/clk.h> 7#include <linux/clk.h>
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h
index c6469b56ce7e..63a24941db3b 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.h
+++ b/drivers/gpu/drm/sti/sti_hdmi.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_HDMI_H_ 7#ifndef _STI_HDMI_H_
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
index 8e0ceb0ced33..01699af6a768 100644
--- a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics. 4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include "sti_hdmi_tx3g4c28phy.h" 7#include "sti_hdmi_tx3g4c28phy.h"
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
index f99a7ff281ef..d261947ef30a 100644
--- a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_HDMI_TX3G4C28PHY_H_ 7#ifndef _STI_HDMI_TX3G4C28PHY_H_
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index b19b3430b296..106be8c4e58b 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. 4 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#include <linux/component.h> 7#include <linux/component.h>
diff --git a/drivers/gpu/drm/sti/sti_hqvdp_lut.h b/drivers/gpu/drm/sti/sti_hqvdp_lut.h
index 619af7f4384e..57cccd9546a3 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp_lut.h
+++ b/drivers/gpu/drm/sti/sti_hqvdp_lut.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. 4 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_HQVDP_LUT_H_ 7#ifndef _STI_HQVDP_LUT_H_
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
index 2bd1d46fe1cd..a4f45c74d678 100644
--- a/drivers/gpu/drm/sti/sti_mixer.c
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8#include <linux/seq_file.h> 8#include <linux/seq_file.h>
9 9
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h
index e64a00e61049..4cb3cfddc03a 100644
--- a/drivers/gpu/drm/sti/sti_mixer.h
+++ b/drivers/gpu/drm/sti/sti_mixer.h
@@ -1,9 +1,9 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#ifndef _STI_MIXER_H_ 9#ifndef _STI_MIXER_H_
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index 427d8f58c6b1..b074609c960a 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#include <drm/drmP.h> 9#include <drm/drmP.h>
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
index c36c13faaa18..b8d7fae2a014 100644
--- a/drivers/gpu/drm/sti/sti_plane.h
+++ b/drivers/gpu/drm/sti/sti_plane.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_PLANE_H_ 7#ifndef _STI_PLANE_H_
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index 8959fcc743a8..ea4a3b87fa55 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -1,9 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Vincent Abriou <vincent.abriou@st.com> 5 * Vincent Abriou <vincent.abriou@st.com>
5 * for STMicroelectronics. 6 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */ 7 */
8 8
9#include <linux/clk.h> 9#include <linux/clk.h>
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c
index 577a3341d3c1..2aac36c95835 100644
--- a/drivers/gpu/drm/sti/sti_vid.c
+++ b/drivers/gpu/drm/sti/sti_vid.c
@@ -1,7 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. 4 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6#include <linux/seq_file.h> 6#include <linux/seq_file.h>
7 7
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h
index fdc90f922a05..9dbd78461de1 100644
--- a/drivers/gpu/drm/sti/sti_vid.h
+++ b/drivers/gpu/drm/sti/sti_vid.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. 4 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_VID_H_ 7#ifndef _STI_VID_H_
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c
index 3aa2fa6f2228..6c421644de18 100644
--- a/drivers/gpu/drm/sti/sti_vtg.c
+++ b/drivers/gpu/drm/sti/sti_vtg.c
@@ -1,10 +1,10 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Fabien Dessenne <fabien.dessenne@st.com>
5 * Vincent Abriou <vincent.abriou@st.com> 6 * Vincent Abriou <vincent.abriou@st.com>
6 * for STMicroelectronics. 7 * for STMicroelectronics.
7 * License terms: GNU General Public License (GPL), version 2
8 */ 8 */
9 9
10#include <linux/module.h> 10#include <linux/module.h>
diff --git a/drivers/gpu/drm/sti/sti_vtg.h b/drivers/gpu/drm/sti/sti_vtg.h
index f1dcdf9c2342..d177129e5bcb 100644
--- a/drivers/gpu/drm/sti/sti_vtg.h
+++ b/drivers/gpu/drm/sti/sti_vtg.h
@@ -1,7 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2014 3 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. 4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */ 5 */
6 6
7#ifndef _STI_VTG_H_ 7#ifndef _STI_VTG_H_
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index c857663eafc2..2d6e9ca0450b 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -1,3 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2017 3 * Copyright (C) STMicroelectronics SA 2017
3 * 4 *
@@ -5,8 +6,6 @@
5 * Yannick Fertre <yannick.fertre@st.com> 6 * Yannick Fertre <yannick.fertre@st.com>
6 * Fabien Dessenne <fabien.dessenne@st.com> 7 * Fabien Dessenne <fabien.dessenne@st.com>
7 * Mickael Reulier <mickael.reulier@st.com> 8 * Mickael Reulier <mickael.reulier@st.com>
8 *
9 * License terms: GNU General Public License (GPL), version 2
10 */ 9 */
11 10
12#include <linux/component.h> 11#include <linux/component.h>
diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
index 3e8b9ed7e8b3..82dcb20cdaa3 100644
--- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
@@ -1,10 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2017 3 * Copyright (C) STMicroelectronics SA 2017
3 * 4 *
4 * Authors: Philippe Cornu <philippe.cornu@st.com> 5 * Authors: Philippe Cornu <philippe.cornu@st.com>
5 * Yannick Fertre <yannick.fertre@st.com> 6 * Yannick Fertre <yannick.fertre@st.com>
6 *
7 * License terms: GNU General Public License (GPL), version 2
8 */ 7 */
9 8
10#include <linux/clk.h> 9#include <linux/clk.h>
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 35e884239f60..394613b0fd46 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -1,3 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2017 3 * Copyright (C) STMicroelectronics SA 2017
3 * 4 *
@@ -5,8 +6,6 @@
5 * Yannick Fertre <yannick.fertre@st.com> 6 * Yannick Fertre <yannick.fertre@st.com>
6 * Fabien Dessenne <fabien.dessenne@st.com> 7 * Fabien Dessenne <fabien.dessenne@st.com>
7 * Mickael Reulier <mickael.reulier@st.com> 8 * Mickael Reulier <mickael.reulier@st.com>
8 *
9 * License terms: GNU General Public License (GPL), version 2
10 */ 9 */
11 10
12#include <linux/clk.h> 11#include <linux/clk.h>
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index ae437557d715..d5da74d24995 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -1,3 +1,4 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (C) STMicroelectronics SA 2017 3 * Copyright (C) STMicroelectronics SA 2017
3 * 4 *
@@ -5,8 +6,6 @@
5 * Yannick Fertre <yannick.fertre@st.com> 6 * Yannick Fertre <yannick.fertre@st.com>
6 * Fabien Dessenne <fabien.dessenne@st.com> 7 * Fabien Dessenne <fabien.dessenne@st.com>
7 * Mickael Reulier <mickael.reulier@st.com> 8 * Mickael Reulier <mickael.reulier@st.com>
8 *
9 * License terms: GNU General Public License (GPL), version 2
10 */ 9 */
11 10
12#ifndef _LTDC_H_ 11#ifndef _LTDC_H_
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 0c2f8c7facae..82a6ac57fbe3 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -9,7 +9,9 @@ sun4i-drm-hdmi-y += sun4i_hdmi_enc.o
9sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o 9sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
10sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o 10sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
11 11
12sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o 12sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
13 sun8i_vi_layer.o sun8i_ui_scaler.o \
14 sun8i_vi_scaler.o sun8i_csc.o
13 15
14sun4i-tcon-y += sun4i_crtc.o 16sun4i-tcon-y += sun4i_crtc.o
15sun4i-tcon-y += sun4i_dotclock.o 17sun4i-tcon-y += sun4i_dotclock.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 75c76cdd82bc..49215d91c853 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -187,13 +187,7 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node)
187 187
188static bool sun4i_drv_node_is_tcon(struct device_node *node) 188static bool sun4i_drv_node_is_tcon(struct device_node *node)
189{ 189{
190 return of_device_is_compatible(node, "allwinner,sun4i-a10-tcon") || 190 return !!of_match_node(sun4i_tcon_of_table, node);
191 of_device_is_compatible(node, "allwinner,sun5i-a13-tcon") ||
192 of_device_is_compatible(node, "allwinner,sun6i-a31-tcon") ||
193 of_device_is_compatible(node, "allwinner,sun6i-a31s-tcon") ||
194 of_device_is_compatible(node, "allwinner,sun7i-a20-tcon") ||
195 of_device_is_compatible(node, "allwinner,sun8i-a33-tcon") ||
196 of_device_is_compatible(node, "allwinner,sun8i-v3s-tcon");
197} 191}
198 192
199static int compare_of(struct device *dev, void *data) 193static int compare_of(struct device *dev, void *data)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index e122f5b2a395..a1ed462c2430 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -900,7 +900,8 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
900 /* nothing is supported */ 900 /* nothing is supported */
901}; 901};
902 902
903static const struct of_device_id sun4i_tcon_of_table[] = { 903/* sun4i_drv uses this list to check if a device node is a TCON */
904const struct of_device_id sun4i_tcon_of_table[] = {
904 { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks }, 905 { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
905 { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks }, 906 { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
906 { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks }, 907 { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
@@ -911,6 +912,7 @@ static const struct of_device_id sun4i_tcon_of_table[] = {
911 { } 912 { }
912}; 913};
913MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); 914MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
915EXPORT_SYMBOL(sun4i_tcon_of_table);
914 916
915static struct platform_driver sun4i_tcon_platform_driver = { 917static struct platform_driver sun4i_tcon_platform_driver = {
916 .probe = sun4i_tcon_probe, 918 .probe = sun4i_tcon_probe,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index f61bf6d83b4a..839266a38505 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -197,4 +197,6 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
197void sun4i_tcon_set_status(struct sun4i_tcon *crtc, 197void sun4i_tcon_set_status(struct sun4i_tcon *crtc,
198 const struct drm_encoder *encoder, bool enable); 198 const struct drm_encoder *encoder, bool enable);
199 199
200extern const struct of_device_id sun4i_tcon_of_table[];
201
200#endif /* __SUN4I_TCON_H__ */ 202#endif /* __SUN4I_TCON_H__ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
new file mode 100644
index 000000000000..b14925b40ccf
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 */
9
10#include <drm/drmP.h>
11
12#include "sun8i_csc.h"
13#include "sun8i_mixer.h"
14
15static const u32 ccsc_base[2][2] = {
16 {CCSC00_OFFSET, CCSC01_OFFSET},
17 {CCSC10_OFFSET, CCSC11_OFFSET},
18};
19
20/*
21 * Factors are in two's complement format, 10 bits for fractinal part.
22 * First tree values in each line are multiplication factor and last
23 * value is constant, which is added at the end.
24 */
25static const u32 yuv2rgb[] = {
26 0x000004A8, 0x00000000, 0x00000662, 0xFFFC845A,
27 0x000004A8, 0xFFFFFE6F, 0xFFFFFCBF, 0x00021DF4,
28 0x000004A8, 0x00000813, 0x00000000, 0xFFFBAC4A,
29};
30
31static const u32 yvu2rgb[] = {
32 0x000004A8, 0x00000662, 0x00000000, 0xFFFC845A,
33 0x000004A8, 0xFFFFFCBF, 0xFFFFFE6F, 0x00021DF4,
34 0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A,
35};
36
37static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
38 enum sun8i_csc_mode mode)
39{
40 const u32 *table;
41 int i, data;
42
43 switch (mode) {
44 case SUN8I_CSC_MODE_YUV2RGB:
45 table = yuv2rgb;
46 break;
47 case SUN8I_CSC_MODE_YVU2RGB:
48 table = yvu2rgb;
49 break;
50 default:
51 DRM_WARN("Wrong CSC mode specified.\n");
52 return;
53 }
54
55 for (i = 0; i < 12; i++) {
56 data = table[i];
57 /* For some reason, 0x200 must be added to constant parts */
58 if (((i + 1) & 3) == 0)
59 data += 0x200;
60 regmap_write(map, SUN8I_CSC_COEFF(base, i), data);
61 }
62}
63
64static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
65{
66 u32 val;
67
68 if (enable)
69 val = SUN8I_CSC_CTRL_EN;
70 else
71 val = 0;
72
73 regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
74}
75
76void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
77 enum sun8i_csc_mode mode)
78{
79 u32 base;
80
81 base = ccsc_base[mixer->cfg->ccsc][layer];
82
83 sun8i_csc_set_coefficients(mixer->engine.regs, base, mode);
84}
85
86void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
87{
88 u32 base;
89
90 base = ccsc_base[mixer->cfg->ccsc][layer];
91
92 sun8i_csc_enable(mixer->engine.regs, base, enable);
93}
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
new file mode 100644
index 000000000000..880e8fbb0855
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 */
9
10#ifndef _SUN8I_CSC_H_
11#define _SUN8I_CSC_H_
12
13struct sun8i_mixer;
14
15/* VI channel CSC units offsets */
16#define CCSC00_OFFSET 0xAA050
17#define CCSC01_OFFSET 0xFA000
18#define CCSC10_OFFSET 0xA0000
19#define CCSC11_OFFSET 0xF0000
20
21#define SUN8I_CSC_CTRL(base) (base + 0x0)
22#define SUN8I_CSC_COEFF(base, i) (base + 0x10 + 4 * i)
23
24#define SUN8I_CSC_CTRL_EN BIT(0)
25
26enum sun8i_csc_mode {
27 SUN8I_CSC_MODE_OFF,
28 SUN8I_CSC_MODE_YUV2RGB,
29 SUN8I_CSC_MODE_YVU2RGB,
30};
31
32void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
33 enum sun8i_csc_mode mode);
34void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable);
35
36#endif
diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c b/drivers/gpu/drm/sun4i/sun8i_layer.c
deleted file mode 100644
index 23810ff72684..000000000000
--- a/drivers/gpu/drm/sun4i/sun8i_layer.c
+++ /dev/null
@@ -1,134 +0,0 @@
1/*
2 * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
3 *
4 * Based on sun4i_layer.h, which is:
5 * Copyright (C) 2015 Free Electrons
6 * Copyright (C) 2015 NextThing Co
7 *
8 * Maxime Ripard <maxime.ripard@free-electrons.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 */
15
16#include <drm/drm_atomic_helper.h>
17#include <drm/drm_plane_helper.h>
18#include <drm/drmP.h>
19
20#include "sun8i_layer.h"
21#include "sun8i_mixer.h"
22
23struct sun8i_plane_desc {
24 enum drm_plane_type type;
25 const uint32_t *formats;
26 uint32_t nformats;
27};
28
29static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
30 struct drm_plane_state *old_state)
31{
32 struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
33 struct sun8i_mixer *mixer = layer->mixer;
34
35 sun8i_mixer_layer_enable(mixer, layer->id, false);
36}
37
38static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
39 struct drm_plane_state *old_state)
40{
41 struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
42 struct sun8i_mixer *mixer = layer->mixer;
43
44 sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
45 sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
46 sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
47 sun8i_mixer_layer_enable(mixer, layer->id, true);
48}
49
50static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = {
51 .atomic_disable = sun8i_mixer_layer_atomic_disable,
52 .atomic_update = sun8i_mixer_layer_atomic_update,
53};
54
55static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
56 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
57 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
58 .destroy = drm_plane_cleanup,
59 .disable_plane = drm_atomic_helper_disable_plane,
60 .reset = drm_atomic_helper_plane_reset,
61 .update_plane = drm_atomic_helper_update_plane,
62};
63
64static const uint32_t sun8i_mixer_layer_formats[] = {
65 DRM_FORMAT_RGB888,
66 DRM_FORMAT_ARGB8888,
67 DRM_FORMAT_XRGB8888,
68};
69
70static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
71 {
72 .type = DRM_PLANE_TYPE_PRIMARY,
73 .formats = sun8i_mixer_layer_formats,
74 .nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
75 },
76};
77
78static struct sun8i_layer *sun8i_layer_init_one(struct drm_device *drm,
79 struct sun8i_mixer *mixer,
80 const struct sun8i_plane_desc *plane)
81{
82 struct sun8i_layer *layer;
83 int ret;
84
85 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
86 if (!layer)
87 return ERR_PTR(-ENOMEM);
88
89 /* possible crtcs are set later */
90 ret = drm_universal_plane_init(drm, &layer->plane, 0,
91 &sun8i_mixer_layer_funcs,
92 plane->formats, plane->nformats,
93 NULL, plane->type, NULL);
94 if (ret) {
95 dev_err(drm->dev, "Couldn't initialize layer\n");
96 return ERR_PTR(ret);
97 }
98
99 drm_plane_helper_add(&layer->plane,
100 &sun8i_mixer_layer_helper_funcs);
101 layer->mixer = mixer;
102
103 return layer;
104}
105
106struct drm_plane **sun8i_layers_init(struct drm_device *drm,
107 struct sunxi_engine *engine)
108{
109 struct drm_plane **planes;
110 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
111 int i;
112
113 planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
114 sizeof(*planes), GFP_KERNEL);
115 if (!planes)
116 return ERR_PTR(-ENOMEM);
117
118 for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
119 const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
120 struct sun8i_layer *layer;
121
122 layer = sun8i_layer_init_one(drm, mixer, plane);
123 if (IS_ERR(layer)) {
124 dev_err(drm->dev, "Couldn't initialize %s plane\n",
125 i ? "overlay" : "primary");
126 return ERR_CAST(layer);
127 };
128
129 layer->id = i;
130 planes[i] = &layer->plane;
131 };
132
133 return planes;
134}
diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h b/drivers/gpu/drm/sun4i/sun8i_layer.h
deleted file mode 100644
index e5eccd27cff0..000000000000
--- a/drivers/gpu/drm/sun4i/sun8i_layer.h
+++ /dev/null
@@ -1,36 +0,0 @@
1/*
2 * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
3 *
4 * Based on sun4i_layer.h, which is:
5 * Copyright (C) 2015 Free Electrons
6 * Copyright (C) 2015 NextThing Co
7 *
8 * Maxime Ripard <maxime.ripard@free-electrons.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 */
15
16#ifndef _SUN8I_LAYER_H_
17#define _SUN8I_LAYER_H_
18
19struct sunxi_engine;
20
21struct sun8i_layer {
22 struct drm_plane plane;
23 struct sun4i_drv *drv;
24 struct sun8i_mixer *mixer;
25 int id;
26};
27
28static inline struct sun8i_layer *
29plane_to_sun8i_layer(struct drm_plane *plane)
30{
31 return container_of(plane, struct sun8i_layer, plane);
32}
33
34struct drm_plane **sun8i_layers_init(struct drm_device *drm,
35 struct sunxi_engine *engine);
36#endif /* _SUN8I_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index cb193c5f1686..29ceeb016d72 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -26,204 +26,288 @@
26 26
27#include "sun4i_drv.h" 27#include "sun4i_drv.h"
28#include "sun8i_mixer.h" 28#include "sun8i_mixer.h"
29#include "sun8i_layer.h" 29#include "sun8i_ui_layer.h"
30#include "sun8i_vi_layer.h"
30#include "sunxi_engine.h" 31#include "sunxi_engine.h"
31 32
32static void sun8i_mixer_commit(struct sunxi_engine *engine) 33static const struct de2_fmt_info de2_formats[] = {
33{ 34 {
34 DRM_DEBUG_DRIVER("Committing changes\n"); 35 .drm_fmt = DRM_FORMAT_ARGB8888,
35 36 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
36 regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF, 37 .rgb = true,
37 SUN8I_MIXER_GLOBAL_DBUFF_ENABLE); 38 .csc = SUN8I_CSC_MODE_OFF,
38} 39 },
39 40 {
40void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer, 41 .drm_fmt = DRM_FORMAT_ABGR8888,
41 int layer, bool enable) 42 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
42{ 43 .rgb = true,
43 u32 val; 44 .csc = SUN8I_CSC_MODE_OFF,
44 /* Currently the first UI channel is used */ 45 },
45 int chan = mixer->cfg->vi_num; 46 {
46 47 .drm_fmt = DRM_FORMAT_RGBA8888,
47 DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan); 48 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
48 49 .rgb = true,
49 if (enable) 50 .csc = SUN8I_CSC_MODE_OFF,
50 val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN; 51 },
51 else 52 {
52 val = 0; 53 .drm_fmt = DRM_FORMAT_BGRA8888,
53 54 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
54 regmap_update_bits(mixer->engine.regs, 55 .rgb = true,
55 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer), 56 .csc = SUN8I_CSC_MODE_OFF,
56 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); 57 },
57 58 {
58 /* Set the alpha configuration */ 59 .drm_fmt = DRM_FORMAT_XRGB8888,
59 regmap_update_bits(mixer->engine.regs, 60 .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
60 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer), 61 .rgb = true,
61 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK, 62 .csc = SUN8I_CSC_MODE_OFF,
62 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF); 63 },
63 regmap_update_bits(mixer->engine.regs, 64 {
64 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer), 65 .drm_fmt = DRM_FORMAT_XBGR8888,
65 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK, 66 .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
66 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF); 67 .rgb = true,
67} 68 .csc = SUN8I_CSC_MODE_OFF,
68 69 },
69static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane, 70 {
70 u32 format, u32 *mode) 71 .drm_fmt = DRM_FORMAT_RGBX8888,
71{ 72 .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
72 switch (format) { 73 .rgb = true,
73 case DRM_FORMAT_ARGB8888: 74 .csc = SUN8I_CSC_MODE_OFF,
74 *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888; 75 },
75 break; 76 {
76 77 .drm_fmt = DRM_FORMAT_BGRX8888,
77 case DRM_FORMAT_XRGB8888: 78 .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
78 *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888; 79 .rgb = true,
79 break; 80 .csc = SUN8I_CSC_MODE_OFF,
80 81 },
81 case DRM_FORMAT_RGB888: 82 {
82 *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888; 83 .drm_fmt = DRM_FORMAT_RGB888,
83 break; 84 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
84 85 .rgb = true,
85 default: 86 .csc = SUN8I_CSC_MODE_OFF,
86 return -EINVAL; 87 },
87 } 88 {
88 89 .drm_fmt = DRM_FORMAT_BGR888,
89 return 0; 90 .de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
90} 91 .rgb = true,
92 .csc = SUN8I_CSC_MODE_OFF,
93 },
94 {
95 .drm_fmt = DRM_FORMAT_RGB565,
96 .de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
97 .rgb = true,
98 .csc = SUN8I_CSC_MODE_OFF,
99 },
100 {
101 .drm_fmt = DRM_FORMAT_BGR565,
102 .de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
103 .rgb = true,
104 .csc = SUN8I_CSC_MODE_OFF,
105 },
106 {
107 .drm_fmt = DRM_FORMAT_ARGB4444,
108 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
109 .rgb = true,
110 .csc = SUN8I_CSC_MODE_OFF,
111 },
112 {
113 .drm_fmt = DRM_FORMAT_ABGR4444,
114 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
115 .rgb = true,
116 .csc = SUN8I_CSC_MODE_OFF,
117 },
118 {
119 .drm_fmt = DRM_FORMAT_RGBA4444,
120 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
121 .rgb = true,
122 .csc = SUN8I_CSC_MODE_OFF,
123 },
124 {
125 .drm_fmt = DRM_FORMAT_BGRA4444,
126 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
127 .rgb = true,
128 .csc = SUN8I_CSC_MODE_OFF,
129 },
130 {
131 .drm_fmt = DRM_FORMAT_ARGB1555,
132 .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
133 .rgb = true,
134 .csc = SUN8I_CSC_MODE_OFF,
135 },
136 {
137 .drm_fmt = DRM_FORMAT_ABGR1555,
138 .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
139 .rgb = true,
140 .csc = SUN8I_CSC_MODE_OFF,
141 },
142 {
143 .drm_fmt = DRM_FORMAT_RGBA5551,
144 .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
145 .rgb = true,
146 .csc = SUN8I_CSC_MODE_OFF,
147 },
148 {
149 .drm_fmt = DRM_FORMAT_BGRA5551,
150 .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
151 .rgb = true,
152 .csc = SUN8I_CSC_MODE_OFF,
153 },
154 {
155 .drm_fmt = DRM_FORMAT_UYVY,
156 .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
157 .rgb = false,
158 .csc = SUN8I_CSC_MODE_YUV2RGB,
159 },
160 {
161 .drm_fmt = DRM_FORMAT_VYUY,
162 .de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
163 .rgb = false,
164 .csc = SUN8I_CSC_MODE_YUV2RGB,
165 },
166 {
167 .drm_fmt = DRM_FORMAT_YUYV,
168 .de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
169 .rgb = false,
170 .csc = SUN8I_CSC_MODE_YUV2RGB,
171 },
172 {
173 .drm_fmt = DRM_FORMAT_YVYU,
174 .de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
175 .rgb = false,
176 .csc = SUN8I_CSC_MODE_YUV2RGB,
177 },
178 {
179 .drm_fmt = DRM_FORMAT_NV16,
180 .de2_fmt = SUN8I_MIXER_FBFMT_NV16,
181 .rgb = false,
182 .csc = SUN8I_CSC_MODE_YUV2RGB,
183 },
184 {
185 .drm_fmt = DRM_FORMAT_NV61,
186 .de2_fmt = SUN8I_MIXER_FBFMT_NV61,
187 .rgb = false,
188 .csc = SUN8I_CSC_MODE_YUV2RGB,
189 },
190 {
191 .drm_fmt = DRM_FORMAT_NV12,
192 .de2_fmt = SUN8I_MIXER_FBFMT_NV12,
193 .rgb = false,
194 .csc = SUN8I_CSC_MODE_YUV2RGB,
195 },
196 {
197 .drm_fmt = DRM_FORMAT_NV21,
198 .de2_fmt = SUN8I_MIXER_FBFMT_NV21,
199 .rgb = false,
200 .csc = SUN8I_CSC_MODE_YUV2RGB,
201 },
202 {
203 .drm_fmt = DRM_FORMAT_YUV444,
204 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
205 .rgb = true,
206 .csc = SUN8I_CSC_MODE_YUV2RGB,
207 },
208 {
209 .drm_fmt = DRM_FORMAT_YUV422,
210 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
211 .rgb = false,
212 .csc = SUN8I_CSC_MODE_YUV2RGB,
213 },
214 {
215 .drm_fmt = DRM_FORMAT_YUV420,
216 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
217 .rgb = false,
218 .csc = SUN8I_CSC_MODE_YUV2RGB,
219 },
220 {
221 .drm_fmt = DRM_FORMAT_YUV411,
222 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
223 .rgb = false,
224 .csc = SUN8I_CSC_MODE_YUV2RGB,
225 },
226 {
227 .drm_fmt = DRM_FORMAT_YVU444,
228 .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
229 .rgb = true,
230 .csc = SUN8I_CSC_MODE_YVU2RGB,
231 },
232 {
233 .drm_fmt = DRM_FORMAT_YVU422,
234 .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
235 .rgb = false,
236 .csc = SUN8I_CSC_MODE_YVU2RGB,
237 },
238 {
239 .drm_fmt = DRM_FORMAT_YVU420,
240 .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
241 .rgb = false,
242 .csc = SUN8I_CSC_MODE_YVU2RGB,
243 },
244 {
245 .drm_fmt = DRM_FORMAT_YVU411,
246 .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
247 .rgb = false,
248 .csc = SUN8I_CSC_MODE_YVU2RGB,
249 },
250};
91 251
92int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer, 252const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
93 int layer, struct drm_plane *plane)
94{ 253{
95 struct drm_plane_state *state = plane->state; 254 unsigned int i;
96 struct drm_framebuffer *fb = state->fb;
97 /* Currently the first UI channel is used */
98 int chan = mixer->cfg->vi_num;
99
100 DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
101
102 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
103 DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
104 state->crtc_w, state->crtc_h);
105 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
106 SUN8I_MIXER_SIZE(state->crtc_w,
107 state->crtc_h));
108 DRM_DEBUG_DRIVER("Updating blender size\n");
109 regmap_write(mixer->engine.regs,
110 SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
111 SUN8I_MIXER_SIZE(state->crtc_w,
112 state->crtc_h));
113 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
114 SUN8I_MIXER_SIZE(state->crtc_w,
115 state->crtc_h));
116 DRM_DEBUG_DRIVER("Updating channel size\n");
117 regmap_write(mixer->engine.regs,
118 SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
119 SUN8I_MIXER_SIZE(state->crtc_w,
120 state->crtc_h));
121 }
122 255
123 /* Set the line width */ 256 for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
124 DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); 257 if (de2_formats[i].drm_fmt == format)
125 regmap_write(mixer->engine.regs, 258 return &de2_formats[i];
126 SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
127 fb->pitches[0]);
128
129 /* Set height and width */
130 DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
131 state->crtc_w, state->crtc_h);
132 regmap_write(mixer->engine.regs,
133 SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
134 SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
135
136 /* Set base coordinates */
137 DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
138 state->crtc_x, state->crtc_y);
139 regmap_write(mixer->engine.regs,
140 SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
141 SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
142 259
143 return 0; 260 return NULL;
144} 261}
145 262
146int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer, 263static void sun8i_mixer_commit(struct sunxi_engine *engine)
147 int layer, struct drm_plane *plane)
148{ 264{
149 struct drm_plane_state *state = plane->state; 265 DRM_DEBUG_DRIVER("Committing changes\n");
150 struct drm_framebuffer *fb = state->fb;
151 bool interlaced = false;
152 u32 val;
153 /* Currently the first UI channel is used */
154 int chan = mixer->cfg->vi_num;
155 int ret;
156
157 if (plane->state->crtc)
158 interlaced = plane->state->crtc->state->adjusted_mode.flags
159 & DRM_MODE_FLAG_INTERLACE;
160
161 regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
162 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
163 interlaced ?
164 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
165
166 DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
167 interlaced ? "on" : "off");
168
169 ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
170 &val);
171 if (ret) {
172 DRM_DEBUG_DRIVER("Invalid format\n");
173 return ret;
174 }
175
176 regmap_update_bits(mixer->engine.regs,
177 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
178 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
179 266
180 return 0; 267 regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
268 SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
181} 269}
182 270
183int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer, 271static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
184 int layer, struct drm_plane *plane) 272 struct sunxi_engine *engine)
185{ 273{
186 struct drm_plane_state *state = plane->state; 274 struct drm_plane **planes;
187 struct drm_framebuffer *fb = state->fb; 275 struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
188 struct drm_gem_cma_object *gem; 276 int i;
189 dma_addr_t paddr; 277
190 /* Currently the first UI channel is used */ 278 planes = devm_kcalloc(drm->dev,
191 int chan = mixer->cfg->vi_num; 279 mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
192 int bpp; 280 sizeof(*planes), GFP_KERNEL);
193 281 if (!planes)
194 /* Get the physical address of the buffer in memory */ 282 return ERR_PTR(-ENOMEM);
195 gem = drm_fb_cma_get_gem_obj(fb, 0); 283
196 284 for (i = 0; i < mixer->cfg->vi_num; i++) {
197 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); 285 struct sun8i_vi_layer *layer;
198 286
199 /* Compute the start of the displayed memory */ 287 layer = sun8i_vi_layer_init_one(drm, mixer, i);
200 bpp = fb->format->cpp[0]; 288 if (IS_ERR(layer)) {
201 paddr = gem->paddr + fb->offsets[0]; 289 dev_err(drm->dev,
202 290 "Couldn't initialize overlay plane\n");
203 /* Fixup framebuffer address for src coordinates */ 291 return ERR_CAST(layer);
204 paddr += (state->src_x >> 16) * bpp; 292 };
205 paddr += (state->src_y >> 16) * fb->pitches[0]; 293
206 294 planes[i] = &layer->plane;
207 /* 295 };
208 * The hardware cannot correctly deal with negative crtc 296
209 * coordinates, the display is cropped to the requested size, 297 for (i = 0; i < mixer->cfg->ui_num; i++) {
210 * but the display content is not moved. 298 struct sun8i_ui_layer *layer;
211 * Manually move the display content by fixup the framebuffer 299
212 * address when crtc_x or crtc_y is negative, like what we 300 layer = sun8i_ui_layer_init_one(drm, mixer, i);
213 * have did for src_x and src_y. 301 if (IS_ERR(layer)) {
214 */ 302 dev_err(drm->dev, "Couldn't initialize %s plane\n",
215 if (state->crtc_x < 0) 303 i ? "overlay" : "primary");
216 paddr += -state->crtc_x * bpp; 304 return ERR_CAST(layer);
217 if (state->crtc_y < 0) 305 };
218 paddr += -state->crtc_y * fb->pitches[0]; 306
219 307 planes[mixer->cfg->vi_num + i] = &layer->plane;
220 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); 308 };
221 309
222 regmap_write(mixer->engine.regs, 310 return planes;
223 SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
224 lower_32_bits(paddr));
225
226 return 0;
227} 311}
228 312
229static const struct sunxi_engine_ops sun8i_engine_ops = { 313static const struct sunxi_engine_ops sun8i_engine_ops = {
@@ -247,6 +331,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
247 struct sun8i_mixer *mixer; 331 struct sun8i_mixer *mixer;
248 struct resource *res; 332 struct resource *res;
249 void __iomem *regs; 333 void __iomem *regs;
334 int plane_cnt;
250 int i, ret; 335 int i, ret;
251 336
252 /* 337 /*
@@ -325,27 +410,26 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
325 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL, 410 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
326 SUN8I_MIXER_GLOBAL_CTL_RT_EN); 411 SUN8I_MIXER_GLOBAL_CTL_RT_EN);
327 412
328 /* Initialize blender */ 413 /* Set background color to black */
329 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
330 SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
331 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
332 SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
333 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR, 414 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
334 SUN8I_MIXER_BLEND_BKCOLOR_DEF); 415 SUN8I_MIXER_BLEND_COLOR_BLACK);
335 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0), 416
336 SUN8I_MIXER_BLEND_MODE_DEF); 417 /*
337 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL, 418 * Set fill color of bottom plane to black. Generally not needed
338 SUN8I_MIXER_BLEND_CK_CTL_DEF); 419 * except when VI plane is at bottom (zpos = 0) and enabled.
339 420 */
340 regmap_write(mixer->engine.regs, 421 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
341 SUN8I_MIXER_BLEND_ATTR_FCOLOR(0), 422 SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
342 SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF); 423 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
343 424 SUN8I_MIXER_BLEND_COLOR_BLACK);
344 /* Select the first UI channel */ 425
345 DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n", 426 /* Fixed zpos for now */
346 mixer->cfg->vi_num); 427 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE, 0x43210);
347 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE, 428
348 mixer->cfg->vi_num); 429 plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
430 for (i = 0; i < plane_cnt; i++)
431 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i),
432 SUN8I_MIXER_BLEND_MODE_DEF);
349 433
350 return 0; 434 return 0;
351 435
@@ -388,6 +472,8 @@ static int sun8i_mixer_remove(struct platform_device *pdev)
388static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = { 472static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
389 .vi_num = 2, 473 .vi_num = 2,
390 .ui_num = 1, 474 .ui_num = 1,
475 .scaler_mask = 0x3,
476 .ccsc = 0,
391}; 477};
392 478
393static const struct of_device_id sun8i_mixer_of_table[] = { 479static const struct of_device_id sun8i_mixer_of_table[] = {
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 4785ac090b8c..bc58040a88f9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -14,10 +14,9 @@
14#include <linux/regmap.h> 14#include <linux/regmap.h>
15#include <linux/reset.h> 15#include <linux/reset.h>
16 16
17#include "sun8i_csc.h"
17#include "sunxi_engine.h" 18#include "sunxi_engine.h"
18 19
19#define SUN8I_MIXER_MAX_CHAN_COUNT 4
20
21#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1)) 20#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
22#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x)) 21#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x))
23 22
@@ -26,14 +25,14 @@
26#define SUN8I_MIXER_GLOBAL_DBUFF 0x8 25#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
27#define SUN8I_MIXER_GLOBAL_SIZE 0xc 26#define SUN8I_MIXER_GLOBAL_SIZE 0xc
28 27
29#define SUN8I_MIXER_GLOBAL_CTL_RT_EN 0x1 28#define SUN8I_MIXER_GLOBAL_CTL_RT_EN BIT(0)
30 29
31#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE 0x1 30#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0)
32 31
33#define SUN8I_MIXER_BLEND_FCOLOR_CTL 0x1000 32#define SUN8I_MIXER_BLEND_PIPE_CTL 0x1000
34#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0) 33#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0)
35#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4) 34#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4)
36#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x) (0x1004 + 0x10 * (x) + 0x8) 35#define SUN8I_MIXER_BLEND_ATTR_COORD(x) (0x1004 + 0x10 * (x) + 0x8)
37#define SUN8I_MIXER_BLEND_ROUTE 0x1080 36#define SUN8I_MIXER_BLEND_ROUTE 0x1080
38#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084 37#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084
39#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088 38#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088
@@ -45,57 +44,56 @@
45#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x)) 44#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x))
46#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc 45#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc
47 46
47#define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe)
48#define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe)
49/* colors are always in AARRGGBB format */
50#define SUN8I_MIXER_BLEND_COLOR_BLACK 0xff000000
48/* The following numbers are some still unknown magic numbers */ 51/* The following numbers are some still unknown magic numbers */
49#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF 0xff000000
50#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF 0x00000101
51#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF 0x0
52#define SUN8I_MIXER_BLEND_BKCOLOR_DEF 0xff000000
53#define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301 52#define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301
54#define SUN8I_MIXER_BLEND_CK_CTL_DEF 0x0
55 53
56#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1) 54#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
57 55
58/* 56#define SUN8I_MIXER_FBFMT_ARGB8888 0
59 * VI channels are not used now, but the support of them may be introduced in 57#define SUN8I_MIXER_FBFMT_ABGR8888 1
60 * the future. 58#define SUN8I_MIXER_FBFMT_RGBA8888 2
61 */ 59#define SUN8I_MIXER_FBFMT_BGRA8888 3
62 60#define SUN8I_MIXER_FBFMT_XRGB8888 4
63#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \ 61#define SUN8I_MIXER_FBFMT_XBGR8888 5
64 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0) 62#define SUN8I_MIXER_FBFMT_RGBX8888 6
65#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \ 63#define SUN8I_MIXER_FBFMT_BGRX8888 7
66 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4) 64#define SUN8I_MIXER_FBFMT_RGB888 8
67#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \ 65#define SUN8I_MIXER_FBFMT_BGR888 9
68 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8) 66#define SUN8I_MIXER_FBFMT_RGB565 10
69#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \ 67#define SUN8I_MIXER_FBFMT_BGR565 11
70 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc) 68#define SUN8I_MIXER_FBFMT_ARGB4444 12
71#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \ 69#define SUN8I_MIXER_FBFMT_ABGR4444 13
72 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10) 70#define SUN8I_MIXER_FBFMT_RGBA4444 14
73#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \ 71#define SUN8I_MIXER_FBFMT_BGRA4444 15
74 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14) 72#define SUN8I_MIXER_FBFMT_ARGB1555 16
75#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \ 73#define SUN8I_MIXER_FBFMT_ABGR1555 17
76 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18) 74#define SUN8I_MIXER_FBFMT_RGBA5551 18
77#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80) 75#define SUN8I_MIXER_FBFMT_BGRA5551 19
78#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84) 76
79#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88) 77#define SUN8I_MIXER_FBFMT_YUYV 0
80 78#define SUN8I_MIXER_FBFMT_UYVY 1
81#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0) 79#define SUN8I_MIXER_FBFMT_YVYU 2
82#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1) 80#define SUN8I_MIXER_FBFMT_VYUY 3
83#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(11, 8) 81#define SUN8I_MIXER_FBFMT_NV16 4
84#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24) 82#define SUN8I_MIXER_FBFMT_NV61 5
85#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF (1 << 1) 83#define SUN8I_MIXER_FBFMT_YUV422 6
86#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888 (0 << 8) 84/* format 7 doesn't exist */
87#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888 (4 << 8) 85#define SUN8I_MIXER_FBFMT_NV12 8
88#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888 (8 << 8) 86#define SUN8I_MIXER_FBFMT_NV21 9
89#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF (0xff << 24) 87#define SUN8I_MIXER_FBFMT_YUV420 10
88/* format 11 doesn't exist */
89/* format 12 is semi-planar YUV411 UVUV */
90/* format 13 is semi-planar YUV411 VUVU */
91#define SUN8I_MIXER_FBFMT_YUV411 14
90 92
91/* 93/*
92 * These sub-engines are still unknown now, the EN registers are here only to 94 * These sub-engines are still unknown now, the EN registers are here only to
93 * be used to disable these sub-engines. 95 * be used to disable these sub-engines.
94 */ 96 */
95#define SUN8I_MIXER_VSU_EN 0x20000
96#define SUN8I_MIXER_GSU1_EN 0x30000
97#define SUN8I_MIXER_GSU2_EN 0x40000
98#define SUN8I_MIXER_GSU3_EN 0x50000
99#define SUN8I_MIXER_FCE_EN 0xa0000 97#define SUN8I_MIXER_FCE_EN 0xa0000
100#define SUN8I_MIXER_BWS_EN 0xa2000 98#define SUN8I_MIXER_BWS_EN 0xa2000
101#define SUN8I_MIXER_LTI_EN 0xa4000 99#define SUN8I_MIXER_LTI_EN 0xa4000
@@ -104,9 +102,31 @@
104#define SUN8I_MIXER_FCC_EN 0xaa000 102#define SUN8I_MIXER_FCC_EN 0xaa000
105#define SUN8I_MIXER_DCSC_EN 0xb0000 103#define SUN8I_MIXER_DCSC_EN 0xb0000
106 104
105struct de2_fmt_info {
106 u32 drm_fmt;
107 u32 de2_fmt;
108 bool rgb;
109 enum sun8i_csc_mode csc;
110};
111
112/**
113 * struct sun8i_mixer_cfg - mixer HW configuration
114 * @vi_num: number of VI channels
115 * @ui_num: number of UI channels
116 * @scaler_mask: bitmask which tells which channel supports scaling
117 * First, scaler supports for VI channels is defined and after that, scaler
118 * support for UI channels. For example, if mixer has 2 VI channels without
119 * scaler and 2 UI channels with scaler, bitmask would be 0xC.
120 * @ccsc: select set of CCSC base addresses
121 * Set value to 0 if this is first mixer or second mixer with VEP support.
122 * Set value to 1 if this is second mixer without VEP support. Other values
123 * are invalid.
124 */
107struct sun8i_mixer_cfg { 125struct sun8i_mixer_cfg {
108 int vi_num; 126 int vi_num;
109 int ui_num; 127 int ui_num;
128 int scaler_mask;
129 int ccsc;
110}; 130};
111 131
112struct sun8i_mixer { 132struct sun8i_mixer {
@@ -126,12 +146,5 @@ engine_to_sun8i_mixer(struct sunxi_engine *engine)
126 return container_of(engine, struct sun8i_mixer, engine); 146 return container_of(engine, struct sun8i_mixer, engine);
127} 147}
128 148
129void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer, 149const struct de2_fmt_info *sun8i_mixer_format_info(u32 format);
130 int layer, bool enable);
131int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
132 int layer, struct drm_plane *plane);
133int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
134 int layer, struct drm_plane *plane);
135int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
136 int layer, struct drm_plane *plane);
137#endif /* _SUN8I_MIXER_H_ */ 150#endif /* _SUN8I_MIXER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
new file mode 100644
index 000000000000..28d7c48d50fe
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -0,0 +1,349 @@
1/*
2 * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
3 *
4 * Based on sun4i_layer.h, which is:
5 * Copyright (C) 2015 Free Electrons
6 * Copyright (C) 2015 NextThing Co
7 *
8 * Maxime Ripard <maxime.ripard@free-electrons.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 */
15
16#include <drm/drm_atomic.h>
17#include <drm/drm_atomic_helper.h>
18#include <drm/drm_crtc.h>
19#include <drm/drm_crtc_helper.h>
20#include <drm/drm_fb_cma_helper.h>
21#include <drm/drm_gem_cma_helper.h>
22#include <drm/drm_plane_helper.h>
23#include <drm/drmP.h>
24
25#include "sun8i_ui_layer.h"
26#include "sun8i_mixer.h"
27#include "sun8i_ui_scaler.h"
28
29static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
30 int overlay, bool enable)
31{
32 u32 val;
33
34 DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
35 enable ? "En" : "Dis", channel, overlay);
36
37 if (enable)
38 val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
39 else
40 val = 0;
41
42 regmap_update_bits(mixer->engine.regs,
43 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
44 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
45
46 if (enable)
47 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel);
48 else
49 val = 0;
50
51 regmap_update_bits(mixer->engine.regs,
52 SUN8I_MIXER_BLEND_PIPE_CTL,
53 SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val);
54}
55
56static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
57 int overlay, struct drm_plane *plane)
58{
59 struct drm_plane_state *state = plane->state;
60 u32 src_w, src_h, dst_w, dst_h;
61 u32 outsize, insize;
62 u32 hphase, vphase;
63
64 DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
65 channel, overlay);
66
67 src_w = drm_rect_width(&state->src) >> 16;
68 src_h = drm_rect_height(&state->src) >> 16;
69 dst_w = drm_rect_width(&state->dst);
70 dst_h = drm_rect_height(&state->dst);
71
72 hphase = state->src.x1 & 0xffff;
73 vphase = state->src.y1 & 0xffff;
74
75 insize = SUN8I_MIXER_SIZE(src_w, src_h);
76 outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
77
78 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
79 bool interlaced = false;
80 u32 val;
81
82 DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
83 dst_w, dst_h);
84 regmap_write(mixer->engine.regs,
85 SUN8I_MIXER_GLOBAL_SIZE,
86 outsize);
87 regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
88 outsize);
89
90 if (state->crtc)
91 interlaced = state->crtc->state->adjusted_mode.flags
92 & DRM_MODE_FLAG_INTERLACE;
93
94 if (interlaced)
95 val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
96 else
97 val = 0;
98
99 regmap_update_bits(mixer->engine.regs,
100 SUN8I_MIXER_BLEND_OUTCTL,
101 SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
102 val);
103
104 DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
105 interlaced ? "on" : "off");
106 }
107
108 /* Set height and width */
109 DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
110 state->src.x1 >> 16, state->src.y1 >> 16);
111 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
112 regmap_write(mixer->engine.regs,
113 SUN8I_MIXER_CHAN_UI_LAYER_SIZE(channel, overlay),
114 insize);
115 regmap_write(mixer->engine.regs,
116 SUN8I_MIXER_CHAN_UI_OVL_SIZE(channel),
117 insize);
118
119 if (insize != outsize || hphase || vphase) {
120 u32 hscale, vscale;
121
122 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
123
124 hscale = state->src_w / state->crtc_w;
125 vscale = state->src_h / state->crtc_h;
126
127 sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
128 dst_h, hscale, vscale, hphase, vphase);
129 sun8i_ui_scaler_enable(mixer, channel, true);
130 } else {
131 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
132 sun8i_ui_scaler_enable(mixer, channel, false);
133 }
134
135 /* Set base coordinates */
136 DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
137 state->dst.x1, state->dst.y1);
138 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
139 regmap_write(mixer->engine.regs,
140 SUN8I_MIXER_BLEND_ATTR_COORD(channel),
141 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
142 regmap_write(mixer->engine.regs,
143 SUN8I_MIXER_BLEND_ATTR_INSIZE(channel),
144 outsize);
145
146 return 0;
147}
148
149static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
150 int overlay, struct drm_plane *plane)
151{
152 struct drm_plane_state *state = plane->state;
153 const struct de2_fmt_info *fmt_info;
154 u32 val;
155
156 fmt_info = sun8i_mixer_format_info(state->fb->format->format);
157 if (!fmt_info || !fmt_info->rgb) {
158 DRM_DEBUG_DRIVER("Invalid format\n");
159 return -EINVAL;
160 }
161
162 val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
163 regmap_update_bits(mixer->engine.regs,
164 SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
165 SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
166
167 return 0;
168}
169
170static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
171 int overlay, struct drm_plane *plane)
172{
173 struct drm_plane_state *state = plane->state;
174 struct drm_framebuffer *fb = state->fb;
175 struct drm_gem_cma_object *gem;
176 dma_addr_t paddr;
177 int bpp;
178
179 /* Get the physical address of the buffer in memory */
180 gem = drm_fb_cma_get_gem_obj(fb, 0);
181
182 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
183
184 /* Compute the start of the displayed memory */
185 bpp = fb->format->cpp[0];
186 paddr = gem->paddr + fb->offsets[0];
187
188 /* Fixup framebuffer address for src coordinates */
189 paddr += (state->src.x1 >> 16) * bpp;
190 paddr += (state->src.y1 >> 16) * fb->pitches[0];
191
192 /* Set the line width */
193 DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
194 regmap_write(mixer->engine.regs,
195 SUN8I_MIXER_CHAN_UI_LAYER_PITCH(channel, overlay),
196 fb->pitches[0]);
197
198 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
199
200 regmap_write(mixer->engine.regs,
201 SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(channel, overlay),
202 lower_32_bits(paddr));
203
204 return 0;
205}
206
207static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
208 struct drm_plane_state *state)
209{
210 struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
211 struct drm_crtc *crtc = state->crtc;
212 struct drm_crtc_state *crtc_state;
213 int min_scale, max_scale;
214 struct drm_rect clip;
215
216 if (!crtc)
217 return 0;
218
219 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
220 if (WARN_ON(!crtc_state))
221 return -EINVAL;
222
223 clip.x1 = 0;
224 clip.y1 = 0;
225 clip.x2 = crtc_state->adjusted_mode.hdisplay;
226 clip.y2 = crtc_state->adjusted_mode.vdisplay;
227
228 min_scale = DRM_PLANE_HELPER_NO_SCALING;
229 max_scale = DRM_PLANE_HELPER_NO_SCALING;
230
231 if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
232 min_scale = SUN8I_UI_SCALER_SCALE_MIN;
233 max_scale = SUN8I_UI_SCALER_SCALE_MAX;
234 }
235
236 return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
237 min_scale, max_scale,
238 true, true);
239}
240
241static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane,
242 struct drm_plane_state *old_state)
243{
244 struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
245 struct sun8i_mixer *mixer = layer->mixer;
246
247 sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false);
248}
249
250static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
251 struct drm_plane_state *old_state)
252{
253 struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
254 struct sun8i_mixer *mixer = layer->mixer;
255
256 if (!plane->state->visible) {
257 sun8i_ui_layer_enable(mixer, layer->channel,
258 layer->overlay, false);
259 return;
260 }
261
262 sun8i_ui_layer_update_coord(mixer, layer->channel,
263 layer->overlay, plane);
264 sun8i_ui_layer_update_formats(mixer, layer->channel,
265 layer->overlay, plane);
266 sun8i_ui_layer_update_buffer(mixer, layer->channel,
267 layer->overlay, plane);
268 sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, true);
269}
270
271static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
272 .atomic_check = sun8i_ui_layer_atomic_check,
273 .atomic_disable = sun8i_ui_layer_atomic_disable,
274 .atomic_update = sun8i_ui_layer_atomic_update,
275};
276
277static const struct drm_plane_funcs sun8i_ui_layer_funcs = {
278 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
279 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
280 .destroy = drm_plane_cleanup,
281 .disable_plane = drm_atomic_helper_disable_plane,
282 .reset = drm_atomic_helper_plane_reset,
283 .update_plane = drm_atomic_helper_update_plane,
284};
285
286static const u32 sun8i_ui_layer_formats[] = {
287 DRM_FORMAT_ABGR1555,
288 DRM_FORMAT_ABGR4444,
289 DRM_FORMAT_ABGR8888,
290 DRM_FORMAT_ARGB1555,
291 DRM_FORMAT_ARGB4444,
292 DRM_FORMAT_ARGB8888,
293 DRM_FORMAT_BGR565,
294 DRM_FORMAT_BGR888,
295 DRM_FORMAT_BGRA5551,
296 DRM_FORMAT_BGRA4444,
297 DRM_FORMAT_BGRA8888,
298 DRM_FORMAT_BGRX8888,
299 DRM_FORMAT_RGB565,
300 DRM_FORMAT_RGB888,
301 DRM_FORMAT_RGBA4444,
302 DRM_FORMAT_RGBA5551,
303 DRM_FORMAT_RGBA8888,
304 DRM_FORMAT_RGBX8888,
305 DRM_FORMAT_XBGR8888,
306 DRM_FORMAT_XRGB8888,
307};
308
309struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
310 struct sun8i_mixer *mixer,
311 int index)
312{
313 enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
314 int channel = mixer->cfg->vi_num + index;
315 struct sun8i_ui_layer *layer;
316 int ret;
317
318 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
319 if (!layer)
320 return ERR_PTR(-ENOMEM);
321
322 if (index == 0)
323 type = DRM_PLANE_TYPE_PRIMARY;
324
325 /* possible crtcs are set later */
326 ret = drm_universal_plane_init(drm, &layer->plane, 0,
327 &sun8i_ui_layer_funcs,
328 sun8i_ui_layer_formats,
329 ARRAY_SIZE(sun8i_ui_layer_formats),
330 NULL, type, NULL);
331 if (ret) {
332 dev_err(drm->dev, "Couldn't initialize layer\n");
333 return ERR_PTR(ret);
334 }
335
336 /* fixed zpos for now */
337 ret = drm_plane_create_zpos_immutable_property(&layer->plane, channel);
338 if (ret) {
339 dev_err(drm->dev, "Couldn't add zpos property\n");
340 return ERR_PTR(ret);
341 }
342
343 drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
344 layer->mixer = mixer;
345 layer->channel = channel;
346 layer->overlay = 0;
347
348 return layer;
349}
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
new file mode 100644
index 000000000000..123b15ea9918
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
3 *
4 * Based on sun4i_layer.h, which is:
5 * Copyright (C) 2015 Free Electrons
6 * Copyright (C) 2015 NextThing Co
7 *
8 * Maxime Ripard <maxime.ripard@free-electrons.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 */
15
16#ifndef _SUN8I_UI_LAYER_H_
17#define _SUN8I_UI_LAYER_H_
18
19#include <drm/drm_plane.h>
20
21#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
22 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
23#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
24 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
25#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
26 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
27#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
28 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
29#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
30 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
31#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
32 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
33#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
34 (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
35#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80)
36#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84)
37#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88)
38
39#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
40#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
41#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8)
42#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET 8
43#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
44
45struct sun8i_mixer;
46
47struct sun8i_ui_layer {
48 struct drm_plane plane;
49 struct sun8i_mixer *mixer;
50 int channel;
51 int overlay;
52};
53
54static inline struct sun8i_ui_layer *
55plane_to_sun8i_ui_layer(struct drm_plane *plane)
56{
57 return container_of(plane, struct sun8i_ui_layer, plane);
58}
59
60struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
61 struct sun8i_mixer *mixer,
62 int index);
63#endif /* _SUN8I_UI_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
new file mode 100644
index 000000000000..6bb2aa164c8e
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * Coefficients are taken from BSP driver, which is:
5 * Copyright (C) 2014-2015 Allwinner
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include "sun8i_ui_scaler.h"
13
14static const u32 lan2coefftab16[240] = {
15 0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb,
16 0xff0f37fb, 0xfe1433fb, 0xfd192ffb, 0xfd1f29fb,
17 0xfc2424fc, 0xfb291ffd, 0xfb2f19fd, 0xfb3314fe,
18 0xfb370fff, 0xfb3b0a00, 0xfc3e0600, 0xfe3f0300,
19
20 0xff053804, 0xff083801, 0xff0a3700, 0xff0e34ff,
21 0xff1232fd, 0xfe162ffd, 0xfd1b2cfc, 0xfd1f28fc,
22 0xfd2323fd, 0xfc281ffd, 0xfc2c1bfd, 0xfd2f16fe,
23 0xfd3212ff, 0xff340eff, 0x00360a00, 0x02370700,
24
25 0xff083207, 0xff0a3205, 0xff0d3103, 0xfe113001,
26 0xfe142e00, 0xfe182bff, 0xfe1b29fe, 0xfe1f25fe,
27 0xfe2222fe, 0xfe251ffe, 0xfe291bfe, 0xff2b18fe,
28 0x002e14fe, 0x013010ff, 0x03310dff, 0x05310a00,
29
30 0xff0a2e09, 0xff0c2e07, 0xff0f2d05, 0xff122c03,
31 0xfe152b02, 0xfe182901, 0xfe1b2700, 0xff1e24ff,
32 0xff2121ff, 0xff241eff, 0x00261bff, 0x012818ff,
33 0x022a15ff, 0x032c12ff, 0x052d0fff, 0x072d0c00,
34
35 0xff0c2a0b, 0xff0e2a09, 0xff102a07, 0xff132905,
36 0xff162803, 0xff182702, 0xff1b2501, 0xff1e2300,
37 0x00202000, 0x01221d00, 0x01251bff, 0x032618ff,
38 0x042815ff, 0x052913ff, 0x072a10ff, 0x092a0d00,
39
40 0xff0d280c, 0xff0f280a, 0xff112808, 0xff142706,
41 0xff162605, 0xff192503, 0x001b2302, 0x001d2201,
42 0x011f1f01, 0x01221d00, 0x02231b00, 0x04241800,
43 0x052616ff, 0x072713ff, 0x08271100, 0x0a280e00,
44
45 0xff0e260d, 0xff10260b, 0xff122609, 0xff142508,
46 0x00152506, 0x00182305, 0x001b2203, 0x011d2002,
47 0x011f1f01, 0x02201d01, 0x03221b00, 0x04231801,
48 0x06241600, 0x08251300, 0x09261100, 0x0b260f00,
49
50 0xff0e250e, 0xff10250c, 0x0011250a, 0x00142408,
51 0x00162307, 0x00182206, 0x011a2104, 0x011c2003,
52 0x021e1e02, 0x03201c01, 0x04211a01, 0x05221801,
53 0x07231600, 0x08241400, 0x0a241200, 0x0c241000,
54
55 0x000e240e, 0x0010240c, 0x0013230a, 0x00142309,
56 0x00162208, 0x01182106, 0x011a2005, 0x021b1f04,
57 0x031d1d03, 0x041e1c02, 0x05201a01, 0x06211801,
58 0x07221601, 0x09231400, 0x0a231300, 0x0c231100,
59
60 0x000f220f, 0x0011220d, 0x0013220b, 0x0015210a,
61 0x01162108, 0x01182007, 0x02191f06, 0x031a1e05,
62 0x041c1c04, 0x051d1b03, 0x061f1902, 0x07201801,
63 0x08211601, 0x0a211500, 0x0b221300, 0x0d221100,
64
65 0x0010210f, 0x0011210e, 0x0013210c, 0x0114200b,
66 0x01161f0a, 0x02171f08, 0x03181e07, 0x031a1d06,
67 0x041c1c04, 0x051d1a04, 0x071d1903, 0x081e1802,
68 0x091f1602, 0x0b1f1501, 0x0c211300, 0x0e201200,
69
70 0x00102010, 0x0012200e, 0x0013200d, 0x01151f0b,
71 0x01161f0a, 0x02171e09, 0x03191d07, 0x041a1c06,
72 0x051b1b05, 0x061c1a04, 0x071d1903, 0x081e1703,
73 0x0a1f1601, 0x0b1f1501, 0x0d201300, 0x0e201200,
74
75 0x00102010, 0x00121f0f, 0x00141f0d, 0x01141f0c,
76 0x02161e0a, 0x03171d09, 0x03181d08, 0x041a1c06,
77 0x051b1b05, 0x061c1a04, 0x081c1903, 0x091d1703,
78 0x0a1e1602, 0x0c1e1501, 0x0d1f1400, 0x0e1f1201,
79
80 0x00111e11, 0x00131e0f, 0x01131e0e, 0x02151d0c,
81 0x02161d0b, 0x03171c0a, 0x04181b09, 0x05191b07,
82 0x061a1a06, 0x071b1905, 0x091b1804, 0x0a1c1703,
83 0x0b1d1602, 0x0c1d1502, 0x0e1d1401, 0x0f1e1300,
84
85 0x00111e11, 0x00131d10, 0x01141d0e, 0x02151c0d,
86 0x03161c0b, 0x04171b0a, 0x05171b09, 0x06181a08,
87 0x07191907, 0x081a1806, 0x091a1805, 0x0a1b1704,
88 0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
89};
90
91static int sun8i_ui_scaler_coef_index(unsigned int step)
92{
93 unsigned int scale, int_part, float_part;
94
95 scale = step >> (SUN8I_UI_SCALER_SCALE_FRAC - 3);
96 int_part = scale >> 3;
97 float_part = scale & 0x7;
98
99 switch (int_part) {
100 case 0:
101 return 0;
102 case 1:
103 return float_part;
104 case 2:
105 return 8 + (float_part >> 1);
106 case 3:
107 return 12;
108 case 4:
109 return 13;
110 default:
111 return 14;
112 }
113}
114
115void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
116{
117 int vi_cnt = mixer->cfg->vi_num;
118 u32 val;
119
120 if (WARN_ON(layer < vi_cnt))
121 return;
122
123 if (enable)
124 val = SUN8I_SCALER_GSU_CTRL_EN |
125 SUN8I_SCALER_GSU_CTRL_COEFF_RDY;
126 else
127 val = 0;
128
129 regmap_write(mixer->engine.regs,
130 SUN8I_SCALER_GSU_CTRL(vi_cnt, layer - vi_cnt), val);
131}
132
133void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
134 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
135 u32 hscale, u32 vscale, u32 hphase, u32 vphase)
136{
137 int vi_cnt = mixer->cfg->vi_num;
138 u32 insize, outsize;
139 int i, offset;
140
141 if (WARN_ON(layer < vi_cnt))
142 return;
143
144 hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
145 vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
146 hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
147 vscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
148
149 insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
150 outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
151
152 layer -= vi_cnt;
153
154 regmap_write(mixer->engine.regs,
155 SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, layer), outsize);
156 regmap_write(mixer->engine.regs,
157 SUN8I_SCALER_GSU_INSIZE(vi_cnt, layer), insize);
158 regmap_write(mixer->engine.regs,
159 SUN8I_SCALER_GSU_HSTEP(vi_cnt, layer), hscale);
160 regmap_write(mixer->engine.regs,
161 SUN8I_SCALER_GSU_VSTEP(vi_cnt, layer), vscale);
162 regmap_write(mixer->engine.regs,
163 SUN8I_SCALER_GSU_HPHASE(vi_cnt, layer), hphase);
164 regmap_write(mixer->engine.regs,
165 SUN8I_SCALER_GSU_VPHASE(vi_cnt, layer), vphase);
166 offset = sun8i_ui_scaler_coef_index(hscale) *
167 SUN8I_UI_SCALER_COEFF_COUNT;
168 for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
169 regmap_write(mixer->engine.regs,
170 SUN8I_SCALER_GSU_HCOEFF(vi_cnt, layer, i),
171 lan2coefftab16[offset + i]);
172}
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
new file mode 100644
index 000000000000..86295be8be78
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * This file is licensed under the terms of the GNU General Public
5 * License version 2. This program is licensed "as is" without any
6 * warranty of any kind, whether express or implied.
7 */
8
9#ifndef _SUN8I_UI_SCALER_H_
10#define _SUN8I_UI_SCALER_H_
11
12#include "sun8i_mixer.h"
13
14/* this two macros assumes 16 fractional bits which is standard in DRM */
15#define SUN8I_UI_SCALER_SCALE_MIN 1
16#define SUN8I_UI_SCALER_SCALE_MAX ((1UL << 20) - 1)
17
18#define SUN8I_UI_SCALER_SCALE_FRAC 20
19#define SUN8I_UI_SCALER_PHASE_FRAC 20
20#define SUN8I_UI_SCALER_COEFF_COUNT 16
21#define SUN8I_UI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
22
23#define SUN8I_SCALER_GSU_CTRL(vi_cnt, ui_idx) \
24 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x0)
25#define SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, ui_idx) \
26 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x40)
27#define SUN8I_SCALER_GSU_INSIZE(vi_cnt, ui_idx) \
28 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x80)
29#define SUN8I_SCALER_GSU_HSTEP(vi_cnt, ui_idx) \
30 (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x88)
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
41#define SUN8I_SCALER_GSU_CTRL_EN BIT(0)
42#define SUN8I_SCALER_GSU_CTRL_COEFF_RDY BIT(4)
43
44void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
45void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
46 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
47 u32 hscale, u32 vscale, u32 hphase, u32 vphase);
48
49#endif
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
new file mode 100644
index 000000000000..40c3b303068a
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -0,0 +1,390 @@
1/*
2 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 */
9
10#include <drm/drm_atomic.h>
11#include <drm/drm_atomic_helper.h>
12#include <drm/drm_crtc.h>
13#include <drm/drm_crtc_helper.h>
14#include <drm/drm_fb_cma_helper.h>
15#include <drm/drm_gem_cma_helper.h>
16#include <drm/drm_plane_helper.h>
17#include <drm/drmP.h>
18
19#include "sun8i_vi_layer.h"
20#include "sun8i_mixer.h"
21#include "sun8i_vi_scaler.h"
22
23static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
24 int overlay, bool enable)
25{
26 u32 val;
27
28 DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
29 enable ? "En" : "Dis", channel, overlay);
30
31 if (enable)
32 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
33 else
34 val = 0;
35
36 regmap_update_bits(mixer->engine.regs,
37 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
38 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
39
40 if (enable)
41 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel);
42 else
43 val = 0;
44
45 regmap_update_bits(mixer->engine.regs,
46 SUN8I_MIXER_BLEND_PIPE_CTL,
47 SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val);
48}
49
50static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
51 int overlay, struct drm_plane *plane)
52{
53 struct drm_plane_state *state = plane->state;
54 const struct drm_format_info *format = state->fb->format;
55 u32 src_w, src_h, dst_w, dst_h;
56 u32 outsize, insize;
57 u32 hphase, vphase;
58 bool subsampled;
59
60 DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
61 channel, overlay);
62
63 src_w = drm_rect_width(&state->src) >> 16;
64 src_h = drm_rect_height(&state->src) >> 16;
65 dst_w = drm_rect_width(&state->dst);
66 dst_h = drm_rect_height(&state->dst);
67
68 hphase = state->src.x1 & 0xffff;
69 vphase = state->src.y1 & 0xffff;
70
71 /* make coordinates dividable by subsampling factor */
72 if (format->hsub > 1) {
73 int mask, remainder;
74
75 mask = format->hsub - 1;
76 remainder = (state->src.x1 >> 16) & mask;
77 src_w = (src_w + remainder) & ~mask;
78 hphase += remainder << 16;
79 }
80
81 if (format->vsub > 1) {
82 int mask, remainder;
83
84 mask = format->vsub - 1;
85 remainder = (state->src.y1 >> 16) & mask;
86 src_h = (src_h + remainder) & ~mask;
87 vphase += remainder << 16;
88 }
89
90 insize = SUN8I_MIXER_SIZE(src_w, src_h);
91 outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
92
93 /* Set height and width */
94 DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
95 (state->src.x1 >> 16) & ~(format->hsub - 1),
96 (state->src.y1 >> 16) & ~(format->vsub - 1));
97 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
98 regmap_write(mixer->engine.regs,
99 SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay),
100 insize);
101 regmap_write(mixer->engine.regs,
102 SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel),
103 insize);
104
105 /*
106 * Scaler must be enabled for subsampled formats, so it scales
107 * chroma to same size as luma.
108 */
109 subsampled = format->hsub > 1 || format->vsub > 1;
110
111 if (insize != outsize || subsampled || hphase || vphase) {
112 u32 hscale, vscale;
113
114 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
115
116 hscale = state->src_w / state->crtc_w;
117 vscale = state->src_h / state->crtc_h;
118
119 sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
120 dst_h, hscale, vscale, hphase, vphase,
121 format);
122 sun8i_vi_scaler_enable(mixer, channel, true);
123 } else {
124 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
125 sun8i_vi_scaler_enable(mixer, channel, false);
126 }
127
128 /* Set base coordinates */
129 DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
130 state->dst.x1, state->dst.y1);
131 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
132 regmap_write(mixer->engine.regs,
133 SUN8I_MIXER_BLEND_ATTR_COORD(channel),
134 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
135 regmap_write(mixer->engine.regs,
136 SUN8I_MIXER_BLEND_ATTR_INSIZE(channel),
137 outsize);
138
139 return 0;
140}
141
142static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
143 int overlay, struct drm_plane *plane)
144{
145 struct drm_plane_state *state = plane->state;
146 const struct de2_fmt_info *fmt_info;
147 u32 val;
148
149 fmt_info = sun8i_mixer_format_info(state->fb->format->format);
150 if (!fmt_info) {
151 DRM_DEBUG_DRIVER("Invalid format\n");
152 return -EINVAL;
153 }
154
155 val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
156 regmap_update_bits(mixer->engine.regs,
157 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
158 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
159
160 if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
161 sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc);
162 sun8i_csc_enable_ccsc(mixer, channel, true);
163 } else {
164 sun8i_csc_enable_ccsc(mixer, channel, false);
165 }
166
167 if (fmt_info->rgb)
168 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
169 else
170 val = 0;
171
172 regmap_update_bits(mixer->engine.regs,
173 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
174 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
175
176 return 0;
177}
178
179static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
180 int overlay, struct drm_plane *plane)
181{
182 struct drm_plane_state *state = plane->state;
183 struct drm_framebuffer *fb = state->fb;
184 const struct drm_format_info *format = fb->format;
185 struct drm_gem_cma_object *gem;
186 u32 dx, dy, src_x, src_y;
187 dma_addr_t paddr;
188 int i;
189
190 /* Adjust x and y to be dividable by subsampling factor */
191 src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
192 src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
193
194 for (i = 0; i < format->num_planes; i++) {
195 /* Get the physical address of the buffer in memory */
196 gem = drm_fb_cma_get_gem_obj(fb, i);
197
198 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
199
200 /* Compute the start of the displayed memory */
201 paddr = gem->paddr + fb->offsets[i];
202
203 dx = src_x;
204 dy = src_y;
205
206 if (i > 0) {
207 dx /= format->hsub;
208 dy /= format->vsub;
209 }
210
211 /* Fixup framebuffer address for src coordinates */
212 paddr += dx * format->cpp[i];
213 paddr += dy * fb->pitches[i];
214
215 /* Set the line width */
216 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
217 i + 1, fb->pitches[i]);
218 regmap_write(mixer->engine.regs,
219 SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel,
220 overlay, i),
221 fb->pitches[i]);
222
223 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
224 i + 1, &paddr);
225
226 regmap_write(mixer->engine.regs,
227 SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel,
228 overlay, i),
229 lower_32_bits(paddr));
230 }
231
232 return 0;
233}
234
235static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
236 struct drm_plane_state *state)
237{
238 struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
239 struct drm_crtc *crtc = state->crtc;
240 struct drm_crtc_state *crtc_state;
241 int min_scale, max_scale;
242 struct drm_rect clip;
243
244 if (!crtc)
245 return 0;
246
247 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
248 if (WARN_ON(!crtc_state))
249 return -EINVAL;
250
251 clip.x1 = 0;
252 clip.y1 = 0;
253 clip.x2 = crtc_state->adjusted_mode.hdisplay;
254 clip.y2 = crtc_state->adjusted_mode.vdisplay;
255
256 min_scale = DRM_PLANE_HELPER_NO_SCALING;
257 max_scale = DRM_PLANE_HELPER_NO_SCALING;
258
259 if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
260 min_scale = SUN8I_VI_SCALER_SCALE_MIN;
261 max_scale = SUN8I_VI_SCALER_SCALE_MAX;
262 }
263
264 return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
265 min_scale, max_scale,
266 true, true);
267}
268
269static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
270 struct drm_plane_state *old_state)
271{
272 struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
273 struct sun8i_mixer *mixer = layer->mixer;
274
275 sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false);
276}
277
278static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
279 struct drm_plane_state *old_state)
280{
281 struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
282 struct sun8i_mixer *mixer = layer->mixer;
283
284 if (!plane->state->visible) {
285 sun8i_vi_layer_enable(mixer, layer->channel,
286 layer->overlay, false);
287 return;
288 }
289
290 sun8i_vi_layer_update_coord(mixer, layer->channel,
291 layer->overlay, plane);
292 sun8i_vi_layer_update_formats(mixer, layer->channel,
293 layer->overlay, plane);
294 sun8i_vi_layer_update_buffer(mixer, layer->channel,
295 layer->overlay, plane);
296 sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, true);
297}
298
299static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
300 .atomic_check = sun8i_vi_layer_atomic_check,
301 .atomic_disable = sun8i_vi_layer_atomic_disable,
302 .atomic_update = sun8i_vi_layer_atomic_update,
303};
304
305static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
306 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
307 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
308 .destroy = drm_plane_cleanup,
309 .disable_plane = drm_atomic_helper_disable_plane,
310 .reset = drm_atomic_helper_plane_reset,
311 .update_plane = drm_atomic_helper_update_plane,
312};
313
314/*
315 * While all RGB formats are supported, VI planes don't support
316 * alpha blending, so there is no point having formats with alpha
317 * channel if their opaque analog exist.
318 */
319static const u32 sun8i_vi_layer_formats[] = {
320 DRM_FORMAT_ABGR1555,
321 DRM_FORMAT_ABGR4444,
322 DRM_FORMAT_ARGB1555,
323 DRM_FORMAT_ARGB4444,
324 DRM_FORMAT_BGR565,
325 DRM_FORMAT_BGR888,
326 DRM_FORMAT_BGRA5551,
327 DRM_FORMAT_BGRA4444,
328 DRM_FORMAT_BGRX8888,
329 DRM_FORMAT_RGB565,
330 DRM_FORMAT_RGB888,
331 DRM_FORMAT_RGBA4444,
332 DRM_FORMAT_RGBA5551,
333 DRM_FORMAT_RGBX8888,
334 DRM_FORMAT_XBGR8888,
335 DRM_FORMAT_XRGB8888,
336
337 DRM_FORMAT_NV16,
338 DRM_FORMAT_NV12,
339 DRM_FORMAT_NV21,
340 DRM_FORMAT_NV61,
341 DRM_FORMAT_UYVY,
342 DRM_FORMAT_VYUY,
343 DRM_FORMAT_YUYV,
344 DRM_FORMAT_YVYU,
345 DRM_FORMAT_YUV411,
346 DRM_FORMAT_YUV420,
347 DRM_FORMAT_YUV422,
348 DRM_FORMAT_YUV444,
349 DRM_FORMAT_YVU411,
350 DRM_FORMAT_YVU420,
351 DRM_FORMAT_YVU422,
352 DRM_FORMAT_YVU444,
353};
354
355struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
356 struct sun8i_mixer *mixer,
357 int index)
358{
359 struct sun8i_vi_layer *layer;
360 int ret;
361
362 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
363 if (!layer)
364 return ERR_PTR(-ENOMEM);
365
366 /* possible crtcs are set later */
367 ret = drm_universal_plane_init(drm, &layer->plane, 0,
368 &sun8i_vi_layer_funcs,
369 sun8i_vi_layer_formats,
370 ARRAY_SIZE(sun8i_vi_layer_formats),
371 NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
372 if (ret) {
373 dev_err(drm->dev, "Couldn't initialize layer\n");
374 return ERR_PTR(ret);
375 }
376
377 /* fixed zpos for now */
378 ret = drm_plane_create_zpos_immutable_property(&layer->plane, index);
379 if (ret) {
380 dev_err(drm->dev, "Couldn't add zpos property\n");
381 return ERR_PTR(ret);
382 }
383
384 drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
385 layer->mixer = mixer;
386 layer->channel = index;
387 layer->overlay = 0;
388
389 return layer;
390}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
new file mode 100644
index 000000000000..6996627a0a76
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 */
9
10#ifndef _SUN8I_VI_LAYER_H_
11#define _SUN8I_VI_LAYER_H_
12
13#include <drm/drm_plane.h>
14
15#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch, layer) \
16 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x0)
17#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch, layer) \
18 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x4)
19#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(ch, layer) \
20 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x8)
21#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch, layer, plane) \
22 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0xc + 4 * (plane))
23#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch, layer, plane) \
24 (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x18 + 4 * (plane))
25#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0xe8)
26
27#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN BIT(0)
28/* 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_FBFMT_OFFSET 8
31#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8)
32
33struct sun8i_mixer;
34
35struct sun8i_vi_layer {
36 struct drm_plane plane;
37 struct sun8i_mixer *mixer;
38 int channel;
39 int overlay;
40};
41
42static inline struct sun8i_vi_layer *
43plane_to_sun8i_vi_layer(struct drm_plane *plane)
44{
45 return container_of(plane, struct sun8i_vi_layer, plane);
46}
47
48struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
49 struct sun8i_mixer *mixer,
50 int index);
51#endif /* _SUN8I_VI_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
new file mode 100644
index 000000000000..d3f1acb234b7
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -0,0 +1,971 @@
1/*
2 * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * Coefficients are taken from BSP driver, which is:
5 * Copyright (C) 2014-2015 Allwinner
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include "sun8i_vi_scaler.h"
13
14static const u32 lan3coefftab32_left[480] = {
15 0x40000000, 0x40fe0000, 0x3ffd0100, 0x3efc0100,
16 0x3efb0100, 0x3dfa0200, 0x3cf90200, 0x3bf80200,
17 0x39f70200, 0x37f70200, 0x35f70200, 0x33f70200,
18 0x31f70200, 0x2ef70200, 0x2cf70200, 0x2af70200,
19 0x27f70200, 0x24f80100, 0x22f80100, 0x1ef90100,
20 0x1cf90100, 0x19fa0100, 0x17fa0100, 0x14fb0100,
21 0x11fc0000, 0x0ffc0000, 0x0cfd0000, 0x0afd0000,
22 0x08fe0000, 0x05ff0000, 0x03ff0000, 0x02000000,
23
24 0x3806fc02, 0x3805fc02, 0x3803fd01, 0x3801fe01,
25 0x3700fe01, 0x35ffff01, 0x35fdff01, 0x34fc0001,
26 0x34fb0000, 0x33fa0000, 0x31fa0100, 0x2ff90100,
27 0x2df80200, 0x2bf80200, 0x2af70200, 0x28f70200,
28 0x27f70200, 0x24f70300, 0x22f70300, 0x1ff70300,
29 0x1ef70300, 0x1cf70300, 0x1af70300, 0x18f70300,
30 0x16f80300, 0x13f80300, 0x11f90300, 0x0ef90300,
31 0x0efa0200, 0x0cfa0200, 0x0afb0200, 0x08fb0200,
32
33 0x320bfa02, 0x3309fa02, 0x3208fb02, 0x3206fb02,
34 0x3205fb02, 0x3104fc02, 0x3102fc01, 0x3001fd01,
35 0x3000fd01, 0x2ffffd01, 0x2efefe01, 0x2dfdfe01,
36 0x2bfcff01, 0x29fcff01, 0x28fbff01, 0x27fa0001,
37 0x26fa0000, 0x24f90000, 0x22f90100, 0x20f90100,
38 0x1ff80100, 0x1ef80100, 0x1cf80100, 0x1af80200,
39 0x18f80200, 0x17f80200, 0x15f80200, 0x12f80200,
40 0x11f90200, 0x0ff90200, 0x0df90200, 0x0cfa0200,
41
42 0x2e0efa01, 0x2f0dfa01, 0x2f0bfa01, 0x2e0afa01,
43 0x2e09fa01, 0x2e07fb01, 0x2d06fb01, 0x2d05fb01,
44 0x2c04fb01, 0x2b03fc01, 0x2a02fc01, 0x2a01fc01,
45 0x2800fd01, 0x28fffd01, 0x26fefd01, 0x25fefe01,
46 0x24fdfe01, 0x23fcfe01, 0x21fcff01, 0x20fbff01,
47 0x1efbff01, 0x1efbff00, 0x1cfa0000, 0x1bfa0000,
48 0x19fa0000, 0x18fa0000, 0x17f90000, 0x15f90100,
49 0x14f90100, 0x12f90100, 0x11f90100, 0x0ff90100,
50
51 0x2b10fa00, 0x2b0ffa00, 0x2b0efa00, 0x2b0cfa00,
52 0x2b0bfa00, 0x2a0afb01, 0x2a09fb01, 0x2908fb01,
53 0x2807fb01, 0x2806fb01, 0x2805fb01, 0x2604fc01,
54 0x2503fc01, 0x2502fc01, 0x2401fc01, 0x2301fc01,
55 0x2100fd01, 0x21fffd01, 0x21fffd01, 0x20fefd01,
56 0x1dfefe01, 0x1cfdfe01, 0x1cfdfe00, 0x1bfcfe00,
57 0x19fcff00, 0x19fbff00, 0x17fbff00, 0x16fbff00,
58 0x15fbff00, 0x14fb0000, 0x13fa0000, 0x11fa0000,
59
60 0x2811fcff, 0x2810fcff, 0x280ffbff, 0x280efbff,
61 0x270dfb00, 0x270cfb00, 0x270bfb00, 0x260afb00,
62 0x2609fb00, 0x2508fb00, 0x2507fb00, 0x2407fb00,
63 0x2406fc00, 0x2305fc00, 0x2204fc00, 0x2203fc00,
64 0x2103fc00, 0x2002fc00, 0x1f01fd00, 0x1e01fd00,
65 0x1d00fd00, 0x1dfffd00, 0x1cfffd00, 0x1bfefd00,
66 0x1afefe00, 0x19fefe00, 0x18fdfe00, 0x17fdfe00,
67 0x16fdfe00, 0x15fcff00, 0x13fcff00, 0x12fcff00,
68
69 0x2512fdfe, 0x2511fdff, 0x2410fdff, 0x240ffdff,
70 0x240efcff, 0x240dfcff, 0x240dfcff, 0x240cfcff,
71 0x230bfcff, 0x230afc00, 0x2209fc00, 0x2108fc00,
72 0x2108fc00, 0x2007fc00, 0x2006fc00, 0x2005fc00,
73 0x1f05fc00, 0x1e04fc00, 0x1e03fc00, 0x1c03fd00,
74 0x1c02fd00, 0x1b02fd00, 0x1b01fd00, 0x1a00fd00,
75 0x1900fd00, 0x1800fd00, 0x17fffe00, 0x16fffe00,
76 0x16fefe00, 0x14fefe00, 0x13fefe00, 0x13fdfe00,
77
78 0x2212fffe, 0x2211fefe, 0x2211fefe, 0x2110fefe,
79 0x210ffeff, 0x220efdff, 0x210dfdff, 0x210dfdff,
80 0x210cfdff, 0x210bfdff, 0x200afdff, 0x200afdff,
81 0x1f09fdff, 0x1f08fdff, 0x1d08fd00, 0x1c07fd00,
82 0x1d06fd00, 0x1b06fd00, 0x1b05fd00, 0x1c04fd00,
83 0x1b04fd00, 0x1a03fd00, 0x1a03fd00, 0x1902fd00,
84 0x1802fd00, 0x1801fd00, 0x1701fd00, 0x1600fd00,
85 0x1400fe00, 0x1400fe00, 0x14fffe00, 0x13fffe00,
86
87 0x201200fe, 0x201100fe, 0x1f11fffe, 0x2010fffe,
88 0x1f0ffffe, 0x1e0ffffe, 0x1f0efeff, 0x1f0dfeff,
89 0x1f0dfeff, 0x1e0cfeff, 0x1e0bfeff, 0x1d0bfeff,
90 0x1d0afeff, 0x1d09fdff, 0x1d09fdff, 0x1c08fdff,
91 0x1c07fdff, 0x1b07fd00, 0x1b06fd00, 0x1a06fd00,
92 0x1a05fd00, 0x1805fd00, 0x1904fd00, 0x1804fd00,
93 0x1703fd00, 0x1703fd00, 0x1602fe00, 0x1502fe00,
94 0x1501fe00, 0x1401fe00, 0x1301fe00, 0x1300fe00,
95
96 0x1c1202fe, 0x1c1102fe, 0x1b1102fe, 0x1c1001fe,
97 0x1b1001fe, 0x1b0f01ff, 0x1b0e00ff, 0x1b0e00ff,
98 0x1b0d00ff, 0x1a0d00ff, 0x1a0c00ff, 0x1a0cffff,
99 0x1a0bffff, 0x1a0bffff, 0x1a0affff, 0x180affff,
100 0x1909ffff, 0x1809ffff, 0x1808ffff, 0x1808feff,
101 0x1807feff, 0x1707fe00, 0x1606fe00, 0x1506fe00,
102 0x1605fe00, 0x1505fe00, 0x1504fe00, 0x1304fe00,
103 0x1304fe00, 0x1303fe00, 0x1203fe00, 0x1203fe00,
104
105 0x181104ff, 0x191103ff, 0x191003ff, 0x181003ff,
106 0x180f03ff, 0x190f02ff, 0x190e02ff, 0x180e02ff,
107 0x180d02ff, 0x180d01ff, 0x180d01ff, 0x180c01ff,
108 0x180c01ff, 0x180b00ff, 0x170b00ff, 0x170a00ff,
109 0x170a00ff, 0x170900ff, 0x160900ff, 0x160900ff,
110 0x1608ffff, 0x1508ffff, 0x1507ff00, 0x1507ff00,
111 0x1407ff00, 0x1306ff00, 0x1306ff00, 0x1305ff00,
112 0x1205ff00, 0x1105ff00, 0x1204ff00, 0x1104ff00,
113
114 0x171005ff, 0x171005ff, 0x171004ff, 0x170f04ff,
115 0x160f04ff, 0x170f03ff, 0x170e03ff, 0x160e03ff,
116 0x160d03ff, 0x160d02ff, 0x160d02ff, 0x160c02ff,
117 0x160c02ff, 0x160c02ff, 0x160b01ff, 0x150b01ff,
118 0x150a01ff, 0x150a01ff, 0x150a01ff, 0x140901ff,
119 0x14090000, 0x14090000, 0x14080000, 0x13080000,
120 0x13070000, 0x12070000, 0x12070000, 0x12060000,
121 0x11060000, 0x11060000, 0x11050000, 0x1105ff00,
122
123 0x14100600, 0x15100500, 0x150f0500, 0x150f0500,
124 0x140f0500, 0x150e0400, 0x140e0400, 0x130e0400,
125 0x140d0400, 0x150d0300, 0x130d0300, 0x140c0300,
126 0x140c0300, 0x140c0200, 0x140b0200, 0x130b0200,
127 0x120b0200, 0x130a0200, 0x130a0200, 0x130a0100,
128 0x13090100, 0x12090100, 0x11090100, 0x12080100,
129 0x11080100, 0x10080100, 0x11070100, 0x11070000,
130 0x10070000, 0x11060000, 0x10060000, 0x10060000,
131
132 0x140f0600, 0x140f0600, 0x130f0600, 0x140f0500,
133 0x140e0500, 0x130e0500, 0x130e0500, 0x140d0400,
134 0x140d0400, 0x130d0400, 0x120d0400, 0x130c0400,
135 0x130c0300, 0x130c0300, 0x130b0300, 0x130b0300,
136 0x110b0300, 0x130a0200, 0x120a0200, 0x120a0200,
137 0x120a0200, 0x12090200, 0x10090200, 0x11090100,
138 0x11080100, 0x11080100, 0x10080100, 0x10080100,
139 0x10070100, 0x10070100, 0x0f070100, 0x10060100,
140
141 0x120f0701, 0x130f0601, 0x130e0601, 0x130e0601,
142 0x120e0601, 0x130e0501, 0x130e0500, 0x130d0500,
143 0x120d0500, 0x120d0500, 0x130c0400, 0x130c0400,
144 0x120c0400, 0x110c0400, 0x120b0400, 0x120b0300,
145 0x120b0300, 0x120b0300, 0x120a0300, 0x110a0300,
146 0x110a0200, 0x11090200, 0x11090200, 0x10090200,
147 0x10090200, 0x10080200, 0x10080200, 0x10080100,
148 0x0f080100, 0x10070100, 0x0f070100, 0x0f070100
149};
150
151static const u32 lan3coefftab32_right[480] = {
152 0x00000000, 0x00000002, 0x0000ff04, 0x0000ff06,
153 0x0000fe08, 0x0000fd0a, 0x0000fd0c, 0x0000fc0f,
154 0x0000fc12, 0x0001fb14, 0x0001fa17, 0x0001fa19,
155 0x0001f91c, 0x0001f91f, 0x0001f822, 0x0001f824,
156 0x0002f727, 0x0002f72a, 0x0002f72c, 0x0002f72f,
157 0x0002f731, 0x0002f733, 0x0002f735, 0x0002f737,
158 0x0002f73a, 0x0002f83b, 0x0002f93c, 0x0002fa3d,
159 0x0001fb3e, 0x0001fc3f, 0x0001fd40, 0x0000fe40,
160
161 0x0002fc06, 0x0002fb08, 0x0002fb0a, 0x0002fa0c,
162 0x0002fa0e, 0x0003f910, 0x0003f912, 0x0003f814,
163 0x0003f816, 0x0003f719, 0x0003f71a, 0x0003f71d,
164 0x0003f71f, 0x0003f721, 0x0003f723, 0x0003f725,
165 0x0002f727, 0x0002f729, 0x0002f72b, 0x0002f82d,
166 0x0002f82e, 0x0001f930, 0x0001fa31, 0x0000fa34,
167 0x0000fb34, 0x0100fc35, 0x01fffd36, 0x01ffff37,
168 0x01fe0037, 0x01fe0138, 0x01fd0338, 0x02fc0538,
169
170 0x0002fa0b, 0x0002fa0c, 0x0002f90e, 0x0002f910,
171 0x0002f911, 0x0002f813, 0x0002f816, 0x0002f817,
172 0x0002f818, 0x0002f81a, 0x0001f81c, 0x0001f81e,
173 0x0001f820, 0x0001f921, 0x0001f923, 0x0000f925,
174 0x0000fa26, 0x0100fa28, 0x01fffb29, 0x01fffc2a,
175 0x01fffc2c, 0x01fefd2d, 0x01fefe2e, 0x01fdff2f,
176 0x01fd0030, 0x01fd0130, 0x01fc0232, 0x02fc0432,
177 0x02fb0532, 0x02fb0633, 0x02fb0833, 0x02fa0933,
178
179 0x0001fa0e, 0x0001f90f, 0x0001f911, 0x0001f913,
180 0x0001f914, 0x0001f915, 0x0000f918, 0x0000fa18,
181 0x0000fa1a, 0x0000fa1b, 0x0000fa1d, 0x00fffb1e,
182 0x01fffb1f, 0x01fffb20, 0x01fffc22, 0x01fefc23,
183 0x01fefd24, 0x01fefe25, 0x01fdfe27, 0x01fdff28,
184 0x01fd0029, 0x01fc012a, 0x01fc022b, 0x01fc032b,
185 0x01fb042d, 0x01fb052d, 0x01fb062e, 0x01fb072e,
186 0x01fa092e, 0x01fa0a2f, 0x01fa0b2f, 0x01fa0d2f,
187
188 0x0000fa11, 0x0000fa12, 0x0000fa13, 0x0000fb14,
189 0x00fffb16, 0x00fffb16, 0x00fffb17, 0x00fffb19,
190 0x00fffc1a, 0x00fefc1c, 0x00fefd1c, 0x01fefd1d,
191 0x01fefe1e, 0x01fdfe20, 0x01fdff21, 0x01fdff22,
192 0x01fd0023, 0x01fc0124, 0x01fc0124, 0x01fc0225,
193 0x01fc0326, 0x01fc0427, 0x01fb0528, 0x01fb0629,
194 0x01fb0729, 0x01fb0829, 0x01fb092a, 0x01fb0a2a,
195 0x00fa0b2c, 0x00fa0c2b, 0x00fa0e2b, 0x00fa0f2c,
196
197 0x00fffc11, 0x00fffc12, 0x00fffc14, 0x00fffc15,
198 0x00fefd16, 0x00fefd17, 0x00fefd18, 0x00fefe19,
199 0x00fefe1a, 0x00fdfe1d, 0x00fdff1d, 0x00fdff1e,
200 0x00fd001d, 0x00fd011e, 0x00fd0120, 0x00fc0221,
201 0x00fc0321, 0x00fc0323, 0x00fc0423, 0x00fc0523,
202 0x00fc0624, 0x00fb0725, 0x00fb0726, 0x00fb0827,
203 0x00fb0926, 0x00fb0a26, 0x00fb0b27, 0x00fb0c27,
204 0x00fb0d27, 0xfffb0e28, 0xfffb0f29, 0xfffc1028,
205
206 0x00fefd13, 0x00fefd13, 0x00fefe14, 0x00fefe15,
207 0x00fefe17, 0x00feff17, 0x00feff17, 0x00fd0018,
208 0x00fd001a, 0x00fd001a, 0x00fd011b, 0x00fd021c,
209 0x00fd021c, 0x00fd031d, 0x00fc031f, 0x00fc041f,
210 0x00fc051f, 0x00fc0521, 0x00fc0621, 0x00fc0721,
211 0x00fc0821, 0x00fc0822, 0x00fc0922, 0x00fc0a23,
212 0xfffc0b24, 0xfffc0c24, 0xfffc0d24, 0xfffc0d25,
213 0xfffc0e25, 0xfffd0f25, 0xfffd1025, 0xfffd1125,
214
215 0x00feff12, 0x00feff14, 0x00feff14, 0x00fe0015,
216 0x00fe0015, 0x00fd0017, 0x00fd0118, 0x00fd0118,
217 0x00fd0218, 0x00fd0219, 0x00fd031a, 0x00fd031a,
218 0x00fd041b, 0x00fd041c, 0x00fd051c, 0x00fd061d,
219 0x00fd061d, 0x00fd071e, 0x00fd081e, 0xfffd081f,
220 0xfffd091f, 0xfffd0a20, 0xfffd0a20, 0xfffd0b21,
221 0xfffd0c21, 0xfffd0d21, 0xfffd0d22, 0xfffd0e23,
222 0xfffe0f22, 0xfefe1022, 0xfefe1122, 0xfefe1123,
223
224 0x00fe0012, 0x00fe0013, 0x00fe0114, 0x00fe0114,
225 0x00fe0116, 0x00fe0216, 0x00fe0216, 0x00fd0317,
226 0x00fd0317, 0x00fd0418, 0x00fd0419, 0x00fd0519,
227 0x00fd051a, 0x00fd061b, 0x00fd061b, 0x00fd071c,
228 0xfffd071e, 0xfffd081d, 0xfffd091d, 0xfffd091e,
229 0xfffe0a1d, 0xfffe0b1e, 0xfffe0b1e, 0xfffe0c1e,
230 0xfffe0d1f, 0xfffe0d1f, 0xfffe0e1f, 0xfeff0f1f,
231 0xfeff0f20, 0xfeff1020, 0xfeff1120, 0xfe001120,
232
233 0x00fe0212, 0x00fe0312, 0x00fe0313, 0x00fe0314,
234 0x00fe0414, 0x00fe0414, 0x00fe0416, 0x00fe0515,
235 0x00fe0516, 0x00fe0616, 0x00fe0617, 0x00fe0717,
236 0xfffe0719, 0xfffe0818, 0xffff0818, 0xffff0919,
237 0xffff0919, 0xffff0a19, 0xffff0a1a, 0xffff0b1a,
238 0xffff0b1b, 0xffff0c1a, 0xff000c1b, 0xff000d1b,
239 0xff000d1b, 0xff000e1b, 0xff000e1c, 0xff010f1c,
240 0xfe01101c, 0xfe01101d, 0xfe02111c, 0xfe02111c,
241
242 0x00ff0411, 0x00ff0411, 0x00ff0412, 0x00ff0512,
243 0x00ff0513, 0x00ff0513, 0x00ff0613, 0x00ff0614,
244 0x00ff0714, 0x00ff0715, 0x00ff0715, 0xffff0816,
245 0xffff0816, 0xff000916, 0xff000917, 0xff000918,
246 0xff000a17, 0xff000a18, 0xff000b18, 0xff000b18,
247 0xff010c18, 0xff010c19, 0xff010d18, 0xff010d18,
248 0xff020d18, 0xff020e19, 0xff020e19, 0xff020f19,
249 0xff030f19, 0xff031019, 0xff031019, 0xff031119,
250
251 0x00ff0511, 0x00ff0511, 0x00000511, 0x00000611,
252 0x00000612, 0x00000612, 0x00000712, 0x00000713,
253 0x00000714, 0x00000814, 0x00000814, 0x00000914,
254 0x00000914, 0xff010914, 0xff010a15, 0xff010a16,
255 0xff010a17, 0xff010b16, 0xff010b16, 0xff020c16,
256 0xff020c16, 0xff020c16, 0xff020d16, 0xff020d17,
257 0xff030d17, 0xff030e17, 0xff030e17, 0xff030f17,
258 0xff040f17, 0xff040f17, 0xff041017, 0xff051017,
259
260 0x00000610, 0x00000610, 0x00000611, 0x00000611,
261 0x00000711, 0x00000712, 0x00010712, 0x00010812,
262 0x00010812, 0x00010812, 0x00010913, 0x00010913,
263 0x00010913, 0x00010a13, 0x00020a13, 0x00020a14,
264 0x00020b14, 0x00020b14, 0x00020b14, 0x00020c14,
265 0x00030c14, 0x00030c15, 0x00030d15, 0x00030d15,
266 0x00040d15, 0x00040e15, 0x00040e15, 0x00040e16,
267 0x00050f15, 0x00050f15, 0x00050f16, 0x00051015,
268
269 0x00000611, 0x00010610, 0x00010710, 0x00010710,
270 0x00010711, 0x00010811, 0x00010811, 0x00010812,
271 0x00010812, 0x00010912, 0x00020912, 0x00020912,
272 0x00020a12, 0x00020a12, 0x00020a13, 0x00020a13,
273 0x00030b13, 0x00030b13, 0x00030b14, 0x00030c13,
274 0x00030c13, 0x00040c13, 0x00040d14, 0x00040d14,
275 0x00040d15, 0x00040d15, 0x00050e14, 0x00050e14,
276 0x00050e15, 0x00050f14, 0x00060f14, 0x00060f14,
277
278 0x0001070f, 0x0001070f, 0x00010710, 0x00010710,
279 0x00010810, 0x00010810, 0x00020810, 0x00020811,
280 0x00020911, 0x00020911, 0x00020912, 0x00020912,
281 0x00020a12, 0x00030a12, 0x00030a12, 0x00030b12,
282 0x00030b12, 0x00030b12, 0x00040b12, 0x00040c12,
283 0x00040c13, 0x00040c14, 0x00040c14, 0x00050d13,
284 0x00050d13, 0x00050d14, 0x00050e13, 0x01050e13,
285 0x01060e13, 0x01060e13, 0x01060e14, 0x01060f13
286};
287
288static const u32 lan2coefftab32[480] = {
289 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
290 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
291 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
292 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
293 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
294 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
295 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
296 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
297
298 0xff053804, 0xff063803, 0xff083801, 0xff093701,
299 0xff0a3700, 0xff0c3500, 0xff0e34ff, 0xff1033fe,
300 0xff1232fd, 0xfe1431fd, 0xfe162ffd, 0xfe182dfd,
301 0xfd1b2cfc, 0xfd1d2afc, 0xfd1f28fc, 0xfd2126fc,
302 0xfd2323fd, 0xfc2621fd, 0xfc281ffd, 0xfc2a1dfd,
303 0xfc2c1bfd, 0xfd2d18fe, 0xfd2f16fe, 0xfd3114fe,
304 0xfd3212ff, 0xfe3310ff, 0xff340eff, 0x00350cff,
305 0x00360a00, 0x01360900, 0x02370700, 0x03370600,
306
307 0xff083207, 0xff093206, 0xff0a3205, 0xff0c3203,
308 0xff0d3103, 0xff0e3102, 0xfe113001, 0xfe132f00,
309 0xfe142e00, 0xfe162dff, 0xfe182bff, 0xfe192aff,
310 0xfe1b29fe, 0xfe1d27fe, 0xfe1f25fe, 0xfd2124fe,
311 0xfe2222fe, 0xfe2421fd, 0xfe251ffe, 0xfe271dfe,
312 0xfe291bfe, 0xff2a19fe, 0xff2b18fe, 0xff2d16fe,
313 0x002e14fe, 0x002f12ff, 0x013010ff, 0x02300fff,
314 0x03310dff, 0x04310cff, 0x05310a00, 0x06310900,
315
316 0xff0a2e09, 0xff0b2e08, 0xff0c2e07, 0xff0e2d06,
317 0xff0f2d05, 0xff102d04, 0xff122c03, 0xfe142c02,
318 0xfe152b02, 0xfe172a01, 0xfe182901, 0xfe1a2800,
319 0xfe1b2700, 0xfe1d2500, 0xff1e24ff, 0xfe2023ff,
320 0xff2121ff, 0xff2320fe, 0xff241eff, 0x00251dfe,
321 0x00261bff, 0x00281afe, 0x012818ff, 0x012a16ff,
322 0x022a15ff, 0x032b13ff, 0x032c12ff, 0x052c10ff,
323 0x052d0fff, 0x062d0d00, 0x072d0c00, 0x082d0b00,
324
325 0xff0c2a0b, 0xff0d2a0a, 0xff0e2a09, 0xff0f2a08,
326 0xff102a07, 0xff112a06, 0xff132905, 0xff142904,
327 0xff162803, 0xff172703, 0xff182702, 0xff1a2601,
328 0xff1b2501, 0xff1c2401, 0xff1e2300, 0xff1f2200,
329 0x00202000, 0x00211f00, 0x01221d00, 0x01231c00,
330 0x01251bff, 0x02251aff, 0x032618ff, 0x032717ff,
331 0x042815ff, 0x052814ff, 0x052913ff, 0x06291100,
332 0x072a10ff, 0x082a0e00, 0x092a0d00, 0x0a2a0c00,
333
334 0xff0d280c, 0xff0e280b, 0xff0f280a, 0xff102809,
335 0xff112808, 0xff122708, 0xff142706, 0xff152705,
336 0xff162605, 0xff172604, 0xff192503, 0xff1a2403,
337 0x001b2302, 0x001c2202, 0x001d2201, 0x001e2101,
338 0x011f1f01, 0x01211e00, 0x01221d00, 0x02221c00,
339 0x02231b00, 0x03241900, 0x04241800, 0x04251700,
340 0x052616ff, 0x06261400, 0x072713ff, 0x08271100,
341 0x08271100, 0x09271000, 0x0a280e00, 0x0b280d00,
342
343 0xff0e260d, 0xff0f260c, 0xff10260b, 0xff11260a,
344 0xff122609, 0xff132608, 0xff142508, 0xff152507,
345 0x00152506, 0x00172405, 0x00182305, 0x00192304,
346 0x001b2203, 0x001c2103, 0x011d2002, 0x011d2002,
347 0x011f1f01, 0x021f1e01, 0x02201d01, 0x03211c00,
348 0x03221b00, 0x04221a00, 0x04231801, 0x05241700,
349 0x06241600, 0x07241500, 0x08251300, 0x09251200,
350 0x09261100, 0x0a261000, 0x0b260f00, 0x0c260e00,
351
352 0xff0e250e, 0xff0f250d, 0xff10250c, 0xff11250b,
353 0x0011250a, 0x00132409, 0x00142408, 0x00152407,
354 0x00162307, 0x00172306, 0x00182206, 0x00192205,
355 0x011a2104, 0x011b2004, 0x011c2003, 0x021c1f03,
356 0x021e1e02, 0x031e1d02, 0x03201c01, 0x04201b01,
357 0x04211a01, 0x05221900, 0x05221801, 0x06231700,
358 0x07231600, 0x07241500, 0x08241400, 0x09241300,
359 0x0a241200, 0x0b241100, 0x0c241000, 0x0d240f00,
360
361 0x000e240e, 0x000f240d, 0x0010240c, 0x0011240b,
362 0x0013230a, 0x0013230a, 0x00142309, 0x00152308,
363 0x00162208, 0x00172207, 0x01182106, 0x01192105,
364 0x011a2005, 0x021b1f04, 0x021b1f04, 0x021d1e03,
365 0x031d1d03, 0x031e1d02, 0x041e1c02, 0x041f1b02,
366 0x05201a01, 0x05211901, 0x06211801, 0x07221700,
367 0x07221601, 0x08231500, 0x09231400, 0x0a231300,
368 0x0a231300, 0x0b231200, 0x0c231100, 0x0d231000,
369
370 0x000f220f, 0x0010220e, 0x0011220d, 0x0012220c,
371 0x0013220b, 0x0013220b, 0x0015210a, 0x0015210a,
372 0x01162108, 0x01172008, 0x01182007, 0x02191f06,
373 0x02191f06, 0x021a1e06, 0x031a1e05, 0x031c1d04,
374 0x041c1c04, 0x041d1c03, 0x051d1b03, 0x051e1a03,
375 0x061f1902, 0x061f1902, 0x07201801, 0x08201701,
376 0x08211601, 0x09211501, 0x0a211500, 0x0b211400,
377 0x0b221300, 0x0c221200, 0x0d221100, 0x0e221000,
378
379 0x0010210f, 0x0011210e, 0x0011210e, 0x0012210d,
380 0x0013210c, 0x0014200c, 0x0114200b, 0x0115200a,
381 0x01161f0a, 0x01171f09, 0x02171f08, 0x02181e08,
382 0x03181e07, 0x031a1d06, 0x031a1d06, 0x041b1c05,
383 0x041c1c04, 0x051c1b04, 0x051d1a04, 0x061d1a03,
384 0x071d1903, 0x071e1803, 0x081e1802, 0x081f1702,
385 0x091f1602, 0x0a201501, 0x0b1f1501, 0x0b201401,
386 0x0c211300, 0x0d211200, 0x0e201200, 0x0e211100,
387
388 0x00102010, 0x0011200f, 0x0012200e, 0x0013200d,
389 0x0013200d, 0x01141f0c, 0x01151f0b, 0x01151f0b,
390 0x01161f0a, 0x02171e09, 0x02171e09, 0x03181d08,
391 0x03191d07, 0x03191d07, 0x041a1c06, 0x041b1c05,
392 0x051b1b05, 0x051c1b04, 0x061c1a04, 0x071d1903,
393 0x071d1903, 0x081d1803, 0x081e1703, 0x091e1702,
394 0x0a1f1601, 0x0a1f1502, 0x0b1f1501, 0x0c1f1401,
395 0x0d201300, 0x0d201300, 0x0e201200, 0x0f201100,
396
397 0x00102010, 0x0011200f, 0x00121f0f, 0x00131f0e,
398 0x00141f0d, 0x01141f0c, 0x01141f0c, 0x01151e0c,
399 0x02161e0a, 0x02171e09, 0x03171d09, 0x03181d08,
400 0x03181d08, 0x04191c07, 0x041a1c06, 0x051a1b06,
401 0x051b1b05, 0x061b1a05, 0x061c1a04, 0x071c1904,
402 0x081c1903, 0x081d1803, 0x091d1703, 0x091e1702,
403 0x0a1e1602, 0x0b1e1502, 0x0c1e1501, 0x0c1f1401,
404 0x0d1f1400, 0x0e1f1300, 0x0e1f1201, 0x0f1f1200,
405
406 0x00111e11, 0x00121e10, 0x00131e0f, 0x00131e0f,
407 0x01131e0e, 0x01141d0e, 0x02151d0c, 0x02151d0c,
408 0x02161d0b, 0x03161c0b, 0x03171c0a, 0x04171c09,
409 0x04181b09, 0x05181b08, 0x05191b07, 0x06191a07,
410 0x061a1a06, 0x071a1906, 0x071b1905, 0x081b1805,
411 0x091b1804, 0x091c1704, 0x0a1c1703, 0x0a1c1604,
412 0x0b1d1602, 0x0c1d1502, 0x0c1d1502, 0x0d1d1402,
413 0x0e1d1401, 0x0e1e1301, 0x0f1e1300, 0x101e1200,
414
415 0x00111e11, 0x00121e10, 0x00131d10, 0x01131d0f,
416 0x01141d0e, 0x01141d0e, 0x02151c0d, 0x02151c0d,
417 0x03161c0b, 0x03161c0b, 0x04171b0a, 0x04171b0a,
418 0x05171b09, 0x05181a09, 0x06181a08, 0x06191a07,
419 0x07191907, 0x071a1906, 0x081a1806, 0x081a1806,
420 0x091a1805, 0x0a1b1704, 0x0a1b1704, 0x0b1c1603,
421 0x0b1c1603, 0x0c1c1503, 0x0d1c1502, 0x0d1d1402,
422 0x0e1d1401, 0x0f1d1301, 0x0f1d1301, 0x101e1200,
423};
424
425static const u32 bicubic8coefftab32_left[480] = {
426 0x40000000, 0x40ff0000, 0x3ffe0000, 0x3efe0000,
427 0x3dfd0000, 0x3cfc0000, 0x3bfc0000, 0x39fc0000,
428 0x36fc0000, 0x35fb0000, 0x33fb0000, 0x31fb0000,
429 0x2ffb0000, 0x2cfb0000, 0x29fc0000, 0x27fc0000,
430 0x24fc0000, 0x21fc0000, 0x1efd0000, 0x1cfd0000,
431 0x19fd0000, 0x16fe0000, 0x14fe0000, 0x11fe0000,
432 0x0dff0000, 0x0cff0000, 0x0aff0000, 0x08ff0000,
433 0x05000000, 0x03000000, 0x02000000, 0x01000000,
434
435 0x3904ff00, 0x3903ff00, 0x3902ff00, 0x38010000,
436 0x37000000, 0x36ff0000, 0x35ff0000, 0x34fe0000,
437 0x32fe0000, 0x31fd0000, 0x30fd0000, 0x2efc0000,
438 0x2cfc0000, 0x2afc0000, 0x28fc0000, 0x26fc0000,
439 0x24fc0000, 0x22fc0000, 0x20fc0000, 0x1efc0000,
440 0x1cfc0000, 0x19fc0000, 0x17fc0000, 0x15fd0000,
441 0x12fd0000, 0x11fd0000, 0x0ffd0000, 0x0dfe0000,
442 0x0bfe0000, 0x09fe0000, 0x08fe0000, 0x06ff0000,
443
444 0x3209fe00, 0x3407fe00, 0x3306fe00, 0x3305fe00,
445 0x3204fe00, 0x3102ff00, 0x3102ff00, 0x3001ff00,
446 0x2f00ff00, 0x2effff00, 0x2cff0000, 0x2bfe0000,
447 0x29fe0000, 0x28fe0000, 0x26fd0000, 0x24fd0000,
448 0x23fd0000, 0x21fd0000, 0x20fc0000, 0x1efc0000,
449 0x1dfc0000, 0x1bfc0000, 0x19fc0000, 0x17fc0000,
450 0x16fc0000, 0x14fc0000, 0x12fc0000, 0x10fd0000,
451 0x0ffd0000, 0x0dfd0000, 0x0cfd0000, 0x0afd0000,
452
453 0x2e0cfd00, 0x2e0bfd00, 0x2e09fd00, 0x2e08fd00,
454 0x2e07fd00, 0x2c06fe00, 0x2c05fe00, 0x2b04fe00,
455 0x2b03fe00, 0x2a02fe00, 0x2901fe00, 0x2701ff00,
456 0x2700ff00, 0x26ffff00, 0x24ffff00, 0x23ffff00,
457 0x22feff00, 0x20fe0000, 0x1ffe0000, 0x1efd0000,
458 0x1dfd0000, 0x1bfd0000, 0x1afd0000, 0x19fd0000,
459 0x17fd0000, 0x15fd0000, 0x13fd0000, 0x12fd0000,
460 0x11fd0000, 0x10fd0000, 0x0ffd0000, 0x0cfd0000,
461
462 0x2a0efd00, 0x2a0dfd00, 0x2a0cfd00, 0x290bfd00,
463 0x290afd00, 0x2909fd00, 0x2908fd00, 0x2807fd00,
464 0x2706fd00, 0x2705fd00, 0x2604fe00, 0x2603fe00,
465 0x2502fe00, 0x2402fe00, 0x2401fe00, 0x2200fe00,
466 0x2200fe00, 0x2000ff00, 0x1fffff00, 0x1effff00,
467 0x1dfeff00, 0x1cfeff00, 0x1afeff00, 0x19feff00,
468 0x17fe0000, 0x16fd0000, 0x15fd0000, 0x14fd0000,
469 0x12fd0000, 0x11fd0000, 0x10fd0000, 0x0ffd0000,
470
471 0x2610fd00, 0x260ffd00, 0x260efd00, 0x260dfd00,
472 0x260cfd00, 0x260bfd00, 0x260afd00, 0x2609fd00,
473 0x2508fd00, 0x2507fd00, 0x2406fd00, 0x2406fd00,
474 0x2305fd00, 0x2304fd00, 0x2203fe00, 0x2103fe00,
475 0x2002fe00, 0x1f01fe00, 0x1e01fe00, 0x1e00fe00,
476 0x1c00fe00, 0x1b00fe00, 0x1afffe00, 0x19ffff00,
477 0x18ffff00, 0x17feff00, 0x16feff00, 0x15feff00,
478 0x14feff00, 0x13feff00, 0x11feff00, 0x10fd0000,
479
480 0x2411feff, 0x2410feff, 0x240ffeff, 0x230efeff,
481 0x240dfeff, 0x240cfeff, 0x230cfd00, 0x230bfd00,
482 0x230afd00, 0x2309fd00, 0x2208fd00, 0x2108fd00,
483 0x2007fd00, 0x2106fd00, 0x2005fd00, 0x1f05fd00,
484 0x1f04fd00, 0x1e03fd00, 0x1d03fe00, 0x1c02fe00,
485 0x1b02fe00, 0x1a01fe00, 0x1a01fe00, 0x1900fe00,
486 0x1800fe00, 0x1700fe00, 0x16fffe00, 0x15fffe00,
487 0x13ffff00, 0x12ffff00, 0x12feff00, 0x11feff00,
488
489 0x2212fffe, 0x2211fffe, 0x2210ffff, 0x220ffeff,
490 0x220efeff, 0x210efeff, 0x210dfeff, 0x210cfeff,
491 0x210bfeff, 0x200bfeff, 0x200afeff, 0x1f09feff,
492 0x1f08feff, 0x1d08fe00, 0x1e07fd00, 0x1e06fd00,
493 0x1d06fd00, 0x1c05fd00, 0x1b04fe00, 0x1a04fe00,
494 0x1a03fe00, 0x1903fe00, 0x1802fe00, 0x1802fe00,
495 0x1701fe00, 0x1601fe00, 0x1501fe00, 0x1500fe00,
496 0x1400fe00, 0x1400fe00, 0x13fffe00, 0x12fffe00,
497
498 0x201200fe, 0x201100fe, 0x1f1100fe, 0x2010fffe,
499 0x200ffffe, 0x1f0ffffe, 0x1f0efffe, 0x1e0dffff,
500 0x1f0cfeff, 0x1e0cfeff, 0x1e0bfeff, 0x1e0afeff,
501 0x1d0afeff, 0x1d09feff, 0x1c08feff, 0x1b08feff,
502 0x1b07feff, 0x1a07feff, 0x1a06feff, 0x1a05feff,
503 0x1805fe00, 0x1904fe00, 0x1704fe00, 0x1703fe00,
504 0x1603fe00, 0x1602fe00, 0x1402fe00, 0x1402fe00,
505 0x1401fe00, 0x1301fe00, 0x1201fe00, 0x1200fe00,
506
507 0x1c1202fe, 0x1c1102fe, 0x1b1102fe, 0x1c1001fe,
508 0x1b1001fe, 0x1c0f01fe, 0x1b0f00fe, 0x1b0e00fe,
509 0x1b0e00fe, 0x1b0d00fe, 0x1b0c00fe, 0x1a0cfffe,
510 0x1a0bfffe, 0x1a0bfffe, 0x190afffe, 0x190afffe,
511 0x1909fffe, 0x1709ffff, 0x1808ffff, 0x1708feff,
512 0x1707feff, 0x1707feff, 0x1606feff, 0x1506feff,
513 0x1505feff, 0x1505feff, 0x1404feff, 0x1404feff,
514 0x1404feff, 0x1303feff, 0x1203feff, 0x1202feff,
515
516 0x191104fe, 0x191104fe, 0x191003fe, 0x191003fe,
517 0x171003fe, 0x180f03fe, 0x180f02fe, 0x180e02fe,
518 0x180e02fe, 0x180d01fe, 0x180d01fe, 0x180d01fe,
519 0x170c01fe, 0x160c01fe, 0x170b00fe, 0x170b00fe,
520 0x160a00fe, 0x160a00fe, 0x160a00fe, 0x150900fe,
521 0x1509fffe, 0x1508fffe, 0x1508fffe, 0x1408fffe,
522 0x1407fffe, 0x1307ffff, 0x1306ffff, 0x1206ffff,
523 0x1206ffff, 0x1205ffff, 0x1205ffff, 0x1104feff,
524
525 0x161006ff, 0x161005ff, 0x161005ff, 0x160f05ff,
526 0x160f04ff, 0x150f04ff, 0x150e04ff, 0x150e04ff,
527 0x150e03ff, 0x150d03ff, 0x150d03ff, 0x150d02ff,
528 0x140c02ff, 0x150c02fe, 0x150c02fe, 0x150b02fe,
529 0x140b01fe, 0x140b01fe, 0x140a01fe, 0x140a01fe,
530 0x140a01fe, 0x130900fe, 0x130900fe, 0x130900fe,
531 0x130800fe, 0x120800fe, 0x120800fe, 0x120700fe,
532 0x120700fe, 0x1107fffe, 0x1106fffe, 0x1106fffe,
533
534 0x140f0700, 0x140f0600, 0x140f0600, 0x140f0600,
535 0x140e0600, 0x130e0500, 0x140e05ff, 0x130e05ff,
536 0x140d05ff, 0x130d04ff, 0x130d04ff, 0x120d04ff,
537 0x130c04ff, 0x130c03ff, 0x130c03ff, 0x120c03ff,
538 0x120b03ff, 0x120b02ff, 0x120b02ff, 0x120a02ff,
539 0x120a02ff, 0x110a02ff, 0x110a01ff, 0x120901ff,
540 0x100901ff, 0x100901ff, 0x110801ff, 0x110801ff,
541 0x100800ff, 0x100800ff, 0x100700ff, 0x100700fe,
542
543 0x120f0701, 0x120e0701, 0x120e0701, 0x120e0701,
544 0x120e0600, 0x110e0600, 0x120d0600, 0x120d0600,
545 0x120d0500, 0x120d0500, 0x110d0500, 0x110c0500,
546 0x110c0500, 0x110c0400, 0x110c0400, 0x110b04ff,
547 0x110b04ff, 0x110b04ff, 0x110b03ff, 0x110b03ff,
548 0x110a03ff, 0x110a03ff, 0x100a03ff, 0x110a02ff,
549 0x100902ff, 0x100902ff, 0x100902ff, 0x0f0902ff,
550 0x0e0902ff, 0x100801ff, 0x0f0801ff, 0x0f0801ff,
551
552 0x100e0802, 0x100e0802, 0x110e0702, 0x110d0701,
553 0x110d0701, 0x100d0701, 0x100d0701, 0x110d0601,
554 0x110d0601, 0x110c0601, 0x110c0601, 0x100c0600,
555 0x100c0500, 0x100c0500, 0x100c0500, 0x100b0500,
556 0x100b0500, 0x100b0400, 0x100b0400, 0x0f0b0400,
557 0x100a0400, 0x0f0a0400, 0x0f0a0400, 0x0f0a0300,
558 0x0f0a03ff, 0x0f0903ff, 0x0f0903ff, 0x0f0903ff,
559 0x0f0903ff, 0x0f0902ff, 0x0f0902ff, 0x0f0802ff
560};
561
562static const u32 bicubic8coefftab32_right[480] = {
563 0x00000000, 0x00000001, 0x00000003, 0x00000004,
564 0x00000006, 0x0000ff09, 0x0000ff0a, 0x0000ff0c,
565 0x0000ff0f, 0x0000fe12, 0x0000fe14, 0x0000fe16,
566 0x0000fd19, 0x0000fd1c, 0x0000fd1e, 0x0000fc21,
567 0x0000fc24, 0x0000fc27, 0x0000fc29, 0x0000fb2c,
568 0x0000fb2f, 0x0000fb31, 0x0000fb33, 0x0000fb36,
569 0x0000fc38, 0x0000fc39, 0x0000fc3b, 0x0000fc3d,
570 0x0000fd3e, 0x0000fe3f, 0x0000fe40, 0x0000ff40,
571
572 0x0000ff05, 0x0000ff06, 0x0000fe08, 0x0000fe09,
573 0x0000fe0b, 0x0000fe0d, 0x0000fd0f, 0x0000fd11,
574 0x0000fd13, 0x0000fd15, 0x0000fc17, 0x0000fc1a,
575 0x0000fc1c, 0x0000fc1e, 0x0000fc20, 0x0000fc22,
576 0x0000fc24, 0x0000fc26, 0x0000fc28, 0x0000fc2a,
577 0x0000fc2c, 0x0000fc2f, 0x0000fd30, 0x0000fd31,
578 0x0000fe33, 0x0000fe34, 0x0000ff35, 0x0000ff36,
579 0x00000037, 0x00000138, 0x00ff0239, 0x00ff0339,
580
581 0x0000fe09, 0x0000fd0a, 0x0000fd0c, 0x0000fd0d,
582 0x0000fd0f, 0x0000fd11, 0x0000fc12, 0x0000fc14,
583 0x0000fc16, 0x0000fc18, 0x0000fc19, 0x0000fc1b,
584 0x0000fc1d, 0x0000fc1e, 0x0000fc21, 0x0000fd22,
585 0x0000fd23, 0x0000fd25, 0x0000fd27, 0x0000fe28,
586 0x0000fe29, 0x0000fe2b, 0x0000ff2c, 0x00ffff2f,
587 0x00ff002f, 0x00ff0130, 0x00ff0231, 0x00ff0232,
588 0x00fe0432, 0x00fe0533, 0x00fe0633, 0x00fe0734,
589
590 0x0000fd0c, 0x0000fd0d, 0x0000fd0f, 0x0000fd10,
591 0x0000fd11, 0x0000fd13, 0x0000fd14, 0x0000fd16,
592 0x0000fd17, 0x0000fd19, 0x0000fd1b, 0x0000fd1c,
593 0x0000fd1d, 0x0000fd1f, 0x0000fe20, 0x0000fe21,
594 0x00fffe24, 0x00ffff24, 0x00ffff25, 0x00ffff27,
595 0x00ff0027, 0x00ff0128, 0x00fe012a, 0x00fe022a,
596 0x00fe032b, 0x00fe042c, 0x00fe052d, 0x00fe062d,
597 0x00fd072e, 0x00fd082e, 0x00fd092e, 0x00fd0b2f,
598
599 0x0000fd0e, 0x0000fd0f, 0x0000fd10, 0x0000fd12,
600 0x0000fd13, 0x0000fd14, 0x0000fd15, 0x0000fd17,
601 0x0000fe18, 0x00fffe1a, 0x00fffe1b, 0x00fffe1c,
602 0x00fffe1e, 0x00ffff1e, 0x00ffff1f, 0x00ff0021,
603 0x00fe0022, 0x00fe0023, 0x00fe0124, 0x00fe0224,
604 0x00fe0226, 0x00fe0326, 0x00fe0427, 0x00fd0528,
605 0x00fd0628, 0x00fd0729, 0x00fd0829, 0x00fd0929,
606 0x00fd0a2a, 0x00fd0b2a, 0x00fd0c2a, 0x00fd0d2a,
607
608 0x0000fd10, 0x0000fd11, 0x00fffe12, 0x00fffe13,
609 0x00fffe14, 0x00fffe15, 0x00fffe16, 0x00fffe17,
610 0x00ffff18, 0x00ffff19, 0x00feff1c, 0x00fe001b,
611 0x00fe001d, 0x00fe001e, 0x00fe011e, 0x00fe011f,
612 0x00fe0220, 0x00fe0321, 0x00fe0322, 0x00fd0423,
613 0x00fd0524, 0x00fd0624, 0x00fd0626, 0x00fd0725,
614 0x00fd0825, 0x00fd0926, 0x00fd0a26, 0x00fd0b26,
615 0x00fd0c26, 0x00fd0d26, 0x00fd0e27, 0x00fd0f27,
616
617 0x00fffe11, 0x00fffe12, 0x00fffe13, 0x00ffff14,
618 0x00ffff14, 0x00feff16, 0x00feff17, 0x00fe0017,
619 0x00fe0018, 0x00fe0019, 0x00fe011a, 0x00fe011b,
620 0x00fe021c, 0x00fe021c, 0x00fe031d, 0x00fd031f,
621 0x00fd041f, 0x00fd0520, 0x00fd0520, 0x00fd0621,
622 0x00fd0721, 0x00fd0822, 0x00fd0822, 0x00fd0923,
623 0x00fd0a23, 0x00fd0b23, 0x00fd0b25, 0x00fe0c24,
624 0x00fe0d24, 0x00fe0e24, 0x00fe0f24, 0x00fe1024,
625
626 0x00feff12, 0x00feff13, 0x00feff13, 0x00fe0014,
627 0x00fe0015, 0x00fe0016, 0x00fe0116, 0x00fe0117,
628 0x00fe0118, 0x00fe0218, 0x00fe0219, 0x00fe031a,
629 0x00fe031b, 0x00fe041b, 0x00fd041d, 0x00fd051d,
630 0x00fd061d, 0x00fd061f, 0x00fe071e, 0x00fe081e,
631 0x00fe081f, 0x00fe091f, 0x00fe0a20, 0x00fe0a20,
632 0x00fe0b21, 0x00fe0c21, 0x00fe0d21, 0x00fe0d22,
633 0x00fe0e22, 0x00fe0f21, 0x00ff1021, 0x00ff1022,
634
635 0x00fe0012, 0x00fe0013, 0x00fe0113, 0x00fe0114,
636 0x00fe0115, 0x00fe0215, 0x00fe0216, 0x00fe0217,
637 0x00fe0317, 0x00fe0318, 0x00fe0418, 0x00fe0419,
638 0x00fe0519, 0x00fe051a, 0x00fe061b, 0x00fe071b,
639 0x00fe071c, 0x00fe081c, 0x00fe081d, 0x00fe091d,
640 0x00fe0a1d, 0x00fe0a1d, 0x00fe0b1e, 0x00fe0c1e,
641 0x00ff0c1e, 0x00ff0d1e, 0x00ff0e1f, 0x00ff0e1f,
642 0x00ff0f1f, 0x00ff0f20, 0x0000101f, 0x0000111f,
643
644 0x00fe0212, 0x00fe0312, 0x00fe0313, 0x00fe0314,
645 0x00fe0414, 0x00fe0414, 0x00fe0515, 0x00fe0516,
646 0x00fe0516, 0x00fe0616, 0x00fe0617, 0x00fe0718,
647 0x00fe0719, 0x00fe0818, 0x00ff0819, 0x00ff0918,
648 0x00ff0919, 0x00ff0a19, 0x00ff0a19, 0x00ff0b1a,
649 0x00ff0b1b, 0x00ff0c1a, 0x00000c1b, 0x00000d1b,
650 0x00000d1c, 0x00000e1b, 0x00000e1d, 0x00010f1b,
651 0x00010f1b, 0x0001101c, 0x0001101d, 0x0002111c,
652
653 0x00fe0412, 0x00fe0412, 0x00ff0512, 0x00ff0512,
654 0x00ff0613, 0x00ff0613, 0x00ff0614, 0x00ff0714,
655 0x00ff0714, 0x00ff0815, 0x00ff0815, 0x00ff0815,
656 0x00ff0916, 0x00000916, 0x00000a16, 0x00000a16,
657 0x00000a18, 0x00000b17, 0x00000b17, 0x00010c17,
658 0x00010c18, 0x00010d18, 0x00010d18, 0x00010d19,
659 0x00020e18, 0x00020e18, 0x00020f18, 0x00030f18,
660 0x00030f18, 0x00031018, 0x00031018, 0x00041119,
661
662 0x00ff0610, 0x00ff0611, 0x00ff0611, 0x00ff0711,
663 0x00000711, 0x00000712, 0x00000812, 0x00000812,
664 0x00000813, 0x00000913, 0x00000913, 0x00000914,
665 0x00010a14, 0x00010a14, 0x00010a14, 0x00010b14,
666 0x00010b16, 0x00020b15, 0x00020c15, 0x00020c15,
667 0x00020c15, 0x00020d17, 0x00030d16, 0x00030d16,
668 0x00030e16, 0x00040e16, 0x00040e16, 0x00040f16,
669 0x00040f16, 0x00050f17, 0x00051017, 0x00051017,
670
671 0x0000070f, 0x00000710, 0x00000710, 0x00000710,
672 0x00000810, 0x00010811, 0x00010811, 0x00010911,
673 0x00010911, 0x00010913, 0x00010913, 0x00020a12,
674 0x00020a12, 0x00020a13, 0x00020b12, 0x00020b13,
675 0x00030b13, 0x00030c13, 0x00030c13, 0x00030c14,
676 0x00040c13, 0x00040d13, 0x00040d14, 0x00040d14,
677 0x00050e14, 0x00050e14, 0x00050e14, 0x00050e14,
678 0x00060f14, 0x00060f14, 0x00060f15, 0x00061015,
679
680 0x0001070f, 0x0001080f, 0x0001080f, 0x0001080f,
681 0x00010811, 0x00020910, 0x00020910, 0x00020910,
682 0x00020911, 0x00020a10, 0x00030a10, 0x00030a11,
683 0x00030a11, 0x00030b11, 0x00030b11, 0x00040b12,
684 0x00040b12, 0x00040c11, 0x00040c12, 0x00040c12,
685 0x00050c12, 0x00050c12, 0x00050d12, 0x00050d12,
686 0x00060d13, 0x00060d13, 0x00060e12, 0x00060e13,
687 0x00070e13, 0x00070e13, 0x00070f13, 0x00070f13,
688
689 0x0002080e, 0x0002080e, 0x0002080e, 0x00020810,
690 0x0002090f, 0x0003090f, 0x0003090f, 0x0003090f,
691 0x0003090f, 0x00030a0f, 0x00030a0f, 0x00040a10,
692 0x00040a11, 0x00040b10, 0x00040b10, 0x00040b11,
693 0x00050b10, 0x00050b11, 0x00050c10, 0x00050c11,
694 0x00050c11, 0x00060c11, 0x00060c11, 0x00060d11,
695 0x00060d12, 0x00070d12, 0x00070d12, 0x00070e11,
696 0x00070e11, 0x00070e12, 0x00080e11, 0x00080e12
697};
698
699static const u32 bicubic4coefftab32[480] = {
700 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
701 0x00063dfd, 0xff083dfc, 0xff0a3bfc, 0xff0c39fc,
702 0xff0e37fc, 0xfe1136fb, 0xfe1433fb, 0xfe1631fb,
703 0xfd192ffb, 0xfd1c2cfb, 0xfd1e29fc, 0xfc2127fc,
704 0xfc2424fc, 0xfc2721fc, 0xfc291efd, 0xfb2c1cfd,
705 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfb3611fe,
706 0xfc370eff, 0xfc390cff, 0xfc3b0aff, 0xfc3d08ff,
707 0xfd3d0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
708
709 0xfe053904, 0xfe063903, 0xfe083901, 0xfe0a3800,
710 0xfd0b3800, 0xfe0d36ff, 0xfd0f35ff, 0xfd1134fe,
711 0xfd1332fe, 0xfd1531fd, 0xfc1730fd, 0xfc1a2efc,
712 0xfc1c2cfc, 0xfc1e2afc, 0xfc2028fc, 0xfc2226fc,
713 0xfc2424fc, 0xfc2622fc, 0xfc2820fc, 0xfc2a1efc,
714 0xfc2c1cfc, 0xfc2e1afc, 0xfd3017fc, 0xfd3115fd,
715 0xfe3213fd, 0xfe3411fd, 0xff350ffd, 0xff360dfe,
716 0x00370bfe, 0x013809fe, 0x023808fe, 0x033806ff,
717
718 0xfd093208, 0xfd0a3207, 0xfd0c3205, 0xfd0d3204,
719 0xfc0f3203, 0xfc113102, 0xfc123002, 0xfc143000,
720 0xfc152f00, 0xfc172d00, 0xfc192cff, 0xfc1b2bfe,
721 0xfc1d29fe, 0xfc1e28fe, 0xfc2027fd, 0xfd2125fd,
722 0xfd2323fd, 0xfd2521fd, 0xfd2720fc, 0xfe281efc,
723 0xfe291dfc, 0xfe2b1bfc, 0xff2c19fc, 0x002d17fc,
724 0x002e16fc, 0x012f14fc, 0x022f12fd, 0x023110fd,
725 0x03310ffd, 0x05310dfd, 0x06320bfd, 0x07320afd,
726
727 0xfc0c2d0b, 0xfc0d2d0a, 0xfc0e2d09, 0xfc102d07,
728 0xfc112c07, 0xfc132c05, 0xfc142c04, 0xfc162b03,
729 0xfc172a03, 0xfc192a01, 0xfc1a2901, 0xfd1b2800,
730 0xfd1c2700, 0xfd1e2500, 0xfe1f24ff, 0xfe2023ff,
731 0xfe2222fe, 0xff2320fe, 0xff241ffe, 0x00251efd,
732 0x00271cfd, 0x01271bfd, 0x01281afd, 0x022918fd,
733 0x032a16fd, 0x032b15fd, 0x042b14fd, 0x052c12fd,
734 0x072c10fd, 0x082c0ffd, 0x092c0efd, 0x0a2c0dfd,
735
736 0xfd0d290d, 0xfd0e290c, 0xfd0f290b, 0xfd11280a,
737 0xfd122809, 0xfd132808, 0xfd142807, 0xfd162706,
738 0xfd172705, 0xfd192604, 0xfe1a2503, 0xfe1b2502,
739 0xfe1c2402, 0xfe1d2302, 0xff1e2201, 0xff1f2101,
740 0x00202000, 0x00211f00, 0x01221eff, 0x02221dff,
741 0x02241cfe, 0x03241bfe, 0x042519fe, 0x042618fe,
742 0x052617fe, 0x062716fd, 0x072714fe, 0x082713fe,
743 0x092812fd, 0x0a2811fd, 0x0b2810fd, 0x0c280ffd,
744
745 0xfd0f250f, 0xfd10250e, 0xfd11250d, 0xfd12250c,
746 0xfd13250b, 0xfe13250a, 0xfe152409, 0xfe162408,
747 0xfe172308, 0xff182306, 0xff192305, 0xff1a2205,
748 0x001b2104, 0x001c2103, 0x001d2003, 0x011e1f02,
749 0x011f1f01, 0x021f1e01, 0x03201d00, 0x03211c00,
750 0x04211b00, 0x05221aff, 0x062219ff, 0x062318ff,
751 0x082316ff, 0x082316ff, 0x092415fe, 0x0a2414fe,
752 0x0b2413fe, 0x0c2412fe, 0x0d2411fe, 0x0e2410fe,
753
754 0xfe10230f, 0xfe11230e, 0xfe12220e, 0xfe13220d,
755 0xfe14220c, 0xff14220b, 0xff15220a, 0xff16210a,
756 0x00162109, 0x00172108, 0x00182008, 0x01192006,
757 0x011a1f06, 0x021a1f05, 0x021b1e05, 0x031c1d04,
758 0x031d1d03, 0x041d1c03, 0x041e1b03, 0x051e1b02,
759 0x061f1a01, 0x06201901, 0x07201801, 0x08201800,
760 0x09201700, 0x0a211500, 0x0b2115ff, 0x0c2114ff,
761 0x0c2213ff, 0x0d2212ff, 0x0e2211ff, 0x0f2211fe,
762
763 0xff112010, 0xff12200f, 0xff12200f, 0xff13200e,
764 0x0013200d, 0x0014200c, 0x00151f0c, 0x00161f0b,
765 0x01161f0a, 0x01171e0a, 0x02171e09, 0x02181e08,
766 0x03191d07, 0x03191d07, 0x041a1c06, 0x041b1c05,
767 0x051b1b05, 0x051c1b04, 0x061c1a04, 0x071c1a03,
768 0x071d1903, 0x081e1802, 0x091d1802, 0x091e1702,
769 0x0a1f1601, 0x0b1f1600, 0x0b1f1501, 0x0c201400,
770 0x0d1f1400, 0x0e2013ff, 0x0f1f1200, 0x102011ff,
771
772 0x00111f10, 0x00121e10, 0x00131e0f, 0x00131e0f,
773 0x01131e0e, 0x01141e0d, 0x01151d0d, 0x02151d0c,
774 0x02161d0b, 0x03161d0a, 0x03171c0a, 0x04171c09,
775 0x04181c08, 0x05181b08, 0x05191b07, 0x06191a07,
776 0x061a1a06, 0x071a1906, 0x071b1905, 0x081b1805,
777 0x081c1804, 0x091c1704, 0x0a1c1703, 0x0a1d1603,
778 0x0b1d1602, 0x0c1d1502, 0x0c1d1502, 0x0d1e1401,
779 0x0e1d1401, 0x0e1e1301, 0x0f1e1300, 0x101e1200,
780
781 0x02111c11, 0x02121c10, 0x02131b10, 0x03131b0f,
782 0x03131b0f, 0x03141b0e, 0x04141b0d, 0x04151a0d,
783 0x05151a0c, 0x05151a0c, 0x05161a0b, 0x0616190b,
784 0x0616190b, 0x0716190a, 0x0717180a, 0x08171809,
785 0x08181808, 0x09181708, 0x09181708, 0x0a181707,
786 0x0a191607, 0x0b191606, 0x0b1a1605, 0x0c1a1505,
787 0x0c1a1505, 0x0d1a1504, 0x0d1b1404, 0x0e1b1403,
788 0x0f1b1303, 0x0f1b1303, 0x101b1302, 0x101c1202,
789
790 0x04111a11, 0x04121911, 0x04131910, 0x0513190f,
791 0x0513190f, 0x0513190f, 0x0613190e, 0x0614180e,
792 0x0714180d, 0x0714180d, 0x0715180c, 0x0814180c,
793 0x0815170c, 0x0816170b, 0x0916170a, 0x0916170a,
794 0x0a16160a, 0x0a171609, 0x0a171609, 0x0b171608,
795 0x0b171509, 0x0c171508, 0x0c181507, 0x0d171507,
796 0x0d181407, 0x0e181406, 0x0e181406, 0x0e191306,
797 0x0f191305, 0x0f191305, 0x10191304, 0x10191205,
798
799 0x05121811, 0x06121810, 0x06121810, 0x06131710,
800 0x0713170f, 0x0713170f, 0x0713170f, 0x0813170e,
801 0x0813170e, 0x0814170d, 0x0914160d, 0x0914160d,
802 0x0914160d, 0x0a14160c, 0x0a15160b, 0x0a15150c,
803 0x0b15150b, 0x0b15150b, 0x0b16150a, 0x0c15150a,
804 0x0c16140a, 0x0d161409, 0x0d161409, 0x0d171408,
805 0x0e161408, 0x0e171308, 0x0e171308, 0x0f171307,
806 0x0f171307, 0x10171306, 0x10181206, 0x10181206,
807
808 0x07111711, 0x07121710, 0x07121611, 0x08121610,
809 0x08121610, 0x0813160f, 0x0912160f, 0x0913160e,
810 0x0913160e, 0x0913160e, 0x0a14150d, 0x0a14150d,
811 0x0a14150d, 0x0b14150c, 0x0b14150c, 0x0b14150c,
812 0x0c14140c, 0x0c15140b, 0x0c15140b, 0x0c15140b,
813 0x0d15140a, 0x0d15140a, 0x0d15140a, 0x0e161309,
814 0x0e161309, 0x0e161309, 0x0f151309, 0x0f161308,
815 0x0f161209, 0x10161208, 0x10161208, 0x10171207,
816
817 0x0a111411, 0x0b111410, 0x0b111410, 0x0b111410,
818 0x0b111410, 0x0b12140f, 0x0b12140f, 0x0c12130f,
819 0x0c12130f, 0x0c12130f, 0x0c12130f, 0x0c12130f,
820 0x0d12130e, 0x0d12130e, 0x0d12130e, 0x0d13130d,
821 0x0d13130d, 0x0d13130d, 0x0e12130d, 0x0e13120d,
822 0x0e13120d, 0x0e13120d, 0x0e13120d, 0x0f13120c,
823 0x0f13120c, 0x0f13120c, 0x0f14120b, 0x0f14120b,
824 0x1013120b, 0x1013120b, 0x1013120b, 0x1014110b,
825
826 0x0c111310, 0x0c111310, 0x0c111310, 0x0d101310,
827 0x0d101310, 0x0d111210, 0x0d111210, 0x0d111210,
828 0x0d12120f, 0x0d12120f, 0x0d12120f, 0x0d12120f,
829 0x0e11120f, 0x0e12120e, 0x0e12120e, 0x0e12120e,
830 0x0e12120e, 0x0e12120e, 0x0e12120e, 0x0e12120e,
831 0x0f11120e, 0x0f12120d, 0x0f12120d, 0x0f12120d,
832 0x0f12120d, 0x0f12110e, 0x0f12110e, 0x0f12110e,
833 0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c,
834};
835
836static int sun8i_vi_scaler_coef_index(unsigned int step)
837{
838 unsigned int scale, int_part, float_part;
839
840 scale = step >> (SUN8I_VI_SCALER_SCALE_FRAC - 3);
841 int_part = scale >> 3;
842 float_part = scale & 0x7;
843
844 switch (int_part) {
845 case 0:
846 return 0;
847 case 1:
848 return float_part;
849 case 2:
850 return 8 + (float_part >> 1);
851 case 3:
852 return 12;
853 case 4:
854 return 13;
855 default:
856 return 14;
857 }
858}
859
860static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
861 u32 hstep, u32 vstep,
862 const struct drm_format_info *format)
863{
864 const u32 *ch_left, *ch_right, *cy;
865 int offset, i;
866
867 if (format->hsub == 1 && format->vsub == 1) {
868 ch_left = lan3coefftab32_left;
869 ch_right = lan3coefftab32_right;
870 cy = lan2coefftab32;
871 } else {
872 ch_left = bicubic8coefftab32_left;
873 ch_right = bicubic8coefftab32_right;
874 cy = bicubic4coefftab32;
875 }
876
877 offset = sun8i_vi_scaler_coef_index(hstep) *
878 SUN8I_VI_SCALER_COEFF_COUNT;
879 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
880 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(layer, i),
881 lan3coefftab32_left[offset + i]);
882 regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(layer, i),
883 lan3coefftab32_right[offset + i]);
884 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(layer, i),
885 ch_left[offset + i]);
886 regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(layer, i),
887 ch_right[offset + i]);
888 }
889
890 offset = sun8i_vi_scaler_coef_index(hstep) *
891 SUN8I_VI_SCALER_COEFF_COUNT;
892 for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
893 regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(layer, i),
894 lan2coefftab32[offset + i]);
895 regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(layer, i),
896 cy[offset + i]);
897 }
898}
899
900void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
901{
902 u32 val;
903
904 if (enable)
905 val = SUN8I_SCALER_VSU_CTRL_EN |
906 SUN8I_SCALER_VSU_CTRL_COEFF_RDY;
907 else
908 val = 0;
909
910 regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(layer), val);
911}
912
913void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
914 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
915 u32 hscale, u32 vscale, u32 hphase, u32 vphase,
916 const struct drm_format_info *format)
917{
918 u32 chphase, cvphase;
919 u32 insize, outsize;
920
921 hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
922 vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
923 hscale <<= SUN8I_VI_SCALER_SCALE_FRAC - 16;
924 vscale <<= SUN8I_VI_SCALER_SCALE_FRAC - 16;
925
926 insize = SUN8I_VI_SCALER_SIZE(src_w, src_h);
927 outsize = SUN8I_VI_SCALER_SIZE(dst_w, dst_h);
928
929 /*
930 * This is chroma V/H phase calculation as it appears in
931 * BSP driver. There is no detailed explanation. YUV 420
932 * chroma is threated specialy for some reason.
933 */
934 if (format->hsub == 2 && format->vsub == 2) {
935 chphase = hphase >> 1;
936 cvphase = (vphase >> 1) -
937 (1UL << (SUN8I_VI_SCALER_SCALE_FRAC - 2));
938 } else {
939 chphase = hphase;
940 cvphase = vphase;
941 }
942
943 regmap_write(mixer->engine.regs,
944 SUN8I_SCALER_VSU_OUTSIZE(layer), outsize);
945 regmap_write(mixer->engine.regs,
946 SUN8I_SCALER_VSU_YINSIZE(layer), insize);
947 regmap_write(mixer->engine.regs,
948 SUN8I_SCALER_VSU_YHSTEP(layer), hscale);
949 regmap_write(mixer->engine.regs,
950 SUN8I_SCALER_VSU_YVSTEP(layer), vscale);
951 regmap_write(mixer->engine.regs,
952 SUN8I_SCALER_VSU_YHPHASE(layer), hphase);
953 regmap_write(mixer->engine.regs,
954 SUN8I_SCALER_VSU_YVPHASE(layer), vphase);
955 regmap_write(mixer->engine.regs,
956 SUN8I_SCALER_VSU_CINSIZE(layer),
957 SUN8I_VI_SCALER_SIZE(src_w / format->hsub,
958 src_h / format->vsub));
959 regmap_write(mixer->engine.regs,
960 SUN8I_SCALER_VSU_CHSTEP(layer),
961 hscale / format->hsub);
962 regmap_write(mixer->engine.regs,
963 SUN8I_SCALER_VSU_CVSTEP(layer),
964 vscale / format->vsub);
965 regmap_write(mixer->engine.regs,
966 SUN8I_SCALER_VSU_CHPHASE(layer), chphase);
967 regmap_write(mixer->engine.regs,
968 SUN8I_SCALER_VSU_CVPHASE(layer), cvphase);
969 sun8i_vi_scaler_set_coeff(mixer->engine.regs, layer,
970 hscale, vscale, format);
971}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
new file mode 100644
index 000000000000..a595ab643a5a
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
3 *
4 * This file is licensed under the terms of the GNU General Public
5 * License version 2. This program is licensed "as is" without any
6 * warranty of any kind, whether express or implied.
7 */
8
9#ifndef _SUN8I_VI_SCALER_H_
10#define _SUN8I_VI_SCALER_H_
11
12#include <drm/drm_fourcc.h>
13#include "sun8i_mixer.h"
14
15/* this two macros assumes 16 fractional bits which is standard in DRM */
16#define SUN8I_VI_SCALER_SCALE_MIN 1
17#define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1)
18
19#define SUN8I_VI_SCALER_SCALE_FRAC 20
20#define SUN8I_VI_SCALER_PHASE_FRAC 20
21#define SUN8I_VI_SCALER_COEFF_COUNT 32
22#define SUN8I_VI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
23
24#define SUN8I_SCALER_VSU_CTRL(ch) (0x20000 + 0x20000 * (ch) + 0x0)
25#define SUN8I_SCALER_VSU_OUTSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x40)
26#define SUN8I_SCALER_VSU_YINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x80)
27#define SUN8I_SCALER_VSU_YHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x88)
28#define SUN8I_SCALER_VSU_YVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x8c)
29#define SUN8I_SCALER_VSU_YHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x90)
30#define SUN8I_SCALER_VSU_YVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x98)
31#define SUN8I_SCALER_VSU_CINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0xc0)
32#define SUN8I_SCALER_VSU_CHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xc8)
33#define SUN8I_SCALER_VSU_CVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xcc)
34#define SUN8I_SCALER_VSU_CHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd0)
35#define SUN8I_SCALER_VSU_CVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd8)
36#define SUN8I_SCALER_VSU_YHCOEFF0(ch, i) \
37 (0x20000 + 0x20000 * (ch) + 0x200 + 0x4 * (i))
38#define SUN8I_SCALER_VSU_YHCOEFF1(ch, i) \
39 (0x20000 + 0x20000 * (ch) + 0x300 + 0x4 * (i))
40#define SUN8I_SCALER_VSU_YVCOEFF(ch, i) \
41 (0x20000 + 0x20000 * (ch) + 0x400 + 0x4 * (i))
42#define SUN8I_SCALER_VSU_CHCOEFF0(ch, i) \
43 (0x20000 + 0x20000 * (ch) + 0x600 + 0x4 * (i))
44#define SUN8I_SCALER_VSU_CHCOEFF1(ch, i) \
45 (0x20000 + 0x20000 * (ch) + 0x700 + 0x4 * (i))
46#define SUN8I_SCALER_VSU_CVCOEFF(ch, i) \
47 (0x20000 + 0x20000 * (ch) + 0x800 + 0x4 * (i))
48
49#define SUN8I_SCALER_VSU_CTRL_EN BIT(0)
50#define SUN8I_SCALER_VSU_CTRL_COEFF_RDY BIT(4)
51
52void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
53void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
54 u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
55 u32 hscale, u32 vscale, u32 hphase, u32 vphase,
56 const struct drm_format_info *format);
57
58#endif
diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
index 2e790e7dced5..90c5bd5ef81b 100644
--- a/drivers/gpu/drm/tinydrm/Kconfig
+++ b/drivers/gpu/drm/tinydrm/Kconfig
@@ -12,6 +12,16 @@ menuconfig DRM_TINYDRM
12config TINYDRM_MIPI_DBI 12config TINYDRM_MIPI_DBI
13 tristate 13 tristate
14 14
15config TINYDRM_ILI9225
16 tristate "DRM support for ILI9225 display panels"
17 depends on DRM_TINYDRM && SPI
18 select TINYDRM_MIPI_DBI
19 help
20 DRM driver for the following Ilitek ILI9225 panels:
21 * No-name 2.2" color screen module
22
23 If M is selected the module will be called ili9225.
24
15config TINYDRM_MI0283QT 25config TINYDRM_MI0283QT
16 tristate "DRM support for MI0283QT" 26 tristate "DRM support for MI0283QT"
17 depends on DRM_TINYDRM && SPI 27 depends on DRM_TINYDRM && SPI
diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile
index 0c184bd1bb59..8aeee532474f 100644
--- a/drivers/gpu/drm/tinydrm/Makefile
+++ b/drivers/gpu/drm/tinydrm/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM) += core/
4obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o 4obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o
5 5
6# Displays 6# Displays
7obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o
7obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o 8obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o
8obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o 9obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o
9obj-$(CONFIG_TINYDRM_ST7586) += st7586.o 10obj-$(CONFIG_TINYDRM_ST7586) += st7586.o
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 1a8a57cad431..bd7b82824a34 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -292,71 +292,4 @@ void tinydrm_shutdown(struct tinydrm_device *tdev)
292} 292}
293EXPORT_SYMBOL(tinydrm_shutdown); 293EXPORT_SYMBOL(tinydrm_shutdown);
294 294
295/**
296 * tinydrm_suspend - Suspend tinydrm
297 * @tdev: tinydrm device
298 *
299 * Used in driver PM operations to suspend tinydrm.
300 * Suspends fbdev and DRM.
301 * Resume with tinydrm_resume().
302 *
303 * Returns:
304 * Zero on success, negative error code on failure.
305 */
306int tinydrm_suspend(struct tinydrm_device *tdev)
307{
308 struct drm_atomic_state *state;
309
310 if (tdev->suspend_state) {
311 DRM_ERROR("Failed to suspend: state already set\n");
312 return -EINVAL;
313 }
314
315 drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 1);
316 state = drm_atomic_helper_suspend(tdev->drm);
317 if (IS_ERR(state)) {
318 drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 0);
319 return PTR_ERR(state);
320 }
321
322 tdev->suspend_state = state;
323
324 return 0;
325}
326EXPORT_SYMBOL(tinydrm_suspend);
327
328/**
329 * tinydrm_resume - Resume tinydrm
330 * @tdev: tinydrm device
331 *
332 * Used in driver PM operations to resume tinydrm.
333 * Suspend with tinydrm_suspend().
334 *
335 * Returns:
336 * Zero on success, negative error code on failure.
337 */
338int tinydrm_resume(struct tinydrm_device *tdev)
339{
340 struct drm_atomic_state *state = tdev->suspend_state;
341 int ret;
342
343 if (!state) {
344 DRM_ERROR("Failed to resume: state is not set\n");
345 return -EINVAL;
346 }
347
348 tdev->suspend_state = NULL;
349
350 ret = drm_atomic_helper_resume(tdev->drm, state);
351 if (ret) {
352 DRM_ERROR("Error resuming state: %d\n", ret);
353 return ret;
354 }
355
356 drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 0);
357
358 return 0;
359}
360EXPORT_SYMBOL(tinydrm_resume);
361
362MODULE_LICENSE("GPL"); 295MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c
new file mode 100644
index 000000000000..3b766a26aa61
--- /dev/null
+++ b/drivers/gpu/drm/tinydrm/ili9225.c
@@ -0,0 +1,468 @@
1/*
2 * DRM driver for Ilitek ILI9225 panels
3 *
4 * Copyright 2017 David Lechner <david@lechnology.com>
5 *
6 * Some code copied from mipi-dbi.c
7 * Copyright 2016 Noralf Trønnes
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15#include <linux/delay.h>
16#include <linux/dma-buf.h>
17#include <linux/gpio/consumer.h>
18#include <linux/module.h>
19#include <linux/property.h>
20#include <linux/spi/spi.h>
21#include <video/mipi_display.h>
22
23#include <drm/drm_gem_framebuffer_helper.h>
24#include <drm/tinydrm/mipi-dbi.h>
25#include <drm/tinydrm/tinydrm-helpers.h>
26
27#define ILI9225_DRIVER_READ_CODE 0x00
28#define ILI9225_DRIVER_OUTPUT_CONTROL 0x01
29#define ILI9225_LCD_AC_DRIVING_CONTROL 0x02
30#define ILI9225_ENTRY_MODE 0x03
31#define ILI9225_DISPLAY_CONTROL_1 0x07
32#define ILI9225_BLANK_PERIOD_CONTROL_1 0x08
33#define ILI9225_FRAME_CYCLE_CONTROL 0x0b
34#define ILI9225_INTERFACE_CONTROL 0x0c
35#define ILI9225_OSCILLATION_CONTROL 0x0f
36#define ILI9225_POWER_CONTROL_1 0x10
37#define ILI9225_POWER_CONTROL_2 0x11
38#define ILI9225_POWER_CONTROL_3 0x12
39#define ILI9225_POWER_CONTROL_4 0x13
40#define ILI9225_POWER_CONTROL_5 0x14
41#define ILI9225_VCI_RECYCLING 0x15
42#define ILI9225_RAM_ADDRESS_SET_1 0x20
43#define ILI9225_RAM_ADDRESS_SET_2 0x21
44#define ILI9225_WRITE_DATA_TO_GRAM 0x22
45#define ILI9225_SOFTWARE_RESET 0x28
46#define ILI9225_GATE_SCAN_CONTROL 0x30
47#define ILI9225_VERTICAL_SCROLL_1 0x31
48#define ILI9225_VERTICAL_SCROLL_2 0x32
49#define ILI9225_VERTICAL_SCROLL_3 0x33
50#define ILI9225_PARTIAL_DRIVING_POS_1 0x34
51#define ILI9225_PARTIAL_DRIVING_POS_2 0x35
52#define ILI9225_HORIZ_WINDOW_ADDR_1 0x36
53#define ILI9225_HORIZ_WINDOW_ADDR_2 0x37
54#define ILI9225_VERT_WINDOW_ADDR_1 0x38
55#define ILI9225_VERT_WINDOW_ADDR_2 0x39
56#define ILI9225_GAMMA_CONTROL_1 0x50
57#define ILI9225_GAMMA_CONTROL_2 0x51
58#define ILI9225_GAMMA_CONTROL_3 0x52
59#define ILI9225_GAMMA_CONTROL_4 0x53
60#define ILI9225_GAMMA_CONTROL_5 0x54
61#define ILI9225_GAMMA_CONTROL_6 0x55
62#define ILI9225_GAMMA_CONTROL_7 0x56
63#define ILI9225_GAMMA_CONTROL_8 0x57
64#define ILI9225_GAMMA_CONTROL_9 0x58
65#define ILI9225_GAMMA_CONTROL_10 0x59
66
67static inline int ili9225_command(struct mipi_dbi *mipi, u8 cmd, u16 data)
68{
69 u8 par[2] = { data >> 8, data & 0xff };
70
71 return mipi_dbi_command_buf(mipi, cmd, par, 2);
72}
73
74static int ili9225_fb_dirty(struct drm_framebuffer *fb,
75 struct drm_file *file_priv, unsigned int flags,
76 unsigned int color, struct drm_clip_rect *clips,
77 unsigned int num_clips)
78{
79 struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
80 struct tinydrm_device *tdev = fb->dev->dev_private;
81 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
82 bool swap = mipi->swap_bytes;
83 struct drm_clip_rect clip;
84 u16 x_start, y_start;
85 u16 x1, x2, y1, y2;
86 int ret = 0;
87 bool full;
88 void *tr;
89
90 mutex_lock(&tdev->dirty_lock);
91
92 if (!mipi->enabled)
93 goto out_unlock;
94
95 /* fbdev can flush even when we're not interested */
96 if (tdev->pipe.plane.fb != fb)
97 goto out_unlock;
98
99 full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
100 fb->width, fb->height);
101
102 DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
103 clip.x1, clip.x2, clip.y1, clip.y2);
104
105 if (!mipi->dc || !full || swap ||
106 fb->format->format == DRM_FORMAT_XRGB8888) {
107 tr = mipi->tx_buf;
108 ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap);
109 if (ret)
110 goto out_unlock;
111 } else {
112 tr = cma_obj->vaddr;
113 }
114
115 switch (mipi->rotation) {
116 default:
117 x1 = clip.x1;
118 x2 = clip.x2 - 1;
119 y1 = clip.y1;
120 y2 = clip.y2 - 1;
121 x_start = x1;
122 y_start = y1;
123 break;
124 case 90:
125 x1 = clip.y1;
126 x2 = clip.y2 - 1;
127 y1 = fb->width - clip.x2;
128 y2 = fb->width - clip.x1 - 1;
129 x_start = x1;
130 y_start = y2;
131 break;
132 case 180:
133 x1 = fb->width - clip.x2;
134 x2 = fb->width - clip.x1 - 1;
135 y1 = fb->height - clip.y2;
136 y2 = fb->height - clip.y1 - 1;
137 x_start = x2;
138 y_start = y2;
139 break;
140 case 270:
141 x1 = fb->height - clip.y2;
142 x2 = fb->height - clip.y1 - 1;
143 y1 = clip.x1;
144 y2 = clip.x2 - 1;
145 x_start = x2;
146 y_start = y1;
147 break;
148 }
149
150 ili9225_command(mipi, ILI9225_HORIZ_WINDOW_ADDR_1, x2);
151 ili9225_command(mipi, ILI9225_HORIZ_WINDOW_ADDR_2, x1);
152 ili9225_command(mipi, ILI9225_VERT_WINDOW_ADDR_1, y2);
153 ili9225_command(mipi, ILI9225_VERT_WINDOW_ADDR_2, y1);
154
155 ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_1, x_start);
156 ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, y_start);
157
158 ret = mipi_dbi_command_buf(mipi, ILI9225_WRITE_DATA_TO_GRAM, tr,
159 (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
160
161out_unlock:
162 mutex_unlock(&tdev->dirty_lock);
163
164 if (ret)
165 dev_err_once(fb->dev->dev, "Failed to update display %d\n",
166 ret);
167
168 return ret;
169}
170
171static const struct drm_framebuffer_funcs ili9225_fb_funcs = {
172 .destroy = drm_gem_fb_destroy,
173 .create_handle = drm_gem_fb_create_handle,
174 .dirty = ili9225_fb_dirty,
175};
176
177static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
178 struct drm_crtc_state *crtc_state)
179{
180 struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
181 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
182 struct drm_framebuffer *fb = pipe->plane.fb;
183 struct device *dev = tdev->drm->dev;
184 int ret;
185 u8 am_id;
186
187 DRM_DEBUG_KMS("\n");
188
189 mipi_dbi_hw_reset(mipi);
190
191 /*
192 * There don't seem to be two example init sequences that match, so
193 * using the one from the popular Arduino library for this display.
194 * https://github.com/Nkawu/TFT_22_ILI9225/blob/master/src/TFT_22_ILI9225.cpp
195 */
196
197 ret = ili9225_command(mipi, ILI9225_POWER_CONTROL_1, 0x0000);
198 if (ret) {
199 DRM_DEV_ERROR(dev, "Error sending command %d\n", ret);
200 return;
201 }
202 ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x0000);
203 ili9225_command(mipi, ILI9225_POWER_CONTROL_3, 0x0000);
204 ili9225_command(mipi, ILI9225_POWER_CONTROL_4, 0x0000);
205 ili9225_command(mipi, ILI9225_POWER_CONTROL_5, 0x0000);
206
207 msleep(40);
208
209 ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x0018);
210 ili9225_command(mipi, ILI9225_POWER_CONTROL_3, 0x6121);
211 ili9225_command(mipi, ILI9225_POWER_CONTROL_4, 0x006f);
212 ili9225_command(mipi, ILI9225_POWER_CONTROL_5, 0x495f);
213 ili9225_command(mipi, ILI9225_POWER_CONTROL_1, 0x0800);
214
215 msleep(10);
216
217 ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x103b);
218
219 msleep(50);
220
221 switch (mipi->rotation) {
222 default:
223 am_id = 0x30;
224 break;
225 case 90:
226 am_id = 0x18;
227 break;
228 case 180:
229 am_id = 0x00;
230 break;
231 case 270:
232 am_id = 0x28;
233 break;
234 }
235 ili9225_command(mipi, ILI9225_DRIVER_OUTPUT_CONTROL, 0x011c);
236 ili9225_command(mipi, ILI9225_LCD_AC_DRIVING_CONTROL, 0x0100);
237 ili9225_command(mipi, ILI9225_ENTRY_MODE, 0x1000 | am_id);
238 ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x0000);
239 ili9225_command(mipi, ILI9225_BLANK_PERIOD_CONTROL_1, 0x0808);
240 ili9225_command(mipi, ILI9225_FRAME_CYCLE_CONTROL, 0x1100);
241 ili9225_command(mipi, ILI9225_INTERFACE_CONTROL, 0x0000);
242 ili9225_command(mipi, ILI9225_OSCILLATION_CONTROL, 0x0d01);
243 ili9225_command(mipi, ILI9225_VCI_RECYCLING, 0x0020);
244 ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_1, 0x0000);
245 ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, 0x0000);
246
247 ili9225_command(mipi, ILI9225_GATE_SCAN_CONTROL, 0x0000);
248 ili9225_command(mipi, ILI9225_VERTICAL_SCROLL_1, 0x00db);
249 ili9225_command(mipi, ILI9225_VERTICAL_SCROLL_2, 0x0000);
250 ili9225_command(mipi, ILI9225_VERTICAL_SCROLL_3, 0x0000);
251 ili9225_command(mipi, ILI9225_PARTIAL_DRIVING_POS_1, 0x00db);
252 ili9225_command(mipi, ILI9225_PARTIAL_DRIVING_POS_2, 0x0000);
253
254 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_1, 0x0000);
255 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_2, 0x0808);
256 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_3, 0x080a);
257 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_4, 0x000a);
258 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_5, 0x0a08);
259 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_6, 0x0808);
260 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_7, 0x0000);
261 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_8, 0x0a00);
262 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_9, 0x0710);
263 ili9225_command(mipi, ILI9225_GAMMA_CONTROL_10, 0x0710);
264
265 ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x0012);
266
267 msleep(50);
268
269 ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017);
270
271 mipi->enabled = true;
272
273 if (fb)
274 fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
275}
276
277static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe)
278{
279 struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
280 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
281
282 DRM_DEBUG_KMS("\n");
283
284 if (!mipi->enabled)
285 return;
286
287 ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x0000);
288 msleep(50);
289 ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x0007);
290 msleep(50);
291 ili9225_command(mipi, ILI9225_POWER_CONTROL_1, 0x0a02);
292
293 mipi->enabled = false;
294}
295
296static int ili9225_dbi_command(struct mipi_dbi *mipi, u8 cmd, u8 *par,
297 size_t num)
298{
299 struct spi_device *spi = mipi->spi;
300 unsigned int bpw = 8;
301 u32 speed_hz;
302 int ret;
303
304 gpiod_set_value_cansleep(mipi->dc, 0);
305 speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
306 ret = tinydrm_spi_transfer(spi, speed_hz, NULL, 8, &cmd, 1);
307 if (ret || !num)
308 return ret;
309
310 if (cmd == ILI9225_WRITE_DATA_TO_GRAM && !mipi->swap_bytes)
311 bpw = 16;
312
313 gpiod_set_value_cansleep(mipi->dc, 1);
314 speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
315
316 return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num);
317}
318
319static const u32 ili9225_formats[] = {
320 DRM_FORMAT_RGB565,
321 DRM_FORMAT_XRGB8888,
322};
323
324static int ili9225_init(struct device *dev, struct mipi_dbi *mipi,
325 const struct drm_simple_display_pipe_funcs *pipe_funcs,
326 struct drm_driver *driver,
327 const struct drm_display_mode *mode,
328 unsigned int rotation)
329{
330 size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
331 struct tinydrm_device *tdev = &mipi->tinydrm;
332 int ret;
333
334 if (!mipi->command)
335 return -EINVAL;
336
337 mutex_init(&mipi->cmdlock);
338
339 mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
340 if (!mipi->tx_buf)
341 return -ENOMEM;
342
343 ret = devm_tinydrm_init(dev, tdev, &ili9225_fb_funcs, driver);
344 if (ret)
345 return ret;
346
347 ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
348 DRM_MODE_CONNECTOR_VIRTUAL,
349 ili9225_formats,
350 ARRAY_SIZE(ili9225_formats), mode,
351 rotation);
352 if (ret)
353 return ret;
354
355 tdev->drm->mode_config.preferred_depth = 16;
356 mipi->rotation = rotation;
357
358 drm_mode_config_reset(tdev->drm);
359
360 DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
361 tdev->drm->mode_config.preferred_depth, rotation);
362
363 return 0;
364}
365
366static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = {
367 .enable = ili9225_pipe_enable,
368 .disable = ili9225_pipe_disable,
369 .update = tinydrm_display_pipe_update,
370 .prepare_fb = tinydrm_display_pipe_prepare_fb,
371};
372
373static const struct drm_display_mode ili9225_mode = {
374 TINYDRM_MODE(176, 220, 35, 44),
375};
376
377DEFINE_DRM_GEM_CMA_FOPS(ili9225_fops);
378
379static struct drm_driver ili9225_driver = {
380 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
381 DRIVER_ATOMIC,
382 .fops = &ili9225_fops,
383 TINYDRM_GEM_DRIVER_OPS,
384 .lastclose = tinydrm_lastclose,
385 .name = "ili9225",
386 .desc = "Ilitek ILI9225",
387 .date = "20171106",
388 .major = 1,
389 .minor = 0,
390};
391
392static const struct of_device_id ili9225_of_match[] = {
393 { .compatible = "ilitek,ili9225-2.2in-176x220" },
394 {},
395};
396MODULE_DEVICE_TABLE(of, ili9225_of_match);
397
398static const struct spi_device_id ili9225_id[] = {
399 { "ili9225-2.2in-176x220", 0 },
400 { },
401};
402MODULE_DEVICE_TABLE(spi, ili9225_id);
403
404static int ili9225_probe(struct spi_device *spi)
405{
406 struct device *dev = &spi->dev;
407 struct mipi_dbi *mipi;
408 struct gpio_desc *rs;
409 u32 rotation = 0;
410 int ret;
411
412 mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
413 if (!mipi)
414 return -ENOMEM;
415
416 mipi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
417 if (IS_ERR(mipi->reset)) {
418 DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
419 return PTR_ERR(mipi->reset);
420 }
421
422 rs = devm_gpiod_get(dev, "rs", GPIOD_OUT_LOW);
423 if (IS_ERR(rs)) {
424 DRM_DEV_ERROR(dev, "Failed to get gpio 'rs'\n");
425 return PTR_ERR(rs);
426 }
427
428 device_property_read_u32(dev, "rotation", &rotation);
429
430 ret = mipi_dbi_spi_init(spi, mipi, rs);
431 if (ret)
432 return ret;
433
434 /* override the command function set in mipi_dbi_spi_init() */
435 mipi->command = ili9225_dbi_command;
436
437 ret = ili9225_init(&spi->dev, mipi, &ili9225_pipe_funcs,
438 &ili9225_driver, &ili9225_mode, rotation);
439 if (ret)
440 return ret;
441
442 spi_set_drvdata(spi, mipi);
443
444 return devm_tinydrm_register(&mipi->tinydrm);
445}
446
447static void ili9225_shutdown(struct spi_device *spi)
448{
449 struct mipi_dbi *mipi = spi_get_drvdata(spi);
450
451 tinydrm_shutdown(&mipi->tinydrm);
452}
453
454static struct spi_driver ili9225_spi_driver = {
455 .driver = {
456 .name = "ili9225",
457 .owner = THIS_MODULE,
458 .of_match_table = ili9225_of_match,
459 },
460 .id_table = ili9225_id,
461 .probe = ili9225_probe,
462 .shutdown = ili9225_shutdown,
463};
464module_spi_driver(ili9225_spi_driver);
465
466MODULE_DESCRIPTION("Ilitek ILI9225 DRM driver");
467MODULE_AUTHOR("David Lechner <david@lechnology.com>");
468MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c
index 6a83b3093254..70ae4f76f455 100644
--- a/drivers/gpu/drm/tinydrm/mi0283qt.c
+++ b/drivers/gpu/drm/tinydrm/mi0283qt.c
@@ -9,6 +9,7 @@
9 * (at your option) any later version. 9 * (at your option) any later version.
10 */ 10 */
11 11
12#include <drm/drm_modeset_helper.h>
12#include <drm/tinydrm/ili9341.h> 13#include <drm/tinydrm/ili9341.h>
13#include <drm/tinydrm/mipi-dbi.h> 14#include <drm/tinydrm/mipi-dbi.h>
14#include <drm/tinydrm/tinydrm-helpers.h> 15#include <drm/tinydrm/tinydrm-helpers.h>
@@ -231,7 +232,7 @@ static int __maybe_unused mi0283qt_pm_suspend(struct device *dev)
231 struct mipi_dbi *mipi = dev_get_drvdata(dev); 232 struct mipi_dbi *mipi = dev_get_drvdata(dev);
232 int ret; 233 int ret;
233 234
234 ret = tinydrm_suspend(&mipi->tinydrm); 235 ret = drm_mode_config_helper_suspend(mipi->tinydrm.drm);
235 if (ret) 236 if (ret)
236 return ret; 237 return ret;
237 238
@@ -249,7 +250,9 @@ static int __maybe_unused mi0283qt_pm_resume(struct device *dev)
249 if (ret) 250 if (ret)
250 return ret; 251 return ret;
251 252
252 return tinydrm_resume(&mipi->tinydrm); 253 drm_mode_config_helper_resume(mipi->tinydrm.drm);
254
255 return 0;
253} 256}
254 257
255static const struct dev_pm_ops mi0283qt_pm_ops = { 258static const struct dev_pm_ops mi0283qt_pm_ops = {
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c
index 347f9b226f26..aa6b6ce56891 100644
--- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
+++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
@@ -154,8 +154,18 @@ int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len)
154} 154}
155EXPORT_SYMBOL(mipi_dbi_command_buf); 155EXPORT_SYMBOL(mipi_dbi_command_buf);
156 156
157static int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, 157/**
158 struct drm_clip_rect *clip, bool swap) 158 * mipi_dbi_buf_copy - Copy a framebuffer, transforming it if necessary
159 * @dst: The destination buffer
160 * @fb: The source framebuffer
161 * @clip: Clipping rectangle of the area to be copied
162 * @swap: When true, swap MSB/LSB of 16-bit values
163 *
164 * Returns:
165 * Zero on success, negative error code on failure.
166 */
167int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
168 struct drm_clip_rect *clip, bool swap)
159{ 169{
160 struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 170 struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
161 struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; 171 struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
@@ -192,6 +202,7 @@ static int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
192 DMA_FROM_DEVICE); 202 DMA_FROM_DEVICE);
193 return ret; 203 return ret;
194} 204}
205EXPORT_SYMBOL(mipi_dbi_buf_copy);
195 206
196static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb, 207static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
197 struct drm_file *file_priv, 208 struct drm_file *file_priv,
@@ -444,18 +455,23 @@ EXPORT_SYMBOL(mipi_dbi_display_is_on);
444 455
445#if IS_ENABLED(CONFIG_SPI) 456#if IS_ENABLED(CONFIG_SPI)
446 457
447/* 458/**
459 * mipi_dbi_spi_cmd_max_speed - get the maximum SPI bus speed
460 * @spi: SPI device
461 * @len: The transfer buffer length.
462 *
448 * Many controllers have a max speed of 10MHz, but can be pushed way beyond 463 * Many controllers have a max speed of 10MHz, but can be pushed way beyond
449 * that. Increase reliability by running pixel data at max speed and the rest 464 * that. Increase reliability by running pixel data at max speed and the rest
450 * at 10MHz, preventing transfer glitches from messing up the init settings. 465 * at 10MHz, preventing transfer glitches from messing up the init settings.
451 */ 466 */
452static u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len) 467u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
453{ 468{
454 if (len > 64) 469 if (len > 64)
455 return 0; /* use default */ 470 return 0; /* use default */
456 471
457 return min_t(u32, 10000000, spi->max_speed_hz); 472 return min_t(u32, 10000000, spi->max_speed_hz);
458} 473}
474EXPORT_SYMBOL(mipi_dbi_spi_cmd_max_speed);
459 475
460/* 476/*
461 * MIPI DBI Type C Option 1 477 * MIPI DBI Type C Option 1
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 2f615b7f1c9f..2566cfbdebfb 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -772,6 +772,7 @@ config FB_VESA
772config FB_EFI 772config FB_EFI
773 bool "EFI-based Framebuffer Support" 773 bool "EFI-based Framebuffer Support"
774 depends on (FB = y) && !IA64 && EFI 774 depends on (FB = y) && !IA64 && EFI
775 select DRM_PANEL_ORIENTATION_QUIRKS
775 select FB_CFB_FILLRECT 776 select FB_CFB_FILLRECT
776 select FB_CFB_COPYAREA 777 select FB_CFB_COPYAREA
777 select FB_CFB_IMAGEBLIT 778 select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
index d34fd182ca68..37710316a680 100644
--- a/drivers/video/fbdev/core/Makefile
+++ b/drivers/video/fbdev/core/Makefile
@@ -15,9 +15,6 @@ ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y)
15fb-y += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \ 15fb-y += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
16 fbcon_ccw.o 16 fbcon_ccw.o
17endif 17endif
18ifeq ($(CONFIG_DMI),y)
19fb-y += fbcon_dmi_quirks.o
20endif
21endif 18endif
22fb-objs := $(fb-y) 19fb-objs := $(fb-y)
23 20
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 929ca472c524..5baf7bc054e1 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -964,10 +964,13 @@ static const char *fbcon_startup(void)
964 ops->cur_blink_jiffies = HZ / 5; 964 ops->cur_blink_jiffies = HZ / 5;
965 ops->info = info; 965 ops->info = info;
966 info->fbcon_par = ops; 966 info->fbcon_par = ops;
967 if (initial_rotation != -1) 967
968 p->con_rotate = initial_rotation; 968 p->con_rotate = initial_rotation;
969 else 969 if (p->con_rotate == -1)
970 p->con_rotate = fbcon_platform_get_rotate(info); 970 p->con_rotate = info->fbcon_rotate_hint;
971 if (p->con_rotate == -1)
972 p->con_rotate = FB_ROTATE_UR;
973
971 set_blitting_type(vc, info); 974 set_blitting_type(vc, info);
972 975
973 if (info->fix.type != FB_TYPE_TEXT) { 976 if (info->fix.type != FB_TYPE_TEXT) {
@@ -1104,10 +1107,13 @@ static void fbcon_init(struct vc_data *vc, int init)
1104 1107
1105 ops = info->fbcon_par; 1108 ops = info->fbcon_par;
1106 ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); 1109 ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
1107 if (initial_rotation != -1) 1110
1108 p->con_rotate = initial_rotation; 1111 p->con_rotate = initial_rotation;
1109 else 1112 if (p->con_rotate == -1)
1110 p->con_rotate = fbcon_platform_get_rotate(info); 1113 p->con_rotate = info->fbcon_rotate_hint;
1114 if (p->con_rotate == -1)
1115 p->con_rotate = FB_ROTATE_UR;
1116
1111 set_blitting_type(vc, info); 1117 set_blitting_type(vc, info);
1112 1118
1113 cols = vc->vc_cols; 1119 cols = vc->vc_cols;
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 9f7744fbc962..21912a3ba32f 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -262,10 +262,4 @@ extern void fbcon_set_rotate(struct fbcon_ops *ops);
262#define fbcon_set_rotate(x) do {} while(0) 262#define fbcon_set_rotate(x) do {} while(0)
263#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ 263#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
264 264
265#ifdef CONFIG_DMI
266int fbcon_platform_get_rotate(struct fb_info *info);
267#else
268#define fbcon_platform_get_rotate(i) FB_ROTATE_UR
269#endif /* CONFIG_DMI */
270
271#endif /* _VIDEO_FBCON_H */ 265#endif /* _VIDEO_FBCON_H */
diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c
index 15755ce1d26c..e31a182b42bf 100644
--- a/drivers/video/fbdev/core/fbsysfs.c
+++ b/drivers/video/fbdev/core/fbsysfs.c
@@ -58,6 +58,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
58 info->par = p + fb_info_size; 58 info->par = p + fb_info_size;
59 59
60 info->device = dev; 60 info->device = dev;
61 info->fbcon_rotate_hint = -1;
61 62
62#ifdef CONFIG_FB_BACKLIGHT 63#ifdef CONFIG_FB_BACKLIGHT
63 mutex_init(&info->bl_curve_mutex); 64 mutex_init(&info->bl_curve_mutex);
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index d1bf9c2a78a7..46a4484e3da7 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -16,6 +16,8 @@
16#include <linux/screen_info.h> 16#include <linux/screen_info.h>
17#include <video/vga.h> 17#include <video/vga.h>
18#include <asm/efi.h> 18#include <asm/efi.h>
19#include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
20#include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */
19 21
20static bool request_mem_succeeded = false; 22static bool request_mem_succeeded = false;
21static bool nowc = false; 23static bool nowc = false;
@@ -157,7 +159,7 @@ static u64 bar_offset;
157static int efifb_probe(struct platform_device *dev) 159static int efifb_probe(struct platform_device *dev)
158{ 160{
159 struct fb_info *info; 161 struct fb_info *info;
160 int err; 162 int err, orientation;
161 unsigned int size_vmode; 163 unsigned int size_vmode;
162 unsigned int size_remap; 164 unsigned int size_remap;
163 unsigned int size_total; 165 unsigned int size_total;
@@ -329,6 +331,23 @@ static int efifb_probe(struct platform_device *dev)
329 info->fix = efifb_fix; 331 info->fix = efifb_fix;
330 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; 332 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
331 333
334 orientation = drm_get_panel_orientation_quirk(efifb_defined.xres,
335 efifb_defined.yres);
336 switch (orientation) {
337 default:
338 info->fbcon_rotate_hint = FB_ROTATE_UR;
339 break;
340 case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
341 info->fbcon_rotate_hint = FB_ROTATE_UD;
342 break;
343 case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
344 info->fbcon_rotate_hint = FB_ROTATE_CCW;
345 break;
346 case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
347 info->fbcon_rotate_hint = FB_ROTATE_CW;
348 break;
349 }
350
332 err = sysfs_create_groups(&dev->dev.kobj, efifb_groups); 351 err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
333 if (err) { 352 if (err) {
334 pr_err("efifb: cannot add sysfs attrs\n"); 353 pr_err("efifb: cannot add sysfs attrs\n");
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 66d6c99d15e5..f39ff52feb3b 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -176,6 +176,35 @@ enum drm_link_status {
176}; 176};
177 177
178/** 178/**
179 * enum drm_panel_orientation - panel_orientation info for &drm_display_info
180 *
181 * This enum is used to track the (LCD) panel orientation. There are no
182 * separate #defines for the uapi!
183 *
184 * @DRM_MODE_PANEL_ORIENTATION_UNKNOWN: The drm driver has not provided any
185 * panel orientation information (normal
186 * for non panels) in this case the "panel
187 * orientation" connector prop will not be
188 * attached.
189 * @DRM_MODE_PANEL_ORIENTATION_NORMAL: The top side of the panel matches the
190 * top side of the device's casing.
191 * @DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP: The top side of the panel matches the
192 * bottom side of the device's casing, iow
193 * the panel is mounted upside-down.
194 * @DRM_MODE_PANEL_ORIENTATION_LEFT_UP: The left side of the panel matches the
195 * top side of the device's casing.
196 * @DRM_MODE_PANEL_ORIENTATION_RIGHT_UP: The right side of the panel matches the
197 * top side of the device's casing.
198 */
199enum drm_panel_orientation {
200 DRM_MODE_PANEL_ORIENTATION_UNKNOWN = -1,
201 DRM_MODE_PANEL_ORIENTATION_NORMAL = 0,
202 DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP,
203 DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
204 DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
205};
206
207/**
179 * struct drm_display_info - runtime data about the connected sink 208 * struct drm_display_info - runtime data about the connected sink
180 * 209 *
181 * Describes a given display (e.g. CRT or flat panel) and its limitations. For 210 * Describes a given display (e.g. CRT or flat panel) and its limitations. For
@@ -223,6 +252,15 @@ struct drm_display_info {
223#define DRM_COLOR_FORMAT_YCRCB420 (1<<3) 252#define DRM_COLOR_FORMAT_YCRCB420 (1<<3)
224 253
225 /** 254 /**
255 * @panel_orientation: Read only connector property for built-in panels,
256 * indicating the orientation of the panel vs the device's casing.
257 * drm_connector_init() sets this to DRM_MODE_PANEL_ORIENTATION_UNKNOWN.
258 * When not UNKNOWN this gets used by the drm_fb_helpers to rotate the
259 * fb to compensate and gets exported as prop to userspace.
260 */
261 int panel_orientation;
262
263 /**
226 * @color_formats: HDMI Color formats, selects between RGB and YCrCb 264 * @color_formats: HDMI Color formats, selects between RGB and YCrCb
227 * modes. Used DRM_COLOR_FORMAT\_ defines, which are _not_ the same ones 265 * modes. Used DRM_COLOR_FORMAT\_ defines, which are _not_ the same ones
228 * as used to describe the pixel format in framebuffers, and also don't 266 * as used to describe the pixel format in framebuffers, and also don't
@@ -1035,6 +1073,8 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
1035 const struct edid *edid); 1073 const struct edid *edid);
1036void drm_mode_connector_set_link_status_property(struct drm_connector *connector, 1074void drm_mode_connector_set_link_status_property(struct drm_connector *connector,
1037 uint64_t link_status); 1075 uint64_t link_status);
1076int drm_connector_init_panel_orientation_property(
1077 struct drm_connector *connector, int width, int height);
1038 1078
1039/** 1079/**
1040 * struct drm_tile_group - Tile group metadata 1080 * struct drm_tile_group - Tile group metadata
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 877e5b395c02..1494b12a984a 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -48,6 +48,7 @@ struct drm_fb_helper_crtc {
48 struct drm_mode_set mode_set; 48 struct drm_mode_set mode_set;
49 struct drm_display_mode *desired_mode; 49 struct drm_display_mode *desired_mode;
50 int x, y; 50 int x, y;
51 int rotation;
51}; 52};
52 53
53/** 54/**
@@ -159,6 +160,13 @@ struct drm_fb_helper {
159 int connector_count; 160 int connector_count;
160 int connector_info_alloc_count; 161 int connector_info_alloc_count;
161 /** 162 /**
163 * @sw_rotations:
164 * Bitmask of all rotations requested for panel-orientation which
165 * could not be handled in hardware. If only one bit is set
166 * fbdev->fbcon_rotate_hint gets set to the requested rotation.
167 */
168 int sw_rotations;
169 /**
162 * @connector_info: 170 * @connector_info:
163 * 171 *
164 * Array of per-connector information. Do not iterate directly, but use 172 * Array of per-connector information. Do not iterate directly, but use
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 5306ebd537b2..a0afeb591dcb 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -735,6 +735,13 @@ struct drm_mode_config {
735 */ 735 */
736 struct drm_property *non_desktop_property; 736 struct drm_property *non_desktop_property;
737 737
738 /**
739 * @panel_orientation_property: Optional connector property indicating
740 * how the lcd-panel is mounted inside the casing (e.g. normal or
741 * upside-down).
742 */
743 struct drm_property *panel_orientation_property;
744
738 /* dumb ioctl parameters */ 745 /* dumb ioctl parameters */
739 uint32_t preferred_depth, prefer_shadow; 746 uint32_t preferred_depth, prefer_shadow;
740 747
@@ -760,6 +767,15 @@ struct drm_mode_config {
760 /* cursor size */ 767 /* cursor size */
761 uint32_t cursor_width, cursor_height; 768 uint32_t cursor_width, cursor_height;
762 769
770 /**
771 * @suspend_state:
772 *
773 * Atomic state when suspended.
774 * Set by drm_mode_config_helper_suspend() and cleared by
775 * drm_mode_config_helper_resume().
776 */
777 struct drm_atomic_state *suspend_state;
778
763 const struct drm_mode_config_helper_funcs *helper_private; 779 const struct drm_mode_config_helper_funcs *helper_private;
764}; 780};
765 781
diff --git a/include/drm/drm_modeset_helper.h b/include/drm/drm_modeset_helper.h
index cb0ec92e11e6..efa337f03129 100644
--- a/include/drm/drm_modeset_helper.h
+++ b/include/drm/drm_modeset_helper.h
@@ -34,4 +34,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
34int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 34int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
35 const struct drm_crtc_funcs *funcs); 35 const struct drm_crtc_funcs *funcs);
36 36
37int drm_mode_config_helper_suspend(struct drm_device *dev);
38int drm_mode_config_helper_resume(struct drm_device *dev);
39
37#endif 40#endif
diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h
new file mode 100644
index 000000000000..a803988d8579
--- /dev/null
+++ b/include/drm/drm_utils.h
@@ -0,0 +1,15 @@
1/* SPDX-License-Identifier: MIT */
2/*
3 * Function prototypes for misc. drm utility functions.
4 * Specifically this file is for function prototypes for functions which
5 * may also be used outside of drm code (e.g. in fbdev drivers).
6 *
7 * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
8 */
9
10#ifndef __DRM_UTILS_H__
11#define __DRM_UTILS_H__
12
13int drm_get_panel_orientation_quirk(int width, int height);
14
15#endif
diff --git a/include/drm/tinydrm/mipi-dbi.h b/include/drm/tinydrm/mipi-dbi.h
index 83346ddb9dba..5d0e82b36eaf 100644
--- a/include/drm/tinydrm/mipi-dbi.h
+++ b/include/drm/tinydrm/mipi-dbi.h
@@ -72,10 +72,12 @@ void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe,
72void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe); 72void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe);
73void mipi_dbi_hw_reset(struct mipi_dbi *mipi); 73void mipi_dbi_hw_reset(struct mipi_dbi *mipi);
74bool mipi_dbi_display_is_on(struct mipi_dbi *mipi); 74bool mipi_dbi_display_is_on(struct mipi_dbi *mipi);
75u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len);
75 76
76int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val); 77int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val);
77int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len); 78int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len);
78 79int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
80 struct drm_clip_rect *clip, bool swap);
79/** 81/**
80 * mipi_dbi_command - MIPI DCS command with optional parameter(s) 82 * mipi_dbi_command - MIPI DCS command with optional parameter(s)
81 * @mipi: MIPI structure 83 * @mipi: MIPI structure
diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h
index 423828922e5a..03cd9d72308c 100644
--- a/include/drm/tinydrm/tinydrm.h
+++ b/include/drm/tinydrm/tinydrm.h
@@ -20,7 +20,6 @@
20 * @pipe: Display pipe structure 20 * @pipe: Display pipe structure
21 * @dirty_lock: Serializes framebuffer flushing 21 * @dirty_lock: Serializes framebuffer flushing
22 * @fbdev_cma: CMA fbdev structure 22 * @fbdev_cma: CMA fbdev structure
23 * @suspend_state: Atomic state when suspended
24 * @fb_funcs: Framebuffer functions used when creating framebuffers 23 * @fb_funcs: Framebuffer functions used when creating framebuffers
25 */ 24 */
26struct tinydrm_device { 25struct tinydrm_device {
@@ -28,7 +27,6 @@ struct tinydrm_device {
28 struct drm_simple_display_pipe pipe; 27 struct drm_simple_display_pipe pipe;
29 struct mutex dirty_lock; 28 struct mutex dirty_lock;
30 struct drm_fbdev_cma *fbdev_cma; 29 struct drm_fbdev_cma *fbdev_cma;
31 struct drm_atomic_state *suspend_state;
32 const struct drm_framebuffer_funcs *fb_funcs; 30 const struct drm_framebuffer_funcs *fb_funcs;
33}; 31};
34 32
@@ -93,8 +91,6 @@ int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
93 struct drm_driver *driver); 91 struct drm_driver *driver);
94int devm_tinydrm_register(struct tinydrm_device *tdev); 92int devm_tinydrm_register(struct tinydrm_device *tdev);
95void tinydrm_shutdown(struct tinydrm_device *tdev); 93void tinydrm_shutdown(struct tinydrm_device *tdev);
96int tinydrm_suspend(struct tinydrm_device *tdev);
97int tinydrm_resume(struct tinydrm_device *tdev);
98 94
99void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe, 95void tinydrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
100 struct drm_plane_state *old_state); 96 struct drm_plane_state *old_state);
diff --git a/include/linux/fb.h b/include/linux/fb.h
index bc24e48e396d..d1e5bed39140 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -465,6 +465,11 @@ struct fb_info {
465 atomic_t count; 465 atomic_t count;
466 int node; 466 int node;
467 int flags; 467 int flags;
468 /*
469 * -1 by default, set to a FB_ROTATE_* value by the driver, if it knows
470 * a lcd is not mounted upright and fbcon should rotate to compensate.
471 */
472 int fbcon_rotate_hint;
468 struct mutex lock; /* Lock for open/release/ioctl funcs */ 473 struct mutex lock; /* Lock for open/release/ioctl funcs */
469 struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */ 474 struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
470 struct fb_var_screeninfo var; /* Current var */ 475 struct fb_var_screeninfo var; /* Current var */