summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-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.c174
-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
70 files changed, 3600 insertions, 599 deletions
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 @@
menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA
+ select DRM_PANEL_ORIENTATION_QUIRKS
select HDMI
select FB_CMDLINE
select I2C
@@ -26,6 +27,10 @@ config DRM_MIPI_DSI
bool
depends on DRM
+# Separate option because drm_panel_orientation_quirks.c is shared with fbdev
+config DRM_PANEL_ORIENTATION_QUIRKS
+ tristate
+
config DRM_DP_AUX_CHARDEV
bool "DRM DP AUX Interface"
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/
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
+obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
obj-$(CONFIG_DRM_ARM) += arm/
obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(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 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_of.h>
#include "malidp_drv.h"
@@ -745,34 +746,15 @@ static int malidp_platform_remove(struct platform_device *pdev)
static int __maybe_unused malidp_pm_suspend(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct malidp_drm *malidp = drm->dev_private;
-
- drm_kms_helper_poll_disable(drm);
- console_lock();
- drm_fbdev_cma_set_suspend(malidp->fbdev, 1);
- console_unlock();
- malidp->pm_state = drm_atomic_helper_suspend(drm);
- if (IS_ERR(malidp->pm_state)) {
- console_lock();
- drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
- console_unlock();
- drm_kms_helper_poll_enable(drm);
- return PTR_ERR(malidp->pm_state);
- }
- return 0;
+ return drm_mode_config_helper_suspend(drm);
}
static int __maybe_unused malidp_pm_resume(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct malidp_drm *malidp = drm->dev_private;
- drm_atomic_helper_resume(drm, malidp->pm_state);
- console_lock();
- drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
- console_unlock();
- drm_kms_helper_poll_enable(drm);
+ drm_mode_config_helper_resume(drm);
return 0;
}
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 {
struct drm_crtc crtc;
wait_queue_head_t wq;
atomic_t config_valid;
- struct drm_atomic_state *pm_state;
u32 core_id;
};
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 @@
#include <drm/drm_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_utils.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@@ -212,6 +213,8 @@ int drm_connector_init(struct drm_device *dev,
mutex_init(&connector->mutex);
connector->edid_blob_ptr = NULL;
connector->status = connector_status_unknown;
+ connector->display_info.panel_orientation =
+ DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
drm_connector_get_cmdline_mode(connector);
@@ -668,6 +671,13 @@ static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
{ DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
};
+static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = {
+ { DRM_MODE_PANEL_ORIENTATION_NORMAL, "Normal" },
+ { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, "Upside Down" },
+ { DRM_MODE_PANEL_ORIENTATION_LEFT_UP, "Left Side Up" },
+ { DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, "Right Side Up" },
+};
+
static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
@@ -776,6 +786,18 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
*
* CRTC_ID:
* Mode object ID of the &drm_crtc this connector should be connected to.
+ *
+ * Connectors for LCD panels may also have one standardized property:
+ *
+ * panel orientation:
+ * On some devices the LCD panel is mounted in the casing in such a way
+ * that the up/top side of the panel does not match with the top side of
+ * the device. Userspace can use this property to check for this.
+ * Note that input coordinates from touchscreens (input devices with
+ * INPUT_PROP_DIRECT) will still map 1:1 to the actual LCD panel
+ * coordinates, so if userspace rotates the picture to adjust for
+ * the orientation it must also apply the same transformation to the
+ * touchscreen input coordinates.
*/
int 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
}
EXPORT_SYMBOL(drm_mode_connector_set_link_status_property);
+/**
+ * drm_connector_init_panel_orientation_property -
+ * initialize the connecters panel_orientation property
+ * @connector: connector for which to init the panel-orientation property.
+ * @width: width in pixels of the panel, used for panel quirk detection
+ * @height: height in pixels of the panel, used for panel quirk detection
+ *
+ * This function should only be called for built-in panels, after setting
+ * connector->display_info.panel_orientation first (if known).
+ *
+ * This function will check for platform specific (e.g. DMI based) quirks
+ * overriding display_info.panel_orientation first, then if panel_orientation
+ * is not DRM_MODE_PANEL_ORIENTATION_UNKNOWN it will attach the
+ * "panel orientation" property to the connector.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_init_panel_orientation_property(
+ struct drm_connector *connector, int width, int height)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_property *prop;
+ int orientation_quirk;
+
+ orientation_quirk = drm_get_panel_orientation_quirk(width, height);
+ if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+ info->panel_orientation = orientation_quirk;
+
+ if (info->panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
+ return 0;
+
+ prop = dev->mode_config.panel_orientation_property;
+ if (!prop) {
+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+ "panel orientation",
+ drm_panel_orientation_enum_list,
+ ARRAY_SIZE(drm_panel_orientation_enum_list));
+ if (!prop)
+ return -ENOMEM;
+
+ dev->mode_config.panel_orientation_property = prop;
+ }
+
+ drm_object_attach_property(&connector->base, prop,
+ info->panel_orientation);
+ return 0;
+}
+EXPORT_SYMBOL(drm_connector_init_panel_orientation_property);
+
int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
struct drm_property *property,
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 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include "drm_crtc_internal.h"
#include "drm_crtc_helper_internal.h"
static bool drm_fbdev_emulation = true;
@@ -177,7 +178,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
*/
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
{
- struct drm_device *dev = fb_helper->dev;
+ struct drm_device *dev;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int i, ret = 0;
@@ -185,6 +186,8 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
if (!drm_fbdev_emulation || !fb_helper)
return 0;
+ dev = fb_helper->dev;
+
mutex_lock(&fb_helper->lock);
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
@@ -356,6 +359,7 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave);
static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
{
struct drm_device *dev = fb_helper->dev;
+ struct drm_plane_state *plane_state;
struct drm_plane *plane;
struct drm_atomic_state *state;
int i, ret;
@@ -374,8 +378,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
retry:
plane_mask = 0;
drm_for_each_plane(plane, dev) {
- struct drm_plane_state *plane_state;
-
plane_state = drm_atomic_get_plane_state(state, plane);
if (IS_ERR(plane_state)) {
ret = PTR_ERR(plane_state);
@@ -398,6 +400,11 @@ retry:
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+ struct drm_plane *primary = mode_set->crtc->primary;
+
+ /* Cannot fail as we've already gotten the plane state above */
+ plane_state = drm_atomic_get_new_plane_state(state, primary);
+ plane_state->rotation = fb_helper->crtc_info[i].rotation;
ret = __drm_atomic_helper_set_config(mode_set, state);
if (ret != 0)
@@ -829,6 +836,7 @@ int drm_fb_helper_init(struct drm_device *dev,
if (!fb_helper->crtc_info[i].mode_set.connectors)
goto out_free;
fb_helper->crtc_info[i].mode_set.num_connectors = 0;
+ fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
}
i = 0;
@@ -2357,6 +2365,62 @@ out:
return best_score;
}
+/*
+ * This function checks if rotation is necessary because of panel orientation
+ * and if it is, if it is supported.
+ * If rotation is necessary and supported, its gets set in fb_crtc.rotation.
+ * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
+ * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
+ * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
+ * the unsupported rotation.
+ */
+static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_crtc *fb_crtc,
+ struct drm_connector *connector)
+{
+ struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
+ uint64_t valid_mask = 0;
+ int i, rotation;
+
+ fb_crtc->rotation = DRM_MODE_ROTATE_0;
+
+ switch (connector->display_info.panel_orientation) {
+ case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+ rotation = DRM_MODE_ROTATE_180;
+ break;
+ case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+ rotation = DRM_MODE_ROTATE_90;
+ break;
+ case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+ rotation = DRM_MODE_ROTATE_270;
+ break;
+ default:
+ rotation = DRM_MODE_ROTATE_0;
+ }
+
+ /*
+ * TODO: support 90 / 270 degree hardware rotation,
+ * depending on the hardware this may require the framebuffer
+ * to be in a specific tiling format.
+ */
+ if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) {
+ fb_helper->sw_rotations |= rotation;
+ return;
+ }
+
+ for (i = 0; i < plane->rotation_property->num_values; i++)
+ valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+ if (!(rotation & valid_mask)) {
+ fb_helper->sw_rotations |= rotation;
+ return;
+ }
+
+ fb_crtc->rotation = rotation;
+ /* Rotating in hardware, fbcon should not rotate */
+ fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
+}
+
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
u32 width, u32 height)
{
@@ -2416,6 +2480,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
drm_fb_helper_modeset_release(fb_helper,
&fb_helper->crtc_info[i].mode_set);
+ fb_helper->sw_rotations = 0;
drm_fb_helper_for_each_connector(fb_helper, i) {
struct drm_display_mode *mode = modes[i];
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
@@ -2435,6 +2500,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
modeset->mode = drm_mode_duplicate(dev,
fb_crtc->desired_mode);
drm_connector_get(connector);
+ drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
modeset->connectors[modeset->num_connectors++] = connector;
modeset->x = offset->x;
modeset->y = offset->y;
@@ -2476,6 +2542,28 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
}
}
mutex_unlock(&fb_helper->dev->mode_config.mutex);
+
+ switch (fb_helper->sw_rotations) {
+ case DRM_MODE_ROTATE_0:
+ info->fbcon_rotate_hint = FB_ROTATE_UR;
+ break;
+ case DRM_MODE_ROTATE_90:
+ info->fbcon_rotate_hint = FB_ROTATE_CCW;
+ break;
+ case DRM_MODE_ROTATE_180:
+ info->fbcon_rotate_hint = FB_ROTATE_UD;
+ break;
+ case DRM_MODE_ROTATE_270:
+ info->fbcon_rotate_hint = FB_ROTATE_CW;
+ break;
+ default:
+ /*
+ * Multiple bits are set / multiple rotations requested
+ * fbcon cannot handle separate rotation settings per
+ * output, so fallback to unrotated.
+ */
+ info->fbcon_rotate_hint = FB_ROTATE_UR;
+ }
}
/* 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 @@
* OF THIS SOFTWARE.
*/
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_plane_helper.h>
@@ -156,3 +159,76 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
NULL);
}
EXPORT_SYMBOL(drm_crtc_init);
+
+/**
+ * drm_mode_config_helper_suspend - Modeset suspend helper
+ * @dev: DRM device
+ *
+ * This helper function takes care of suspending the modeset side. It disables
+ * output polling if initialized, suspends fbdev if used and finally calls
+ * drm_atomic_helper_suspend().
+ * If suspending fails, fbdev and polling is re-enabled.
+ *
+ * Returns:
+ * Zero on success, negative error code on error.
+ *
+ * See also:
+ * drm_kms_helper_poll_disable() and drm_fb_helper_set_suspend_unlocked().
+ */
+int drm_mode_config_helper_suspend(struct drm_device *dev)
+{
+ struct drm_atomic_state *state;
+
+ if (!dev)
+ return 0;
+
+ drm_kms_helper_poll_disable(dev);
+ drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 1);
+ state = drm_atomic_helper_suspend(dev);
+ if (IS_ERR(state)) {
+ drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
+ drm_kms_helper_poll_enable(dev);
+ return PTR_ERR(state);
+ }
+
+ dev->mode_config.suspend_state = state;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_mode_config_helper_suspend);
+
+/**
+ * drm_mode_config_helper_resume - Modeset resume helper
+ * @dev: DRM device
+ *
+ * This helper function takes care of resuming the modeset side. It calls
+ * drm_atomic_helper_resume(), resumes fbdev if used and enables output polling
+ * if initiaized.
+ *
+ * Returns:
+ * Zero on success, negative error code on error.
+ *
+ * See also:
+ * drm_fb_helper_set_suspend_unlocked() and drm_kms_helper_poll_enable().
+ */
+int drm_mode_config_helper_resume(struct drm_device *dev)
+{
+ int ret;
+
+ if (!dev)
+ return 0;
+
+ if (WARN_ON(!dev->mode_config.suspend_state))
+ return -EINVAL;
+
+ ret = drm_atomic_helper_resume(dev, dev->mode_config.suspend_state);
+ if (ret)
+ DRM_ERROR("Failed to resume (%d)\n", ret);
+ dev->mode_config.suspend_state = NULL;
+
+ drm_fb_helper_set_suspend_unlocked(dev->fb_helper, 0);
+ drm_kms_helper_poll_enable(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_mode_config_helper_resume);
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
new file mode 100644
index 000000000000..901a4e9a87a3
--- /dev/null
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * drm_panel_orientation_quirks.c -- Quirks for non-normal panel orientation
+ *
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Note the quirks in this file are shared with fbdev/efifb and as such
+ * must not depend on other drm code.
+ */
+
+#include <linux/dmi.h>
+#include <drm/drm_connector.h>
+
+#ifdef CONFIG_DMI
+
+/*
+ * Some x86 clamshell design devices use portrait tablet screens and a display
+ * engine which cannot rotate in hardware, so we need to rotate the fbcon to
+ * compensate. Unfortunately these (cheap) devices also typically have quite
+ * generic DMI data, so we match on a combination of DMI data, screen resolution
+ * and a list of known BIOS dates to avoid false positives.
+ */
+
+struct drm_dmi_panel_orientation_data {
+ int width;
+ int height;
+ const char * const *bios_dates;
+ int orientation;
+};
+
+static const struct drm_dmi_panel_orientation_data asus_t100ha = {
+ .width = 800,
+ .height = 1280,
+ .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
+};
+
+static const struct drm_dmi_panel_orientation_data gpd_pocket = {
+ .width = 1200,
+ .height = 1920,
+ .bios_dates = (const char * const []){ "05/26/2017", "06/28/2017",
+ "07/05/2017", "08/07/2017", NULL },
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
+static const struct drm_dmi_panel_orientation_data gpd_win = {
+ .width = 720,
+ .height = 1280,
+ .bios_dates = (const char * const []){
+ "10/25/2016", "11/18/2016", "12/23/2016", "12/26/2016",
+ "02/21/2017", "03/20/2017", "05/25/2017", NULL },
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
+static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
+ .width = 800,
+ .height = 1280,
+ .bios_dates = (const char * const []){ "10/16/2015", NULL },
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
+static const struct drm_dmi_panel_orientation_data vios_lth17 = {
+ .width = 800,
+ .height = 1280,
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
+static const struct dmi_system_id orientation_data[] = {
+ { /* Asus T100HA */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
+ },
+ .driver_data = (void *)&asus_t100ha,
+ }, { /*
+ * GPD Pocket, note that the the DMI data is less generic then
+ * it seems, devices with a board-vendor of "AMI Corporation"
+ * are quite rare, as are devices which have both board- *and*
+ * product-id set to "Default String"
+ */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
+ DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ },
+ .driver_data = (void *)&gpd_pocket,
+ }, { /* GPD Win (same note on DMI match as GPD Pocket) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
+ DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ },
+ .driver_data = (void *)&gpd_win,
+ }, { /* I.T.Works TW891 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"),
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"),
+ },
+ .driver_data = (void *)&itworks_tw891,
+ }, { /* VIOS LTH17 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"),
+ },
+ .driver_data = (void *)&vios_lth17,
+ },
+ {}
+};
+
+/**
+ * drm_get_panel_orientation_quirk - Check for panel orientation quirks
+ * @width: width in pixels of the panel
+ * @height: height in pixels of the panel
+ *
+ * This function checks for platform specific (e.g. DMI based) quirks
+ * providing info on panel_orientation for systems where this cannot be
+ * probed from the hard-/firm-ware. To avoid false-positive this function
+ * takes the panel resolution as argument and checks that against the
+ * resolution expected by the quirk-table entry.
+ *
+ * Note this function is also used outside of the drm-subsys, by for example
+ * the efifb code. Because of this this function gets compiled into its own
+ * kernel-module when built as a module.
+ *
+ * Returns:
+ * A DRM_MODE_PANEL_ORIENTATION_* value if there is a quirk for this system,
+ * or DRM_MODE_PANEL_ORIENTATION_UNKNOWN if there is no quirk.
+ */
+int drm_get_panel_orientation_quirk(int width, int height)
+{
+ const struct dmi_system_id *match;
+ const struct drm_dmi_panel_orientation_data *data;
+ const char *bios_date;
+ int i;
+
+ for (match = dmi_first_match(orientation_data);
+ match;
+ match = dmi_first_match(match + 1)) {
+ data = match->driver_data;
+
+ if (data->width != width ||
+ data->height != height)
+ continue;
+
+ if (!data->bios_dates)
+ return data->orientation;
+
+ bios_date = dmi_get_system_info(DMI_BIOS_DATE);
+ if (!bios_date)
+ continue;
+
+ for (i = 0; data->bios_dates[i]; i++) {
+ if (!strcmp(data->bios_dates[i], bios_date))
+ return data->orientation;
+ }
+ }
+
+ return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+}
+EXPORT_SYMBOL(drm_get_panel_orientation_quirk);
+
+#else
+
+/* There are no quirks for non x86 devices yet */
+int drm_get_panel_orientation_quirk(int width, int height)
+{
+ return DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+}
+EXPORT_SYMBOL(drm_get_panel_orientation_quirk);
+
+#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,
sgt = prime_attach->sgt;
if (sgt) {
if (prime_attach->dir != DMA_NONE)
- dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
- prime_attach->dir);
+ dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents,
+ prime_attach->dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
}
@@ -277,7 +278,8 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
if (!IS_ERR(sgt)) {
- if (!dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir)) {
+ if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
+ DMA_ATTR_SKIP_CPU_SYNC)) {
sg_free_table(sgt);
kfree(sgt);
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,
* suspend/resume.
*
* Drivers can call this helper from their device resume implementation. It is
- * an error to call this when the output polling support has not yet been set
- * up.
+ * not an error to call this even when output polling isn't enabled.
*
* Note that calls to enable and disable polling must be strictly ordered, which
* 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 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_modeset_helper.h>
#include "fsl_dcu_drm_crtc.h"
#include "fsl_dcu_drm_drv.h"
@@ -188,26 +189,17 @@ static struct drm_driver fsl_dcu_drm_driver = {
static int fsl_dcu_drm_pm_suspend(struct device *dev)
{
struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
+ int ret;
if (!fsl_dev)
return 0;
disable_irq(fsl_dev->irq);
- drm_kms_helper_poll_disable(fsl_dev->drm);
-
- console_lock();
- drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 1);
- console_unlock();
-
- fsl_dev->state = drm_atomic_helper_suspend(fsl_dev->drm);
- if (IS_ERR(fsl_dev->state)) {
- console_lock();
- drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 0);
- console_unlock();
- drm_kms_helper_poll_enable(fsl_dev->drm);
+ ret = drm_mode_config_helper_suspend(fsl_dev->drm);
+ if (ret) {
enable_irq(fsl_dev->irq);
- return PTR_ERR(fsl_dev->state);
+ return ret;
}
clk_disable_unprepare(fsl_dev->clk);
@@ -233,13 +225,8 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
fsl_tcon_bypass_enable(fsl_dev->tcon);
fsl_dcu_drm_init_planes(fsl_dev->drm);
enable_irq(fsl_dev->irq);
- drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state);
-
- console_lock();
- drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 0);
- console_unlock();
- drm_kms_helper_poll_enable(fsl_dev->drm);
+ drm_mode_config_helper_resume(fsl_dev->drm);
return 0;
}
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 {
struct drm_encoder encoder;
struct fsl_dcu_drm_connector connector;
const struct fsl_dcu_soc_data *soc;
- struct drm_atomic_state *state;
};
int 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 = {
.atomic_duplicate_state = intel_digital_connector_duplicate_state,
};
+static int intel_dsi_get_panel_orientation(struct intel_connector *connector)
+{
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ int orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+ enum plane plane;
+ u32 val;
+
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ if (connector->encoder->crtc_mask == BIT(PIPE_B))
+ plane = PLANE_B;
+ else
+ plane = PLANE_A;
+
+ val = I915_READ(DSPCNTR(plane));
+ if (val & DISPPLANE_ROTATE_180)
+ orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+ }
+
+ return orientation;
+}
+
static void intel_dsi_add_properties(struct intel_connector *connector)
{
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)
allowed_scalers);
connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
+
+ connector->base.display_info.panel_orientation =
+ intel_dsi_get_panel_orientation(connector);
+ drm_connector_init_panel_orientation_property(
+ &connector->base,
+ connector->panel.fixed_mode->hdisplay,
+ connector->panel.fixed_mode->vdisplay);
}
}
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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Vincent Abriou <vincent.abriou@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2013
* Authors: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#include <linux/seq_file.h>
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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#include <linux/seq_file.h>
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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Vincent Abriou <vincent.abriou@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#include <linux/seq_file.h>
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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2014
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* Vincent Abriou <vincent.abriou@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2017
*
@@ -5,8 +6,6 @@
* Yannick Fertre <yannick.fertre@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* Mickael Reulier <mickael.reulier@st.com>
- *
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2017
*
* Authors: Philippe Cornu <philippe.cornu@st.com>
* Yannick Fertre <yannick.fertre@st.com>
- *
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2017
*
@@ -5,8 +6,6 @@
* Yannick Fertre <yannick.fertre@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* Mickael Reulier <mickael.reulier@st.com>
- *
- * License terms: GNU General Public License (GPL), version 2
*/
#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 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2017
*
@@ -5,8 +6,6 @@
* Yannick Fertre <yannick.fertre@st.com>
* Fabien Dessenne <fabien.dessenne@st.com>
* Mickael Reulier <mickael.reulier@st.com>
- *
- * License terms: GNU General Public License (GPL), version 2
*/
#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
sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
-sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
+sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
+ sun8i_vi_layer.o sun8i_ui_scaler.o \
+ sun8i_vi_scaler.o sun8i_csc.o
sun4i-tcon-y += sun4i_crtc.o
sun4i-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)
static bool sun4i_drv_node_is_tcon(struct device_node *node)
{
- return of_device_is_compatible(node, "allwinner,sun4i-a10-tcon") ||
- of_device_is_compatible(node, "allwinner,sun5i-a13-tcon") ||
- of_device_is_compatible(node, "allwinner,sun6i-a31-tcon") ||
- of_device_is_compatible(node, "allwinner,sun6i-a31s-tcon") ||
- of_device_is_compatible(node, "allwinner,sun7i-a20-tcon") ||
- of_device_is_compatible(node, "allwinner,sun8i-a33-tcon") ||
- of_device_is_compatible(node, "allwinner,sun8i-v3s-tcon");
+ return !!of_match_node(sun4i_tcon_of_table, node);
}
static 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 = {
/* nothing is supported */
};
-static const struct of_device_id sun4i_tcon_of_table[] = {
+/* sun4i_drv uses this list to check if a device node is a TCON */
+const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
{ .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
@@ -911,6 +912,7 @@ static const struct of_device_id sun4i_tcon_of_table[] = {
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
+EXPORT_SYMBOL(sun4i_tcon_of_table);
static struct platform_driver sun4i_tcon_platform_driver = {
.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,
void sun4i_tcon_set_status(struct sun4i_tcon *crtc,
const struct drm_encoder *encoder, bool enable);
+extern const struct of_device_id sun4i_tcon_of_table[];
+
#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 @@
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+
+#include "sun8i_csc.h"
+#include "sun8i_mixer.h"
+
+static const u32 ccsc_base[2][2] = {
+ {CCSC00_OFFSET, CCSC01_OFFSET},
+ {CCSC10_OFFSET, CCSC11_OFFSET},
+};
+
+/*
+ * Factors are in two's complement format, 10 bits for fractinal part.
+ * First tree values in each line are multiplication factor and last
+ * value is constant, which is added at the end.
+ */
+static const u32 yuv2rgb[] = {
+ 0x000004A8, 0x00000000, 0x00000662, 0xFFFC845A,
+ 0x000004A8, 0xFFFFFE6F, 0xFFFFFCBF, 0x00021DF4,
+ 0x000004A8, 0x00000813, 0x00000000, 0xFFFBAC4A,
+};
+
+static const u32 yvu2rgb[] = {
+ 0x000004A8, 0x00000662, 0x00000000, 0xFFFC845A,
+ 0x000004A8, 0xFFFFFCBF, 0xFFFFFE6F, 0x00021DF4,
+ 0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A,
+};
+
+static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
+ enum sun8i_csc_mode mode)
+{
+ const u32 *table;
+ int i, data;
+
+ switch (mode) {
+ case SUN8I_CSC_MODE_YUV2RGB:
+ table = yuv2rgb;
+ break;
+ case SUN8I_CSC_MODE_YVU2RGB:
+ table = yvu2rgb;
+ break;
+ default:
+ DRM_WARN("Wrong CSC mode specified.\n");
+ return;
+ }
+
+ for (i = 0; i < 12; i++) {
+ data = table[i];
+ /* For some reason, 0x200 must be added to constant parts */
+ if (((i + 1) & 3) == 0)
+ data += 0x200;
+ regmap_write(map, SUN8I_CSC_COEFF(base, i), data);
+ }
+}
+
+static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = SUN8I_CSC_CTRL_EN;
+ else
+ val = 0;
+
+ regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
+}
+
+void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
+ enum sun8i_csc_mode mode)
+{
+ u32 base;
+
+ base = ccsc_base[mixer->cfg->ccsc][layer];
+
+ sun8i_csc_set_coefficients(mixer->engine.regs, base, mode);
+}
+
+void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
+{
+ u32 base;
+
+ base = ccsc_base[mixer->cfg->ccsc][layer];
+
+ sun8i_csc_enable(mixer->engine.regs, base, enable);
+}
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 @@
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN8I_CSC_H_
+#define _SUN8I_CSC_H_
+
+struct sun8i_mixer;
+
+/* VI channel CSC units offsets */
+#define CCSC00_OFFSET 0xAA050
+#define CCSC01_OFFSET 0xFA000
+#define CCSC10_OFFSET 0xA0000
+#define CCSC11_OFFSET 0xF0000
+
+#define SUN8I_CSC_CTRL(base) (base + 0x0)
+#define SUN8I_CSC_COEFF(base, i) (base + 0x10 + 4 * i)
+
+#define SUN8I_CSC_CTRL_EN BIT(0)
+
+enum sun8i_csc_mode {
+ SUN8I_CSC_MODE_OFF,
+ SUN8I_CSC_MODE_YUV2RGB,
+ SUN8I_CSC_MODE_YVU2RGB,
+};
+
+void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
+ enum sun8i_csc_mode mode);
+void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable);
+
+#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 @@
-/*
- * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
- *
- * Based on sun4i_layer.h, which is:
- * Copyright (C) 2015 Free Electrons
- * Copyright (C) 2015 NextThing Co
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drmP.h>
-
-#include "sun8i_layer.h"
-#include "sun8i_mixer.h"
-
-struct sun8i_plane_desc {
- enum drm_plane_type type;
- const uint32_t *formats;
- uint32_t nformats;
-};
-
-static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
- struct drm_plane_state *old_state)
-{
- struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
- struct sun8i_mixer *mixer = layer->mixer;
-
- sun8i_mixer_layer_enable(mixer, layer->id, false);
-}
-
-static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
- struct drm_plane_state *old_state)
-{
- struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
- struct sun8i_mixer *mixer = layer->mixer;
-
- sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
- sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
- sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
- sun8i_mixer_layer_enable(mixer, layer->id, true);
-}
-
-static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = {
- .atomic_disable = sun8i_mixer_layer_atomic_disable,
- .atomic_update = sun8i_mixer_layer_atomic_update,
-};
-
-static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .destroy = drm_plane_cleanup,
- .disable_plane = drm_atomic_helper_disable_plane,
- .reset = drm_atomic_helper_plane_reset,
- .update_plane = drm_atomic_helper_update_plane,
-};
-
-static const uint32_t sun8i_mixer_layer_formats[] = {
- DRM_FORMAT_RGB888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_XRGB8888,
-};
-
-static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
- {
- .type = DRM_PLANE_TYPE_PRIMARY,
- .formats = sun8i_mixer_layer_formats,
- .nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
- },
-};
-
-static struct sun8i_layer *sun8i_layer_init_one(struct drm_device *drm,
- struct sun8i_mixer *mixer,
- const struct sun8i_plane_desc *plane)
-{
- struct sun8i_layer *layer;
- int ret;
-
- layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
- if (!layer)
- return ERR_PTR(-ENOMEM);
-
- /* possible crtcs are set later */
- ret = drm_universal_plane_init(drm, &layer->plane, 0,
- &sun8i_mixer_layer_funcs,
- plane->formats, plane->nformats,
- NULL, plane->type, NULL);
- if (ret) {
- dev_err(drm->dev, "Couldn't initialize layer\n");
- return ERR_PTR(ret);
- }
-
- drm_plane_helper_add(&layer->plane,
- &sun8i_mixer_layer_helper_funcs);
- layer->mixer = mixer;
-
- return layer;
-}
-
-struct drm_plane **sun8i_layers_init(struct drm_device *drm,
- struct sunxi_engine *engine)
-{
- struct drm_plane **planes;
- struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
- int i;
-
- planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
- sizeof(*planes), GFP_KERNEL);
- if (!planes)
- return ERR_PTR(-ENOMEM);
-
- for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
- const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
- struct sun8i_layer *layer;
-
- layer = sun8i_layer_init_one(drm, mixer, plane);
- if (IS_ERR(layer)) {
- dev_err(drm->dev, "Couldn't initialize %s plane\n",
- i ? "overlay" : "primary");
- return ERR_CAST(layer);
- };
-
- layer->id = i;
- planes[i] = &layer->plane;
- };
-
- return planes;
-}
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 @@
-/*
- * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
- *
- * Based on sun4i_layer.h, which is:
- * Copyright (C) 2015 Free Electrons
- * Copyright (C) 2015 NextThing Co
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
-#ifndef _SUN8I_LAYER_H_
-#define _SUN8I_LAYER_H_
-
-struct sunxi_engine;
-
-struct sun8i_layer {
- struct drm_plane plane;
- struct sun4i_drv *drv;
- struct sun8i_mixer *mixer;
- int id;
-};
-
-static inline struct sun8i_layer *
-plane_to_sun8i_layer(struct drm_plane *plane)
-{
- return container_of(plane, struct sun8i_layer, plane);
-}
-
-struct drm_plane **sun8i_layers_init(struct drm_device *drm,
- struct sunxi_engine *engine);
-#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 @@
#include "sun4i_drv.h"
#include "sun8i_mixer.h"
-#include "sun8i_layer.h"
+#include "sun8i_ui_layer.h"
+#include "sun8i_vi_layer.h"
#include "sunxi_engine.h"
-static void sun8i_mixer_commit(struct sunxi_engine *engine)
-{
- DRM_DEBUG_DRIVER("Committing changes\n");
-
- regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
- SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
-}
-
-void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
- int layer, bool enable)
-{
- u32 val;
- /* Currently the first UI channel is used */
- int chan = mixer->cfg->vi_num;
-
- DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
-
- if (enable)
- val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
- else
- val = 0;
-
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
-
- /* Set the alpha configuration */
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
-}
-
-static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
- u32 format, u32 *mode)
-{
- switch (format) {
- case DRM_FORMAT_ARGB8888:
- *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888;
- break;
-
- case DRM_FORMAT_XRGB8888:
- *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
- break;
-
- case DRM_FORMAT_RGB888:
- *mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
+static const struct de2_fmt_info de2_formats[] = {
+ {
+ .drm_fmt = DRM_FORMAT_ARGB8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_ARGB8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_ABGR8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_ABGR8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_RGBA8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGBA8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_BGRA8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_BGRA8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_XRGB8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_XRGB8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_XBGR8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_XBGR8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_RGBX8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGBX8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_BGRX8888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_BGRX8888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_RGB888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_BGR888,
+ .de2_fmt = SUN8I_MIXER_FBFMT_BGR888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_RGB565,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGB565,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_BGR565,
+ .de2_fmt = SUN8I_MIXER_FBFMT_BGR565,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_ARGB4444,
+ .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_ABGR4444,
+ .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_RGBA4444,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_BGRA4444,
+ .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_ARGB1555,
+ .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_ABGR1555,
+ .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_RGBA5551,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_BGRA5551,
+ .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_OFF,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_UYVY,
+ .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_VYUY,
+ .de2_fmt = SUN8I_MIXER_FBFMT_VYUY,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YUYV,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUYV,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YVYU,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YVYU,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_NV16,
+ .de2_fmt = SUN8I_MIXER_FBFMT_NV16,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_NV61,
+ .de2_fmt = SUN8I_MIXER_FBFMT_NV61,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_NV12,
+ .de2_fmt = SUN8I_MIXER_FBFMT_NV12,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_NV21,
+ .de2_fmt = SUN8I_MIXER_FBFMT_NV21,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YUV444,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YUV422,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YUV420,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YUV411,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YUV2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YVU444,
+ .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
+ .rgb = true,
+ .csc = SUN8I_CSC_MODE_YVU2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YVU422,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YVU2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YVU420,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUV420,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YVU2RGB,
+ },
+ {
+ .drm_fmt = DRM_FORMAT_YVU411,
+ .de2_fmt = SUN8I_MIXER_FBFMT_YUV411,
+ .rgb = false,
+ .csc = SUN8I_CSC_MODE_YVU2RGB,
+ },
+};
-int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
- int layer, struct drm_plane *plane)
+const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
{
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- /* Currently the first UI channel is used */
- int chan = mixer->cfg->vi_num;
-
- DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
-
- if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
- DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
- state->crtc_w, state->crtc_h);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
- SUN8I_MIXER_SIZE(state->crtc_w,
- state->crtc_h));
- DRM_DEBUG_DRIVER("Updating blender size\n");
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
- SUN8I_MIXER_SIZE(state->crtc_w,
- state->crtc_h));
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
- SUN8I_MIXER_SIZE(state->crtc_w,
- state->crtc_h));
- DRM_DEBUG_DRIVER("Updating channel size\n");
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
- SUN8I_MIXER_SIZE(state->crtc_w,
- state->crtc_h));
- }
+ unsigned int i;
- /* Set the line width */
- DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
- fb->pitches[0]);
-
- /* Set height and width */
- DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
- state->crtc_w, state->crtc_h);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
- SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
-
- /* Set base coordinates */
- DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
- state->crtc_x, state->crtc_y);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
- SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
+ for (i = 0; i < ARRAY_SIZE(de2_formats); ++i)
+ if (de2_formats[i].drm_fmt == format)
+ return &de2_formats[i];
- return 0;
+ return NULL;
}
-int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
- int layer, struct drm_plane *plane)
+static void sun8i_mixer_commit(struct sunxi_engine *engine)
{
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- bool interlaced = false;
- u32 val;
- /* Currently the first UI channel is used */
- int chan = mixer->cfg->vi_num;
- int ret;
-
- if (plane->state->crtc)
- interlaced = plane->state->crtc->state->adjusted_mode.flags
- & DRM_MODE_FLAG_INTERLACE;
-
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
- SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
- interlaced ?
- SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
-
- DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
- interlaced ? "on" : "off");
-
- ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
- &val);
- if (ret) {
- DRM_DEBUG_DRIVER("Invalid format\n");
- return ret;
- }
-
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
+ DRM_DEBUG_DRIVER("Committing changes\n");
- return 0;
+ regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+ SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
}
-int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
- int layer, struct drm_plane *plane)
+static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
+ struct sunxi_engine *engine)
{
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *gem;
- dma_addr_t paddr;
- /* Currently the first UI channel is used */
- int chan = mixer->cfg->vi_num;
- int bpp;
-
- /* Get the physical address of the buffer in memory */
- gem = drm_fb_cma_get_gem_obj(fb, 0);
-
- DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
-
- /* Compute the start of the displayed memory */
- bpp = fb->format->cpp[0];
- paddr = gem->paddr + fb->offsets[0];
-
- /* Fixup framebuffer address for src coordinates */
- paddr += (state->src_x >> 16) * bpp;
- paddr += (state->src_y >> 16) * fb->pitches[0];
-
- /*
- * The hardware cannot correctly deal with negative crtc
- * coordinates, the display is cropped to the requested size,
- * but the display content is not moved.
- * Manually move the display content by fixup the framebuffer
- * address when crtc_x or crtc_y is negative, like what we
- * have did for src_x and src_y.
- */
- if (state->crtc_x < 0)
- paddr += -state->crtc_x * bpp;
- if (state->crtc_y < 0)
- paddr += -state->crtc_y * fb->pitches[0];
-
- DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
-
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
- lower_32_bits(paddr));
-
- return 0;
+ struct drm_plane **planes;
+ struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+ int i;
+
+ planes = devm_kcalloc(drm->dev,
+ mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
+ sizeof(*planes), GFP_KERNEL);
+ if (!planes)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < mixer->cfg->vi_num; i++) {
+ struct sun8i_vi_layer *layer;
+
+ layer = sun8i_vi_layer_init_one(drm, mixer, i);
+ if (IS_ERR(layer)) {
+ dev_err(drm->dev,
+ "Couldn't initialize overlay plane\n");
+ return ERR_CAST(layer);
+ };
+
+ planes[i] = &layer->plane;
+ };
+
+ for (i = 0; i < mixer->cfg->ui_num; i++) {
+ struct sun8i_ui_layer *layer;
+
+ layer = sun8i_ui_layer_init_one(drm, mixer, i);
+ if (IS_ERR(layer)) {
+ dev_err(drm->dev, "Couldn't initialize %s plane\n",
+ i ? "overlay" : "primary");
+ return ERR_CAST(layer);
+ };
+
+ planes[mixer->cfg->vi_num + i] = &layer->plane;
+ };
+
+ return planes;
}
static const struct sunxi_engine_ops sun8i_engine_ops = {
@@ -247,6 +331,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
struct sun8i_mixer *mixer;
struct resource *res;
void __iomem *regs;
+ int plane_cnt;
int i, ret;
/*
@@ -325,27 +410,26 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
SUN8I_MIXER_GLOBAL_CTL_RT_EN);
- /* Initialize blender */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
- SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
- SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
+ /* Set background color to black */
regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
- SUN8I_MIXER_BLEND_BKCOLOR_DEF);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
- SUN8I_MIXER_BLEND_MODE_DEF);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
- SUN8I_MIXER_BLEND_CK_CTL_DEF);
-
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
- SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
-
- /* Select the first UI channel */
- DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
- mixer->cfg->vi_num);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
- mixer->cfg->vi_num);
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
+
+ /*
+ * Set fill color of bottom plane to black. Generally not needed
+ * except when VI plane is at bottom (zpos = 0) and enabled.
+ */
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
+ SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
+
+ /* Fixed zpos for now */
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE, 0x43210);
+
+ plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
+ for (i = 0; i < plane_cnt; i++)
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i),
+ SUN8I_MIXER_BLEND_MODE_DEF);
return 0;
@@ -388,6 +472,8 @@ static int sun8i_mixer_remove(struct platform_device *pdev)
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.vi_num = 2,
.ui_num = 1,
+ .scaler_mask = 0x3,
+ .ccsc = 0,
};
static 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 @@
#include <linux/regmap.h>
#include <linux/reset.h>
+#include "sun8i_csc.h"
#include "sunxi_engine.h"
-#define SUN8I_MIXER_MAX_CHAN_COUNT 4
-
#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x))
@@ -26,14 +25,14 @@
#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
#define SUN8I_MIXER_GLOBAL_SIZE 0xc
-#define SUN8I_MIXER_GLOBAL_CTL_RT_EN 0x1
+#define SUN8I_MIXER_GLOBAL_CTL_RT_EN BIT(0)
-#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE 0x1
+#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0)
-#define SUN8I_MIXER_BLEND_FCOLOR_CTL 0x1000
+#define SUN8I_MIXER_BLEND_PIPE_CTL 0x1000
#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0)
#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4)
-#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x) (0x1004 + 0x10 * (x) + 0x8)
+#define SUN8I_MIXER_BLEND_ATTR_COORD(x) (0x1004 + 0x10 * (x) + 0x8)
#define SUN8I_MIXER_BLEND_ROUTE 0x1080
#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084
#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088
@@ -45,57 +44,56 @@
#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x))
#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc
+#define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe)
+#define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe)
+/* colors are always in AARRGGBB format */
+#define SUN8I_MIXER_BLEND_COLOR_BLACK 0xff000000
/* The following numbers are some still unknown magic numbers */
-#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF 0xff000000
-#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF 0x00000101
-#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF 0x0
-#define SUN8I_MIXER_BLEND_BKCOLOR_DEF 0xff000000
#define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301
-#define SUN8I_MIXER_BLEND_CK_CTL_DEF 0x0
#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
-/*
- * VI channels are not used now, but the support of them may be introduced in
- * the future.
- */
-
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
-#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
-#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
-#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
-#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
-#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
-#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80)
-#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84)
-#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88)
-
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(11, 8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF (1 << 1)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888 (0 << 8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888 (4 << 8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888 (8 << 8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF (0xff << 24)
+#define SUN8I_MIXER_FBFMT_ARGB8888 0
+#define SUN8I_MIXER_FBFMT_ABGR8888 1
+#define SUN8I_MIXER_FBFMT_RGBA8888 2
+#define SUN8I_MIXER_FBFMT_BGRA8888 3
+#define SUN8I_MIXER_FBFMT_XRGB8888 4
+#define SUN8I_MIXER_FBFMT_XBGR8888 5
+#define SUN8I_MIXER_FBFMT_RGBX8888 6
+#define SUN8I_MIXER_FBFMT_BGRX8888 7
+#define SUN8I_MIXER_FBFMT_RGB888 8
+#define SUN8I_MIXER_FBFMT_BGR888 9
+#define SUN8I_MIXER_FBFMT_RGB565 10
+#define SUN8I_MIXER_FBFMT_BGR565 11
+#define SUN8I_MIXER_FBFMT_ARGB4444 12
+#define SUN8I_MIXER_FBFMT_ABGR4444 13
+#define SUN8I_MIXER_FBFMT_RGBA4444 14
+#define SUN8I_MIXER_FBFMT_BGRA4444 15
+#define SUN8I_MIXER_FBFMT_ARGB1555 16
+#define SUN8I_MIXER_FBFMT_ABGR1555 17
+#define SUN8I_MIXER_FBFMT_RGBA5551 18
+#define SUN8I_MIXER_FBFMT_BGRA5551 19
+
+#define SUN8I_MIXER_FBFMT_YUYV 0
+#define SUN8I_MIXER_FBFMT_UYVY 1
+#define SUN8I_MIXER_FBFMT_YVYU 2
+#define SUN8I_MIXER_FBFMT_VYUY 3
+#define SUN8I_MIXER_FBFMT_NV16 4
+#define SUN8I_MIXER_FBFMT_NV61 5
+#define SUN8I_MIXER_FBFMT_YUV422 6
+/* format 7 doesn't exist */
+#define SUN8I_MIXER_FBFMT_NV12 8
+#define SUN8I_MIXER_FBFMT_NV21 9
+#define SUN8I_MIXER_FBFMT_YUV420 10
+/* format 11 doesn't exist */
+/* format 12 is semi-planar YUV411 UVUV */
+/* format 13 is semi-planar YUV411 VUVU */
+#define SUN8I_MIXER_FBFMT_YUV411 14
/*
* These sub-engines are still unknown now, the EN registers are here only to
* be used to disable these sub-engines.
*/
-#define SUN8I_MIXER_VSU_EN 0x20000
-#define SUN8I_MIXER_GSU1_EN 0x30000
-#define SUN8I_MIXER_GSU2_EN 0x40000
-#define SUN8I_MIXER_GSU3_EN 0x50000
#define SUN8I_MIXER_FCE_EN 0xa0000
#define SUN8I_MIXER_BWS_EN 0xa2000
#define SUN8I_MIXER_LTI_EN 0xa4000
@@ -104,9 +102,31 @@
#define SUN8I_MIXER_FCC_EN 0xaa000
#define SUN8I_MIXER_DCSC_EN 0xb0000
+struct de2_fmt_info {
+ u32 drm_fmt;
+ u32 de2_fmt;
+ bool rgb;
+ enum sun8i_csc_mode csc;
+};
+
+/**
+ * struct sun8i_mixer_cfg - mixer HW configuration
+ * @vi_num: number of VI channels
+ * @ui_num: number of UI channels
+ * @scaler_mask: bitmask which tells which channel supports scaling
+ * First, scaler supports for VI channels is defined and after that, scaler
+ * support for UI channels. For example, if mixer has 2 VI channels without
+ * scaler and 2 UI channels with scaler, bitmask would be 0xC.
+ * @ccsc: select set of CCSC base addresses
+ * Set value to 0 if this is first mixer or second mixer with VEP support.
+ * Set value to 1 if this is second mixer without VEP support. Other values
+ * are invalid.
+ */
struct sun8i_mixer_cfg {
int vi_num;
int ui_num;
+ int scaler_mask;
+ int ccsc;
};
struct sun8i_mixer {
@@ -126,12 +146,5 @@ engine_to_sun8i_mixer(struct sunxi_engine *engine)
return container_of(engine, struct sun8i_mixer, engine);
}
-void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
- int layer, bool enable);
-int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
- int layer, struct drm_plane *plane);
-int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
- int layer, struct drm_plane *plane);
-int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
- int layer, struct drm_plane *plane);
+const struct de2_fmt_info *sun8i_mixer_format_info(u32 format);
#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 @@
+/*
+ * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun4i_layer.h, which is:
+ * Copyright (C) 2015 Free Electrons
+ * Copyright (C) 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drmP.h>
+
+#include "sun8i_ui_layer.h"
+#include "sun8i_mixer.h"
+#include "sun8i_ui_scaler.h"
+
+static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
+ int overlay, bool enable)
+{
+ u32 val;
+
+ DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
+ enable ? "En" : "Dis", channel, overlay);
+
+ if (enable)
+ val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
+ else
+ val = 0;
+
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
+
+ if (enable)
+ val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel);
+ else
+ val = 0;
+
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_PIPE_CTL,
+ SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val);
+}
+
+static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
+ int overlay, struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ u32 src_w, src_h, dst_w, dst_h;
+ u32 outsize, insize;
+ u32 hphase, vphase;
+
+ DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
+ channel, overlay);
+
+ src_w = drm_rect_width(&state->src) >> 16;
+ src_h = drm_rect_height(&state->src) >> 16;
+ dst_w = drm_rect_width(&state->dst);
+ dst_h = drm_rect_height(&state->dst);
+
+ hphase = state->src.x1 & 0xffff;
+ vphase = state->src.y1 & 0xffff;
+
+ insize = SUN8I_MIXER_SIZE(src_w, src_h);
+ outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
+
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+ bool interlaced = false;
+ u32 val;
+
+ DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
+ dst_w, dst_h);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_GLOBAL_SIZE,
+ outsize);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
+ outsize);
+
+ if (state->crtc)
+ interlaced = state->crtc->state->adjusted_mode.flags
+ & DRM_MODE_FLAG_INTERLACE;
+
+ if (interlaced)
+ val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
+ else
+ val = 0;
+
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_OUTCTL,
+ SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
+ val);
+
+ DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
+ interlaced ? "on" : "off");
+ }
+
+ /* Set height and width */
+ DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
+ state->src.x1 >> 16, state->src.y1 >> 16);
+ DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_SIZE(channel, overlay),
+ insize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_UI_OVL_SIZE(channel),
+ insize);
+
+ if (insize != outsize || hphase || vphase) {
+ u32 hscale, vscale;
+
+ DRM_DEBUG_DRIVER("HW scaling is enabled\n");
+
+ hscale = state->src_w / state->crtc_w;
+ vscale = state->src_h / state->crtc_h;
+
+ sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
+ dst_h, hscale, vscale, hphase, vphase);
+ sun8i_ui_scaler_enable(mixer, channel, true);
+ } else {
+ DRM_DEBUG_DRIVER("HW scaling is not needed\n");
+ sun8i_ui_scaler_enable(mixer, channel, false);
+ }
+
+ /* Set base coordinates */
+ DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
+ state->dst.x1, state->dst.y1);
+ DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_ATTR_COORD(channel),
+ SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_ATTR_INSIZE(channel),
+ outsize);
+
+ return 0;
+}
+
+static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
+ int overlay, struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ const struct de2_fmt_info *fmt_info;
+ u32 val;
+
+ fmt_info = sun8i_mixer_format_info(state->fb->format->format);
+ if (!fmt_info || !fmt_info->rgb) {
+ DRM_DEBUG_DRIVER("Invalid format\n");
+ return -EINVAL;
+ }
+
+ val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
+
+ return 0;
+}
+
+static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
+ int overlay, struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *gem;
+ dma_addr_t paddr;
+ int bpp;
+
+ /* Get the physical address of the buffer in memory */
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+ DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+ /* Compute the start of the displayed memory */
+ bpp = fb->format->cpp[0];
+ paddr = gem->paddr + fb->offsets[0];
+
+ /* Fixup framebuffer address for src coordinates */
+ paddr += (state->src.x1 >> 16) * bpp;
+ paddr += (state->src.y1 >> 16) * fb->pitches[0];
+
+ /* Set the line width */
+ DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_PITCH(channel, overlay),
+ fb->pitches[0]);
+
+ DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(channel, overlay),
+ lower_32_bits(paddr));
+
+ return 0;
+}
+
+static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_crtc_state *crtc_state;
+ int min_scale, max_scale;
+ struct drm_rect clip;
+
+ if (!crtc)
+ return 0;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
+
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc_state->adjusted_mode.hdisplay;
+ clip.y2 = crtc_state->adjusted_mode.vdisplay;
+
+ min_scale = DRM_PLANE_HELPER_NO_SCALING;
+ max_scale = DRM_PLANE_HELPER_NO_SCALING;
+
+ if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
+ min_scale = SUN8I_UI_SCALER_SCALE_MIN;
+ max_scale = SUN8I_UI_SCALER_SCALE_MAX;
+ }
+
+ return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
+ min_scale, max_scale,
+ true, true);
+}
+
+static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
+ struct sun8i_mixer *mixer = layer->mixer;
+
+ sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false);
+}
+
+static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
+ struct sun8i_mixer *mixer = layer->mixer;
+
+ if (!plane->state->visible) {
+ sun8i_ui_layer_enable(mixer, layer->channel,
+ layer->overlay, false);
+ return;
+ }
+
+ sun8i_ui_layer_update_coord(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_ui_layer_update_formats(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_ui_layer_update_buffer(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, true);
+}
+
+static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
+ .atomic_check = sun8i_ui_layer_atomic_check,
+ .atomic_disable = sun8i_ui_layer_atomic_disable,
+ .atomic_update = sun8i_ui_layer_atomic_update,
+};
+
+static const struct drm_plane_funcs sun8i_ui_layer_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .destroy = drm_plane_cleanup,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .reset = drm_atomic_helper_plane_reset,
+ .update_plane = drm_atomic_helper_update_plane,
+};
+
+static const u32 sun8i_ui_layer_formats[] = {
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_ABGR4444,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_BGRA5551,
+ DRM_FORMAT_BGRA4444,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB8888,
+};
+
+struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
+ struct sun8i_mixer *mixer,
+ int index)
+{
+ enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
+ int channel = mixer->cfg->vi_num + index;
+ struct sun8i_ui_layer *layer;
+ int ret;
+
+ layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
+ if (!layer)
+ return ERR_PTR(-ENOMEM);
+
+ if (index == 0)
+ type = DRM_PLANE_TYPE_PRIMARY;
+
+ /* possible crtcs are set later */
+ ret = drm_universal_plane_init(drm, &layer->plane, 0,
+ &sun8i_ui_layer_funcs,
+ sun8i_ui_layer_formats,
+ ARRAY_SIZE(sun8i_ui_layer_formats),
+ NULL, type, NULL);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't initialize layer\n");
+ return ERR_PTR(ret);
+ }
+
+ /* fixed zpos for now */
+ ret = drm_plane_create_zpos_immutable_property(&layer->plane, channel);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't add zpos property\n");
+ return ERR_PTR(ret);
+ }
+
+ drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
+ layer->mixer = mixer;
+ layer->channel = channel;
+ layer->overlay = 0;
+
+ return layer;
+}
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 @@
+/*
+ * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun4i_layer.h, which is:
+ * Copyright (C) 2015 Free Electrons
+ * Copyright (C) 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN8I_UI_LAYER_H_
+#define _SUN8I_UI_LAYER_H_
+
+#include <drm/drm_plane.h>
+
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
+#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
+#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
+#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
+#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80)
+#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84)
+#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88)
+
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET 8
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
+
+struct sun8i_mixer;
+
+struct sun8i_ui_layer {
+ struct drm_plane plane;
+ struct sun8i_mixer *mixer;
+ int channel;
+ int overlay;
+};
+
+static inline struct sun8i_ui_layer *
+plane_to_sun8i_ui_layer(struct drm_plane *plane)
+{
+ return container_of(plane, struct sun8i_ui_layer, plane);
+}
+
+struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
+ struct sun8i_mixer *mixer,
+ int index);
+#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 @@
+/*
+ * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Coefficients are taken from BSP driver, which is:
+ * Copyright (C) 2014-2015 Allwinner
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include "sun8i_ui_scaler.h"
+
+static const u32 lan2coefftab16[240] = {
+ 0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb,
+ 0xff0f37fb, 0xfe1433fb, 0xfd192ffb, 0xfd1f29fb,
+ 0xfc2424fc, 0xfb291ffd, 0xfb2f19fd, 0xfb3314fe,
+ 0xfb370fff, 0xfb3b0a00, 0xfc3e0600, 0xfe3f0300,
+
+ 0xff053804, 0xff083801, 0xff0a3700, 0xff0e34ff,
+ 0xff1232fd, 0xfe162ffd, 0xfd1b2cfc, 0xfd1f28fc,
+ 0xfd2323fd, 0xfc281ffd, 0xfc2c1bfd, 0xfd2f16fe,
+ 0xfd3212ff, 0xff340eff, 0x00360a00, 0x02370700,
+
+ 0xff083207, 0xff0a3205, 0xff0d3103, 0xfe113001,
+ 0xfe142e00, 0xfe182bff, 0xfe1b29fe, 0xfe1f25fe,
+ 0xfe2222fe, 0xfe251ffe, 0xfe291bfe, 0xff2b18fe,
+ 0x002e14fe, 0x013010ff, 0x03310dff, 0x05310a00,
+
+ 0xff0a2e09, 0xff0c2e07, 0xff0f2d05, 0xff122c03,
+ 0xfe152b02, 0xfe182901, 0xfe1b2700, 0xff1e24ff,
+ 0xff2121ff, 0xff241eff, 0x00261bff, 0x012818ff,
+ 0x022a15ff, 0x032c12ff, 0x052d0fff, 0x072d0c00,
+
+ 0xff0c2a0b, 0xff0e2a09, 0xff102a07, 0xff132905,
+ 0xff162803, 0xff182702, 0xff1b2501, 0xff1e2300,
+ 0x00202000, 0x01221d00, 0x01251bff, 0x032618ff,
+ 0x042815ff, 0x052913ff, 0x072a10ff, 0x092a0d00,
+
+ 0xff0d280c, 0xff0f280a, 0xff112808, 0xff142706,
+ 0xff162605, 0xff192503, 0x001b2302, 0x001d2201,
+ 0x011f1f01, 0x01221d00, 0x02231b00, 0x04241800,
+ 0x052616ff, 0x072713ff, 0x08271100, 0x0a280e00,
+
+ 0xff0e260d, 0xff10260b, 0xff122609, 0xff142508,
+ 0x00152506, 0x00182305, 0x001b2203, 0x011d2002,
+ 0x011f1f01, 0x02201d01, 0x03221b00, 0x04231801,
+ 0x06241600, 0x08251300, 0x09261100, 0x0b260f00,
+
+ 0xff0e250e, 0xff10250c, 0x0011250a, 0x00142408,
+ 0x00162307, 0x00182206, 0x011a2104, 0x011c2003,
+ 0x021e1e02, 0x03201c01, 0x04211a01, 0x05221801,
+ 0x07231600, 0x08241400, 0x0a241200, 0x0c241000,
+
+ 0x000e240e, 0x0010240c, 0x0013230a, 0x00142309,
+ 0x00162208, 0x01182106, 0x011a2005, 0x021b1f04,
+ 0x031d1d03, 0x041e1c02, 0x05201a01, 0x06211801,
+ 0x07221601, 0x09231400, 0x0a231300, 0x0c231100,
+
+ 0x000f220f, 0x0011220d, 0x0013220b, 0x0015210a,
+ 0x01162108, 0x01182007, 0x02191f06, 0x031a1e05,
+ 0x041c1c04, 0x051d1b03, 0x061f1902, 0x07201801,
+ 0x08211601, 0x0a211500, 0x0b221300, 0x0d221100,
+
+ 0x0010210f, 0x0011210e, 0x0013210c, 0x0114200b,
+ 0x01161f0a, 0x02171f08, 0x03181e07, 0x031a1d06,
+ 0x041c1c04, 0x051d1a04, 0x071d1903, 0x081e1802,
+ 0x091f1602, 0x0b1f1501, 0x0c211300, 0x0e201200,
+
+ 0x00102010, 0x0012200e, 0x0013200d, 0x01151f0b,
+ 0x01161f0a, 0x02171e09, 0x03191d07, 0x041a1c06,
+ 0x051b1b05, 0x061c1a04, 0x071d1903, 0x081e1703,
+ 0x0a1f1601, 0x0b1f1501, 0x0d201300, 0x0e201200,
+
+ 0x00102010, 0x00121f0f, 0x00141f0d, 0x01141f0c,
+ 0x02161e0a, 0x03171d09, 0x03181d08, 0x041a1c06,
+ 0x051b1b05, 0x061c1a04, 0x081c1903, 0x091d1703,
+ 0x0a1e1602, 0x0c1e1501, 0x0d1f1400, 0x0e1f1201,
+
+ 0x00111e11, 0x00131e0f, 0x01131e0e, 0x02151d0c,
+ 0x02161d0b, 0x03171c0a, 0x04181b09, 0x05191b07,
+ 0x061a1a06, 0x071b1905, 0x091b1804, 0x0a1c1703,
+ 0x0b1d1602, 0x0c1d1502, 0x0e1d1401, 0x0f1e1300,
+
+ 0x00111e11, 0x00131d10, 0x01141d0e, 0x02151c0d,
+ 0x03161c0b, 0x04171b0a, 0x05171b09, 0x06181a08,
+ 0x07191907, 0x081a1806, 0x091a1805, 0x0a1b1704,
+ 0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
+};
+
+static int sun8i_ui_scaler_coef_index(unsigned int step)
+{
+ unsigned int scale, int_part, float_part;
+
+ scale = step >> (SUN8I_UI_SCALER_SCALE_FRAC - 3);
+ int_part = scale >> 3;
+ float_part = scale & 0x7;
+
+ switch (int_part) {
+ case 0:
+ return 0;
+ case 1:
+ return float_part;
+ case 2:
+ return 8 + (float_part >> 1);
+ case 3:
+ return 12;
+ case 4:
+ return 13;
+ default:
+ return 14;
+ }
+}
+
+void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+{
+ int vi_cnt = mixer->cfg->vi_num;
+ u32 val;
+
+ if (WARN_ON(layer < vi_cnt))
+ return;
+
+ if (enable)
+ val = SUN8I_SCALER_GSU_CTRL_EN |
+ SUN8I_SCALER_GSU_CTRL_COEFF_RDY;
+ else
+ val = 0;
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_CTRL(vi_cnt, layer - vi_cnt), val);
+}
+
+void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
+ u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
+ u32 hscale, u32 vscale, u32 hphase, u32 vphase)
+{
+ int vi_cnt = mixer->cfg->vi_num;
+ u32 insize, outsize;
+ int i, offset;
+
+ if (WARN_ON(layer < vi_cnt))
+ return;
+
+ hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
+ vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
+ hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
+ vscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
+
+ insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
+ outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
+
+ layer -= vi_cnt;
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, layer), outsize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_INSIZE(vi_cnt, layer), insize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_HSTEP(vi_cnt, layer), hscale);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_VSTEP(vi_cnt, layer), vscale);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_HPHASE(vi_cnt, layer), hphase);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_VPHASE(vi_cnt, layer), vphase);
+ offset = sun8i_ui_scaler_coef_index(hscale) *
+ SUN8I_UI_SCALER_COEFF_COUNT;
+ for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_GSU_HCOEFF(vi_cnt, layer, i),
+ lan2coefftab16[offset + i]);
+}
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 @@
+/*
+ * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _SUN8I_UI_SCALER_H_
+#define _SUN8I_UI_SCALER_H_
+
+#include "sun8i_mixer.h"
+
+/* this two macros assumes 16 fractional bits which is standard in DRM */
+#define SUN8I_UI_SCALER_SCALE_MIN 1
+#define SUN8I_UI_SCALER_SCALE_MAX ((1UL << 20) - 1)
+
+#define SUN8I_UI_SCALER_SCALE_FRAC 20
+#define SUN8I_UI_SCALER_PHASE_FRAC 20
+#define SUN8I_UI_SCALER_COEFF_COUNT 16
+#define SUN8I_UI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
+
+#define SUN8I_SCALER_GSU_CTRL(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x0)
+#define SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x40)
+#define SUN8I_SCALER_GSU_INSIZE(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x80)
+#define SUN8I_SCALER_GSU_HSTEP(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x88)
+#define SUN8I_SCALER_GSU_VSTEP(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x8c)
+#define SUN8I_SCALER_GSU_HPHASE(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x90)
+#define SUN8I_SCALER_GSU_VPHASE(vi_cnt, ui_idx) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x98)
+#define SUN8I_SCALER_GSU_HCOEFF(vi_cnt, ui_idx, index) \
+ (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x200 + \
+ 0x4 * (index))
+
+#define SUN8I_SCALER_GSU_CTRL_EN BIT(0)
+#define SUN8I_SCALER_GSU_CTRL_COEFF_RDY BIT(4)
+
+void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
+ u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
+ u32 hscale, u32 vscale, u32 hphase, u32 vphase);
+
+#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 @@
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drmP.h>
+
+#include "sun8i_vi_layer.h"
+#include "sun8i_mixer.h"
+#include "sun8i_vi_scaler.h"
+
+static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
+ int overlay, bool enable)
+{
+ u32 val;
+
+ DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
+ enable ? "En" : "Dis", channel, overlay);
+
+ if (enable)
+ val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
+ else
+ val = 0;
+
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
+
+ if (enable)
+ val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel);
+ else
+ val = 0;
+
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_PIPE_CTL,
+ SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val);
+}
+
+static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
+ int overlay, struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ const struct drm_format_info *format = state->fb->format;
+ u32 src_w, src_h, dst_w, dst_h;
+ u32 outsize, insize;
+ u32 hphase, vphase;
+ bool subsampled;
+
+ DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
+ channel, overlay);
+
+ src_w = drm_rect_width(&state->src) >> 16;
+ src_h = drm_rect_height(&state->src) >> 16;
+ dst_w = drm_rect_width(&state->dst);
+ dst_h = drm_rect_height(&state->dst);
+
+ hphase = state->src.x1 & 0xffff;
+ vphase = state->src.y1 & 0xffff;
+
+ /* make coordinates dividable by subsampling factor */
+ if (format->hsub > 1) {
+ int mask, remainder;
+
+ mask = format->hsub - 1;
+ remainder = (state->src.x1 >> 16) & mask;
+ src_w = (src_w + remainder) & ~mask;
+ hphase += remainder << 16;
+ }
+
+ if (format->vsub > 1) {
+ int mask, remainder;
+
+ mask = format->vsub - 1;
+ remainder = (state->src.y1 >> 16) & mask;
+ src_h = (src_h + remainder) & ~mask;
+ vphase += remainder << 16;
+ }
+
+ insize = SUN8I_MIXER_SIZE(src_w, src_h);
+ outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
+
+ /* Set height and width */
+ DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
+ (state->src.x1 >> 16) & ~(format->hsub - 1),
+ (state->src.y1 >> 16) & ~(format->vsub - 1));
+ DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay),
+ insize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel),
+ insize);
+
+ /*
+ * Scaler must be enabled for subsampled formats, so it scales
+ * chroma to same size as luma.
+ */
+ subsampled = format->hsub > 1 || format->vsub > 1;
+
+ if (insize != outsize || subsampled || hphase || vphase) {
+ u32 hscale, vscale;
+
+ DRM_DEBUG_DRIVER("HW scaling is enabled\n");
+
+ hscale = state->src_w / state->crtc_w;
+ vscale = state->src_h / state->crtc_h;
+
+ sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
+ dst_h, hscale, vscale, hphase, vphase,
+ format);
+ sun8i_vi_scaler_enable(mixer, channel, true);
+ } else {
+ DRM_DEBUG_DRIVER("HW scaling is not needed\n");
+ sun8i_vi_scaler_enable(mixer, channel, false);
+ }
+
+ /* Set base coordinates */
+ DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
+ state->dst.x1, state->dst.y1);
+ DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_ATTR_COORD(channel),
+ SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_ATTR_INSIZE(channel),
+ outsize);
+
+ return 0;
+}
+
+static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
+ int overlay, struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ const struct de2_fmt_info *fmt_info;
+ u32 val;
+
+ fmt_info = sun8i_mixer_format_info(state->fb->format->format);
+ if (!fmt_info) {
+ DRM_DEBUG_DRIVER("Invalid format\n");
+ return -EINVAL;
+ }
+
+ val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
+
+ if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
+ sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc);
+ sun8i_csc_enable_ccsc(mixer, channel, true);
+ } else {
+ sun8i_csc_enable_ccsc(mixer, channel, false);
+ }
+
+ if (fmt_info->rgb)
+ val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
+ else
+ val = 0;
+
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
+
+ return 0;
+}
+
+static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
+ int overlay, struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ const struct drm_format_info *format = fb->format;
+ struct drm_gem_cma_object *gem;
+ u32 dx, dy, src_x, src_y;
+ dma_addr_t paddr;
+ int i;
+
+ /* Adjust x and y to be dividable by subsampling factor */
+ src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
+ src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
+
+ for (i = 0; i < format->num_planes; i++) {
+ /* Get the physical address of the buffer in memory */
+ gem = drm_fb_cma_get_gem_obj(fb, i);
+
+ DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+ /* Compute the start of the displayed memory */
+ paddr = gem->paddr + fb->offsets[i];
+
+ dx = src_x;
+ dy = src_y;
+
+ if (i > 0) {
+ dx /= format->hsub;
+ dy /= format->vsub;
+ }
+
+ /* Fixup framebuffer address for src coordinates */
+ paddr += dx * format->cpp[i];
+ paddr += dy * fb->pitches[i];
+
+ /* Set the line width */
+ DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
+ i + 1, fb->pitches[i]);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel,
+ overlay, i),
+ fb->pitches[i]);
+
+ DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
+ i + 1, &paddr);
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel,
+ overlay, i),
+ lower_32_bits(paddr));
+ }
+
+ return 0;
+}
+
+static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_crtc_state *crtc_state;
+ int min_scale, max_scale;
+ struct drm_rect clip;
+
+ if (!crtc)
+ return 0;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
+
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc_state->adjusted_mode.hdisplay;
+ clip.y2 = crtc_state->adjusted_mode.vdisplay;
+
+ min_scale = DRM_PLANE_HELPER_NO_SCALING;
+ max_scale = DRM_PLANE_HELPER_NO_SCALING;
+
+ if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
+ min_scale = SUN8I_VI_SCALER_SCALE_MIN;
+ max_scale = SUN8I_VI_SCALER_SCALE_MAX;
+ }
+
+ return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
+ min_scale, max_scale,
+ true, true);
+}
+
+static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
+ struct sun8i_mixer *mixer = layer->mixer;
+
+ sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false);
+}
+
+static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
+ struct sun8i_mixer *mixer = layer->mixer;
+
+ if (!plane->state->visible) {
+ sun8i_vi_layer_enable(mixer, layer->channel,
+ layer->overlay, false);
+ return;
+ }
+
+ sun8i_vi_layer_update_coord(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_vi_layer_update_formats(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_vi_layer_update_buffer(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, true);
+}
+
+static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
+ .atomic_check = sun8i_vi_layer_atomic_check,
+ .atomic_disable = sun8i_vi_layer_atomic_disable,
+ .atomic_update = sun8i_vi_layer_atomic_update,
+};
+
+static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .destroy = drm_plane_cleanup,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .reset = drm_atomic_helper_plane_reset,
+ .update_plane = drm_atomic_helper_update_plane,
+};
+
+/*
+ * While all RGB formats are supported, VI planes don't support
+ * alpha blending, so there is no point having formats with alpha
+ * channel if their opaque analog exist.
+ */
+static const u32 sun8i_vi_layer_formats[] = {
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_ABGR4444,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_BGRA5551,
+ DRM_FORMAT_BGRA4444,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB8888,
+
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_YUV411,
+ DRM_FORMAT_YUV420,
+ DRM_FORMAT_YUV422,
+ DRM_FORMAT_YUV444,
+ DRM_FORMAT_YVU411,
+ DRM_FORMAT_YVU420,
+ DRM_FORMAT_YVU422,
+ DRM_FORMAT_YVU444,
+};
+
+struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
+ struct sun8i_mixer *mixer,
+ int index)
+{
+ struct sun8i_vi_layer *layer;
+ int ret;
+
+ layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
+ if (!layer)
+ return ERR_PTR(-ENOMEM);
+
+ /* possible crtcs are set later */
+ ret = drm_universal_plane_init(drm, &layer->plane, 0,
+ &sun8i_vi_layer_funcs,
+ sun8i_vi_layer_formats,
+ ARRAY_SIZE(sun8i_vi_layer_formats),
+ NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't initialize layer\n");
+ return ERR_PTR(ret);
+ }
+
+ /* fixed zpos for now */
+ ret = drm_plane_create_zpos_immutable_property(&layer->plane, index);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't add zpos property\n");
+ return ERR_PTR(ret);
+ }
+
+ drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
+ layer->mixer = mixer;
+ layer->channel = index;
+ layer->overlay = 0;
+
+ return layer;
+}
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 @@
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN8I_VI_LAYER_H_
+#define _SUN8I_VI_LAYER_H_
+
+#include <drm/drm_plane.h>
+
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(ch, layer) \
+ (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch, layer, plane) \
+ (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0xc + 4 * (plane))
+#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch, layer, plane) \
+ (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x18 + 4 * (plane))
+#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0xe8)
+
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN BIT(0)
+/* RGB mode should be set for RGB formats and cleared for YCbCr */
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE BIT(15)
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET 8
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8)
+
+struct sun8i_mixer;
+
+struct sun8i_vi_layer {
+ struct drm_plane plane;
+ struct sun8i_mixer *mixer;
+ int channel;
+ int overlay;
+};
+
+static inline struct sun8i_vi_layer *
+plane_to_sun8i_vi_layer(struct drm_plane *plane)
+{
+ return container_of(plane, struct sun8i_vi_layer, plane);
+}
+
+struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
+ struct sun8i_mixer *mixer,
+ int index);
+#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 @@
+/*
+ * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Coefficients are taken from BSP driver, which is:
+ * Copyright (C) 2014-2015 Allwinner
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include "sun8i_vi_scaler.h"
+
+static const u32 lan3coefftab32_left[480] = {
+ 0x40000000, 0x40fe0000, 0x3ffd0100, 0x3efc0100,
+ 0x3efb0100, 0x3dfa0200, 0x3cf90200, 0x3bf80200,
+ 0x39f70200, 0x37f70200, 0x35f70200, 0x33f70200,
+ 0x31f70200, 0x2ef70200, 0x2cf70200, 0x2af70200,
+ 0x27f70200, 0x24f80100, 0x22f80100, 0x1ef90100,
+ 0x1cf90100, 0x19fa0100, 0x17fa0100, 0x14fb0100,
+ 0x11fc0000, 0x0ffc0000, 0x0cfd0000, 0x0afd0000,
+ 0x08fe0000, 0x05ff0000, 0x03ff0000, 0x02000000,
+
+ 0x3806fc02, 0x3805fc02, 0x3803fd01, 0x3801fe01,
+ 0x3700fe01, 0x35ffff01, 0x35fdff01, 0x34fc0001,
+ 0x34fb0000, 0x33fa0000, 0x31fa0100, 0x2ff90100,
+ 0x2df80200, 0x2bf80200, 0x2af70200, 0x28f70200,
+ 0x27f70200, 0x24f70300, 0x22f70300, 0x1ff70300,
+ 0x1ef70300, 0x1cf70300, 0x1af70300, 0x18f70300,
+ 0x16f80300, 0x13f80300, 0x11f90300, 0x0ef90300,
+ 0x0efa0200, 0x0cfa0200, 0x0afb0200, 0x08fb0200,
+
+ 0x320bfa02, 0x3309fa02, 0x3208fb02, 0x3206fb02,
+ 0x3205fb02, 0x3104fc02, 0x3102fc01, 0x3001fd01,
+ 0x3000fd01, 0x2ffffd01, 0x2efefe01, 0x2dfdfe01,
+ 0x2bfcff01, 0x29fcff01, 0x28fbff01, 0x27fa0001,
+ 0x26fa0000, 0x24f90000, 0x22f90100, 0x20f90100,
+ 0x1ff80100, 0x1ef80100, 0x1cf80100, 0x1af80200,
+ 0x18f80200, 0x17f80200, 0x15f80200, 0x12f80200,
+ 0x11f90200, 0x0ff90200, 0x0df90200, 0x0cfa0200,
+
+ 0x2e0efa01, 0x2f0dfa01, 0x2f0bfa01, 0x2e0afa01,
+ 0x2e09fa01, 0x2e07fb01, 0x2d06fb01, 0x2d05fb01,
+ 0x2c04fb01, 0x2b03fc01, 0x2a02fc01, 0x2a01fc01,
+ 0x2800fd01, 0x28fffd01, 0x26fefd01, 0x25fefe01,
+ 0x24fdfe01, 0x23fcfe01, 0x21fcff01, 0x20fbff01,
+ 0x1efbff01, 0x1efbff00, 0x1cfa0000, 0x1bfa0000,
+ 0x19fa0000, 0x18fa0000, 0x17f90000, 0x15f90100,
+ 0x14f90100, 0x12f90100, 0x11f90100, 0x0ff90100,
+
+ 0x2b10fa00, 0x2b0ffa00, 0x2b0efa00, 0x2b0cfa00,
+ 0x2b0bfa00, 0x2a0afb01, 0x2a09fb01, 0x2908fb01,
+ 0x2807fb01, 0x2806fb01, 0x2805fb01, 0x2604fc01,
+ 0x2503fc01, 0x2502fc01, 0x2401fc01, 0x2301fc01,
+ 0x2100fd01, 0x21fffd01, 0x21fffd01, 0x20fefd01,
+ 0x1dfefe01, 0x1cfdfe01, 0x1cfdfe00, 0x1bfcfe00,
+ 0x19fcff00, 0x19fbff00, 0x17fbff00, 0x16fbff00,
+ 0x15fbff00, 0x14fb0000, 0x13fa0000, 0x11fa0000,
+
+ 0x2811fcff, 0x2810fcff, 0x280ffbff, 0x280efbff,
+ 0x270dfb00, 0x270cfb00, 0x270bfb00, 0x260afb00,
+ 0x2609fb00, 0x2508fb00, 0x2507fb00, 0x2407fb00,
+ 0x2406fc00, 0x2305fc00, 0x2204fc00, 0x2203fc00,
+ 0x2103fc00, 0x2002fc00, 0x1f01fd00, 0x1e01fd00,
+ 0x1d00fd00, 0x1dfffd00, 0x1cfffd00, 0x1bfefd00,
+ 0x1afefe00, 0x19fefe00, 0x18fdfe00, 0x17fdfe00,
+ 0x16fdfe00, 0x15fcff00, 0x13fcff00, 0x12fcff00,
+
+ 0x2512fdfe, 0x2511fdff, 0x2410fdff, 0x240ffdff,
+ 0x240efcff, 0x240dfcff, 0x240dfcff, 0x240cfcff,
+ 0x230bfcff, 0x230afc00, 0x2209fc00, 0x2108fc00,
+ 0x2108fc00, 0x2007fc00, 0x2006fc00, 0x2005fc00,
+ 0x1f05fc00, 0x1e04fc00, 0x1e03fc00, 0x1c03fd00,
+ 0x1c02fd00, 0x1b02fd00, 0x1b01fd00, 0x1a00fd00,
+ 0x1900fd00, 0x1800fd00, 0x17fffe00, 0x16fffe00,
+ 0x16fefe00, 0x14fefe00, 0x13fefe00, 0x13fdfe00,
+
+ 0x2212fffe, 0x2211fefe, 0x2211fefe, 0x2110fefe,
+ 0x210ffeff, 0x220efdff, 0x210dfdff, 0x210dfdff,
+ 0x210cfdff, 0x210bfdff, 0x200afdff, 0x200afdff,
+ 0x1f09fdff, 0x1f08fdff, 0x1d08fd00, 0x1c07fd00,
+ 0x1d06fd00, 0x1b06fd00, 0x1b05fd00, 0x1c04fd00,
+ 0x1b04fd00, 0x1a03fd00, 0x1a03fd00, 0x1902fd00,
+ 0x1802fd00, 0x1801fd00, 0x1701fd00, 0x1600fd00,
+ 0x1400fe00, 0x1400fe00, 0x14fffe00, 0x13fffe00,
+
+ 0x201200fe, 0x201100fe, 0x1f11fffe, 0x2010fffe,
+ 0x1f0ffffe, 0x1e0ffffe, 0x1f0efeff, 0x1f0dfeff,
+ 0x1f0dfeff, 0x1e0cfeff, 0x1e0bfeff, 0x1d0bfeff,
+ 0x1d0afeff, 0x1d09fdff, 0x1d09fdff, 0x1c08fdff,
+ 0x1c07fdff, 0x1b07fd00, 0x1b06fd00, 0x1a06fd00,
+ 0x1a05fd00, 0x1805fd00, 0x1904fd00, 0x1804fd00,
+ 0x1703fd00, 0x1703fd00, 0x1602fe00, 0x1502fe00,
+ 0x1501fe00, 0x1401fe00, 0x1301fe00, 0x1300fe00,
+
+ 0x1c1202fe, 0x1c1102fe, 0x1b1102fe, 0x1c1001fe,
+ 0x1b1001fe, 0x1b0f01ff, 0x1b0e00ff, 0x1b0e00ff,
+ 0x1b0d00ff, 0x1a0d00ff, 0x1a0c00ff, 0x1a0cffff,
+ 0x1a0bffff, 0x1a0bffff, 0x1a0affff, 0x180affff,
+ 0x1909ffff, 0x1809ffff, 0x1808ffff, 0x1808feff,
+ 0x1807feff, 0x1707fe00, 0x1606fe00, 0x1506fe00,
+ 0x1605fe00, 0x1505fe00, 0x1504fe00, 0x1304fe00,
+ 0x1304fe00, 0x1303fe00, 0x1203fe00, 0x1203fe00,
+
+ 0x181104ff, 0x191103ff, 0x191003ff, 0x181003ff,
+ 0x180f03ff, 0x190f02ff, 0x190e02ff, 0x180e02ff,
+ 0x180d02ff, 0x180d01ff, 0x180d01ff, 0x180c01ff,
+ 0x180c01ff, 0x180b00ff, 0x170b00ff, 0x170a00ff,
+ 0x170a00ff, 0x170900ff, 0x160900ff, 0x160900ff,
+ 0x1608ffff, 0x1508ffff, 0x1507ff00, 0x1507ff00,
+ 0x1407ff00, 0x1306ff00, 0x1306ff00, 0x1305ff00,
+ 0x1205ff00, 0x1105ff00, 0x1204ff00, 0x1104ff00,
+
+ 0x171005ff, 0x171005ff, 0x171004ff, 0x170f04ff,
+ 0x160f04ff, 0x170f03ff, 0x170e03ff, 0x160e03ff,
+ 0x160d03ff, 0x160d02ff, 0x160d02ff, 0x160c02ff,
+ 0x160c02ff, 0x160c02ff, 0x160b01ff, 0x150b01ff,
+ 0x150a01ff, 0x150a01ff, 0x150a01ff, 0x140901ff,
+ 0x14090000, 0x14090000, 0x14080000, 0x13080000,
+ 0x13070000, 0x12070000, 0x12070000, 0x12060000,
+ 0x11060000, 0x11060000, 0x11050000, 0x1105ff00,
+
+ 0x14100600, 0x15100500, 0x150f0500, 0x150f0500,
+ 0x140f0500, 0x150e0400, 0x140e0400, 0x130e0400,
+ 0x140d0400, 0x150d0300, 0x130d0300, 0x140c0300,
+ 0x140c0300, 0x140c0200, 0x140b0200, 0x130b0200,
+ 0x120b0200, 0x130a0200, 0x130a0200, 0x130a0100,
+ 0x13090100, 0x12090100, 0x11090100, 0x12080100,
+ 0x11080100, 0x10080100, 0x11070100, 0x11070000,
+ 0x10070000, 0x11060000, 0x10060000, 0x10060000,
+
+ 0x140f0600, 0x140f0600, 0x130f0600, 0x140f0500,
+ 0x140e0500, 0x130e0500, 0x130e0500, 0x140d0400,
+ 0x140d0400, 0x130d0400, 0x120d0400, 0x130c0400,
+ 0x130c0300, 0x130c0300, 0x130b0300, 0x130b0300,
+ 0x110b0300, 0x130a0200, 0x120a0200, 0x120a0200,
+ 0x120a0200, 0x12090200, 0x10090200, 0x11090100,
+ 0x11080100, 0x11080100, 0x10080100, 0x10080100,
+ 0x10070100, 0x10070100, 0x0f070100, 0x10060100,
+
+ 0x120f0701, 0x130f0601, 0x130e0601, 0x130e0601,
+ 0x120e0601, 0x130e0501, 0x130e0500, 0x130d0500,
+ 0x120d0500, 0x120d0500, 0x130c0400, 0x130c0400,
+ 0x120c0400, 0x110c0400, 0x120b0400, 0x120b0300,
+ 0x120b0300, 0x120b0300, 0x120a0300, 0x110a0300,
+ 0x110a0200, 0x11090200, 0x11090200, 0x10090200,
+ 0x10090200, 0x10080200, 0x10080200, 0x10080100,
+ 0x0f080100, 0x10070100, 0x0f070100, 0x0f070100
+};
+
+static const u32 lan3coefftab32_right[480] = {
+ 0x00000000, 0x00000002, 0x0000ff04, 0x0000ff06,
+ 0x0000fe08, 0x0000fd0a, 0x0000fd0c, 0x0000fc0f,
+ 0x0000fc12, 0x0001fb14, 0x0001fa17, 0x0001fa19,
+ 0x0001f91c, 0x0001f91f, 0x0001f822, 0x0001f824,
+ 0x0002f727, 0x0002f72a, 0x0002f72c, 0x0002f72f,
+ 0x0002f731, 0x0002f733, 0x0002f735, 0x0002f737,
+ 0x0002f73a, 0x0002f83b, 0x0002f93c, 0x0002fa3d,
+ 0x0001fb3e, 0x0001fc3f, 0x0001fd40, 0x0000fe40,
+
+ 0x0002fc06, 0x0002fb08, 0x0002fb0a, 0x0002fa0c,
+ 0x0002fa0e, 0x0003f910, 0x0003f912, 0x0003f814,
+ 0x0003f816, 0x0003f719, 0x0003f71a, 0x0003f71d,
+ 0x0003f71f, 0x0003f721, 0x0003f723, 0x0003f725,
+ 0x0002f727, 0x0002f729, 0x0002f72b, 0x0002f82d,
+ 0x0002f82e, 0x0001f930, 0x0001fa31, 0x0000fa34,
+ 0x0000fb34, 0x0100fc35, 0x01fffd36, 0x01ffff37,
+ 0x01fe0037, 0x01fe0138, 0x01fd0338, 0x02fc0538,
+
+ 0x0002fa0b, 0x0002fa0c, 0x0002f90e, 0x0002f910,
+ 0x0002f911, 0x0002f813, 0x0002f816, 0x0002f817,
+ 0x0002f818, 0x0002f81a, 0x0001f81c, 0x0001f81e,
+ 0x0001f820, 0x0001f921, 0x0001f923, 0x0000f925,
+ 0x0000fa26, 0x0100fa28, 0x01fffb29, 0x01fffc2a,
+ 0x01fffc2c, 0x01fefd2d, 0x01fefe2e, 0x01fdff2f,
+ 0x01fd0030, 0x01fd0130, 0x01fc0232, 0x02fc0432,
+ 0x02fb0532, 0x02fb0633, 0x02fb0833, 0x02fa0933,
+
+ 0x0001fa0e, 0x0001f90f, 0x0001f911, 0x0001f913,
+ 0x0001f914, 0x0001f915, 0x0000f918, 0x0000fa18,
+ 0x0000fa1a, 0x0000fa1b, 0x0000fa1d, 0x00fffb1e,
+ 0x01fffb1f, 0x01fffb20, 0x01fffc22, 0x01fefc23,
+ 0x01fefd24, 0x01fefe25, 0x01fdfe27, 0x01fdff28,
+ 0x01fd0029, 0x01fc012a, 0x01fc022b, 0x01fc032b,
+ 0x01fb042d, 0x01fb052d, 0x01fb062e, 0x01fb072e,
+ 0x01fa092e, 0x01fa0a2f, 0x01fa0b2f, 0x01fa0d2f,
+
+ 0x0000fa11, 0x0000fa12, 0x0000fa13, 0x0000fb14,
+ 0x00fffb16, 0x00fffb16, 0x00fffb17, 0x00fffb19,
+ 0x00fffc1a, 0x00fefc1c, 0x00fefd1c, 0x01fefd1d,
+ 0x01fefe1e, 0x01fdfe20, 0x01fdff21, 0x01fdff22,
+ 0x01fd0023, 0x01fc0124, 0x01fc0124, 0x01fc0225,
+ 0x01fc0326, 0x01fc0427, 0x01fb0528, 0x01fb0629,
+ 0x01fb0729, 0x01fb0829, 0x01fb092a, 0x01fb0a2a,
+ 0x00fa0b2c, 0x00fa0c2b, 0x00fa0e2b, 0x00fa0f2c,
+
+ 0x00fffc11, 0x00fffc12, 0x00fffc14, 0x00fffc15,
+ 0x00fefd16, 0x00fefd17, 0x00fefd18, 0x00fefe19,
+ 0x00fefe1a, 0x00fdfe1d, 0x00fdff1d, 0x00fdff1e,
+ 0x00fd001d, 0x00fd011e, 0x00fd0120, 0x00fc0221,
+ 0x00fc0321, 0x00fc0323, 0x00fc0423, 0x00fc0523,
+ 0x00fc0624, 0x00fb0725, 0x00fb0726, 0x00fb0827,
+ 0x00fb0926, 0x00fb0a26, 0x00fb0b27, 0x00fb0c27,
+ 0x00fb0d27, 0xfffb0e28, 0xfffb0f29, 0xfffc1028,
+
+ 0x00fefd13, 0x00fefd13, 0x00fefe14, 0x00fefe15,
+ 0x00fefe17, 0x00feff17, 0x00feff17, 0x00fd0018,
+ 0x00fd001a, 0x00fd001a, 0x00fd011b, 0x00fd021c,
+ 0x00fd021c, 0x00fd031d, 0x00fc031f, 0x00fc041f,
+ 0x00fc051f, 0x00fc0521, 0x00fc0621, 0x00fc0721,
+ 0x00fc0821, 0x00fc0822, 0x00fc0922, 0x00fc0a23,
+ 0xfffc0b24, 0xfffc0c24, 0xfffc0d24, 0xfffc0d25,
+ 0xfffc0e25, 0xfffd0f25, 0xfffd1025, 0xfffd1125,
+
+ 0x00feff12, 0x00feff14, 0x00feff14, 0x00fe0015,
+ 0x00fe0015, 0x00fd0017, 0x00fd0118, 0x00fd0118,
+ 0x00fd0218, 0x00fd0219, 0x00fd031a, 0x00fd031a,
+ 0x00fd041b, 0x00fd041c, 0x00fd051c, 0x00fd061d,
+ 0x00fd061d, 0x00fd071e, 0x00fd081e, 0xfffd081f,
+ 0xfffd091f, 0xfffd0a20, 0xfffd0a20, 0xfffd0b21,
+ 0xfffd0c21, 0xfffd0d21, 0xfffd0d22, 0xfffd0e23,
+ 0xfffe0f22, 0xfefe1022, 0xfefe1122, 0xfefe1123,
+
+ 0x00fe0012, 0x00fe0013, 0x00fe0114, 0x00fe0114,
+ 0x00fe0116, 0x00fe0216, 0x00fe0216, 0x00fd0317,
+ 0x00fd0317, 0x00fd0418, 0x00fd0419, 0x00fd0519,
+ 0x00fd051a, 0x00fd061b, 0x00fd061b, 0x00fd071c,
+ 0xfffd071e, 0xfffd081d, 0xfffd091d, 0xfffd091e,
+ 0xfffe0a1d, 0xfffe0b1e, 0xfffe0b1e, 0xfffe0c1e,
+ 0xfffe0d1f, 0xfffe0d1f, 0xfffe0e1f, 0xfeff0f1f,
+ 0xfeff0f20, 0xfeff1020, 0xfeff1120, 0xfe001120,
+
+ 0x00fe0212, 0x00fe0312, 0x00fe0313, 0x00fe0314,
+ 0x00fe0414, 0x00fe0414, 0x00fe0416, 0x00fe0515,
+ 0x00fe0516, 0x00fe0616, 0x00fe0617, 0x00fe0717,
+ 0xfffe0719, 0xfffe0818, 0xffff0818, 0xffff0919,
+ 0xffff0919, 0xffff0a19, 0xffff0a1a, 0xffff0b1a,
+ 0xffff0b1b, 0xffff0c1a, 0xff000c1b, 0xff000d1b,
+ 0xff000d1b, 0xff000e1b, 0xff000e1c, 0xff010f1c,
+ 0xfe01101c, 0xfe01101d, 0xfe02111c, 0xfe02111c,
+
+ 0x00ff0411, 0x00ff0411, 0x00ff0412, 0x00ff0512,
+ 0x00ff0513, 0x00ff0513, 0x00ff0613, 0x00ff0614,
+ 0x00ff0714, 0x00ff0715, 0x00ff0715, 0xffff0816,
+ 0xffff0816, 0xff000916, 0xff000917, 0xff000918,
+ 0xff000a17, 0xff000a18, 0xff000b18, 0xff000b18,
+ 0xff010c18, 0xff010c19, 0xff010d18, 0xff010d18,
+ 0xff020d18, 0xff020e19, 0xff020e19, 0xff020f19,
+ 0xff030f19, 0xff031019, 0xff031019, 0xff031119,
+
+ 0x00ff0511, 0x00ff0511, 0x00000511, 0x00000611,
+ 0x00000612, 0x00000612, 0x00000712, 0x00000713,
+ 0x00000714, 0x00000814, 0x00000814, 0x00000914,
+ 0x00000914, 0xff010914, 0xff010a15, 0xff010a16,
+ 0xff010a17, 0xff010b16, 0xff010b16, 0xff020c16,
+ 0xff020c16, 0xff020c16, 0xff020d16, 0xff020d17,
+ 0xff030d17, 0xff030e17, 0xff030e17, 0xff030f17,
+ 0xff040f17, 0xff040f17, 0xff041017, 0xff051017,
+
+ 0x00000610, 0x00000610, 0x00000611, 0x00000611,
+ 0x00000711, 0x00000712, 0x00010712, 0x00010812,
+ 0x00010812, 0x00010812, 0x00010913, 0x00010913,
+ 0x00010913, 0x00010a13, 0x00020a13, 0x00020a14,
+ 0x00020b14, 0x00020b14, 0x00020b14, 0x00020c14,
+ 0x00030c14, 0x00030c15, 0x00030d15, 0x00030d15,
+ 0x00040d15, 0x00040e15, 0x00040e15, 0x00040e16,
+ 0x00050f15, 0x00050f15, 0x00050f16, 0x00051015,
+
+ 0x00000611, 0x00010610, 0x00010710, 0x00010710,
+ 0x00010711, 0x00010811, 0x00010811, 0x00010812,
+ 0x00010812, 0x00010912, 0x00020912, 0x00020912,
+ 0x00020a12, 0x00020a12, 0x00020a13, 0x00020a13,
+ 0x00030b13, 0x00030b13, 0x00030b14, 0x00030c13,
+ 0x00030c13, 0x00040c13, 0x00040d14, 0x00040d14,
+ 0x00040d15, 0x00040d15, 0x00050e14, 0x00050e14,
+ 0x00050e15, 0x00050f14, 0x00060f14, 0x00060f14,
+
+ 0x0001070f, 0x0001070f, 0x00010710, 0x00010710,
+ 0x00010810, 0x00010810, 0x00020810, 0x00020811,
+ 0x00020911, 0x00020911, 0x00020912, 0x00020912,
+ 0x00020a12, 0x00030a12, 0x00030a12, 0x00030b12,
+ 0x00030b12, 0x00030b12, 0x00040b12, 0x00040c12,
+ 0x00040c13, 0x00040c14, 0x00040c14, 0x00050d13,
+ 0x00050d13, 0x00050d14, 0x00050e13, 0x01050e13,
+ 0x01060e13, 0x01060e13, 0x01060e14, 0x01060f13
+};
+
+static const u32 lan2coefftab32[480] = {
+ 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+ 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
+ 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
+ 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
+ 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
+ 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
+ 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
+ 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+
+ 0xff053804, 0xff063803, 0xff083801, 0xff093701,
+ 0xff0a3700, 0xff0c3500, 0xff0e34ff, 0xff1033fe,
+ 0xff1232fd, 0xfe1431fd, 0xfe162ffd, 0xfe182dfd,
+ 0xfd1b2cfc, 0xfd1d2afc, 0xfd1f28fc, 0xfd2126fc,
+ 0xfd2323fd, 0xfc2621fd, 0xfc281ffd, 0xfc2a1dfd,
+ 0xfc2c1bfd, 0xfd2d18fe, 0xfd2f16fe, 0xfd3114fe,
+ 0xfd3212ff, 0xfe3310ff, 0xff340eff, 0x00350cff,
+ 0x00360a00, 0x01360900, 0x02370700, 0x03370600,
+
+ 0xff083207, 0xff093206, 0xff0a3205, 0xff0c3203,
+ 0xff0d3103, 0xff0e3102, 0xfe113001, 0xfe132f00,
+ 0xfe142e00, 0xfe162dff, 0xfe182bff, 0xfe192aff,
+ 0xfe1b29fe, 0xfe1d27fe, 0xfe1f25fe, 0xfd2124fe,
+ 0xfe2222fe, 0xfe2421fd, 0xfe251ffe, 0xfe271dfe,
+ 0xfe291bfe, 0xff2a19fe, 0xff2b18fe, 0xff2d16fe,
+ 0x002e14fe, 0x002f12ff, 0x013010ff, 0x02300fff,
+ 0x03310dff, 0x04310cff, 0x05310a00, 0x06310900,
+
+ 0xff0a2e09, 0xff0b2e08, 0xff0c2e07, 0xff0e2d06,
+ 0xff0f2d05, 0xff102d04, 0xff122c03, 0xfe142c02,
+ 0xfe152b02, 0xfe172a01, 0xfe182901, 0xfe1a2800,
+ 0xfe1b2700, 0xfe1d2500, 0xff1e24ff, 0xfe2023ff,
+ 0xff2121ff, 0xff2320fe, 0xff241eff, 0x00251dfe,
+ 0x00261bff, 0x00281afe, 0x012818ff, 0x012a16ff,
+ 0x022a15ff, 0x032b13ff, 0x032c12ff, 0x052c10ff,
+ 0x052d0fff, 0x062d0d00, 0x072d0c00, 0x082d0b00,
+
+ 0xff0c2a0b, 0xff0d2a0a, 0xff0e2a09, 0xff0f2a08,
+ 0xff102a07, 0xff112a06, 0xff132905, 0xff142904,
+ 0xff162803, 0xff172703, 0xff182702, 0xff1a2601,
+ 0xff1b2501, 0xff1c2401, 0xff1e2300, 0xff1f2200,
+ 0x00202000, 0x00211f00, 0x01221d00, 0x01231c00,
+ 0x01251bff, 0x02251aff, 0x032618ff, 0x032717ff,
+ 0x042815ff, 0x052814ff, 0x052913ff, 0x06291100,
+ 0x072a10ff, 0x082a0e00, 0x092a0d00, 0x0a2a0c00,
+
+ 0xff0d280c, 0xff0e280b, 0xff0f280a, 0xff102809,
+ 0xff112808, 0xff122708, 0xff142706, 0xff152705,
+ 0xff162605, 0xff172604, 0xff192503, 0xff1a2403,
+ 0x001b2302, 0x001c2202, 0x001d2201, 0x001e2101,
+ 0x011f1f01, 0x01211e00, 0x01221d00, 0x02221c00,
+ 0x02231b00, 0x03241900, 0x04241800, 0x04251700,
+ 0x052616ff, 0x06261400, 0x072713ff, 0x08271100,
+ 0x08271100, 0x09271000, 0x0a280e00, 0x0b280d00,
+
+ 0xff0e260d, 0xff0f260c, 0xff10260b, 0xff11260a,
+ 0xff122609, 0xff132608, 0xff142508, 0xff152507,
+ 0x00152506, 0x00172405, 0x00182305, 0x00192304,
+ 0x001b2203, 0x001c2103, 0x011d2002, 0x011d2002,
+ 0x011f1f01, 0x021f1e01, 0x02201d01, 0x03211c00,
+ 0x03221b00, 0x04221a00, 0x04231801, 0x05241700,
+ 0x06241600, 0x07241500, 0x08251300, 0x09251200,
+ 0x09261100, 0x0a261000, 0x0b260f00, 0x0c260e00,
+
+ 0xff0e250e, 0xff0f250d, 0xff10250c, 0xff11250b,
+ 0x0011250a, 0x00132409, 0x00142408, 0x00152407,
+ 0x00162307, 0x00172306, 0x00182206, 0x00192205,
+ 0x011a2104, 0x011b2004, 0x011c2003, 0x021c1f03,
+ 0x021e1e02, 0x031e1d02, 0x03201c01, 0x04201b01,
+ 0x04211a01, 0x05221900, 0x05221801, 0x06231700,
+ 0x07231600, 0x07241500, 0x08241400, 0x09241300,
+ 0x0a241200, 0x0b241100, 0x0c241000, 0x0d240f00,
+
+ 0x000e240e, 0x000f240d, 0x0010240c, 0x0011240b,
+ 0x0013230a, 0x0013230a, 0x00142309, 0x00152308,
+ 0x00162208, 0x00172207, 0x01182106, 0x01192105,
+ 0x011a2005, 0x021b1f04, 0x021b1f04, 0x021d1e03,
+ 0x031d1d03, 0x031e1d02, 0x041e1c02, 0x041f1b02,
+ 0x05201a01, 0x05211901, 0x06211801, 0x07221700,
+ 0x07221601, 0x08231500, 0x09231400, 0x0a231300,
+ 0x0a231300, 0x0b231200, 0x0c231100, 0x0d231000,
+
+ 0x000f220f, 0x0010220e, 0x0011220d, 0x0012220c,
+ 0x0013220b, 0x0013220b, 0x0015210a, 0x0015210a,
+ 0x01162108, 0x01172008, 0x01182007, 0x02191f06,
+ 0x02191f06, 0x021a1e06, 0x031a1e05, 0x031c1d04,
+ 0x041c1c04, 0x041d1c03, 0x051d1b03, 0x051e1a03,
+ 0x061f1902, 0x061f1902, 0x07201801, 0x08201701,
+ 0x08211601, 0x09211501, 0x0a211500, 0x0b211400,
+ 0x0b221300, 0x0c221200, 0x0d221100, 0x0e221000,
+
+ 0x0010210f, 0x0011210e, 0x0011210e, 0x0012210d,
+ 0x0013210c, 0x0014200c, 0x0114200b, 0x0115200a,
+ 0x01161f0a, 0x01171f09, 0x02171f08, 0x02181e08,
+ 0x03181e07, 0x031a1d06, 0x031a1d06, 0x041b1c05,
+ 0x041c1c04, 0x051c1b04, 0x051d1a04, 0x061d1a03,
+ 0x071d1903, 0x071e1803, 0x081e1802, 0x081f1702,
+ 0x091f1602, 0x0a201501, 0x0b1f1501, 0x0b201401,
+ 0x0c211300, 0x0d211200, 0x0e201200, 0x0e211100,
+
+ 0x00102010, 0x0011200f, 0x0012200e, 0x0013200d,
+ 0x0013200d, 0x01141f0c, 0x01151f0b, 0x01151f0b,
+ 0x01161f0a, 0x02171e09, 0x02171e09, 0x03181d08,
+ 0x03191d07, 0x03191d07, 0x041a1c06, 0x041b1c05,
+ 0x051b1b05, 0x051c1b04, 0x061c1a04, 0x071d1903,
+ 0x071d1903, 0x081d1803, 0x081e1703, 0x091e1702,
+ 0x0a1f1601, 0x0a1f1502, 0x0b1f1501, 0x0c1f1401,
+ 0x0d201300, 0x0d201300, 0x0e201200, 0x0f201100,
+
+ 0x00102010, 0x0011200f, 0x00121f0f, 0x00131f0e,
+ 0x00141f0d, 0x01141f0c, 0x01141f0c, 0x01151e0c,
+ 0x02161e0a, 0x02171e09, 0x03171d09, 0x03181d08,
+ 0x03181d08, 0x04191c07, 0x041a1c06, 0x051a1b06,
+ 0x051b1b05, 0x061b1a05, 0x061c1a04, 0x071c1904,
+ 0x081c1903, 0x081d1803, 0x091d1703, 0x091e1702,
+ 0x0a1e1602, 0x0b1e1502, 0x0c1e1501, 0x0c1f1401,
+ 0x0d1f1400, 0x0e1f1300, 0x0e1f1201, 0x0f1f1200,
+
+ 0x00111e11, 0x00121e10, 0x00131e0f, 0x00131e0f,
+ 0x01131e0e, 0x01141d0e, 0x02151d0c, 0x02151d0c,
+ 0x02161d0b, 0x03161c0b, 0x03171c0a, 0x04171c09,
+ 0x04181b09, 0x05181b08, 0x05191b07, 0x06191a07,
+ 0x061a1a06, 0x071a1906, 0x071b1905, 0x081b1805,
+ 0x091b1804, 0x091c1704, 0x0a1c1703, 0x0a1c1604,
+ 0x0b1d1602, 0x0c1d1502, 0x0c1d1502, 0x0d1d1402,
+ 0x0e1d1401, 0x0e1e1301, 0x0f1e1300, 0x101e1200,
+
+ 0x00111e11, 0x00121e10, 0x00131d10, 0x01131d0f,
+ 0x01141d0e, 0x01141d0e, 0x02151c0d, 0x02151c0d,
+ 0x03161c0b, 0x03161c0b, 0x04171b0a, 0x04171b0a,
+ 0x05171b09, 0x05181a09, 0x06181a08, 0x06191a07,
+ 0x07191907, 0x071a1906, 0x081a1806, 0x081a1806,
+ 0x091a1805, 0x0a1b1704, 0x0a1b1704, 0x0b1c1603,
+ 0x0b1c1603, 0x0c1c1503, 0x0d1c1502, 0x0d1d1402,
+ 0x0e1d1401, 0x0f1d1301, 0x0f1d1301, 0x101e1200,
+};
+
+static const u32 bicubic8coefftab32_left[480] = {
+ 0x40000000, 0x40ff0000, 0x3ffe0000, 0x3efe0000,
+ 0x3dfd0000, 0x3cfc0000, 0x3bfc0000, 0x39fc0000,
+ 0x36fc0000, 0x35fb0000, 0x33fb0000, 0x31fb0000,
+ 0x2ffb0000, 0x2cfb0000, 0x29fc0000, 0x27fc0000,
+ 0x24fc0000, 0x21fc0000, 0x1efd0000, 0x1cfd0000,
+ 0x19fd0000, 0x16fe0000, 0x14fe0000, 0x11fe0000,
+ 0x0dff0000, 0x0cff0000, 0x0aff0000, 0x08ff0000,
+ 0x05000000, 0x03000000, 0x02000000, 0x01000000,
+
+ 0x3904ff00, 0x3903ff00, 0x3902ff00, 0x38010000,
+ 0x37000000, 0x36ff0000, 0x35ff0000, 0x34fe0000,
+ 0x32fe0000, 0x31fd0000, 0x30fd0000, 0x2efc0000,
+ 0x2cfc0000, 0x2afc0000, 0x28fc0000, 0x26fc0000,
+ 0x24fc0000, 0x22fc0000, 0x20fc0000, 0x1efc0000,
+ 0x1cfc0000, 0x19fc0000, 0x17fc0000, 0x15fd0000,
+ 0x12fd0000, 0x11fd0000, 0x0ffd0000, 0x0dfe0000,
+ 0x0bfe0000, 0x09fe0000, 0x08fe0000, 0x06ff0000,
+
+ 0x3209fe00, 0x3407fe00, 0x3306fe00, 0x3305fe00,
+ 0x3204fe00, 0x3102ff00, 0x3102ff00, 0x3001ff00,
+ 0x2f00ff00, 0x2effff00, 0x2cff0000, 0x2bfe0000,
+ 0x29fe0000, 0x28fe0000, 0x26fd0000, 0x24fd0000,
+ 0x23fd0000, 0x21fd0000, 0x20fc0000, 0x1efc0000,
+ 0x1dfc0000, 0x1bfc0000, 0x19fc0000, 0x17fc0000,
+ 0x16fc0000, 0x14fc0000, 0x12fc0000, 0x10fd0000,
+ 0x0ffd0000, 0x0dfd0000, 0x0cfd0000, 0x0afd0000,
+
+ 0x2e0cfd00, 0x2e0bfd00, 0x2e09fd00, 0x2e08fd00,
+ 0x2e07fd00, 0x2c06fe00, 0x2c05fe00, 0x2b04fe00,
+ 0x2b03fe00, 0x2a02fe00, 0x2901fe00, 0x2701ff00,
+ 0x2700ff00, 0x26ffff00, 0x24ffff00, 0x23ffff00,
+ 0x22feff00, 0x20fe0000, 0x1ffe0000, 0x1efd0000,
+ 0x1dfd0000, 0x1bfd0000, 0x1afd0000, 0x19fd0000,
+ 0x17fd0000, 0x15fd0000, 0x13fd0000, 0x12fd0000,
+ 0x11fd0000, 0x10fd0000, 0x0ffd0000, 0x0cfd0000,
+
+ 0x2a0efd00, 0x2a0dfd00, 0x2a0cfd00, 0x290bfd00,
+ 0x290afd00, 0x2909fd00, 0x2908fd00, 0x2807fd00,
+ 0x2706fd00, 0x2705fd00, 0x2604fe00, 0x2603fe00,
+ 0x2502fe00, 0x2402fe00, 0x2401fe00, 0x2200fe00,
+ 0x2200fe00, 0x2000ff00, 0x1fffff00, 0x1effff00,
+ 0x1dfeff00, 0x1cfeff00, 0x1afeff00, 0x19feff00,
+ 0x17fe0000, 0x16fd0000, 0x15fd0000, 0x14fd0000,
+ 0x12fd0000, 0x11fd0000, 0x10fd0000, 0x0ffd0000,
+
+ 0x2610fd00, 0x260ffd00, 0x260efd00, 0x260dfd00,
+ 0x260cfd00, 0x260bfd00, 0x260afd00, 0x2609fd00,
+ 0x2508fd00, 0x2507fd00, 0x2406fd00, 0x2406fd00,
+ 0x2305fd00, 0x2304fd00, 0x2203fe00, 0x2103fe00,
+ 0x2002fe00, 0x1f01fe00, 0x1e01fe00, 0x1e00fe00,
+ 0x1c00fe00, 0x1b00fe00, 0x1afffe00, 0x19ffff00,
+ 0x18ffff00, 0x17feff00, 0x16feff00, 0x15feff00,
+ 0x14feff00, 0x13feff00, 0x11feff00, 0x10fd0000,
+
+ 0x2411feff, 0x2410feff, 0x240ffeff, 0x230efeff,
+ 0x240dfeff, 0x240cfeff, 0x230cfd00, 0x230bfd00,
+ 0x230afd00, 0x2309fd00, 0x2208fd00, 0x2108fd00,
+ 0x2007fd00, 0x2106fd00, 0x2005fd00, 0x1f05fd00,
+ 0x1f04fd00, 0x1e03fd00, 0x1d03fe00, 0x1c02fe00,
+ 0x1b02fe00, 0x1a01fe00, 0x1a01fe00, 0x1900fe00,
+ 0x1800fe00, 0x1700fe00, 0x16fffe00, 0x15fffe00,
+ 0x13ffff00, 0x12ffff00, 0x12feff00, 0x11feff00,
+
+ 0x2212fffe, 0x2211fffe, 0x2210ffff, 0x220ffeff,
+ 0x220efeff, 0x210efeff, 0x210dfeff, 0x210cfeff,
+ 0x210bfeff, 0x200bfeff, 0x200afeff, 0x1f09feff,
+ 0x1f08feff, 0x1d08fe00, 0x1e07fd00, 0x1e06fd00,
+ 0x1d06fd00, 0x1c05fd00, 0x1b04fe00, 0x1a04fe00,
+ 0x1a03fe00, 0x1903fe00, 0x1802fe00, 0x1802fe00,
+ 0x1701fe00, 0x1601fe00, 0x1501fe00, 0x1500fe00,
+ 0x1400fe00, 0x1400fe00, 0x13fffe00, 0x12fffe00,
+
+ 0x201200fe, 0x201100fe, 0x1f1100fe, 0x2010fffe,
+ 0x200ffffe, 0x1f0ffffe, 0x1f0efffe, 0x1e0dffff,
+ 0x1f0cfeff, 0x1e0cfeff, 0x1e0bfeff, 0x1e0afeff,
+ 0x1d0afeff, 0x1d09feff, 0x1c08feff, 0x1b08feff,
+ 0x1b07feff, 0x1a07feff, 0x1a06feff, 0x1a05feff,
+ 0x1805fe00, 0x1904fe00, 0x1704fe00, 0x1703fe00,
+ 0x1603fe00, 0x1602fe00, 0x1402fe00, 0x1402fe00,
+ 0x1401fe00, 0x1301fe00, 0x1201fe00, 0x1200fe00,
+
+ 0x1c1202fe, 0x1c1102fe, 0x1b1102fe, 0x1c1001fe,
+ 0x1b1001fe, 0x1c0f01fe, 0x1b0f00fe, 0x1b0e00fe,
+ 0x1b0e00fe, 0x1b0d00fe, 0x1b0c00fe, 0x1a0cfffe,
+ 0x1a0bfffe, 0x1a0bfffe, 0x190afffe, 0x190afffe,
+ 0x1909fffe, 0x1709ffff, 0x1808ffff, 0x1708feff,
+ 0x1707feff, 0x1707feff, 0x1606feff, 0x1506feff,
+ 0x1505feff, 0x1505feff, 0x1404feff, 0x1404feff,
+ 0x1404feff, 0x1303feff, 0x1203feff, 0x1202feff,
+
+ 0x191104fe, 0x191104fe, 0x191003fe, 0x191003fe,
+ 0x171003fe, 0x180f03fe, 0x180f02fe, 0x180e02fe,
+ 0x180e02fe, 0x180d01fe, 0x180d01fe, 0x180d01fe,
+ 0x170c01fe, 0x160c01fe, 0x170b00fe, 0x170b00fe,
+ 0x160a00fe, 0x160a00fe, 0x160a00fe, 0x150900fe,
+ 0x1509fffe, 0x1508fffe, 0x1508fffe, 0x1408fffe,
+ 0x1407fffe, 0x1307ffff, 0x1306ffff, 0x1206ffff,
+ 0x1206ffff, 0x1205ffff, 0x1205ffff, 0x1104feff,
+
+ 0x161006ff, 0x161005ff, 0x161005ff, 0x160f05ff,
+ 0x160f04ff, 0x150f04ff, 0x150e04ff, 0x150e04ff,
+ 0x150e03ff, 0x150d03ff, 0x150d03ff, 0x150d02ff,
+ 0x140c02ff, 0x150c02fe, 0x150c02fe, 0x150b02fe,
+ 0x140b01fe, 0x140b01fe, 0x140a01fe, 0x140a01fe,
+ 0x140a01fe, 0x130900fe, 0x130900fe, 0x130900fe,
+ 0x130800fe, 0x120800fe, 0x120800fe, 0x120700fe,
+ 0x120700fe, 0x1107fffe, 0x1106fffe, 0x1106fffe,
+
+ 0x140f0700, 0x140f0600, 0x140f0600, 0x140f0600,
+ 0x140e0600, 0x130e0500, 0x140e05ff, 0x130e05ff,
+ 0x140d05ff, 0x130d04ff, 0x130d04ff, 0x120d04ff,
+ 0x130c04ff, 0x130c03ff, 0x130c03ff, 0x120c03ff,
+ 0x120b03ff, 0x120b02ff, 0x120b02ff, 0x120a02ff,
+ 0x120a02ff, 0x110a02ff, 0x110a01ff, 0x120901ff,
+ 0x100901ff, 0x100901ff, 0x110801ff, 0x110801ff,
+ 0x100800ff, 0x100800ff, 0x100700ff, 0x100700fe,
+
+ 0x120f0701, 0x120e0701, 0x120e0701, 0x120e0701,
+ 0x120e0600, 0x110e0600, 0x120d0600, 0x120d0600,
+ 0x120d0500, 0x120d0500, 0x110d0500, 0x110c0500,
+ 0x110c0500, 0x110c0400, 0x110c0400, 0x110b04ff,
+ 0x110b04ff, 0x110b04ff, 0x110b03ff, 0x110b03ff,
+ 0x110a03ff, 0x110a03ff, 0x100a03ff, 0x110a02ff,
+ 0x100902ff, 0x100902ff, 0x100902ff, 0x0f0902ff,
+ 0x0e0902ff, 0x100801ff, 0x0f0801ff, 0x0f0801ff,
+
+ 0x100e0802, 0x100e0802, 0x110e0702, 0x110d0701,
+ 0x110d0701, 0x100d0701, 0x100d0701, 0x110d0601,
+ 0x110d0601, 0x110c0601, 0x110c0601, 0x100c0600,
+ 0x100c0500, 0x100c0500, 0x100c0500, 0x100b0500,
+ 0x100b0500, 0x100b0400, 0x100b0400, 0x0f0b0400,
+ 0x100a0400, 0x0f0a0400, 0x0f0a0400, 0x0f0a0300,
+ 0x0f0a03ff, 0x0f0903ff, 0x0f0903ff, 0x0f0903ff,
+ 0x0f0903ff, 0x0f0902ff, 0x0f0902ff, 0x0f0802ff
+};
+
+static const u32 bicubic8coefftab32_right[480] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000004,
+ 0x00000006, 0x0000ff09, 0x0000ff0a, 0x0000ff0c,
+ 0x0000ff0f, 0x0000fe12, 0x0000fe14, 0x0000fe16,
+ 0x0000fd19, 0x0000fd1c, 0x0000fd1e, 0x0000fc21,
+ 0x0000fc24, 0x0000fc27, 0x0000fc29, 0x0000fb2c,
+ 0x0000fb2f, 0x0000fb31, 0x0000fb33, 0x0000fb36,
+ 0x0000fc38, 0x0000fc39, 0x0000fc3b, 0x0000fc3d,
+ 0x0000fd3e, 0x0000fe3f, 0x0000fe40, 0x0000ff40,
+
+ 0x0000ff05, 0x0000ff06, 0x0000fe08, 0x0000fe09,
+ 0x0000fe0b, 0x0000fe0d, 0x0000fd0f, 0x0000fd11,
+ 0x0000fd13, 0x0000fd15, 0x0000fc17, 0x0000fc1a,
+ 0x0000fc1c, 0x0000fc1e, 0x0000fc20, 0x0000fc22,
+ 0x0000fc24, 0x0000fc26, 0x0000fc28, 0x0000fc2a,
+ 0x0000fc2c, 0x0000fc2f, 0x0000fd30, 0x0000fd31,
+ 0x0000fe33, 0x0000fe34, 0x0000ff35, 0x0000ff36,
+ 0x00000037, 0x00000138, 0x00ff0239, 0x00ff0339,
+
+ 0x0000fe09, 0x0000fd0a, 0x0000fd0c, 0x0000fd0d,
+ 0x0000fd0f, 0x0000fd11, 0x0000fc12, 0x0000fc14,
+ 0x0000fc16, 0x0000fc18, 0x0000fc19, 0x0000fc1b,
+ 0x0000fc1d, 0x0000fc1e, 0x0000fc21, 0x0000fd22,
+ 0x0000fd23, 0x0000fd25, 0x0000fd27, 0x0000fe28,
+ 0x0000fe29, 0x0000fe2b, 0x0000ff2c, 0x00ffff2f,
+ 0x00ff002f, 0x00ff0130, 0x00ff0231, 0x00ff0232,
+ 0x00fe0432, 0x00fe0533, 0x00fe0633, 0x00fe0734,
+
+ 0x0000fd0c, 0x0000fd0d, 0x0000fd0f, 0x0000fd10,
+ 0x0000fd11, 0x0000fd13, 0x0000fd14, 0x0000fd16,
+ 0x0000fd17, 0x0000fd19, 0x0000fd1b, 0x0000fd1c,
+ 0x0000fd1d, 0x0000fd1f, 0x0000fe20, 0x0000fe21,
+ 0x00fffe24, 0x00ffff24, 0x00ffff25, 0x00ffff27,
+ 0x00ff0027, 0x00ff0128, 0x00fe012a, 0x00fe022a,
+ 0x00fe032b, 0x00fe042c, 0x00fe052d, 0x00fe062d,
+ 0x00fd072e, 0x00fd082e, 0x00fd092e, 0x00fd0b2f,
+
+ 0x0000fd0e, 0x0000fd0f, 0x0000fd10, 0x0000fd12,
+ 0x0000fd13, 0x0000fd14, 0x0000fd15, 0x0000fd17,
+ 0x0000fe18, 0x00fffe1a, 0x00fffe1b, 0x00fffe1c,
+ 0x00fffe1e, 0x00ffff1e, 0x00ffff1f, 0x00ff0021,
+ 0x00fe0022, 0x00fe0023, 0x00fe0124, 0x00fe0224,
+ 0x00fe0226, 0x00fe0326, 0x00fe0427, 0x00fd0528,
+ 0x00fd0628, 0x00fd0729, 0x00fd0829, 0x00fd0929,
+ 0x00fd0a2a, 0x00fd0b2a, 0x00fd0c2a, 0x00fd0d2a,
+
+ 0x0000fd10, 0x0000fd11, 0x00fffe12, 0x00fffe13,
+ 0x00fffe14, 0x00fffe15, 0x00fffe16, 0x00fffe17,
+ 0x00ffff18, 0x00ffff19, 0x00feff1c, 0x00fe001b,
+ 0x00fe001d, 0x00fe001e, 0x00fe011e, 0x00fe011f,
+ 0x00fe0220, 0x00fe0321, 0x00fe0322, 0x00fd0423,
+ 0x00fd0524, 0x00fd0624, 0x00fd0626, 0x00fd0725,
+ 0x00fd0825, 0x00fd0926, 0x00fd0a26, 0x00fd0b26,
+ 0x00fd0c26, 0x00fd0d26, 0x00fd0e27, 0x00fd0f27,
+
+ 0x00fffe11, 0x00fffe12, 0x00fffe13, 0x00ffff14,
+ 0x00ffff14, 0x00feff16, 0x00feff17, 0x00fe0017,
+ 0x00fe0018, 0x00fe0019, 0x00fe011a, 0x00fe011b,
+ 0x00fe021c, 0x00fe021c, 0x00fe031d, 0x00fd031f,
+ 0x00fd041f, 0x00fd0520, 0x00fd0520, 0x00fd0621,
+ 0x00fd0721, 0x00fd0822, 0x00fd0822, 0x00fd0923,
+ 0x00fd0a23, 0x00fd0b23, 0x00fd0b25, 0x00fe0c24,
+ 0x00fe0d24, 0x00fe0e24, 0x00fe0f24, 0x00fe1024,
+
+ 0x00feff12, 0x00feff13, 0x00feff13, 0x00fe0014,
+ 0x00fe0015, 0x00fe0016, 0x00fe0116, 0x00fe0117,
+ 0x00fe0118, 0x00fe0218, 0x00fe0219, 0x00fe031a,
+ 0x00fe031b, 0x00fe041b, 0x00fd041d, 0x00fd051d,
+ 0x00fd061d, 0x00fd061f, 0x00fe071e, 0x00fe081e,
+ 0x00fe081f, 0x00fe091f, 0x00fe0a20, 0x00fe0a20,
+ 0x00fe0b21, 0x00fe0c21, 0x00fe0d21, 0x00fe0d22,
+ 0x00fe0e22, 0x00fe0f21, 0x00ff1021, 0x00ff1022,
+
+ 0x00fe0012, 0x00fe0013, 0x00fe0113, 0x00fe0114,
+ 0x00fe0115, 0x00fe0215, 0x00fe0216, 0x00fe0217,
+ 0x00fe0317, 0x00fe0318, 0x00fe0418, 0x00fe0419,
+ 0x00fe0519, 0x00fe051a, 0x00fe061b, 0x00fe071b,
+ 0x00fe071c, 0x00fe081c, 0x00fe081d, 0x00fe091d,
+ 0x00fe0a1d, 0x00fe0a1d, 0x00fe0b1e, 0x00fe0c1e,
+ 0x00ff0c1e, 0x00ff0d1e, 0x00ff0e1f, 0x00ff0e1f,
+ 0x00ff0f1f, 0x00ff0f20, 0x0000101f, 0x0000111f,
+
+ 0x00fe0212, 0x00fe0312, 0x00fe0313, 0x00fe0314,
+ 0x00fe0414, 0x00fe0414, 0x00fe0515, 0x00fe0516,
+ 0x00fe0516, 0x00fe0616, 0x00fe0617, 0x00fe0718,
+ 0x00fe0719, 0x00fe0818, 0x00ff0819, 0x00ff0918,
+ 0x00ff0919, 0x00ff0a19, 0x00ff0a19, 0x00ff0b1a,
+ 0x00ff0b1b, 0x00ff0c1a, 0x00000c1b, 0x00000d1b,
+ 0x00000d1c, 0x00000e1b, 0x00000e1d, 0x00010f1b,
+ 0x00010f1b, 0x0001101c, 0x0001101d, 0x0002111c,
+
+ 0x00fe0412, 0x00fe0412, 0x00ff0512, 0x00ff0512,
+ 0x00ff0613, 0x00ff0613, 0x00ff0614, 0x00ff0714,
+ 0x00ff0714, 0x00ff0815, 0x00ff0815, 0x00ff0815,
+ 0x00ff0916, 0x00000916, 0x00000a16, 0x00000a16,
+ 0x00000a18, 0x00000b17, 0x00000b17, 0x00010c17,
+ 0x00010c18, 0x00010d18, 0x00010d18, 0x00010d19,
+ 0x00020e18, 0x00020e18, 0x00020f18, 0x00030f18,
+ 0x00030f18, 0x00031018, 0x00031018, 0x00041119,
+
+ 0x00ff0610, 0x00ff0611, 0x00ff0611, 0x00ff0711,
+ 0x00000711, 0x00000712, 0x00000812, 0x00000812,
+ 0x00000813, 0x00000913, 0x00000913, 0x00000914,
+ 0x00010a14, 0x00010a14, 0x00010a14, 0x00010b14,
+ 0x00010b16, 0x00020b15, 0x00020c15, 0x00020c15,
+ 0x00020c15, 0x00020d17, 0x00030d16, 0x00030d16,
+ 0x00030e16, 0x00040e16, 0x00040e16, 0x00040f16,
+ 0x00040f16, 0x00050f17, 0x00051017, 0x00051017,
+
+ 0x0000070f, 0x00000710, 0x00000710, 0x00000710,
+ 0x00000810, 0x00010811, 0x00010811, 0x00010911,
+ 0x00010911, 0x00010913, 0x00010913, 0x00020a12,
+ 0x00020a12, 0x00020a13, 0x00020b12, 0x00020b13,
+ 0x00030b13, 0x00030c13, 0x00030c13, 0x00030c14,
+ 0x00040c13, 0x00040d13, 0x00040d14, 0x00040d14,
+ 0x00050e14, 0x00050e14, 0x00050e14, 0x00050e14,
+ 0x00060f14, 0x00060f14, 0x00060f15, 0x00061015,
+
+ 0x0001070f, 0x0001080f, 0x0001080f, 0x0001080f,
+ 0x00010811, 0x00020910, 0x00020910, 0x00020910,
+ 0x00020911, 0x00020a10, 0x00030a10, 0x00030a11,
+ 0x00030a11, 0x00030b11, 0x00030b11, 0x00040b12,
+ 0x00040b12, 0x00040c11, 0x00040c12, 0x00040c12,
+ 0x00050c12, 0x00050c12, 0x00050d12, 0x00050d12,
+ 0x00060d13, 0x00060d13, 0x00060e12, 0x00060e13,
+ 0x00070e13, 0x00070e13, 0x00070f13, 0x00070f13,
+
+ 0x0002080e, 0x0002080e, 0x0002080e, 0x00020810,
+ 0x0002090f, 0x0003090f, 0x0003090f, 0x0003090f,
+ 0x0003090f, 0x00030a0f, 0x00030a0f, 0x00040a10,
+ 0x00040a11, 0x00040b10, 0x00040b10, 0x00040b11,
+ 0x00050b10, 0x00050b11, 0x00050c10, 0x00050c11,
+ 0x00050c11, 0x00060c11, 0x00060c11, 0x00060d11,
+ 0x00060d12, 0x00070d12, 0x00070d12, 0x00070e11,
+ 0x00070e11, 0x00070e12, 0x00080e11, 0x00080e12
+};
+
+static const u32 bicubic4coefftab32[480] = {
+ 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
+ 0x00063dfd, 0xff083dfc, 0xff0a3bfc, 0xff0c39fc,
+ 0xff0e37fc, 0xfe1136fb, 0xfe1433fb, 0xfe1631fb,
+ 0xfd192ffb, 0xfd1c2cfb, 0xfd1e29fc, 0xfc2127fc,
+ 0xfc2424fc, 0xfc2721fc, 0xfc291efd, 0xfb2c1cfd,
+ 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfb3611fe,
+ 0xfc370eff, 0xfc390cff, 0xfc3b0aff, 0xfc3d08ff,
+ 0xfd3d0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
+
+ 0xfe053904, 0xfe063903, 0xfe083901, 0xfe0a3800,
+ 0xfd0b3800, 0xfe0d36ff, 0xfd0f35ff, 0xfd1134fe,
+ 0xfd1332fe, 0xfd1531fd, 0xfc1730fd, 0xfc1a2efc,
+ 0xfc1c2cfc, 0xfc1e2afc, 0xfc2028fc, 0xfc2226fc,
+ 0xfc2424fc, 0xfc2622fc, 0xfc2820fc, 0xfc2a1efc,
+ 0xfc2c1cfc, 0xfc2e1afc, 0xfd3017fc, 0xfd3115fd,
+ 0xfe3213fd, 0xfe3411fd, 0xff350ffd, 0xff360dfe,
+ 0x00370bfe, 0x013809fe, 0x023808fe, 0x033806ff,
+
+ 0xfd093208, 0xfd0a3207, 0xfd0c3205, 0xfd0d3204,
+ 0xfc0f3203, 0xfc113102, 0xfc123002, 0xfc143000,
+ 0xfc152f00, 0xfc172d00, 0xfc192cff, 0xfc1b2bfe,
+ 0xfc1d29fe, 0xfc1e28fe, 0xfc2027fd, 0xfd2125fd,
+ 0xfd2323fd, 0xfd2521fd, 0xfd2720fc, 0xfe281efc,
+ 0xfe291dfc, 0xfe2b1bfc, 0xff2c19fc, 0x002d17fc,
+ 0x002e16fc, 0x012f14fc, 0x022f12fd, 0x023110fd,
+ 0x03310ffd, 0x05310dfd, 0x06320bfd, 0x07320afd,
+
+ 0xfc0c2d0b, 0xfc0d2d0a, 0xfc0e2d09, 0xfc102d07,
+ 0xfc112c07, 0xfc132c05, 0xfc142c04, 0xfc162b03,
+ 0xfc172a03, 0xfc192a01, 0xfc1a2901, 0xfd1b2800,
+ 0xfd1c2700, 0xfd1e2500, 0xfe1f24ff, 0xfe2023ff,
+ 0xfe2222fe, 0xff2320fe, 0xff241ffe, 0x00251efd,
+ 0x00271cfd, 0x01271bfd, 0x01281afd, 0x022918fd,
+ 0x032a16fd, 0x032b15fd, 0x042b14fd, 0x052c12fd,
+ 0x072c10fd, 0x082c0ffd, 0x092c0efd, 0x0a2c0dfd,
+
+ 0xfd0d290d, 0xfd0e290c, 0xfd0f290b, 0xfd11280a,
+ 0xfd122809, 0xfd132808, 0xfd142807, 0xfd162706,
+ 0xfd172705, 0xfd192604, 0xfe1a2503, 0xfe1b2502,
+ 0xfe1c2402, 0xfe1d2302, 0xff1e2201, 0xff1f2101,
+ 0x00202000, 0x00211f00, 0x01221eff, 0x02221dff,
+ 0x02241cfe, 0x03241bfe, 0x042519fe, 0x042618fe,
+ 0x052617fe, 0x062716fd, 0x072714fe, 0x082713fe,
+ 0x092812fd, 0x0a2811fd, 0x0b2810fd, 0x0c280ffd,
+
+ 0xfd0f250f, 0xfd10250e, 0xfd11250d, 0xfd12250c,
+ 0xfd13250b, 0xfe13250a, 0xfe152409, 0xfe162408,
+ 0xfe172308, 0xff182306, 0xff192305, 0xff1a2205,
+ 0x001b2104, 0x001c2103, 0x001d2003, 0x011e1f02,
+ 0x011f1f01, 0x021f1e01, 0x03201d00, 0x03211c00,
+ 0x04211b00, 0x05221aff, 0x062219ff, 0x062318ff,
+ 0x082316ff, 0x082316ff, 0x092415fe, 0x0a2414fe,
+ 0x0b2413fe, 0x0c2412fe, 0x0d2411fe, 0x0e2410fe,
+
+ 0xfe10230f, 0xfe11230e, 0xfe12220e, 0xfe13220d,
+ 0xfe14220c, 0xff14220b, 0xff15220a, 0xff16210a,
+ 0x00162109, 0x00172108, 0x00182008, 0x01192006,
+ 0x011a1f06, 0x021a1f05, 0x021b1e05, 0x031c1d04,
+ 0x031d1d03, 0x041d1c03, 0x041e1b03, 0x051e1b02,
+ 0x061f1a01, 0x06201901, 0x07201801, 0x08201800,
+ 0x09201700, 0x0a211500, 0x0b2115ff, 0x0c2114ff,
+ 0x0c2213ff, 0x0d2212ff, 0x0e2211ff, 0x0f2211fe,
+
+ 0xff112010, 0xff12200f, 0xff12200f, 0xff13200e,
+ 0x0013200d, 0x0014200c, 0x00151f0c, 0x00161f0b,
+ 0x01161f0a, 0x01171e0a, 0x02171e09, 0x02181e08,
+ 0x03191d07, 0x03191d07, 0x041a1c06, 0x041b1c05,
+ 0x051b1b05, 0x051c1b04, 0x061c1a04, 0x071c1a03,
+ 0x071d1903, 0x081e1802, 0x091d1802, 0x091e1702,
+ 0x0a1f1601, 0x0b1f1600, 0x0b1f1501, 0x0c201400,
+ 0x0d1f1400, 0x0e2013ff, 0x0f1f1200, 0x102011ff,
+
+ 0x00111f10, 0x00121e10, 0x00131e0f, 0x00131e0f,
+ 0x01131e0e, 0x01141e0d, 0x01151d0d, 0x02151d0c,
+ 0x02161d0b, 0x03161d0a, 0x03171c0a, 0x04171c09,
+ 0x04181c08, 0x05181b08, 0x05191b07, 0x06191a07,
+ 0x061a1a06, 0x071a1906, 0x071b1905, 0x081b1805,
+ 0x081c1804, 0x091c1704, 0x0a1c1703, 0x0a1d1603,
+ 0x0b1d1602, 0x0c1d1502, 0x0c1d1502, 0x0d1e1401,
+ 0x0e1d1401, 0x0e1e1301, 0x0f1e1300, 0x101e1200,
+
+ 0x02111c11, 0x02121c10, 0x02131b10, 0x03131b0f,
+ 0x03131b0f, 0x03141b0e, 0x04141b0d, 0x04151a0d,
+ 0x05151a0c, 0x05151a0c, 0x05161a0b, 0x0616190b,
+ 0x0616190b, 0x0716190a, 0x0717180a, 0x08171809,
+ 0x08181808, 0x09181708, 0x09181708, 0x0a181707,
+ 0x0a191607, 0x0b191606, 0x0b1a1605, 0x0c1a1505,
+ 0x0c1a1505, 0x0d1a1504, 0x0d1b1404, 0x0e1b1403,
+ 0x0f1b1303, 0x0f1b1303, 0x101b1302, 0x101c1202,
+
+ 0x04111a11, 0x04121911, 0x04131910, 0x0513190f,
+ 0x0513190f, 0x0513190f, 0x0613190e, 0x0614180e,
+ 0x0714180d, 0x0714180d, 0x0715180c, 0x0814180c,
+ 0x0815170c, 0x0816170b, 0x0916170a, 0x0916170a,
+ 0x0a16160a, 0x0a171609, 0x0a171609, 0x0b171608,
+ 0x0b171509, 0x0c171508, 0x0c181507, 0x0d171507,
+ 0x0d181407, 0x0e181406, 0x0e181406, 0x0e191306,
+ 0x0f191305, 0x0f191305, 0x10191304, 0x10191205,
+
+ 0x05121811, 0x06121810, 0x06121810, 0x06131710,
+ 0x0713170f, 0x0713170f, 0x0713170f, 0x0813170e,
+ 0x0813170e, 0x0814170d, 0x0914160d, 0x0914160d,
+ 0x0914160d, 0x0a14160c, 0x0a15160b, 0x0a15150c,
+ 0x0b15150b, 0x0b15150b, 0x0b16150a, 0x0c15150a,
+ 0x0c16140a, 0x0d161409, 0x0d161409, 0x0d171408,
+ 0x0e161408, 0x0e171308, 0x0e171308, 0x0f171307,
+ 0x0f171307, 0x10171306, 0x10181206, 0x10181206,
+
+ 0x07111711, 0x07121710, 0x07121611, 0x08121610,
+ 0x08121610, 0x0813160f, 0x0912160f, 0x0913160e,
+ 0x0913160e, 0x0913160e, 0x0a14150d, 0x0a14150d,
+ 0x0a14150d, 0x0b14150c, 0x0b14150c, 0x0b14150c,
+ 0x0c14140c, 0x0c15140b, 0x0c15140b, 0x0c15140b,
+ 0x0d15140a, 0x0d15140a, 0x0d15140a, 0x0e161309,
+ 0x0e161309, 0x0e161309, 0x0f151309, 0x0f161308,
+ 0x0f161209, 0x10161208, 0x10161208, 0x10171207,
+
+ 0x0a111411, 0x0b111410, 0x0b111410, 0x0b111410,
+ 0x0b111410, 0x0b12140f, 0x0b12140f, 0x0c12130f,
+ 0x0c12130f, 0x0c12130f, 0x0c12130f, 0x0c12130f,
+ 0x0d12130e, 0x0d12130e, 0x0d12130e, 0x0d13130d,
+ 0x0d13130d, 0x0d13130d, 0x0e12130d, 0x0e13120d,
+ 0x0e13120d, 0x0e13120d, 0x0e13120d, 0x0f13120c,
+ 0x0f13120c, 0x0f13120c, 0x0f14120b, 0x0f14120b,
+ 0x1013120b, 0x1013120b, 0x1013120b, 0x1014110b,
+
+ 0x0c111310, 0x0c111310, 0x0c111310, 0x0d101310,
+ 0x0d101310, 0x0d111210, 0x0d111210, 0x0d111210,
+ 0x0d12120f, 0x0d12120f, 0x0d12120f, 0x0d12120f,
+ 0x0e11120f, 0x0e12120e, 0x0e12120e, 0x0e12120e,
+ 0x0e12120e, 0x0e12120e, 0x0e12120e, 0x0e12120e,
+ 0x0f11120e, 0x0f12120d, 0x0f12120d, 0x0f12120d,
+ 0x0f12120d, 0x0f12110e, 0x0f12110e, 0x0f12110e,
+ 0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c,
+};
+
+static int sun8i_vi_scaler_coef_index(unsigned int step)
+{
+ unsigned int scale, int_part, float_part;
+
+ scale = step >> (SUN8I_VI_SCALER_SCALE_FRAC - 3);
+ int_part = scale >> 3;
+ float_part = scale & 0x7;
+
+ switch (int_part) {
+ case 0:
+ return 0;
+ case 1:
+ return float_part;
+ case 2:
+ return 8 + (float_part >> 1);
+ case 3:
+ return 12;
+ case 4:
+ return 13;
+ default:
+ return 14;
+ }
+}
+
+static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
+ u32 hstep, u32 vstep,
+ const struct drm_format_info *format)
+{
+ const u32 *ch_left, *ch_right, *cy;
+ int offset, i;
+
+ if (format->hsub == 1 && format->vsub == 1) {
+ ch_left = lan3coefftab32_left;
+ ch_right = lan3coefftab32_right;
+ cy = lan2coefftab32;
+ } else {
+ ch_left = bicubic8coefftab32_left;
+ ch_right = bicubic8coefftab32_right;
+ cy = bicubic4coefftab32;
+ }
+
+ offset = sun8i_vi_scaler_coef_index(hstep) *
+ SUN8I_VI_SCALER_COEFF_COUNT;
+ for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
+ regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(layer, i),
+ lan3coefftab32_left[offset + i]);
+ regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(layer, i),
+ lan3coefftab32_right[offset + i]);
+ regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(layer, i),
+ ch_left[offset + i]);
+ regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(layer, i),
+ ch_right[offset + i]);
+ }
+
+ offset = sun8i_vi_scaler_coef_index(hstep) *
+ SUN8I_VI_SCALER_COEFF_COUNT;
+ for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
+ regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(layer, i),
+ lan2coefftab32[offset + i]);
+ regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(layer, i),
+ cy[offset + i]);
+ }
+}
+
+void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = SUN8I_SCALER_VSU_CTRL_EN |
+ SUN8I_SCALER_VSU_CTRL_COEFF_RDY;
+ else
+ val = 0;
+
+ regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(layer), val);
+}
+
+void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
+ u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
+ u32 hscale, u32 vscale, u32 hphase, u32 vphase,
+ const struct drm_format_info *format)
+{
+ u32 chphase, cvphase;
+ u32 insize, outsize;
+
+ hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
+ vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
+ hscale <<= SUN8I_VI_SCALER_SCALE_FRAC - 16;
+ vscale <<= SUN8I_VI_SCALER_SCALE_FRAC - 16;
+
+ insize = SUN8I_VI_SCALER_SIZE(src_w, src_h);
+ outsize = SUN8I_VI_SCALER_SIZE(dst_w, dst_h);
+
+ /*
+ * This is chroma V/H phase calculation as it appears in
+ * BSP driver. There is no detailed explanation. YUV 420
+ * chroma is threated specialy for some reason.
+ */
+ if (format->hsub == 2 && format->vsub == 2) {
+ chphase = hphase >> 1;
+ cvphase = (vphase >> 1) -
+ (1UL << (SUN8I_VI_SCALER_SCALE_FRAC - 2));
+ } else {
+ chphase = hphase;
+ cvphase = vphase;
+ }
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_OUTSIZE(layer), outsize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_YINSIZE(layer), insize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_YHSTEP(layer), hscale);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_YVSTEP(layer), vscale);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_YHPHASE(layer), hphase);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_YVPHASE(layer), vphase);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_CINSIZE(layer),
+ SUN8I_VI_SCALER_SIZE(src_w / format->hsub,
+ src_h / format->vsub));
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_CHSTEP(layer),
+ hscale / format->hsub);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_CVSTEP(layer),
+ vscale / format->vsub);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_CHPHASE(layer), chphase);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_CVPHASE(layer), cvphase);
+ sun8i_vi_scaler_set_coeff(mixer->engine.regs, layer,
+ hscale, vscale, format);
+}
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 @@
+/*
+ * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _SUN8I_VI_SCALER_H_
+#define _SUN8I_VI_SCALER_H_
+
+#include <drm/drm_fourcc.h>
+#include "sun8i_mixer.h"
+
+/* this two macros assumes 16 fractional bits which is standard in DRM */
+#define SUN8I_VI_SCALER_SCALE_MIN 1
+#define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1)
+
+#define SUN8I_VI_SCALER_SCALE_FRAC 20
+#define SUN8I_VI_SCALER_PHASE_FRAC 20
+#define SUN8I_VI_SCALER_COEFF_COUNT 32
+#define SUN8I_VI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
+
+#define SUN8I_SCALER_VSU_CTRL(ch) (0x20000 + 0x20000 * (ch) + 0x0)
+#define SUN8I_SCALER_VSU_OUTSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x40)
+#define SUN8I_SCALER_VSU_YINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x80)
+#define SUN8I_SCALER_VSU_YHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x88)
+#define SUN8I_SCALER_VSU_YVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x8c)
+#define SUN8I_SCALER_VSU_YHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x90)
+#define SUN8I_SCALER_VSU_YVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x98)
+#define SUN8I_SCALER_VSU_CINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0xc0)
+#define SUN8I_SCALER_VSU_CHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xc8)
+#define SUN8I_SCALER_VSU_CVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xcc)
+#define SUN8I_SCALER_VSU_CHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd0)
+#define SUN8I_SCALER_VSU_CVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd8)
+#define SUN8I_SCALER_VSU_YHCOEFF0(ch, i) \
+ (0x20000 + 0x20000 * (ch) + 0x200 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_YHCOEFF1(ch, i) \
+ (0x20000 + 0x20000 * (ch) + 0x300 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_YVCOEFF(ch, i) \
+ (0x20000 + 0x20000 * (ch) + 0x400 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CHCOEFF0(ch, i) \
+ (0x20000 + 0x20000 * (ch) + 0x600 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CHCOEFF1(ch, i) \
+ (0x20000 + 0x20000 * (ch) + 0x700 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CVCOEFF(ch, i) \
+ (0x20000 + 0x20000 * (ch) + 0x800 + 0x4 * (i))
+
+#define SUN8I_SCALER_VSU_CTRL_EN BIT(0)
+#define SUN8I_SCALER_VSU_CTRL_COEFF_RDY BIT(4)
+
+void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
+ u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
+ u32 hscale, u32 vscale, u32 hphase, u32 vphase,
+ const struct drm_format_info *format);
+
+#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
config TINYDRM_MIPI_DBI
tristate
+config TINYDRM_ILI9225
+ tristate "DRM support for ILI9225 display panels"
+ depends on DRM_TINYDRM && SPI
+ select TINYDRM_MIPI_DBI
+ help
+ DRM driver for the following Ilitek ILI9225 panels:
+ * No-name 2.2" color screen module
+
+ If M is selected the module will be called ili9225.
+
config TINYDRM_MI0283QT
tristate "DRM support for MI0283QT"
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/
obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o
# Displays
+obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o
obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o
obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o
obj-$(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)
}
EXPORT_SYMBOL(tinydrm_shutdown);
-/**
- * tinydrm_suspend - Suspend tinydrm
- * @tdev: tinydrm device
- *
- * Used in driver PM operations to suspend tinydrm.
- * Suspends fbdev and DRM.
- * Resume with tinydrm_resume().
- *
- * Returns:
- * Zero on success, negative error code on failure.
- */
-int tinydrm_suspend(struct tinydrm_device *tdev)
-{
- struct drm_atomic_state *state;
-
- if (tdev->suspend_state) {
- DRM_ERROR("Failed to suspend: state already set\n");
- return -EINVAL;
- }
-
- drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 1);
- state = drm_atomic_helper_suspend(tdev->drm);
- if (IS_ERR(state)) {
- drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 0);
- return PTR_ERR(state);
- }
-
- tdev->suspend_state = state;
-
- return 0;
-}
-EXPORT_SYMBOL(tinydrm_suspend);
-
-/**
- * tinydrm_resume - Resume tinydrm
- * @tdev: tinydrm device
- *
- * Used in driver PM operations to resume tinydrm.
- * Suspend with tinydrm_suspend().
- *
- * Returns:
- * Zero on success, negative error code on failure.
- */
-int tinydrm_resume(struct tinydrm_device *tdev)
-{
- struct drm_atomic_state *state = tdev->suspend_state;
- int ret;
-
- if (!state) {
- DRM_ERROR("Failed to resume: state is not set\n");
- return -EINVAL;
- }
-
- tdev->suspend_state = NULL;
-
- ret = drm_atomic_helper_resume(tdev->drm, state);
- if (ret) {
- DRM_ERROR("Error resuming state: %d\n", ret);
- return ret;
- }
-
- drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 0);
-
- return 0;
-}
-EXPORT_SYMBOL(tinydrm_resume);
-
MODULE_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 @@
+/*
+ * DRM driver for Ilitek ILI9225 panels
+ *
+ * Copyright 2017 David Lechner <david@lechnology.com>
+ *
+ * Some code copied from mipi-dbi.c
+ * Copyright 2016 Noralf Trønnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-buf.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+#include <video/mipi_display.h>
+
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/tinydrm/mipi-dbi.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
+
+#define ILI9225_DRIVER_READ_CODE 0x00
+#define ILI9225_DRIVER_OUTPUT_CONTROL 0x01
+#define ILI9225_LCD_AC_DRIVING_CONTROL 0x02
+#define ILI9225_ENTRY_MODE 0x03
+#define ILI9225_DISPLAY_CONTROL_1 0x07
+#define ILI9225_BLANK_PERIOD_CONTROL_1 0x08
+#define ILI9225_FRAME_CYCLE_CONTROL 0x0b
+#define ILI9225_INTERFACE_CONTROL 0x0c
+#define ILI9225_OSCILLATION_CONTROL 0x0f
+#define ILI9225_POWER_CONTROL_1 0x10
+#define ILI9225_POWER_CONTROL_2 0x11
+#define ILI9225_POWER_CONTROL_3 0x12
+#define ILI9225_POWER_CONTROL_4 0x13
+#define ILI9225_POWER_CONTROL_5 0x14
+#define ILI9225_VCI_RECYCLING 0x15
+#define ILI9225_RAM_ADDRESS_SET_1 0x20
+#define ILI9225_RAM_ADDRESS_SET_2 0x21
+#define ILI9225_WRITE_DATA_TO_GRAM 0x22
+#define ILI9225_SOFTWARE_RESET 0x28
+#define ILI9225_GATE_SCAN_CONTROL 0x30
+#define ILI9225_VERTICAL_SCROLL_1 0x31
+#define ILI9225_VERTICAL_SCROLL_2 0x32
+#define ILI9225_VERTICAL_SCROLL_3 0x33
+#define ILI9225_PARTIAL_DRIVING_POS_1 0x34
+#define ILI9225_PARTIAL_DRIVING_POS_2 0x35
+#define ILI9225_HORIZ_WINDOW_ADDR_1 0x36
+#define ILI9225_HORIZ_WINDOW_ADDR_2 0x37
+#define ILI9225_VERT_WINDOW_ADDR_1 0x38
+#define ILI9225_VERT_WINDOW_ADDR_2 0x39
+#define ILI9225_GAMMA_CONTROL_1 0x50
+#define ILI9225_GAMMA_CONTROL_2 0x51
+#define ILI9225_GAMMA_CONTROL_3 0x52
+#define ILI9225_GAMMA_CONTROL_4 0x53
+#define ILI9225_GAMMA_CONTROL_5 0x54
+#define ILI9225_GAMMA_CONTROL_6 0x55
+#define ILI9225_GAMMA_CONTROL_7 0x56
+#define ILI9225_GAMMA_CONTROL_8 0x57
+#define ILI9225_GAMMA_CONTROL_9 0x58
+#define ILI9225_GAMMA_CONTROL_10 0x59
+
+static inline int ili9225_command(struct mipi_dbi *mipi, u8 cmd, u16 data)
+{
+ u8 par[2] = { data >> 8, data & 0xff };
+
+ return mipi_dbi_command_buf(mipi, cmd, par, 2);
+}
+
+static int ili9225_fb_dirty(struct drm_framebuffer *fb,
+ struct drm_file *file_priv, unsigned int flags,
+ unsigned int color, struct drm_clip_rect *clips,
+ unsigned int num_clips)
+{
+ struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ struct tinydrm_device *tdev = fb->dev->dev_private;
+ struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+ bool swap = mipi->swap_bytes;
+ struct drm_clip_rect clip;
+ u16 x_start, y_start;
+ u16 x1, x2, y1, y2;
+ int ret = 0;
+ bool full;
+ void *tr;
+
+ mutex_lock(&tdev->dirty_lock);
+
+ if (!mipi->enabled)
+ goto out_unlock;
+
+ /* fbdev can flush even when we're not interested */
+ if (tdev->pipe.plane.fb != fb)
+ goto out_unlock;
+
+ full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
+ fb->width, fb->height);
+
+ DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
+ clip.x1, clip.x2, clip.y1, clip.y2);
+
+ if (!mipi->dc || !full || swap ||
+ fb->format->format == DRM_FORMAT_XRGB8888) {
+ tr = mipi->tx_buf;
+ ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap);
+ if (ret)
+ goto out_unlock;
+ } else {
+ tr = cma_obj->vaddr;
+ }
+
+ switch (mipi->rotation) {
+ default:
+ x1 = clip.x1;
+ x2 = clip.x2 - 1;
+ y1 = clip.y1;
+ y2 = clip.y2 - 1;
+ x_start = x1;
+ y_start = y1;
+ break;
+ case 90:
+ x1 = clip.y1;
+ x2 = clip.y2 - 1;
+ y1 = fb->width - clip.x2;
+ y2 = fb->width - clip.x1 - 1;
+ x_start = x1;
+ y_start = y2;
+ break;
+ case 180:
+ x1 = fb->width - clip.x2;
+ x2 = fb->width - clip.x1 - 1;
+ y1 = fb->height - clip.y2;
+ y2 = fb->height - clip.y1 - 1;
+ x_start = x2;
+ y_start = y2;
+ break;
+ case 270:
+ x1 = fb->height - clip.y2;
+ x2 = fb->height - clip.y1 - 1;
+ y1 = clip.x1;
+ y2 = clip.x2 - 1;
+ x_start = x2;
+ y_start = y1;
+ break;
+ }
+
+ ili9225_command(mipi, ILI9225_HORIZ_WINDOW_ADDR_1, x2);
+ ili9225_command(mipi, ILI9225_HORIZ_WINDOW_ADDR_2, x1);
+ ili9225_command(mipi, ILI9225_VERT_WINDOW_ADDR_1, y2);
+ ili9225_command(mipi, ILI9225_VERT_WINDOW_ADDR_2, y1);
+
+ ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_1, x_start);
+ ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, y_start);
+
+ ret = mipi_dbi_command_buf(mipi, ILI9225_WRITE_DATA_TO_GRAM, tr,
+ (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
+
+out_unlock:
+ mutex_unlock(&tdev->dirty_lock);
+
+ if (ret)
+ dev_err_once(fb->dev->dev, "Failed to update display %d\n",
+ ret);
+
+ return ret;
+}
+
+static const struct drm_framebuffer_funcs ili9225_fb_funcs = {
+ .destroy = drm_gem_fb_destroy,
+ .create_handle = drm_gem_fb_create_handle,
+ .dirty = ili9225_fb_dirty,
+};
+
+static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
+ struct drm_crtc_state *crtc_state)
+{
+ struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+ struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+ struct drm_framebuffer *fb = pipe->plane.fb;
+ struct device *dev = tdev->drm->dev;
+ int ret;
+ u8 am_id;
+
+ DRM_DEBUG_KMS("\n");
+
+ mipi_dbi_hw_reset(mipi);
+
+ /*
+ * There don't seem to be two example init sequences that match, so
+ * using the one from the popular Arduino library for this display.
+ * https://github.com/Nkawu/TFT_22_ILI9225/blob/master/src/TFT_22_ILI9225.cpp
+ */
+
+ ret = ili9225_command(mipi, ILI9225_POWER_CONTROL_1, 0x0000);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Error sending command %d\n", ret);
+ return;
+ }
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x0000);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_3, 0x0000);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_4, 0x0000);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_5, 0x0000);
+
+ msleep(40);
+
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x0018);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_3, 0x6121);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_4, 0x006f);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_5, 0x495f);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_1, 0x0800);
+
+ msleep(10);
+
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x103b);
+
+ msleep(50);
+
+ switch (mipi->rotation) {
+ default:
+ am_id = 0x30;
+ break;
+ case 90:
+ am_id = 0x18;
+ break;
+ case 180:
+ am_id = 0x00;
+ break;
+ case 270:
+ am_id = 0x28;
+ break;
+ }
+ ili9225_command(mipi, ILI9225_DRIVER_OUTPUT_CONTROL, 0x011c);
+ ili9225_command(mipi, ILI9225_LCD_AC_DRIVING_CONTROL, 0x0100);
+ ili9225_command(mipi, ILI9225_ENTRY_MODE, 0x1000 | am_id);
+ ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x0000);
+ ili9225_command(mipi, ILI9225_BLANK_PERIOD_CONTROL_1, 0x0808);
+ ili9225_command(mipi, ILI9225_FRAME_CYCLE_CONTROL, 0x1100);
+ ili9225_command(mipi, ILI9225_INTERFACE_CONTROL, 0x0000);
+ ili9225_command(mipi, ILI9225_OSCILLATION_CONTROL, 0x0d01);
+ ili9225_command(mipi, ILI9225_VCI_RECYCLING, 0x0020);
+ ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_1, 0x0000);
+ ili9225_command(mipi, ILI9225_RAM_ADDRESS_SET_2, 0x0000);
+
+ ili9225_command(mipi, ILI9225_GATE_SCAN_CONTROL, 0x0000);
+ ili9225_command(mipi, ILI9225_VERTICAL_SCROLL_1, 0x00db);
+ ili9225_command(mipi, ILI9225_VERTICAL_SCROLL_2, 0x0000);
+ ili9225_command(mipi, ILI9225_VERTICAL_SCROLL_3, 0x0000);
+ ili9225_command(mipi, ILI9225_PARTIAL_DRIVING_POS_1, 0x00db);
+ ili9225_command(mipi, ILI9225_PARTIAL_DRIVING_POS_2, 0x0000);
+
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_1, 0x0000);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_2, 0x0808);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_3, 0x080a);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_4, 0x000a);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_5, 0x0a08);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_6, 0x0808);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_7, 0x0000);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_8, 0x0a00);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_9, 0x0710);
+ ili9225_command(mipi, ILI9225_GAMMA_CONTROL_10, 0x0710);
+
+ ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x0012);
+
+ msleep(50);
+
+ ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x1017);
+
+ mipi->enabled = true;
+
+ if (fb)
+ fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
+}
+
+static void ili9225_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+ struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+ struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+
+ DRM_DEBUG_KMS("\n");
+
+ if (!mipi->enabled)
+ return;
+
+ ili9225_command(mipi, ILI9225_DISPLAY_CONTROL_1, 0x0000);
+ msleep(50);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_2, 0x0007);
+ msleep(50);
+ ili9225_command(mipi, ILI9225_POWER_CONTROL_1, 0x0a02);
+
+ mipi->enabled = false;
+}
+
+static int ili9225_dbi_command(struct mipi_dbi *mipi, u8 cmd, u8 *par,
+ size_t num)
+{
+ struct spi_device *spi = mipi->spi;
+ unsigned int bpw = 8;
+ u32 speed_hz;
+ int ret;
+
+ gpiod_set_value_cansleep(mipi->dc, 0);
+ speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
+ ret = tinydrm_spi_transfer(spi, speed_hz, NULL, 8, &cmd, 1);
+ if (ret || !num)
+ return ret;
+
+ if (cmd == ILI9225_WRITE_DATA_TO_GRAM && !mipi->swap_bytes)
+ bpw = 16;
+
+ gpiod_set_value_cansleep(mipi->dc, 1);
+ speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
+
+ return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num);
+}
+
+static const u32 ili9225_formats[] = {
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+};
+
+static int ili9225_init(struct device *dev, struct mipi_dbi *mipi,
+ const struct drm_simple_display_pipe_funcs *pipe_funcs,
+ struct drm_driver *driver,
+ const struct drm_display_mode *mode,
+ unsigned int rotation)
+{
+ size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
+ struct tinydrm_device *tdev = &mipi->tinydrm;
+ int ret;
+
+ if (!mipi->command)
+ return -EINVAL;
+
+ mutex_init(&mipi->cmdlock);
+
+ mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
+ if (!mipi->tx_buf)
+ return -ENOMEM;
+
+ ret = devm_tinydrm_init(dev, tdev, &ili9225_fb_funcs, driver);
+ if (ret)
+ return ret;
+
+ ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
+ DRM_MODE_CONNECTOR_VIRTUAL,
+ ili9225_formats,
+ ARRAY_SIZE(ili9225_formats), mode,
+ rotation);
+ if (ret)
+ return ret;
+
+ tdev->drm->mode_config.preferred_depth = 16;
+ mipi->rotation = rotation;
+
+ drm_mode_config_reset(tdev->drm);
+
+ DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
+ tdev->drm->mode_config.preferred_depth, rotation);
+
+ return 0;
+}
+
+static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = {
+ .enable = ili9225_pipe_enable,
+ .disable = ili9225_pipe_disable,
+ .update = tinydrm_display_pipe_update,
+ .prepare_fb = tinydrm_display_pipe_prepare_fb,
+};
+
+static const struct drm_display_mode ili9225_mode = {
+ TINYDRM_MODE(176, 220, 35, 44),
+};
+
+DEFINE_DRM_GEM_CMA_FOPS(ili9225_fops);
+
+static struct drm_driver ili9225_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+ DRIVER_ATOMIC,
+ .fops = &ili9225_fops,
+ TINYDRM_GEM_DRIVER_OPS,
+ .lastclose = tinydrm_lastclose,
+ .name = "ili9225",
+ .desc = "Ilitek ILI9225",
+ .date = "20171106",
+ .major = 1,
+ .minor = 0,
+};
+
+static const struct of_device_id ili9225_of_match[] = {
+ { .compatible = "ilitek,ili9225-2.2in-176x220" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ili9225_of_match);
+
+static const struct spi_device_id ili9225_id[] = {
+ { "ili9225-2.2in-176x220", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, ili9225_id);
+
+static int ili9225_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct mipi_dbi *mipi;
+ struct gpio_desc *rs;
+ u32 rotation = 0;
+ int ret;
+
+ mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
+ if (!mipi)
+ return -ENOMEM;
+
+ mipi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(mipi->reset)) {
+ DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
+ return PTR_ERR(mipi->reset);
+ }
+
+ rs = devm_gpiod_get(dev, "rs", GPIOD_OUT_LOW);
+ if (IS_ERR(rs)) {
+ DRM_DEV_ERROR(dev, "Failed to get gpio 'rs'\n");
+ return PTR_ERR(rs);
+ }
+
+ device_property_read_u32(dev, "rotation", &rotation);
+
+ ret = mipi_dbi_spi_init(spi, mipi, rs);
+ if (ret)
+ return ret;
+
+ /* override the command function set in mipi_dbi_spi_init() */
+ mipi->command = ili9225_dbi_command;
+
+ ret = ili9225_init(&spi->dev, mipi, &ili9225_pipe_funcs,
+ &ili9225_driver, &ili9225_mode, rotation);
+ if (ret)
+ return ret;
+
+ spi_set_drvdata(spi, mipi);
+
+ return devm_tinydrm_register(&mipi->tinydrm);
+}
+
+static void ili9225_shutdown(struct spi_device *spi)
+{
+ struct mipi_dbi *mipi = spi_get_drvdata(spi);
+
+ tinydrm_shutdown(&mipi->tinydrm);
+}
+
+static struct spi_driver ili9225_spi_driver = {
+ .driver = {
+ .name = "ili9225",
+ .owner = THIS_MODULE,
+ .of_match_table = ili9225_of_match,
+ },
+ .id_table = ili9225_id,
+ .probe = ili9225_probe,
+ .shutdown = ili9225_shutdown,
+};
+module_spi_driver(ili9225_spi_driver);
+
+MODULE_DESCRIPTION("Ilitek ILI9225 DRM driver");
+MODULE_AUTHOR("David Lechner <david@lechnology.com>");
+MODULE_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 @@
* (at your option) any later version.
*/
+#include <drm/drm_modeset_helper.h>
#include <drm/tinydrm/ili9341.h>
#include <drm/tinydrm/mipi-dbi.h>
#include <drm/tinydrm/tinydrm-helpers.h>
@@ -231,7 +232,7 @@ static int __maybe_unused mi0283qt_pm_suspend(struct device *dev)
struct mipi_dbi *mipi = dev_get_drvdata(dev);
int ret;
- ret = tinydrm_suspend(&mipi->tinydrm);
+ ret = drm_mode_config_helper_suspend(mipi->tinydrm.drm);
if (ret)
return ret;
@@ -249,7 +250,9 @@ static int __maybe_unused mi0283qt_pm_resume(struct device *dev)
if (ret)
return ret;
- return tinydrm_resume(&mipi->tinydrm);
+ drm_mode_config_helper_resume(mipi->tinydrm.drm);
+
+ return 0;
}
static 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)
}
EXPORT_SYMBOL(mipi_dbi_command_buf);
-static int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
- struct drm_clip_rect *clip, bool swap)
+/**
+ * mipi_dbi_buf_copy - Copy a framebuffer, transforming it if necessary
+ * @dst: The destination buffer
+ * @fb: The source framebuffer
+ * @clip: Clipping rectangle of the area to be copied
+ * @swap: When true, swap MSB/LSB of 16-bit values
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
+ struct drm_clip_rect *clip, bool swap)
{
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
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,
DMA_FROM_DEVICE);
return ret;
}
+EXPORT_SYMBOL(mipi_dbi_buf_copy);
static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv,
@@ -444,18 +455,23 @@ EXPORT_SYMBOL(mipi_dbi_display_is_on);
#if IS_ENABLED(CONFIG_SPI)
-/*
+/**
+ * mipi_dbi_spi_cmd_max_speed - get the maximum SPI bus speed
+ * @spi: SPI device
+ * @len: The transfer buffer length.
+ *
* Many controllers have a max speed of 10MHz, but can be pushed way beyond
* that. Increase reliability by running pixel data at max speed and the rest
* at 10MHz, preventing transfer glitches from messing up the init settings.
*/
-static u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
+u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
{
if (len > 64)
return 0; /* use default */
return min_t(u32, 10000000, spi->max_speed_hz);
}
+EXPORT_SYMBOL(mipi_dbi_spi_cmd_max_speed);
/*
* MIPI DBI Type C Option 1