aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Mouroux <jmouroux@xilinx.com>2017-05-08 17:03:25 -0700
committerJeffrey Mouroux <jmouroux@xilinx.com>2017-06-28 12:54:02 -0700
commitd359779442ffc9727fbb0108d40f8158e8f6a55b (patch)
treef47fe65cc3d30bc5b0fede4b6cc2f5b85d80d25f
parent78e25c06fdf8d0897a22d1cf15c6fd4b545eb57c (diff)
downloadlinux-d359779442ffc9727fbb0108d40f8158e8f6a55b.tar.gz
drm: xilinx: Extension of existing DRM driver to support new Video Mixer IP
The Xilinx Video Mixer is IP capable of blending video from multiple sources into a single output video stream. Support for up to 7 overlay layers and an optional logo layer are supported in this driver. This change introduces Linux driver support for this IP via our existing DRM driver framework for crtcs. Signed-off-by: Jeffrey Mouroux <jmouroux@xilinx.com>
-rw-r--r--drivers/gpu/drm/xilinx/Makefile7
-rw-r--r--drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.c1083
-rw-r--r--drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.h363
-rw-r--r--drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_data.h476
-rw-r--r--drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_hw.c897
-rw-r--r--drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_regs.h639
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_connector.c2
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_crtc.c88
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_crtc.h3
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_drv.c16
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_encoder.c8
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_plane.c271
-rw-r--r--drivers/gpu/drm/xilinx/xilinx_drm_plane.h118
13 files changed, 3851 insertions, 120 deletions
diff --git a/drivers/gpu/drm/xilinx/Makefile b/drivers/gpu/drm/xilinx/Makefile
index d6904641f9ed97..85fdd88ec946b4 100644
--- a/drivers/gpu/drm/xilinx/Makefile
+++ b/drivers/gpu/drm/xilinx/Makefile
@@ -2,10 +2,17 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+ccflags-y := -I$(src)
+
+MIXER_CRTC_DRM=crtc/mixer/drm
+MIXER_CRTC_HW=crtc/mixer/hw
+
xilinx_drm-y := xilinx_drm_crtc.o xilinx_drm_connector.o xilinx_drm_drv.o \
xilinx_drm_encoder.o xilinx_drm_fb.o xilinx_drm_gem.o \
xilinx_drm_plane.o
xilinx_drm-y += xilinx_cresample.o xilinx_osd.o xilinx_rgb2yuv.o xilinx_vtc.o
+xilinx_drm-y += $(MIXER_CRTC_HW)/xilinx_mixer_hw.o
+xilinx_drm-y += $(MIXER_CRTC_DRM)/xilinx_drm_mixer.o
obj-$(CONFIG_DRM_XILINX) += xilinx_drm.o
obj-$(CONFIG_DRM_XILINX_DP) += xilinx_drm_dp.o
diff --git a/drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.c b/drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.c
new file mode 100644
index 00000000000000..82f8fb4d16b3d2
--- /dev/null
+++ b/drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.c
@@ -0,0 +1,1083 @@
+/*
+ * (C) Copyright 2016 - 2017, Xilinx, Inc.
+ *
+ * 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_crtc.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include "xilinx_drm_drv.h"
+#include "xilinx_drm_fb.h"
+
+#include "crtc/mixer/drm/xilinx_drm_mixer.h"
+#include "crtc/mixer/hw/xilinx_mixer_regs.h"
+#include "crtc/mixer/hw/xilinx_mixer_data.h"
+
+#define COLOR_NAME_SIZE 10
+#define MASTER_LAYER_IDX 0
+#define LOGO_LAYER_IDX 1
+
+struct color_fmt_tbl {
+ char name[COLOR_NAME_SIZE + 1];
+ enum xv_comm_color_fmt_id fmt_id;
+ u32 drm_format;
+};
+
+/*************************** STATIC DATA ************************************/
+static const struct color_fmt_tbl color_table[] = {
+ {"bgr888", XVIDC_CSF_BGR, DRM_FORMAT_BGR888},
+ {"rgb888", XVIDC_CSF_RGB, DRM_FORMAT_RGB888},
+ {"bgr565", XVIDC_CSF_BGR565, DRM_FORMAT_BGR565},
+ {"yuv422", XVIDC_CSF_YCBCR_422, DRM_FORMAT_YUYV},
+ {"ayuv", XVIDC_CSF_AYCBCR_444, DRM_FORMAT_AYUV},
+ {"nv12", XVIDC_CSF_Y_CBCR8_420, DRM_FORMAT_NV12},
+ {"nv16", XVIDC_CSF_Y_CBCR8, DRM_FORMAT_NV16},
+ {"rgba8888", XVIDC_CSF_RGBA8, DRM_FORMAT_RGBA8888},
+ {"abgr8888", XVIDC_CSF_ABGR8, DRM_FORMAT_ABGR8888},
+ {"argb8888", XVIDC_CSF_ARGB8, DRM_FORMAT_ARGB8888},
+ {"xbgr8888", XVIDC_CSF_XBGR8, DRM_FORMAT_XBGR8888},
+};
+
+static const struct of_device_id xv_mixer_match[] = {
+ {.compatible = "xlnx,v-mix-1.00.a"},
+ {/*end of table*/},
+};
+
+/*************************** PROTOTYPES **************************************/
+
+static int
+xilinx_drm_mixer_of_init_layer_data
+ (struct device *dev,
+ struct device_node *dev_node,
+ char *layer_name,
+ struct xv_mixer_layer_data *layer,
+ u32 max_layer_width,
+ struct xv_mixer_layer_data **drm_primary_layer);
+
+static int xilinx_drm_mixer_parse_dt_logo_data(struct device_node *node,
+ struct xv_mixer *mixer_hw);
+
+static int
+xilinx_drm_mixer_parse_dt_bg_video_fmt(struct device_node *layer_node,
+ struct xv_mixer *mixer_hw);
+
+static irqreturn_t xilinx_drm_mixer_intr_handler(int irq, void *data);
+
+/************************* IMPLEMENTATIONS ***********************************/
+
+struct
+xilinx_drm_mixer *xilinx_drm_mixer_probe
+ (struct device *dev,
+ struct device_node *node,
+ struct xilinx_drm_plane_manager *manager)
+{
+ struct xilinx_drm_mixer *mixer;
+ struct xv_mixer *mixer_hw;
+ char layer_node_name[20] = {0};
+ struct xv_mixer_layer_data *layer_data;
+ const struct of_device_id *match;
+ struct resource res;
+ int ret;
+ int layer_idx;
+ int layer_cnt;
+ int i;
+
+ match = of_match_node(xv_mixer_match, node);
+
+ if (!match) {
+ dev_err(dev, "Failed to match device node for mixer\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ mixer = devm_kzalloc(dev, sizeof(struct xilinx_drm_mixer), GFP_KERNEL);
+ if (!mixer)
+ return ERR_PTR(-ENOMEM);
+
+ mixer_hw = &mixer->mixer_hw;
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(dev, "Invalid io memory address in dts for mixer\n");
+ return ERR_PTR(ret);
+ }
+
+ mixer_hw->reg_base_addr = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(mixer_hw->reg_base_addr)) {
+ dev_err(dev, "Failed to map io mem space for mixer\n");
+ return ERR_CAST(mixer_hw->reg_base_addr);
+ }
+
+ ret = of_property_read_u32(node, "xlnx,num-layers",
+ &mixer_hw->max_layers);
+ if (ret) {
+ dev_err(dev, "No xlnx,num-layers dts prop for mixer node\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (mixer_hw->max_layers > XVMIX_MAX_SUPPORTED_LAYERS) {
+ dev_err(dev, "Num layer nodes in device tree > mixer max\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* establish some global defaults subject to override via dts */
+ mixer_hw->intrpts_enabled = false;
+ mixer_hw->logo_pixel_alpha_enabled = false;
+ mixer_hw->logo_layer_enabled = of_property_read_bool(node,
+ "xlnx,logo-layer");
+
+ /* Alloc num_layers + 1 for logo layer if enabled in dt */
+ layer_cnt = mixer_hw->max_layers +
+ (mixer_hw->logo_layer_enabled ? 1 : 0);
+
+ layer_data =
+ devm_kzalloc(dev,
+ sizeof(struct xv_mixer_layer_data) * layer_cnt,
+ GFP_KERNEL);
+
+ if (layer_data) {
+ mixer_hw->layer_cnt = layer_cnt;
+ } else {
+ dev_err(dev, "Out of mem for mixer layer data\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mixer_hw->layer_data = layer_data;
+
+ /* establish background layer video properties from dts */
+ ret = xilinx_drm_mixer_parse_dt_bg_video_fmt(node, mixer_hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* read logo data from dts */
+ ret = xilinx_drm_mixer_parse_dt_logo_data(node, mixer_hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mixer->plane_manager = manager;
+ mixer->drm_primary_layer = NULL;
+ mixer->hw_logo_layer = NULL;
+ mixer->hw_master_layer = &mixer_hw->layer_data[MASTER_LAYER_IDX];
+
+ if (mixer_hw->logo_layer_enabled)
+ mixer->hw_logo_layer = &mixer_hw->layer_data[LOGO_LAYER_IDX];
+
+ layer_idx = mixer_hw->logo_layer_enabled ? 2 : 1;
+ for (i = 1; i <= (mixer_hw->max_layers - 1); i++, layer_idx++) {
+ snprintf(layer_node_name, sizeof(layer_node_name),
+ "layer_%d", i);
+
+ ret = xilinx_drm_mixer_of_init_layer_data
+ (dev,
+ node,
+ layer_node_name,
+ &mixer_hw->layer_data[layer_idx],
+ mixer_hw->max_layer_width,
+ &mixer->drm_primary_layer);
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (!mixer_hw->layer_data[layer_idx].hw_config.is_streaming &&
+ !mixer_hw->intrpts_enabled)
+ mixer_hw->intrpts_enabled = true;
+ }
+
+ /* If none of the overlay layers were designated as the drm
+ * primary layer, default to the mixer's video0 layer as drm primary
+ */
+ if (!mixer->drm_primary_layer)
+ mixer->drm_primary_layer = mixer->hw_master_layer;
+
+ /* request irq and obtain pixels-per-clock (ppc) property */
+ if (mixer_hw->intrpts_enabled) {
+ mixer_hw->irq = irq_of_parse_and_map(node, 0);
+
+ if (mixer_hw->irq > 0) {
+ ret = devm_request_irq(dev, mixer_hw->irq,
+ xilinx_drm_mixer_intr_handler,
+ IRQF_SHARED, "xilinx_mixer",
+ mixer_hw);
+
+ if (ret) {
+ dev_err(dev,
+ "Failed to request irq for mixer\n");
+ return ERR_PTR(ret);
+ }
+ }
+
+ ret = of_property_read_u32(node, "xlnx,ppc", &mixer_hw->ppc);
+
+ if (ret) {
+ dev_err(dev, "No xlnx,ppc property for mixer dts\n");
+ return ERR_PTR(ret);
+ }
+ }
+
+ mixer_hw->reset_gpio = devm_gpiod_get_optional(dev,
+ "xlnx,mixer-reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(mixer_hw->reset_gpio)) {
+ ret = PTR_ERR(mixer_hw->reset_gpio);
+
+ if (ret == -EPROBE_DEFER) {
+ dev_info(dev, "No gpio probed for mixer. Deferring\n");
+ return ERR_PTR(ret);
+ }
+
+ dev_err(dev, "No reset gpio info from dts for mixer\n");
+ return ERR_PTR(ret);
+ }
+
+ gpiod_set_raw_value(mixer_hw->reset_gpio, 0x1);
+
+ if (mixer_hw->intrpts_enabled)
+ xilinx_mixer_intrpt_enable(mixer_hw);
+ else
+ xilinx_mixer_intrpt_disable(mixer_hw);
+
+ /* Init all layers to inactive state in software. An update_plane()
+ * call to our drm driver will change this to 'active' and permit the
+ * layer to be enabled in hardware
+ */
+ for (i = 0; i < mixer_hw->layer_cnt; i++) {
+ layer_data = &mixer_hw->layer_data[i];
+ mixer_layer_active(layer_data) = false;
+ }
+
+ xilinx_drm_create_mixer_plane_properties(mixer);
+
+ xilinx_mixer_init(mixer_hw);
+
+ return mixer;
+}
+
+int xilinx_drm_mixer_set_plane(struct xilinx_drm_plane *plane,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ u32 src_x, u32 src_y,
+ u32 src_w, u32 src_h)
+{
+ struct xv_mixer *mixer_hw;
+ struct xilinx_drm_mixer *mixer;
+ struct drm_gem_cma_object *buffer;
+ u32 stride = fb->pitches[0];
+ u32 offset = 0;
+ u32 active_area_width;
+ u32 active_area_height;
+ enum xv_mixer_layer_id layer_id;
+ int ret;
+
+ mixer = plane->manager->mixer;
+ mixer_hw = &mixer->mixer_hw;
+ layer_id = plane->mixer_layer->id;
+ active_area_width = mixer_layer_width(mixer->drm_primary_layer);
+ active_area_height = mixer_layer_height(mixer->drm_primary_layer);
+
+ /* compute memory data */
+ buffer = xilinx_drm_fb_get_gem_obj(fb, 0);
+ stride = fb->pitches[0];
+ offset = src_x * drm_format_plane_cpp(fb->pixel_format, 0) +
+ src_y * stride;
+ offset += fb->offsets[0];
+
+ ret = xilinx_drm_mixer_mark_layer_active(plane);
+ if (ret)
+ return ret;
+
+ switch (layer_id) {
+ case XVMIX_LAYER_LOGO:
+ ret = xilinx_drm_mixer_update_logo_img(plane, buffer,
+ src_w, src_h);
+ if (ret)
+ break;
+
+ ret = xilinx_drm_mixer_set_layer_dimensions(plane,
+ crtc_x, crtc_y,
+ src_w, src_h,
+ stride);
+ break;
+
+ case XVMIX_LAYER_MASTER:
+ if (!mixer_layer_is_streaming(plane->mixer_layer))
+ xilinx_drm_mixer_mark_layer_inactive(plane);
+
+ if (mixer->drm_primary_layer == mixer->hw_master_layer) {
+ xilinx_mixer_layer_disable(mixer_hw, layer_id);
+ msleep(50);
+
+ ret = xilinx_mixer_set_active_area(mixer_hw,
+ src_w, src_h);
+
+ xilinx_mixer_layer_enable(mixer_hw, layer_id);
+
+ } else if (src_w != active_area_width ||
+ src_h != active_area_height) {
+ DRM_ERROR("Invalid dimensions for mixer layer 0.\n");
+ return -EINVAL;
+ }
+
+ break;
+
+ default:
+ ret = xilinx_drm_mixer_set_layer_dimensions(plane,
+ crtc_x, crtc_y,
+ src_w, src_h,
+ stride);
+ if (ret)
+ break;
+
+ if (!mixer_layer_is_streaming(plane->mixer_layer))
+ ret = xilinx_mixer_set_layer_buff_addr
+ (mixer_hw,
+ plane->mixer_layer->id,
+ buffer->paddr + offset);
+ }
+
+ return ret;
+}
+
+int xilinx_drm_mixer_set_plane_property(struct xilinx_drm_plane *plane,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct xilinx_drm_mixer *mixer = plane->manager->mixer;
+
+ if (property == mixer->alpha_prop)
+ return xilinx_drm_mixer_set_layer_alpha(plane, value);
+
+ if (property == mixer->scale_prop)
+ return xilinx_drm_mixer_set_layer_scale(plane, value);
+
+ if (property == mixer->bg_color) {
+ xilinx_mixer_set_bkg_col(&mixer->mixer_hw, value);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+void
+xilinx_drm_mixer_plane_dpms(struct xilinx_drm_plane *plane, int dpms)
+{
+ struct xilinx_drm_mixer *mixer = plane->manager->mixer;
+
+ switch (dpms) {
+ case DRM_MODE_DPMS_ON:
+ xilinx_drm_mixer_layer_enable(plane);
+ break;
+
+ default:
+ xilinx_drm_mixer_mark_layer_inactive(plane);
+ xilinx_drm_mixer_layer_disable(plane);
+
+ /* restore to default property values */
+ if (mixer->alpha_prop) {
+ drm_object_property_set_value(&plane->base.base,
+ mixer->alpha_prop,
+ XVMIX_ALPHA_MAX);
+ xilinx_drm_mixer_set_layer_alpha(plane,
+ XVMIX_ALPHA_MAX);
+ }
+
+ if (mixer->scale_prop) {
+ drm_object_property_set_value(&plane->base.base,
+ mixer->scale_prop,
+ XVMIX_SCALE_FACTOR_1X);
+ xilinx_drm_mixer_set_layer_scale(plane,
+ XVMIX_SCALE_FACTOR_1X);
+ }
+ }
+}
+
+void xilinx_drm_mixer_dpms(struct xilinx_drm_mixer *mixer, int dpms)
+{
+ switch (dpms) {
+ case DRM_MODE_DPMS_ON:
+ xilinx_mixer_start(&mixer->mixer_hw);
+ break;
+
+ default:
+ xilinx_drm_mixer_reset(mixer);
+ }
+}
+
+int xilinx_drm_mixer_string_to_fmt(const char *color_fmt, u32 *output)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(color_table); i++) {
+ if (strcmp(color_fmt, (const char *)color_table[i].name) == 0) {
+ *output = color_table[i].fmt_id;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int xilinx_drm_mixer_fmt_to_drm_fmt(enum xv_comm_color_fmt_id id, u32 *output)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(color_table); i++) {
+ if (id == color_table[i].fmt_id)
+ *output = color_table[i].drm_format;
+ }
+
+ if (output)
+ return 0;
+
+ return -EINVAL;
+}
+
+int xilinx_drm_mixer_set_layer_scale(struct xilinx_drm_plane *plane,
+ uint64_t val)
+{
+ struct xv_mixer *mixer_hw = to_xv_mixer_hw(plane);
+ struct xv_mixer_layer_data *layer = plane->mixer_layer;
+ int ret;
+
+ if (!layer || !layer->hw_config.can_scale)
+ return -ENODEV;
+
+ if (val > XVMIX_SCALE_FACTOR_4X ||
+ val < XVMIX_SCALE_FACTOR_1X) {
+ DRM_ERROR("Mixer layer scale value illegal.\n");
+ return -EINVAL;
+ }
+ xilinx_drm_mixer_layer_disable(plane);
+ msleep(50);
+ ret = xilinx_mixer_set_layer_scaling(mixer_hw, layer->id, val);
+ xilinx_drm_mixer_layer_enable(plane);
+
+ return ret;
+}
+
+int xilinx_drm_mixer_set_layer_alpha(struct xilinx_drm_plane *plane,
+ uint64_t val)
+{
+ struct xv_mixer *mixer_hw = to_xv_mixer_hw(plane);
+ struct xv_mixer_layer_data *layer = plane->mixer_layer;
+ int ret;
+
+ if (!layer || !layer->hw_config.can_alpha)
+ return -EINVAL;
+
+ if (val > XVMIX_ALPHA_MAX || val < XVMIX_ALPHA_MIN) {
+ DRM_ERROR("Mixer layer alpha dts value illegal.\n");
+ return -EINVAL;
+ }
+ ret = xilinx_mixer_set_layer_alpha(mixer_hw, layer->id, val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void xilinx_drm_mixer_layer_disable(struct xilinx_drm_plane *plane)
+{
+ struct xv_mixer *mixer_hw;
+ u32 layer_id;
+
+ if (plane)
+ mixer_hw = to_xv_mixer_hw(plane);
+ else
+ return;
+
+ layer_id = plane->mixer_layer->id;
+ if (layer_id < XVMIX_LAYER_MASTER || layer_id > XVMIX_LAYER_LOGO)
+ return;
+
+ xilinx_mixer_layer_disable(mixer_hw, layer_id);
+}
+
+void xilinx_drm_mixer_layer_enable(struct xilinx_drm_plane *plane)
+{
+ struct xv_mixer *mixer_hw;
+ struct xv_mixer_layer_data *layer_data;
+ u32 layer_id;
+
+ if (!plane)
+ return;
+
+ mixer_hw = to_xv_mixer_hw(plane);
+ layer_data = plane->mixer_layer;
+ layer_id = layer_data->id;
+
+ if (layer_id < XVMIX_LAYER_MASTER || layer_id > XVMIX_LAYER_LOGO) {
+ DRM_DEBUG_KMS("Attempt to activate invalid layer: %d\n",
+ layer_id);
+ return;
+ }
+
+ if (layer_id == XVMIX_LAYER_MASTER &&
+ !mixer_layer_is_streaming(layer_data)) {
+ return;
+ }
+
+ xilinx_mixer_layer_enable(mixer_hw, layer_id);
+}
+
+int xilinx_drm_mixer_set_layer_dimensions(struct xilinx_drm_plane *plane,
+ u32 crtc_x, u32 crtc_y,
+ u32 width, u32 height, u32 stride)
+{
+ struct xilinx_drm_mixer *mixer = plane->manager->mixer;
+ struct xv_mixer *mixer_hw = to_xv_mixer_hw(plane);
+ struct xv_mixer_layer_data *layer_data;
+ enum xv_mixer_layer_id layer_id;
+ bool disable_req = false;
+ int ret = 0;
+
+ layer_data = plane->mixer_layer;
+ layer_id = layer_data->id;
+
+ if (mixer_layer_height(layer_data) != height ||
+ mixer_layer_width(layer_data) != width)
+ disable_req = true;
+
+ /* disable any layers necessary */
+ if (disable_req) {
+ if (mixer->drm_primary_layer == layer_data)
+ xilinx_mixer_layer_disable(mixer_hw,
+ XVMIX_LAYER_MASTER);
+
+ if (layer_id != XVMIX_LAYER_MASTER &&
+ layer_id < XVMIX_LAYER_ALL) {
+ xilinx_mixer_layer_disable(mixer_hw, layer_id);
+ } else {
+ DRM_DEBUG_KMS("Invalid mixer layer id %u\n", layer_id);
+ return -EINVAL;
+ }
+ msleep(50);
+ }
+
+ if (mixer->drm_primary_layer == layer_data) {
+ /* likely unneeded but, just to be sure...*/
+ crtc_x = 0;
+ crtc_y = 0;
+
+ ret = xilinx_mixer_set_active_area(mixer_hw,
+ width, height);
+
+ if (ret)
+ return ret;
+
+ xilinx_mixer_layer_enable(mixer_hw, XVMIX_LAYER_MASTER);
+ }
+
+ if (layer_id != XVMIX_LAYER_MASTER && layer_id < XVMIX_LAYER_ALL) {
+ ret = xilinx_mixer_set_layer_window(mixer_hw, layer_id,
+ crtc_x, crtc_y,
+ width, height, stride);
+
+ if (ret)
+ return ret;
+
+ xilinx_drm_mixer_layer_enable(plane);
+ }
+
+ return ret;
+}
+
+struct
+xv_mixer_layer_data *xilinx_drm_mixer_get_layer(struct xv_mixer *mixer_hw,
+ enum xv_mixer_layer_id layer_id)
+{
+ return xilinx_mixer_get_layer_data(mixer_hw, layer_id);
+}
+
+void xilinx_drm_mixer_reset(struct xilinx_drm_mixer *mixer)
+{
+ struct xv_mixer *mixer_hw = &mixer->mixer_hw;
+
+ gpiod_set_raw_value(mixer_hw->reset_gpio, 0x0);
+ udelay(1);
+ gpiod_set_raw_value(mixer_hw->reset_gpio, 0x1);
+
+ /* restore layer properties and bg color after reset */
+ xilinx_mixer_set_bkg_col(mixer_hw, mixer_hw->bg_color);
+
+ if (mixer_hw->intrpts_enabled)
+ xilinx_mixer_intrpt_enable(mixer_hw);
+
+ xilinx_drm_plane_restore(mixer->plane_manager);
+}
+
+int xilinx_drm_mixer_mark_layer_active(struct xilinx_drm_plane *plane)
+{
+ if (!plane->mixer_layer)
+ return -ENODEV;
+
+ mixer_layer_active(plane->mixer_layer) = true;
+
+ return 0;
+}
+
+int xilinx_drm_mixer_mark_layer_inactive(struct xilinx_drm_plane *plane)
+{
+ if (!plane || !plane->mixer_layer)
+ return -ENODEV;
+
+ mixer_layer_active(plane->mixer_layer) = false;
+
+ return 0;
+}
+
+int xilinx_drm_mixer_update_logo_img(struct xilinx_drm_plane *plane,
+ struct drm_gem_cma_object *buffer,
+ u32 src_w, u32 src_h)
+{
+ struct xv_mixer_layer_data *logo_layer = plane->mixer_layer;
+ size_t pixel_cnt = src_h * src_w;
+
+ /* color comp defaults to offset in RG24 buffer */
+ u32 pix_cmp_cnt;
+ u32 logo_cmp_cnt;
+ enum xv_comm_color_fmt_id layer_pixel_fmt = 0;
+ bool per_pixel_alpha = false;
+
+ u32 max_width = logo_layer->hw_config.max_width;
+ u32 max_height = logo_layer->hw_config.max_height;
+ u32 min_width = logo_layer->hw_config.min_width;
+ u32 min_height = logo_layer->hw_config.min_height;
+
+ u8 *r_data = NULL;
+ u8 *g_data = NULL;
+ u8 *b_data = NULL;
+ u8 *a_data = NULL;
+ size_t el_size = sizeof(u8);
+
+ u8 *pixel_mem_data;
+
+ int ret, i, j;
+
+ /* ensure valid conditions for update */
+ if (logo_layer->id != XVMIX_LAYER_LOGO)
+ return 0;
+
+ if (src_h > max_height || src_w > max_width ||
+ src_h < min_height || src_w < min_width) {
+ DRM_ERROR("Mixer logo/cursor layer dimensions illegal.\n");
+
+ return -EINVAL;
+ }
+
+ ret = xilinx_drm_mixer_fmt_to_drm_fmt(logo_layer->hw_config.vid_fmt,
+ &layer_pixel_fmt);
+
+ per_pixel_alpha =
+ (mixer_layer_fmt(logo_layer) == XVIDC_CSF_RGBA8) ? true : false;
+
+ r_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
+ g_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
+ b_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
+
+ if (per_pixel_alpha)
+ a_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
+
+ if (!r_data || !g_data || !b_data || (per_pixel_alpha && !a_data)) {
+ DRM_ERROR("Unable to allocate memory for logo layer data\n");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ pix_cmp_cnt = per_pixel_alpha ? 4 : 3;
+ logo_cmp_cnt = pixel_cnt * pix_cmp_cnt;
+
+ if (ret)
+ return ret;
+
+ /* ensure buffer attributes have changed to indicate new logo
+ * has been created
+ */
+ if ((phys_addr_t)buffer->vaddr == logo_layer->layer_regs.buff_addr &&
+ src_w == logo_layer->layer_regs.width &&
+ src_h == logo_layer->layer_regs.height)
+ return 0;
+
+ /* cache buffer address for future comparison */
+ logo_layer->layer_regs.buff_addr = (phys_addr_t)buffer->vaddr;
+
+ pixel_mem_data = (u8 *)(buffer->vaddr);
+
+ for (i = 0, j = 0; j < pixel_cnt; j++) {
+ if (per_pixel_alpha && a_data)
+ a_data[j] = pixel_mem_data[i++];
+
+ b_data[j] = pixel_mem_data[i++];
+ g_data[j] = pixel_mem_data[i++];
+ r_data[j] = pixel_mem_data[i++];
+ }
+
+ ret = xilinx_mixer_logo_load(to_xv_mixer_hw(plane),
+ src_w, src_h,
+ r_data, g_data, b_data,
+ per_pixel_alpha ? a_data : NULL);
+
+free:
+ kfree(r_data);
+ kfree(g_data);
+ kfree(b_data);
+ kfree(a_data);
+
+ return ret;
+}
+
+void xilinx_drm_mixer_set_intr_handler(struct xilinx_drm_mixer *mixer,
+ void (*intr_handler_fn)(void *),
+ void *data)
+{
+ mixer->mixer_hw.intrpt_handler_fn = intr_handler_fn;
+ mixer->mixer_hw.intrpt_data = data;
+}
+
+void xilinx_drm_create_mixer_plane_properties(struct xilinx_drm_mixer *mixer)
+{
+ u64 bit_shift = (XVMIX_MAX_BPC - mixer->mixer_hw.bg_layer_bpc) * 3;
+ u64 max_scale_range = (XVMIX_MAX_BG_COLOR_BITS >> bit_shift);
+
+ mixer->scale_prop =
+ drm_property_create_range(mixer->plane_manager->drm, 0,
+ "scale",
+ XVMIX_SCALE_FACTOR_1X,
+ XVMIX_SCALE_FACTOR_4X);
+
+ mixer->alpha_prop =
+ drm_property_create_range(mixer->plane_manager->drm, 0,
+ "alpha",
+ XVMIX_ALPHA_MIN,
+ XVMIX_ALPHA_MAX);
+
+ mixer->bg_color =
+ drm_property_create_range(mixer->plane_manager->drm,
+ 0, "bg_color", 0,
+ max_scale_range);
+}
+
+void xilinx_drm_mixer_attach_plane_prop(struct xilinx_drm_plane *plane)
+{
+ struct xilinx_drm_plane_manager *manager = plane->manager;
+ struct xilinx_drm_mixer *mixer = manager->mixer;
+ struct drm_mode_object *base = &plane->base.base;
+
+ if (plane->mixer_layer->hw_config.can_scale)
+ drm_object_attach_property(base,
+ mixer->scale_prop,
+ XVMIX_SCALE_FACTOR_1X);
+
+ if (plane->mixer_layer->hw_config.can_alpha)
+ drm_object_attach_property(base,
+ mixer->alpha_prop,
+ XVMIX_ALPHA_MAX);
+
+ if (mixer->drm_primary_layer == plane->mixer_layer)
+ drm_object_attach_property(base,
+ mixer->bg_color,
+ mixer->mixer_hw.bg_color);
+}
+
+int
+xilinx_drm_create_mixer_layer_plane(struct xilinx_drm_plane_manager *manager,
+ struct xilinx_drm_plane *plane,
+ struct device_node *node)
+{
+ struct xv_mixer_layer_data *layer_data;
+ struct xilinx_drm_mixer *mixer = manager->mixer;
+ u32 layer_id;
+ int ret;
+
+ ret = of_property_read_u32(node, "xlnx,layer-id", &layer_id);
+
+ if (ret) {
+ DRM_ERROR("Missing xlnx,layer-id parameter in mixer dts\n");
+ ret = -EINVAL;
+ }
+
+ layer_data =
+ xilinx_drm_mixer_get_layer(&mixer->mixer_hw, layer_id);
+
+ if (!layer_data)
+ return -ENODEV;
+
+ of_node_put(node);
+
+ plane->mixer_layer = layer_data;
+
+ ret = xilinx_drm_mixer_fmt_to_drm_fmt
+ (mixer_layer_fmt(plane->mixer_layer),
+ &plane->format);
+
+ if (ret)
+ DRM_ERROR("Missing video format in dts for drm plane id %d\n",
+ plane->id);
+ return ret;
+}
+
+static int xilinx_drm_mixer_parse_dt_logo_data(struct device_node *node,
+ struct xv_mixer *mixer_hw)
+{
+ struct xv_mixer_layer_data *layer_data;
+ struct device_node *logo_node;
+ u32 max_width, max_height;
+ int ret;
+
+ /* read in logo data */
+ if (!mixer_hw->logo_layer_enabled)
+ return 0;
+
+ logo_node = of_get_child_by_name(node, "logo");
+ if (!logo_node) {
+ DRM_ERROR("No logo node specified in device tree.\n");
+ return -EINVAL;
+ }
+
+ layer_data = &mixer_hw->layer_data[LOGO_LAYER_IDX];
+
+ /* set defaults for logo layer */
+ layer_data->hw_config.min_height = XVMIX_LOGO_LAYER_HEIGHT_MIN;
+ layer_data->hw_config.min_width = XVMIX_LOGO_LAYER_WIDTH_MIN;
+ layer_data->hw_config.is_streaming = false;
+ layer_data->hw_config.vid_fmt = XVIDC_CSF_RGB;
+ layer_data->hw_config.can_alpha = true;
+ layer_data->hw_config.can_scale = true;
+ layer_data->layer_regs.buff_addr = 0;
+ layer_data->id = XVMIX_LAYER_LOGO;
+
+ ret = of_property_read_u32(logo_node, "xlnx,logo-width", &max_width);
+
+ if (ret) {
+ DRM_ERROR("Failed to get logo width prop\n");
+ return -EINVAL;
+ }
+
+ if (max_width > XVMIX_LOGO_LAYER_WIDTH_MAX ||
+ max_width < XVMIX_LOGO_LAYER_WIDTH_MIN) {
+ DRM_ERROR("Illegal mixer logo layer width.\n");
+ return -EINVAL;
+ }
+
+ layer_data->hw_config.max_width = max_width;
+ mixer_hw->max_logo_layer_width =
+ layer_data->hw_config.max_width;
+
+ ret = of_property_read_u32(logo_node, "xlnx,logo-height", &max_height);
+
+ if (ret) {
+ DRM_ERROR("Failed to get logo height prop\n");
+ return -EINVAL;
+ }
+
+ if (max_height > XVMIX_LOGO_LAYER_HEIGHT_MAX ||
+ max_height < XVMIX_LOGO_LAYER_HEIGHT_MIN) {
+ DRM_ERROR("Illegal mixer logo layer height.\n");
+ return -EINVAL;
+ }
+
+ layer_data->hw_config.max_height = max_height;
+ mixer_hw->max_logo_layer_height = layer_data->hw_config.max_height;
+
+ mixer_hw->logo_color_key_enabled =
+ of_property_read_bool(logo_node,
+ "xlnx,logo-transp");
+
+ mixer_hw->logo_pixel_alpha_enabled =
+ of_property_read_bool(logo_node,
+ "xlnx,logo-pixel-alpha");
+
+ if (mixer_hw->logo_pixel_alpha_enabled)
+ layer_data->hw_config.vid_fmt = XVIDC_CSF_RGBA8;
+
+ return ret;
+}
+
+static int xilinx_drm_mixer_parse_dt_bg_video_fmt(struct device_node *node,
+ struct xv_mixer *mixer_hw)
+{
+ struct device_node *layer_node;
+ const char *vformat;
+ struct xv_mixer_layer_data *layer;
+ u32 *l_width_ptr;
+ u32 *l_height_ptr;
+ u32 *l_vid_fmt_ptr;
+ int ret;
+
+ layer_node = of_get_child_by_name(node, "layer_0");
+ layer = &mixer_hw->layer_data[MASTER_LAYER_IDX];
+ l_width_ptr = &layer->hw_config.max_width;
+ l_height_ptr = &layer->hw_config.max_height;
+ l_vid_fmt_ptr = &layer->hw_config.vid_fmt;
+
+ /* Set default values */
+ layer->hw_config.can_alpha = false;
+ layer->hw_config.can_scale = false;
+ layer->hw_config.is_streaming = false;
+ layer->hw_config.min_width = XVMIX_LAYER_WIDTH_MIN;
+ layer->hw_config.min_height = XVMIX_LAYER_HEIGHT_MIN;
+
+ ret = of_property_read_string(layer_node, "xlnx,vformat", &vformat);
+
+ if (ret) {
+ DRM_ERROR("No xlnx,vformat value for layer_0 in dts.\n");
+ return -EINVAL;
+ }
+
+ mixer_layer_is_streaming(layer) =
+ of_property_read_bool(layer_node, "xlnx,layer-streaming");
+
+ ret = of_property_read_u32(node, "xlnx,bpc",
+ &mixer_hw->bg_layer_bpc);
+ if (ret) {
+ DRM_ERROR("Failed to get bits per component (bpc) prop\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(layer_node, "xlnx,layer-width", l_width_ptr);
+ if (ret) {
+ DRM_ERROR("Failed to get screen width prop\n");
+ return -EINVAL;
+ }
+
+ /* set global max width for mixer which will, ultimately, set the
+ * limit for the crtc
+ */
+ mixer_hw->max_layer_width = *l_width_ptr;
+
+ ret = of_property_read_u32(layer_node, "xlnx,layer-height",
+ l_height_ptr);
+ if (ret) {
+ DRM_ERROR("Failed to get screen height prop\n");
+ return -EINVAL;
+ }
+
+ mixer_hw->max_layer_height = *l_height_ptr;
+
+ /*We'll use the first layer instance to store data of the master layer*/
+ layer->id = XVMIX_LAYER_MASTER;
+
+ ret = xilinx_drm_mixer_string_to_fmt(vformat, l_vid_fmt_ptr);
+ if (ret < 0) {
+ DRM_ERROR("Invalid mixer video format in dts\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static irqreturn_t xilinx_drm_mixer_intr_handler(int irq, void *data)
+{
+ struct xv_mixer *mixer = data;
+
+ u32 intr = xilinx_mixer_get_intr_status(mixer);
+
+ if (!intr)
+ return IRQ_NONE;
+
+ else if (mixer->intrpt_handler_fn)
+ mixer->intrpt_handler_fn(mixer->intrpt_data);
+
+ xilinx_mixer_clear_intr_status(mixer, intr);
+
+ return IRQ_HANDLED;
+}
+
+static int
+xilinx_drm_mixer_of_init_layer_data(struct device *dev,
+ struct device_node *node,
+ char *layer_name,
+ struct xv_mixer_layer_data *layer,
+ u32 max_layer_width,
+ struct xv_mixer_layer_data **drm_pri_layer)
+{
+ struct device_node *layer_node;
+ const char *vformat;
+ int ret;
+
+ layer_node = of_get_child_by_name(node, layer_name);
+
+ if (!layer_node)
+ return -1;
+
+ /* Set default values */
+ layer->hw_config.can_alpha = false;
+ layer->hw_config.can_scale = false;
+ layer->hw_config.is_streaming = false;
+ layer->hw_config.max_width = max_layer_width;
+ layer->hw_config.min_width = XVMIX_LAYER_WIDTH_MIN;
+ layer->hw_config.min_height = XVMIX_LAYER_HEIGHT_MIN;
+ layer->hw_config.vid_fmt = 0;
+ layer->id = 0;
+
+ ret = of_property_read_u32(layer_node, "xlnx,layer-id", &layer->id);
+
+ if (ret || layer->id < 1 ||
+ layer->id > (XVMIX_MAX_SUPPORTED_LAYERS - 1)) {
+ dev_err(dev,
+ "Mixer layer id %u in dts is out of legal range\n",
+ layer->id);
+ ret = -EINVAL;
+ }
+
+ ret = of_property_read_string(layer_node, "xlnx,vformat", &vformat);
+ if (ret) {
+ dev_err(dev,
+ "No mixer layer video format in dts for layer id %d\n",
+ layer->id);
+ return -EINVAL;
+ }
+
+ ret = xilinx_drm_mixer_string_to_fmt(vformat,
+ &layer->hw_config.vid_fmt);
+ if (ret < 0) {
+ dev_err(dev,
+ "No matching video format for mixer layer %d in dts\n",
+ layer->id);
+ return -EINVAL;
+ }
+
+ mixer_layer_can_scale(layer) =
+ of_property_read_bool(layer_node, "xlnx,layer-scale");
+
+ if (mixer_layer_can_scale(layer)) {
+ ret = of_property_read_u32(layer_node, "xlnx,layer-width",
+ &layer->hw_config.max_width);
+ if (ret) {
+ dev_err(dev, "Mixer layer %d dts missing width prop.\n",
+ layer->id);
+ return ret;
+ }
+
+ if (layer->hw_config.max_width > max_layer_width) {
+ dev_err(dev,
+ "Mixer layer %d width in dts > max width\n",
+ layer->id);
+ return -EINVAL;
+ }
+ }
+
+ mixer_layer_can_alpha(layer) =
+ of_property_read_bool(layer_node, "xlnx,layer-alpha");
+
+ mixer_layer_is_streaming(layer) =
+ of_property_read_bool(layer_node, "xlnx,layer-streaming");
+
+ if (of_property_read_bool(layer_node, "xlnx,layer-primary")) {
+ if (*drm_pri_layer) {
+ dev_err(dev,
+ "More than one primary layer in mixer dts\n");
+ return -EINVAL;
+ }
+ mixer_layer_can_scale(layer) = false;
+ *drm_pri_layer = layer;
+ }
+ return 0;
+}
diff --git a/drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.h b/drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.h
new file mode 100644
index 00000000000000..077f9cc2a4d169
--- /dev/null
+++ b/drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.h
@@ -0,0 +1,363 @@
+/*
+ * (C) Copyright 2016 - 2017, Xilinx, Inc.
+ *
+ * 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 __XLNX_DRM_MIXER__
+#define __XLNX_DRM_MIXER__
+#include "crtc/mixer/hw/xilinx_mixer_data.h"
+#include "xilinx_drm_plane.h"
+
+/**
+ * struct xilnx_drm_mixer - Container for interfacing DRM driver to mixer
+ * @mixer_hw: Object representing actual hardware state of mixer
+ * @plane_manager: Xilinx DRM driver crtc object
+ * @drm_primary_layer: Hardware layer serving as logical DRM primary layer
+ * @hw_master_layer: Base video streaming layer
+ * @hw_logo_layer: Hardware logo layer
+ * @alpha_prop: Global layer alpha property
+ * @scale_prop: Layer scale property (1x, 2x or 4x)
+ * @bg_color: Background color property for primary layer
+ *
+ * Contains pointers to logical constructions such as the DRM plane manager as
+ * well as pointers to distinquish the mixer layer serving as the DRM "primary"
+ * plane from the actual mixer layer which serves as the background layer in
+ * hardware.
+ *
+ */
+struct xilinx_drm_mixer {
+ struct xv_mixer mixer_hw;
+ struct xilinx_drm_plane_manager *plane_manager;
+ struct xv_mixer_layer_data *drm_primary_layer;
+ struct xv_mixer_layer_data *hw_master_layer;
+ struct xv_mixer_layer_data *hw_logo_layer;
+ struct drm_property *alpha_prop;
+ struct drm_property *scale_prop;
+ struct drm_property *bg_color;
+};
+
+#define get_mixer_max_height(m) mixer_layer_height((m)->hw_master_layer)
+#define get_mixer_max_width(m) mixer_layer_width((m)->hw_master_layer)
+#define get_mixer_max_logo_height(m) mixer_layer_height((m)->hw_logo_layer)
+#define get_mixer_max_logo_width(m) mixer_layer_width((m)->hw_logo_layer)
+#define get_num_mixer_planes(m) ((m)->mixer_hw.layer_cnt)
+#define get_mixer_vid_out_fmt(m) mixer_video_fmt(&(m)->mixer_hw)
+
+#define to_xv_mixer_hw(p) (&((p)->manager->mixer->mixer_hw))
+
+#define get_xilinx_mixer_mem_align(m) \
+ sizeof((m)->mixer_hw.layer_data[0].layer_regs.buff_addr)
+
+/**
+ * xilinx_drm_mixer_probe - Parse device tree and init mixer node
+ * @dev: Device member of drm device
+ * @node: Open firmware(of) device tree node describing the mixer IP
+ * @mgr: Plane manager object to bind to mixer instance
+ *
+ * Initialize the mixer IP core to a default state wherein a background color
+ * is generated and all layers are initially disabled.
+ *
+ * Returns:
+ * Reference to drm mixer instance struct; err pointer otherwise
+ *
+ */
+struct
+xilinx_drm_mixer * xilinx_drm_mixer_probe(struct device *dev,
+ struct device_node *node,
+ struct xilinx_drm_plane_manager *mgr);
+
+/**
+ * xilinx_drm_mixer_set_plane - Implementation of DRM plane_update callback
+ * @plane: Xilinx_drm_plane object containing references to
+ * the base plane and mixer
+ * @fb: Framebuffer descriptor
+ * @crtc_x: X position of layer on crtc. Note, if the plane represents either
+ * the master hardware layer (video0) or the layer representing the DRM primary
+ * layer, the crtc x/y coordinates are either ignored and/or set to 0/0
+ * respectively.
+ * @crtc_y: Y position of layer. See description of crtc_x handling
+ * for more inforation.
+ * @src_x: x-offset in memory buffer from which to start reading
+ * @src_y: y-offset in memory buffer from which to start reading
+ * @src_w: Number of horizontal pixels to read from memory per row
+ * @src_h: Number of rows of video data to read from memory
+ *
+ * Configures a mixer layer to comply with user space SET_PLANE icotl
+ * call.
+ *
+ * Returns:
+ * Zero on success, non-zero linux error code otherwise.
+ */
+int xilinx_drm_mixer_set_plane(struct xilinx_drm_plane *plane,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ u32 src_x, u32 src_y,
+ u32 src_w, u32 src_h);
+
+/**
+ * xilinx_drm_create_mixer_plane_properties - Creates Mixer-specific drm
+ * property objects
+ * @mixer: Drm mixer object
+ */
+void xilinx_drm_create_mixer_plane_properties(struct xilinx_drm_mixer *mixer);
+
+/**
+ * xilinx_drm_mixer_set_plane_property - Sets the current value for a
+ * particular plane property in the corresponding mixer layer hardware
+ * @plane: Xilinx drm plane object containing references to the mixer
+ * @property: Drm property passed in by user space for update
+ * @value: New value used to set mixer layer hardware for register
+ * mapped to the drm property
+ *
+ * Returns:
+ * Zero on success, EINVAL otherwise
+ */
+int xilinx_drm_mixer_set_plane_property(struct xilinx_drm_plane *plane,
+ struct drm_property *property,
+ uint64_t value);
+
+/**
+ * xilinx_drm_create_mixer_layer_plane - Links the xilinx plane object to a
+ * mixer layer object
+ * @manager: Xilinx drm plane manager object with references to all
+ * of the xilinx planes and the mixer
+ * @plane: The specific plane object to link a layer to
+ * @node: Device tree open firmware node object containing the mixer
+ * layer information from the device tree
+ *
+ * Returns:
+ * Zero on success, -EINVAL if dts properties are missing/invalid; -ENODEV
+ * if no layer object has been create for the referenced layer node
+ * (this may indicate an out-of-memory condition or failed mixer probe)
+ */
+int xilinx_drm_create_mixer_layer_plane(
+ struct xilinx_drm_plane_manager *manager,
+ struct xilinx_drm_plane *plane,
+ struct device_node *node);
+
+/**
+ * xilinx_drm_mixer_attach_plane_prop - Attach mixer-specific drm property to
+ * the given plane
+ * @plane: Xilinx drm plane object to inspect and attach appropriate
+ * properties to
+ *
+ * The linked mixer layer will be inspected to see what capabilities it offers
+ * (e.g. global layer alpha; scaling) and drm property objects that indicate
+ * those capabilities will then be attached and initialized to default values.
+ */
+void xilinx_drm_mixer_attach_plane_prop(struct xilinx_drm_plane *plane);
+
+/**
+ * xilinx_drm_mixer_reset - Used to reset Mixer between mode changes
+ * @mixer: IP core instance to reset
+
+ * Hold the reset line for the IP core low for 1 micro second and then
+ * brings line high to pull out of reset. The core can then be reprogrammed
+ * with new mode settings and subsequently started to begin generating video
+ */
+void xilinx_drm_mixer_reset(struct xilinx_drm_mixer *mixer);
+
+/**
+ * xilinx_drm_mixer_start - Start generation of video stream from mixer
+ * @mixer: IP core instance to reset
+ *
+ * Note:
+ * Sets the mixer to auto-restart so that video will be streamed
+ * continuously
+ */
+void xilinx_drm_mixer_start(struct xv_mixer *mixer);
+
+/**
+ * xilinx_drm_mixer_string_to_fmt - Used to look-up color format index based
+ * on device tree string.
+ * @color_fmt: String value representing color format found in device
+ * tree (e.g. "rgb", "yuv422", "yuv444")
+ * @output: Enum value of video format id
+ *
+ * Returns:
+ * Zero on success, -EINVAL if no entry was found in table
+ *
+ * Note:
+ * Should not be used outside of DRM driver.
+ */
+int xilinx_drm_mixer_string_to_fmt(const char *color_fmt, u32 *output);
+
+/**
+ * xilinx_drm_mixer_fmt_to_drm_fmt - Internal method used to use Xilinx color
+ * id and match to DRM-based fourcc color code.
+ * @id: Xilinx enum value for a color space type (e.g. YUV422)
+ * @output: DRM fourcc value for corresponding Xilinx color space id
+ *
+ * Returns:
+ * Zero on success, -EINVAL if no matching entry found
+ *
+ * Note:
+ * Should not be used outside of DRM driver.
+ */
+int xilinx_drm_mixer_fmt_to_drm_fmt(enum xv_comm_color_fmt_id id, u32 *output);
+
+/**
+ * xilinx_drm_mixer_set_layer_scale - Change video scale factor for video plane
+ * @plane: Drm plane object describing layer to be modified
+ * @val: Index of scale factor to use:
+ * 0 = 1x
+ * 1 = 2x
+ * 2 = 4x
+ *
+ * Returns:
+ * Zero on success, either -EINVAL if scale value is illegal or
+ * -ENODEV if layer does not exist (null)
+ */
+int xilinx_drm_mixer_set_layer_scale(struct xilinx_drm_plane *plane,
+ uint64_t val);
+
+/**
+ * xilinx_drm_mixer_set_layer_alpha - Change the transparency of an entire plane
+ * @plane: Video layer affected by new alpha setting
+ * @val: Value of transparency setting (0-255) with 255 being opaque
+ * 0 being fully transparent
+ *
+ * Returns:
+ * Zero on success, -EINVAL on failure
+ */
+int xilinx_drm_mixer_set_layer_alpha(struct xilinx_drm_plane *plane,
+ uint64_t val);
+
+/**
+ * xilinx_drm_mixer_layer_disable - Disables video output represented by the
+ * plane object
+ * @plane: Drm plane object describing video layer to disable
+ *
+ */
+void xilinx_drm_mixer_layer_disable(struct xilinx_drm_plane *plane);
+
+/**
+ * xilinx_drm_mixer_layer_enable - Enables video output represented by the
+ * plane object
+ * @plane: Drm plane object describing video layer to enable
+ *
+ */
+void xilinx_drm_mixer_layer_enable(struct xilinx_drm_plane *plane);
+
+/**
+ * xilinx_drm_mixer_mark_layer_active - Enables video output represented by
+ * the plane object
+ * @plane: Drm plane object describing video layer to mark
+ * as active. Only layers marked 'active' will be enabled when size or scale
+ * registeres are update. In-active layers can be updated but will not be
+ * enabled in hardware.
+ *
+ * Returns: Zero on success, -ENODEV if mixer layer does not exist
+ */
+int xilinx_drm_mixer_mark_layer_active(struct xilinx_drm_plane *plane);
+
+/**
+ * xilinx_drm_mixer_mark_layer_inactive - Enables video output represented by
+ * the plane object
+ * @plane: Drm plane object describing video layer to mark as inactive.
+ * Only layers marked 'active' will be enabled when size or scale registeres
+ * are update. In-active layers can be updated but will not be enabled in
+ * hardware.
+ *
+ * Returns: Zero on success, -ENODEV if mixer layer does not exist
+ */
+int xilinx_drm_mixer_mark_layer_inactive(struct xilinx_drm_plane *plane);
+
+/**
+ * xilinx_drm_mixer_set_layer_dimensions - Establishes new coordinates and
+ * dimensions for a video plane layer
+ * @plane: Drm plane object desribing video layer to reposition
+ * @crtc_x: New horizontal anchor postion from which to begin rendering
+ * @crtc_y: New vertical anchor position from which to begin rendering
+ * @width: Width, in pixels, to render from stream or memory buffer
+ * @height: Height, in pixels, to render from stream or memory buffer
+ * @stride: Width, in bytes, of a memory buffer. Used only for
+ * memory layers. Use 0 for streaming layers.
+ *
+ * Returns: 0 if successful; Either -EINVAL if coordindate data is invalid
+ * or -ENODEV if layer data not present
+ *
+ * Note:
+ * New size and coordinates of window must fit within the currently active
+ * area of the crtc (e.g. the background resolution)
+ */
+int xilinx_drm_mixer_set_layer_dimensions(struct xilinx_drm_plane *plane,
+ u32 crtc_x, u32 crtc_y,
+ u32 width, u32 height, u32 stride);
+
+/**
+ * xv_mixer_layer_data - Obtains a pointer to a struct containing
+ * layer-specific data for the mixer IP
+ * @mixer: Instance of mixer for which to obtain layer data
+ * @id: logical layer id (e.g. 0=background, 1=overlay) for which to
+ * obtain layer information
+ *
+ * Returns: pointer to struct xv_mixer_layer_data for layer specified by id;
+ * NULL on failure.
+ *
+ * Note:
+ * Does not apply to logo layer. Logo layer data is contained within the
+ * struct xv_mixer instance.
+ */
+struct
+xv_mixer_layer_data * xilinx_drm_mixer_get_layer(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id id);
+
+/**
+ * xilinx_drm_mixer_set_intr_handler - Sets and interrupt handler
+ * @mixer: Mixer object upon which to run handler function when mixer
+ * generates an "done" interrupt for a frame
+ * @intr_handler_fn: Function pointer for interrupt handler. Typically
+ * a drm vertical blank event generation function.
+ * @data: Pointer to crtc object
+ *
+ * Function to run when the mixer generates and ap_done interrupt event (when
+ * frame processing has completed)
+ */
+void xilinx_drm_mixer_set_intr_handler(struct xilinx_drm_mixer *mixer,
+ void (*intr_handler_fn)(void *),
+ void *data);
+
+/**
+ * xilinx_drm_mixer_plane_dpms - Implementation of display power management
+ * system call (dpms).
+ * @plane: Plane/mixer layer to enable/disable (based on dpms value)
+ * @dpms: Display power management state to act upon
+ *
+ * Designed to disable and turn off a plane and restore all attached drm
+ * properities to their initial values. Alterntively, if dpms is "on", will
+ * enable a layer.
+ */
+void xilinx_drm_mixer_plane_dpms(struct xilinx_drm_plane *plane, int dpms);
+
+/**
+ * xilinx_drm_mixer_dpms - Implement drm dpms semantics for video mixer IP
+ *
+ * @mixer: Device instance representing mixer IP
+ * @dpms: Display power management state to act upon
+ */
+void xilinx_drm_mixer_dpms(struct xilinx_drm_mixer *mixer, int dpms);
+
+/**
+ * xilinx_drm_mixer_update_logo_img - Updates internal R, G and B buffer array
+ * of mixer from kernel framebuffer
+ * @plane: Xilinx drm plane object with current video format info
+ * @buffer: GEM object with address references for logo image data
+ * @src_w: Width of buffer to read RGB888 or RGBA8888 data
+ * @src_h: Height of buffer to read RGB888 or RGBA8888 data
+ *
+ * Returns:
+ * Zero on success, -EINVAL if format and/or size of buffer is invalid
+ *
+ * Note:
+ * Initial call caches buffer kernel virtual address. Subsequent calls
+ * will only re-load buffer if virtual address and/or size changes.
+ */
+int xilinx_drm_mixer_update_logo_img(struct xilinx_drm_plane *plane,
+ struct drm_gem_cma_object *buffer,
+ u32 src_w, u32 src_h);
+#endif /* end __XLNX_DRM_MIXER__ */
diff --git a/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_data.h b/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_data.h
new file mode 100644
index 00000000000000..5d508106e63923
--- /dev/null
+++ b/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_data.h
@@ -0,0 +1,476 @@
+/*
+ * (C) Copyright 2016 - 2017, Xilinx, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Defines all of the enums and data structures necessary to utilize the
+ * mixer hardware accessor functions.
+ */
+#ifndef __XV_VIDEO_MIXER_DATA__
+#define __XV_VIDEO_MIXER_DATA__
+
+#include <linux/types.h>
+
+#include "crtc/mixer/hw/xilinx_mixer_regs.h"
+
+/*********************** Inline Functions/Macros *****************************/
+#define mixer_layer_x_pos(l) ((l)->layer_regs.x_pos)
+#define mixer_layer_y_pos(l) ((l)->layer_regs.y_pos)
+#define mixer_layer_width(l) ((l)->layer_regs.width)
+#define mixer_layer_height(l) ((l)->layer_regs.height)
+#define mixer_layer_active(l) ((l)->layer_regs.is_active)
+#define mixer_layer_can_scale(l) ((l)->hw_config.can_scale)
+#define mixer_layer_can_alpha(l) ((l)->hw_config.can_alpha)
+#define mixer_layer_is_streaming(l) ((l)->hw_config.is_streaming)
+#define mixer_layer_fmt(l) ((l)->hw_config.vid_fmt)
+
+#define mixer_video_fmt(m) \
+ ((xilinx_mixer_get_layer_data(m, XVMIX_LAYER_MASTER))->\
+ hw_config.vid_fmt)
+
+/************************** Enums ********************************************/
+/*
+ * enum xv_mixer_layer_id - Describes the layer by index to be acted upon
+ */
+enum xv_mixer_layer_id {
+ XVMIX_LAYER_MASTER = 0,
+ XVMIX_LAYER_1,
+ XVMIX_LAYER_2,
+ XVMIX_LAYER_3,
+ XVMIX_LAYER_4,
+ XVMIX_LAYER_5,
+ XVMIX_LAYER_6,
+ XVMIX_LAYER_7,
+ XVMIX_LAYER_LOGO,
+ XVMIX_LAYER_ALL,
+ XVMIX_LAYER_LAST
+};
+
+/*
+ * enum xv_mixer_scale_factor - Legal scaling factors for layers which support
+ * scaling.
+ */
+enum xv_mixer_scale_factor {
+ XVMIX_SCALE_FACTOR_1X = 0,
+ XVMIX_SCALE_FACTOR_2X,
+ XVMIX_SCALE_FACTOR_4X,
+ XVMIX_SCALE_FACTOR_NOT_SUPPORTED
+};
+
+/*
+ * enum xv_comm_colordepth - Bits per color component.
+ */
+enum xv_comm_colordepth {
+ XVIDC_BPC_6 = 6,
+ XVIDC_BPC_8 = 8,
+ XVIDC_BPC_10 = 10,
+ XVIDC_BPC_12 = 12,
+ XVIDC_BPC_14 = 14,
+ XVIDC_BPC_16 = 16,
+ XVIDC_BPC_NUM_SUPPORTED = 6,
+ XVIDC_BPC_UNKNOWN
+};
+
+/*
+ * enum xv_comm_color_fmt_id - Color space format.
+ */
+enum xv_comm_color_fmt_id {
+ XVIDC_CSF_RGB = 0,
+ XVIDC_CSF_BGR,
+ XVIDC_CSF_BGR565,
+ XVIDC_CSF_RGBA8,
+ XVIDC_CSF_ABGR8,
+ XVIDC_CSF_ARGB8,
+ XVIDC_CSF_XBGR8,
+ XVIDC_CSF_YCBCR_444,
+ XVIDC_CSF_XYCBCR_444,
+ XVIDC_CSF_YCBCR_422,
+ XVIDC_CSF_AYCBCR_444,
+ XVIDC_CSF_YCRCB_420,
+ XVIDC_CSF_YCRCB8,
+ XVIDC_CSF_Y_CBCR8_420,
+ XVIDC_CSF_Y_CBCR8,
+ XVIDC_CSF_YONLY,
+ XVIDC_CSF_NUM_SUPPORTED,
+ XVIDC_CSF_UNKNOWN
+};
+
+/************************** Data Model ***************************************/
+
+/**
+ * struct xv_mixer_layer_data - Describes the hardware configuration of a given
+ * mixer layer
+ * @hw_config: struct specifying the IP hardware constraints for this layer
+ * @vid_fmt: Current video format for this layer
+ * @can_alpha: Indicates that layer alpha is enabled for this layer
+ * @can_scale: Indicates that layer scaling is enabled for this layer
+ * @is_streaming: Indicates layer is not using mixer DMA but streaming from
+ * external DMA
+ * @max_width: Max possible pixel width
+ * @max_height: Max possible pixel height
+ * @min_width: Min possible pixel width
+ * @min_height: Min possible pixel height
+ * @layer_regs: struct containing current cached register values
+ * @buff_addr: Current physical address of image buffer
+ * @x_pos: Current CRTC x offset
+ * @y_pos: Current CRTC y offset
+ * @width: Current width in pixels
+ * @height: Current hight in pixels
+ * @stride: Current stride (when Mixer is performing DMA)
+ * @alpha: Current alpha setting
+ * @is_active: Logical flag indicating layer in use. If false, calls to
+ * enable layer will be ignored.
+ * @scale_fact: Current scaling factor applied to layer
+ * @id: The logical layer id identifies which layer this struct describes
+ * (e.g. 0 = master, 1-7 = overlay).
+ *
+ * All mixer layers are reprsented by an instance of this struct:
+ * output streaming, overlay, logo.
+ * Current layer-specific register state is stored in the layer_regs struct.
+ * The hardware configuration is stored in struct hw_config.
+ *
+ * Note:
+ * Some properties of the logo layer are unique and not described in this
+ * struct. Those properites are part of the xv_mixer struct as global
+ * properties.
+ */
+struct xv_mixer_layer_data {
+ struct {
+ u32 vid_fmt;
+ bool can_alpha;
+ bool can_scale;
+ bool is_streaming;
+ u32 max_width;
+ u32 max_height;
+ u32 min_width;
+ u32 min_height;
+ } hw_config;
+
+ struct {
+ u64 buff_addr; /* JPM TODO mem layer not implemented yet */
+ u32 x_pos;
+ u32 y_pos;
+ u32 width;
+ u32 height;
+ u32 stride; /* JPM TODO mem layer not implemented yet */
+ u32 alpha;
+ bool is_active;
+ enum xv_mixer_scale_factor scale_fact;
+ } layer_regs;
+
+ enum xv_mixer_layer_id id;
+};
+
+/**
+ * struct xv_mixer - Describes a mixer IP block instance within the design
+ * @dn: of device node reference for the Mixer
+ * @reg_base_addr: Base physical address of Mixer IP in memory map
+ * @logo_layer_enabled: Indicates logo layer is enabled in hardware
+ * @logo_color_key_enabled: Not supported/used at this time
+ * @logo_pixel_alpha_enabled: Indicates that per-pixel alpha supported for logo
+ * layer
+ * @intrpts_enabled: Flag indicating interrupt generation is enabled/disabled
+ * @max_layer_width: Max possible width for any layer on this Mixer
+ * @max_layer_height: Max possible height for any layer on this Mixer
+ * @max_logo_layer_width: Min possible width for any layer on this Mixer
+ * @max_logo_layer_height: Min possible height for any layer on this Mixer
+ * @max_layers: Max number of layers (excl: logo)
+ * @bg_layer_bpc: Bits per component for the background streaming layer
+ * @ppc: Pixels per component
+ * @irq: Interrupt request number assigned
+ * @bg_color: Current RGB color value for internal background color generator
+ * @layer_data: Array of layer data
+ * @layer_cnt: Layer data array count
+ * @logo_color_key: not supported/used at this time
+ * @reset_gpio: GPIO line used to reset IP between modesetting operations
+ * @intrpt_handler_fn: Interrupt handler function called when frame is completed
+ * @intrpt_data: Data pointer passed to interrupt handler
+ * @private: Private data for use by higher level drivers if needed
+ *
+ * Used as the primary data structure for many L2 driver functions. Logo layer
+ * data, if enabled within the IP, is described in this structure. All other
+ * layers are described by an instance of xv_mixer_layer_data referenced by this
+ * struct.
+ *
+ */
+struct xv_mixer {
+ struct device_node *dn;
+ void __iomem *reg_base_addr;
+ bool logo_layer_enabled;
+ bool logo_color_key_enabled;
+ bool logo_pixel_alpha_enabled;
+ bool intrpts_enabled;
+ u32 max_layer_width;
+ u32 max_layer_height;
+ u32 max_logo_layer_width;
+ u32 max_logo_layer_height;
+ u32 max_layers;
+ u32 bg_layer_bpc;
+ u32 ppc;
+ int irq;
+ u64 bg_color;
+
+ struct xv_mixer_layer_data *layer_data;
+ u32 layer_cnt;
+
+ /* JPM TODO color key feature not yet implemented */
+ struct {
+ u8 rgb_min[3];
+ u8 rgb_max[3];
+ } logo_color_key;
+
+ struct gpio_desc *reset_gpio;
+
+ void (*intrpt_handler_fn)(void *);
+ void *intrpt_data;
+
+ void *private;
+};
+
+/************************** Function Prototypes ******************************/
+
+/**
+ * xilinx_mixer_set_layer_window - Sets the position of an overlay layer over
+ * the background layer (layer 0)
+ * @mixer: Specific mixer object instance controlling the video
+ * @layer_id: Logical layer id (1-7) to be positioned
+ * @x_pos: new: Column to start display of overlay layer
+ * @y_pos: new: Row to start display of overlay layer
+ * @win_width: Number of active columns to dislay for overlay layer
+ * @win_height: Number of active columns to display for overlay layer
+ * @stride_bytes: Width in bytes of overaly memory buffer (memory layer only)
+ *
+ * Return:
+ * Zero on success, -EINVAL if position is invalid or -ENODEV if layer
+ * data is not found
+ *
+ * Note:
+ * Applicable only for layers 1-7 or the logo layer
+ */
+int
+xilinx_mixer_set_layer_window(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 x_pos, u32 y_pos,
+ u32 win_width, u32 win_height,
+ u32 stride_bytes);
+
+/**
+ * xilinx_mixer_set_active_area - Sets the number of active horizontal and
+ * vertical scan lines for the mixer background layer.
+ * @mixer: Mixer instance for which to set a new viewable area
+ * @hactive: Width of new background image dimension
+ * @vactive: Height of new background image dimension
+ *
+ * Minimum values are 64x64 with maximum values determined by the IP hardware
+ * design.
+ *
+ * Return:
+ * Zero on success, -EINVAL on failure
+ */
+int
+xilinx_mixer_set_active_area(struct xv_mixer *mixer,
+ u32 hactive, u32 vactive);
+
+/**
+ * xilinx_mixer_set_bkg_col - Set the color to be output as background color
+ * when background stream layer
+ * is disabled
+ *
+ * @mixer: Mixer instance to program with new background color
+ * @rgb_value: RGB encoded as 32-bit integer in little-endian format
+ */
+void
+xilinx_mixer_set_bkg_col(struct xv_mixer *mixer, u64 rgb_value);
+
+/**
+ * xilinx_mixer_layer_enable - Enables (permit video output) for layer in mixer
+ * @mixer: Mixer instance in which to enable a video layer
+ * @layer_id: Logical id (e.g. 8 = logo layer) to enable
+ */
+void
+xilinx_mixer_layer_enable(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id);
+
+/**
+ * xilinx_mixer_layer_disable - Disables the layer denoted by layer_id in the
+ * IP core.
+ * @mixer: Mixer for which the layer will be disabled
+ * @layer_id: Logical id of the layer to be disabled (0-8)
+ *
+ * Note:
+ * Layer 0 will indicate the background layer and layer 8 the logo
+ * layer. Passing in the enum value XVMIX_LAYER_ALL will disable all
+ * layers.
+ */
+void
+xilinx_mixer_layer_disable(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id);
+
+static inline uint32_t
+xilinx_mixer_get_intr_status(struct xv_mixer *mixer)
+{
+ return (reg_readl(mixer->reg_base_addr, XV_MIX_CTRL_ADDR_ISR) &
+ XVMIX_IRQ_DONE_MASK);
+}
+
+static inline void
+xilinx_mixer_clear_intr_status(struct xv_mixer *mixer, uint32_t intr)
+{
+ reg_writel(mixer->reg_base_addr, XV_MIX_CTRL_ADDR_ISR, intr);
+}
+
+static inline bool
+xilinx_mixer_g_intrpt_enabled(struct xv_mixer *mixer)
+{
+ return (reg_readl(mixer->reg_base_addr, XV_MIX_CTRL_ADDR_GIE) &
+ XVMIX_IRQ_DONE_MASK);
+}
+
+/**
+ * xilinx_mixer_intrpt_enable - Enables interrupts in the mixer IP core
+ * @mixer: Instance in which to enable interrupts
+ */
+void
+xilinx_mixer_intrpt_enable(struct xv_mixer *mixer);
+
+/**
+ * xilinx_mixer_intrpt_disable - Disables all interrupts in the mixer IP core
+ * @mixer: Instance in which to disable interrupts
+ */
+void
+xilinx_mixer_intrpt_disable(struct xv_mixer *mixer);
+
+/**
+ * xilinx_mixer_get_layer_scaling - Return the current degree of scaling for
+ * the layer specified
+ * @mixer: Mixer instance for which layer information is requested
+ * @layer_id: Logical id of layer for which scale setting is requested
+ *
+ * Return:
+ * current layer scaling setting (defaults to 0 if scaling no enabled)
+ * 0 = no scaling (or scaling not permitted)
+ * 1 = 2x scaling (both horiz. and vert.)
+ * 2 = 4x scaling (both horiz. and vert.)
+ *
+ * Note:
+ * Only applicable to layers 1-7 and logo layer
+ */
+int
+xilinx_mixer_get_layer_scaling(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id);
+
+/**
+ * xilinx_mixer_get_layer_data - Retrieve current hardware and register
+ * values for a logical video layer
+ * @mixer: Mixer instance to interrogate
+ * @layer_id: Logical id of layer for which data is requested
+ *
+ * Return
+ * Structure containing layer-specific data; NULL upon failure
+ */
+struct xv_mixer_layer_data*
+xilinx_mixer_get_layer_data(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id);
+
+/**
+ * xilinx_mixer_set_layer_scaling - Sets the scaling factor for the specified
+ * video layer
+ * @mixer: Instance of mixer to be subject of scaling request
+ * @layer_id: Logical id of video layer subject to new scale setting
+ * @scale: scale Factor (1x, 2x or 4x) for horiz. and vert. dimensions
+ *
+ * Return:
+ * Zero on success, -EINVAL on failure to set scale for layer (likely
+ * returned if resulting size of layer exceeds dimensions of active
+ * display area
+ *
+ * Note:
+ * Not applicable to background stream layer (layer 0)
+ */
+int
+xilinx_mixer_set_layer_scaling(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ enum xv_mixer_scale_factor scale);
+
+/**
+ * xilinx_mixer_set_layer_alpha - Set the layer global transparency for a
+ * video overlay
+ * @mixer: Instance of mixer controlling layer to modify
+ * @layer_id: Logical id of video overlay to adjust alpha setting
+ * @alpha: Desired alpha setting (0-255) for layer specified
+ * 255 = completely opaque
+ * 0 = fully transparent
+ *
+ * Return:
+ * Zero on success, -EINVAL on failure
+ *
+ * Note:
+ * Not applicable to background streaming layer
+ */
+int
+xilinx_mixer_set_layer_alpha(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 alpha);
+
+/**
+ * xilinx_mixer_start - Start the mixer core video generator
+ * @mixer: Mixer core instance for which to begin video output
+ */
+void
+xilinx_mixer_start(struct xv_mixer *mixer);
+
+/**
+ * xilinx_mixer_stop - Stop the mixer core video generator
+ * @mixer: Mixer core instance for which to stop video output
+ */
+void
+xilinx_mixer_stop(struct xv_mixer *mixer);
+
+/**
+ * xilinx_mixer_init - Establishes a default power-on state for the mixer IP
+ * core
+ * @mixer: instance of IP core to initialize to a default state
+ *
+ * Background layer initialized to maximum height and width settings based on
+ * device tree properties and all overlay layers set to minimum height and width
+ * sizes and positioned to 0,0 in the crtc. All layers are inactive (resulting
+ * in video output being generated by the background color generator).
+ * Interrupts are disabled and the IP is started (with auto-restart enabled).
+ */
+void
+xilinx_mixer_init(struct xv_mixer *mixer);
+
+/**
+ * xilinx_mixer_logo_load - Loads mixer's internal bram with planar R, G, B
+ * and A data
+ * @mixer: Mixer instance to act upon
+ * @logo_w: Width of logo in pixels
+ * @logo_h: Height of logo in pixels
+ * @r_buf: Pointer to byte buffer array of R data values
+ * @g_buf: Pointer to byte buffer array of G data values
+ * @b_buf: Pointer to byte buffer array of B data values
+ * @a_buf: Pointer to byte buffer array of A data values
+ *
+ * Return:
+ * Zero on success, -ENODEV if logo layer not enabled; -EINVAL otherwise
+ */
+int
+xilinx_mixer_logo_load(struct xv_mixer *mixer, u32 logo_w, u32 logo_h,
+ u8 *r_buf, u8 *g_buf, u8 *b_buf, u8 *a_buf);
+
+int
+xilinx_mixer_set_layer_buff_addr(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 buff_addr);
+
+int
+xilinx_mixer_get_layer_buff_addr(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 *buff_addr);
+
+#endif /* __XV_VIDEO_MIXER_DATA__ */
diff --git a/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_hw.c b/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_hw.c
new file mode 100644
index 00000000000000..da483614ca9beb
--- /dev/null
+++ b/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_hw.c
@@ -0,0 +1,897 @@
+/*
+ * (C) Copyright 2016 - 2017, Xilinx, Inc.
+ *
+ * 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/types.h>
+
+#include "crtc/mixer/hw/xilinx_mixer_regs.h"
+#include "crtc/mixer/hw/xilinx_mixer_data.h"
+
+/************************** Constant Definitions *****************************/
+#define XVMIX_MASK_ENABLE_ALL_LAYERS (0x01FF)
+#define XVMIX_MASK_DISABLE_ALL_LAYERS (0)
+#define XVMIX_REG_OFFSET (8)
+
+/************************** Function Prototypes ******************************/
+static int is_window_valid(struct xv_mixer *mixer,
+ u32 new_x_pos, u32 new_y_pos,
+ u32 width, u32 height,
+ enum xv_mixer_scale_factor scale);
+
+/******************************************************************************
+ * Initializes the core instance.
+ * Sets initial state of mixer primary video layer and max height/width
+ * settings which should be retrieved from the device tree.
+ ******************************************************************************/
+void xilinx_mixer_init(struct xv_mixer *mixer)
+{
+ int i;
+ u32 bg_bpc = mixer->bg_layer_bpc;
+ u64 init_rgb_bg_color = (0xFFFF >> (XVMIX_MAX_BPC - bg_bpc))
+ << (bg_bpc * 2);
+ enum xv_mixer_layer_id layer_id;
+ struct xv_mixer_layer_data *layer_data;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, XVMIX_LAYER_MASTER);
+
+ xilinx_mixer_layer_disable(mixer, XVMIX_LAYER_ALL);
+
+ xilinx_mixer_set_active_area(mixer,
+ layer_data->hw_config.max_width,
+ layer_data->hw_config.max_height);
+
+ reg_writel(mixer->reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_VIDEO_FORMAT_DATA, 2);
+
+ /* default to blue */
+ xilinx_mixer_set_bkg_col(mixer, init_rgb_bg_color);
+
+ for (i = 0; i <= mixer->layer_cnt; i++) {
+ layer_id = mixer->layer_data[i].id;
+ layer_data = &mixer->layer_data[i];
+
+ if (layer_id == XVMIX_LAYER_MASTER)
+ continue;
+
+ xilinx_mixer_set_layer_window(mixer, layer_id, 0, 0,
+ XVMIX_LAYER_WIDTH_MIN,
+ XVMIX_LAYER_HEIGHT_MIN,
+ 0);
+
+ if (mixer_layer_can_scale(layer_data))
+ xilinx_mixer_set_layer_scaling(mixer, layer_id, 0);
+
+ if (mixer_layer_can_alpha(layer_data))
+ xilinx_mixer_set_layer_alpha(mixer, layer_id,
+ XVMIX_ALPHA_MAX);
+ }
+}
+
+/******************************************************************************
+ * Enables interrupts in the core
+ ******************************************************************************/
+void xilinx_mixer_intrpt_enable(struct xv_mixer *mixer)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ u32 curr_val = reg_readl(reg_base_addr, XV_MIX_CTRL_ADDR_IER);
+
+ /* Enable Interrupts */
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_IER,
+ curr_val | XVMIX_IRQ_DONE_MASK);
+
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_GIE, 0x1);
+}
+
+/******************************************************************************
+ * Disables interrupts in the core
+ ******************************************************************************/
+void xilinx_mixer_intrpt_disable(struct xv_mixer *mixer)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ u32 curr_val = reg_readl(reg_base_addr, XV_MIX_CTRL_ADDR_IER);
+
+ /* Disable Interrupts */
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_IER,
+ curr_val & (~XVMIX_IRQ_DONE_MASK));
+
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_GIE, 0);
+}
+
+/******************************************************************************
+ * Starts the core instance
+ ******************************************************************************/
+/* JPM TODO consider adding boolean param to indicate if free-running mode is
+ * desired. Right now, defaulting to free running mode
+ */
+void xilinx_mixer_start(struct xv_mixer *mixer)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ u32 curr_val;
+
+ curr_val = reg_readl(reg_base_addr, XV_MIX_CTRL_ADDR_AP_CTRL) & 0x80;
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_AP_CTRL, curr_val | 0x81);
+}
+
+/******************************************************************************
+ * Stops the core instance
+ ******************************************************************************/
+void xilinx_mixer_stop(struct xv_mixer *mixer)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_AP_CTRL, 0);
+}
+
+/******************************************************************************
+ * Validates if the requested window is within the frame boundary
+ ******************************************************************************/
+static int is_window_valid(struct xv_mixer *mixer,
+ u32 new_x_pos, u32 new_y_pos,
+ u32 width, u32 height,
+ enum xv_mixer_scale_factor scale)
+{
+ struct xv_mixer_layer_data *master_layer;
+ int scale_factor[3] = {1, 2, 4};
+
+ master_layer = xilinx_mixer_get_layer_data(mixer, XVMIX_LAYER_MASTER);
+
+ /* Check if window scale factor is set */
+ if (scale < XVMIX_SCALE_FACTOR_NOT_SUPPORTED) {
+ /* update window per scale factor before validating */
+ width *= scale_factor[scale];
+ height *= scale_factor[scale];
+ }
+
+ /* verify overlay falls within currently active background area */
+ if ((new_x_pos >= 0) && (new_y_pos >= 0) &&
+ ((new_x_pos + width) <= master_layer->layer_regs.width) &&
+ ((new_y_pos + height) <= master_layer->layer_regs.height)) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/******************************************************************************
+ * Configures the mixer input stream
+ ******************************************************************************/
+int xilinx_mixer_set_active_area(struct xv_mixer *mixer,
+ u32 hactive, u32 vactive)
+{
+ struct xv_mixer_layer_data *ld =
+ xilinx_mixer_get_layer_data(mixer, XVMIX_LAYER_MASTER);
+
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+
+ if (hactive > ld->hw_config.max_width ||
+ vactive > ld->hw_config.max_height)
+ return -EINVAL;
+
+ /* set resolution */
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_HWREG_HEIGHT_DATA, vactive);
+ reg_writel(reg_base_addr, XV_MIX_CTRL_ADDR_HWREG_WIDTH_DATA, hactive);
+
+ ld->layer_regs.width = hactive;
+ ld->layer_regs.height = vactive;
+
+ return 0;
+}
+
+/******************************************************************************
+ * Enables the specified layer of the core instance
+ ******************************************************************************/
+void xilinx_mixer_layer_enable(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id)
+{
+ u32 num_layers = mixer->layer_cnt;
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ struct xv_mixer_layer_data *layer_data;
+ u32 curr_state;
+
+ /* Ensure layer is marked as 'active' by application before
+ * turning on in hardware. In some cases, layer register data
+ * may be written to otherwise inactive layers in lieu of, eventually,
+ * turning them on.
+ */
+ layer_data = xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ if (layer_data) {
+ if (!mixer_layer_active(layer_data))
+ return;
+ } else {
+ return;
+ }
+
+ /*Check if request is to enable all layers or single layer*/
+ if (layer_id == XVMIX_LAYER_ALL) {
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA,
+ XVMIX_MASK_ENABLE_ALL_LAYERS);
+
+ } else if ((layer_id < num_layers) ||
+ ((layer_id == XVMIX_LAYER_LOGO) &&
+ mixer->logo_layer_enabled)) {
+ curr_state = reg_readl(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA);
+
+ curr_state |= (1 << layer_id);
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA,
+ curr_state);
+ }
+}
+
+/******************************************************************************
+ * Disables the specified layer of the core instance
+ ******************************************************************************/
+void xilinx_mixer_layer_disable(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id)
+{
+ u32 num_layers, curr_state;
+ void __iomem *reg_addr = mixer->reg_base_addr;
+
+ num_layers = mixer->layer_cnt;
+
+ if (layer_id == XVMIX_LAYER_ALL) {
+ reg_writel(reg_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA,
+ XVMIX_MASK_DISABLE_ALL_LAYERS);
+
+ } else if ((layer_id < num_layers) ||
+ ((layer_id == XVMIX_LAYER_LOGO) &&
+ (mixer->logo_layer_enabled))) {
+ curr_state = reg_readl(reg_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA);
+
+ curr_state &= ~(1 << layer_id);
+
+ reg_writel(reg_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA,
+ curr_state);
+ }
+}
+
+/******************************************************************************
+ * Returns state of the specified layer [enabled or disabled]
+ ******************************************************************************/
+int xilinx_mixer_is_layer_enabled(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id)
+{
+ u32 state, mask;
+
+ mask = (1 << layer_id);
+ state = reg_readl(mixer->reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA);
+ return ((state & mask) ? 1 : 0);
+}
+
+/******************************************************************************
+ * Sets the background color to be displayed when stream layer is
+ * disabled
+ ******************************************************************************/
+void xilinx_mixer_set_bkg_col(struct xv_mixer *mixer, u64 rgb_value)
+{
+ u32 bg_bpc = mixer->bg_layer_bpc;
+ u32 bpc_mask_shift = XVMIX_MAX_BPC - bg_bpc;
+ u32 val_mask = (0xFFFF >> bpc_mask_shift);
+
+ u16 b_val = (rgb_value >> (bg_bpc * 2)) & val_mask;
+ u16 g_val = (rgb_value >> bg_bpc) & val_mask;
+ u16 r_val = (rgb_value >> 0) & val_mask;
+
+ /* Set Background Color */
+ reg_writel(mixer->reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_BACKGROUND_Y_R_DATA, r_val);
+ reg_writel(mixer->reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_BACKGROUND_U_G_DATA, g_val);
+ reg_writel(mixer->reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_BACKGROUND_V_B_DATA, b_val);
+
+ mixer->bg_color = rgb_value;
+}
+
+/******************************************************************************
+ * Configures the window coordinates of the specified layer
+ ******************************************************************************/
+int xilinx_mixer_set_layer_window(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 x_pos, u32 y_pos,
+ u32 win_width, u32 win_height,
+ u32 stride_bytes)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ struct xv_mixer_layer_data *layer_data;
+ enum xv_mixer_scale_factor scale = 0;
+ int status = 0;
+ bool win_valid = false;
+ u32 x_reg, y_reg, w_reg, h_reg, s_reg;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ if (!layer_data)
+ return (-ENODEV);
+
+ /* Check window coordinates */
+ scale = xilinx_mixer_get_layer_scaling(mixer, layer_id);
+
+ if (is_window_valid(mixer, x_pos, y_pos, win_width, win_height, scale))
+ return(-EINVAL);
+
+ switch (layer_id) {
+ case XVMIX_LAYER_LOGO:
+ if (mixer->logo_layer_enabled &&
+ win_width <= layer_data->hw_config.max_width &&
+ win_height <= layer_data->hw_config.max_height &&
+ win_height >= layer_data->hw_config.min_height &&
+ win_height >= layer_data->hw_config.min_width) {
+ x_reg = XV_MIX_CTRL_ADDR_HWREG_LOGOSTARTX_DATA;
+ y_reg = XV_MIX_CTRL_ADDR_HWREG_LOGOSTARTY_DATA;
+ w_reg = XV_MIX_CTRL_ADDR_HWREG_LOGOWIDTH_DATA;
+ h_reg = XV_MIX_CTRL_ADDR_HWREG_LOGOHEIGHT_DATA;
+
+ reg_writel(reg_base_addr, x_reg, x_pos);
+
+ reg_writel(reg_base_addr, y_reg, y_pos);
+
+ reg_writel(reg_base_addr, w_reg, win_width);
+
+ reg_writel(reg_base_addr, h_reg, win_height);
+
+ layer_data->layer_regs.x_pos = x_pos;
+ layer_data->layer_regs.y_pos = y_pos;
+
+ layer_data->layer_regs.width = win_width;
+ layer_data->layer_regs.height = win_height;
+
+ } else {
+ status = -EINVAL;
+ }
+ break;
+
+ default: /*Layer1-Layer7*/
+ if (layer_id < mixer->layer_cnt &&
+ win_width <= layer_data->hw_config.max_width &&
+ win_width >= layer_data->hw_config.min_width) {
+ x_reg = XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_0_DATA;
+ y_reg = XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_0_DATA;
+ w_reg = XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_0_DATA;
+ h_reg = XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_0_DATA;
+ s_reg = XV_MIX_CTRL_ADDR_HWREG_STRIDE_0_DATA;
+ /* Check layer interface is Stream or Memory */
+ if (layer_data->hw_config.is_streaming) {
+ /* Stride is not required for stream layer */
+ win_valid = true;
+ } else {
+ /* Check if stride is aligned to aximm width
+ * (2*PPC*32-bits)
+ */
+ u32 align = 2 * mixer->ppc * 4;
+
+ if ((stride_bytes % align) != 0) {
+ win_valid = false;
+ status = -EINVAL;
+ } else {
+ win_valid = true;
+ }
+ }
+
+ if (win_valid) {
+ u32 offset = layer_id * XVMIX_REG_OFFSET;
+
+ reg_writel(reg_base_addr,
+ (x_reg + offset), x_pos);
+
+ reg_writel(reg_base_addr,
+ (y_reg + offset), y_pos);
+
+ reg_writel(reg_base_addr,
+ (w_reg + offset), win_width);
+
+ reg_writel(reg_base_addr,
+ (h_reg + offset), win_height);
+
+ layer_data->layer_regs.x_pos = x_pos;
+ layer_data->layer_regs.y_pos = y_pos;
+
+ layer_data->layer_regs.width = win_width;
+ layer_data->layer_regs.height = win_height;
+
+ if (!(layer_data->hw_config.is_streaming)) {
+ reg_writel(reg_base_addr,
+ (s_reg + offset),
+ stride_bytes);
+ }
+ status = 0;
+ }
+ } else {
+ status = -EINVAL;
+ }
+ break;
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Configures the scaling factor of the specified layer
+ *
+ * Applicable only for overlay layers
+ ******************************************************************************/
+int xilinx_mixer_set_layer_scaling(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ enum xv_mixer_scale_factor scale)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ struct xv_mixer_layer_data *layer_data;
+
+ int status = 0;
+ int win_status = 0;
+ u32 layer_x_pos, layer_y_pos, layer_width, layer_height;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ if (win_status != 0)
+ return win_status;
+
+ layer_x_pos = mixer_layer_x_pos(layer_data);
+ layer_y_pos = mixer_layer_y_pos(layer_data);
+
+ layer_width = mixer_layer_width(layer_data);
+ layer_height = mixer_layer_height(layer_data);
+
+ if (is_window_valid(mixer, layer_x_pos, layer_y_pos,
+ layer_width, layer_height, scale)) {
+ return(-EINVAL);
+ }
+
+ switch (layer_id) {
+ case XVMIX_LAYER_LOGO:
+ if (mixer->logo_layer_enabled) {
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOSCALEFACTOR_DATA,
+ scale);
+
+ layer_data->layer_regs.scale_fact = scale;
+
+ status = 0;
+ }
+ break;
+
+ default: /*Layer0-Layer7*/
+ if (layer_id < mixer->layer_cnt &&
+ mixer_layer_can_scale(layer_data)) {
+ u32 offset = layer_id * XVMIX_REG_OFFSET;
+
+ reg_writel
+ (reg_base_addr,
+ (XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_0_DATA +
+ offset), scale);
+
+ layer_data->layer_regs.scale_fact = scale;
+
+ status = 0;
+ }
+ break;
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Returns the scaling factor of the specified layer
+ *
+ * Applicable only for overlay layers
+ ******************************************************************************/
+int xilinx_mixer_get_layer_scaling(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id)
+{
+ int scale_factor = 0;
+ u32 reg;
+ struct xv_mixer_layer_data *layer_data =
+ xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ switch (layer_id) {
+ case XVMIX_LAYER_LOGO:
+ if (mixer->logo_layer_enabled) {
+ reg = XV_MIX_CTRL_ADDR_HWREG_LOGOSCALEFACTOR_DATA;
+ scale_factor = reg_readl(mixer->reg_base_addr, reg);
+ layer_data->layer_regs.scale_fact = scale_factor;
+ }
+ break;
+
+ default: /*Layer0-Layer7*/
+ if ((layer_id < XVMIX_LAYER_LOGO) &&
+ mixer_layer_can_scale(layer_data)) {
+ reg = XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_0_DATA;
+ scale_factor =
+ reg_readl(mixer->reg_base_addr,
+ (reg +
+ (layer_id * XVMIX_REG_OFFSET)));
+
+ layer_data->layer_regs.scale_fact = scale_factor;
+ }
+ break;
+ }
+ return scale_factor;
+}
+
+/******************************************************************************
+ * Configures the Alpha level of the specified layer
+ *
+ * Applicable only for overlay layers
+ *
+ ******************************************************************************/
+int xilinx_mixer_set_layer_alpha(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 alpha)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ struct xv_mixer_layer_data *layer_data;
+ u32 reg;
+ int status = 0;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ switch (layer_id) {
+ case XVMIX_LAYER_LOGO:
+ if (mixer->logo_layer_enabled) {
+ reg = XV_MIX_CTRL_ADDR_HWREG_LOGOALPHA_DATA;
+ reg_writel(reg_base_addr, reg, alpha);
+ layer_data->layer_regs.alpha = alpha;
+ status = 0;
+
+ } else {
+ status = -EINVAL;
+ }
+ break;
+
+ default: /*Layer1-Layer7*/
+ if ((layer_id < mixer->layer_cnt) &&
+ mixer_layer_can_alpha(layer_data)) {
+ u32 offset = layer_id * XVMIX_REG_OFFSET;
+
+ reg = XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_0_DATA;
+ reg_writel(reg_base_addr, (reg + offset), alpha);
+ layer_data->layer_regs.alpha = alpha;
+ status = 0;
+ } else {
+ status = -EINVAL;
+ }
+ break;
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Returns the alpha of the specified layer
+ ******************************************************************************/
+int xilinx_mixer_get_layer_alpha(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id, u32 *reg_val)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ struct xv_mixer_layer_data *layer_data;
+ u32 reg;
+ int status = -EINVAL;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ switch (layer_id) {
+ case XVMIX_LAYER_LOGO:
+ if (mixer->logo_layer_enabled) {
+ *reg_val = reg_readl(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOALPHA_DATA);
+ status = 0;
+ layer_data->layer_regs.alpha = *reg_val;
+ }
+ break;
+
+ default: /*Layer1-Layer7*/
+ if ((layer_id < mixer->layer_cnt) &&
+ mixer_layer_can_alpha(layer_data)) {
+ u32 offset = layer_id * XVMIX_REG_OFFSET;
+
+ reg = XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_0_DATA;
+ *reg_val = reg_readl(reg_base_addr, (reg + offset));
+ layer_data->layer_regs.alpha = *reg_val;
+ status = 0;
+ }
+ break;
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Reads the color format of the specified layer
+ ******************************************************************************/
+int xilinx_mixer_get_layer_colorspace_fmt(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ enum xv_comm_color_fmt_id *c_fmt)
+{
+ struct xv_mixer_layer_data *layer_data;
+ int status = -EINVAL;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, layer_id);
+
+ if (layer_id <= mixer->layer_cnt) {
+ *c_fmt = layer_data->hw_config.vid_fmt;
+ status = 0;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Sets the buffer address of the specified layer
+ ******************************************************************************/
+int xilinx_mixer_set_layer_buff_addr(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 buff_addr)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ int status = 0;
+ u32 align;
+ u32 reg;
+ u32 win_valid = 0;
+
+ if (layer_id < mixer->layer_cnt) {
+ /* Check if addr is aligned to aximm width (PPC * 64-bits) */
+ align = mixer->ppc * 8;
+ if ((buff_addr % align) != 0) {
+ win_valid = 0;
+ status = -EINVAL;
+ } else {
+ win_valid = 1;
+ }
+ if (win_valid) {
+ struct xv_mixer_layer_data *layer_data;
+ u32 offset = (layer_id - 1) * XVMIX_REG_OFFSET;
+
+ reg = XV_MIX_CTRL_ADDR_HWREG_LAYER1_V_DATA;
+
+ layer_data = &mixer->layer_data[layer_id];
+
+ reg_writel(reg_base_addr, (reg + offset), buff_addr);
+
+ layer_data->layer_regs.buff_addr = buff_addr;
+ }
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Reads the buffer address of the specified layer
+ ******************************************************************************/
+int xilinx_mixer_get_layer_buff_addr(struct xv_mixer *mixer,
+ enum xv_mixer_layer_id layer_id,
+ u32 *buff_addr)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ u32 reg;
+ int status = -ENODEV;
+
+ if (layer_id < mixer->layer_cnt) {
+ u32 offset = (layer_id - 1) * XVMIX_REG_OFFSET;
+
+ reg = XV_MIX_CTRL_ADDR_HWREG_LAYER1_V_DATA;
+ *buff_addr = reg_readl(reg_base_addr, (reg + offset));
+ status = 0;
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Sets the logo layer color key data
+ ******************************************************************************/
+int xilinx_mixer_set_logo_color_key(struct xv_mixer *mixer)
+{
+ int status = -ENODEV;
+
+ if (mixer->logo_layer_enabled && mixer->logo_color_key_enabled) {
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ u8 *rgb_min = mixer->logo_color_key.rgb_min;
+ u8 *rgb_max = mixer->logo_color_key.rgb_max;
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_R_DATA,
+ rgb_min[0]);
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_G_DATA,
+ rgb_min[1]);
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_B_DATA,
+ rgb_min[2]);
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMAX_R_DATA,
+ rgb_max[0]);
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMAX_G_DATA,
+ rgb_max[1]);
+
+ reg_writel(reg_base_addr,
+ XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMAX_B_DATA,
+ rgb_max[2]);
+
+ status = 0;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Reads the logo layer color key data
+ ******************************************************************************/
+int xilinx_mixer_get_logo_color_key(struct xv_mixer *mixer)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ u32 reg_r, reg_g, reg_b;
+ u8 *rgb_min = mixer->logo_color_key.rgb_min;
+ u8 *rgb_max = mixer->logo_color_key.rgb_max;
+ int status = -ENODEV;
+
+ reg_r = XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_R_DATA;
+ reg_g = XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_G_DATA;
+ reg_b = XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_B_DATA;
+
+ if (mixer->logo_layer_enabled && mixer->logo_color_key_enabled) {
+ rgb_min[0] = reg_readl(reg_base_addr, reg_r);
+ rgb_min[1] = reg_readl(reg_base_addr, reg_g);
+ rgb_min[2] = reg_readl(reg_base_addr, reg_b);
+ rgb_max[0] = reg_readl(reg_base_addr, reg_r);
+ rgb_max[1] = reg_readl(reg_base_addr, reg_g);
+ rgb_max[2] = reg_readl(reg_base_addr, reg_b);
+
+ status = 0;
+ }
+ return status;
+}
+
+/******************************************************************************
+ * Loads the logo data into core BRAM
+ ******************************************************************************/
+int xilinx_mixer_logo_load(struct xv_mixer *mixer, u32 logo_w, u32 logo_h,
+ u8 *r_buffer, u8 *g_buffer, u8 *b_buffer,
+ u8 *a_buffer)
+{
+ void __iomem *reg_base_addr = mixer->reg_base_addr;
+ struct xv_mixer_layer_data *layer_data;
+
+ int status = 0;
+ int x;
+ u32 aligned_pix_cnt;
+ u32 rword, gword, bword, aword;
+ u32 pixel_cnt = logo_w * logo_h;
+ u32 unaligned_pix_cnt = pixel_cnt % 4;
+ u32 width, height, curr_x_pos, curr_y_pos;
+ u32 rbase_addr, gbase_addr, bbase_addr, abase_addr;
+
+ layer_data = xilinx_mixer_get_layer_data(mixer, XVMIX_LAYER_LOGO);
+ rword = 0;
+ gword = 0;
+ bword = 0;
+ aword = 0;
+
+ if (!layer_data)
+ return -ENODEV;
+
+ /* RGBA data should be 32-bit word aligned */
+ if (unaligned_pix_cnt && mixer->logo_pixel_alpha_enabled)
+ return -EINVAL;
+
+ if (mixer->logo_layer_enabled &&
+ logo_w <= layer_data->hw_config.max_width &&
+ logo_h <= layer_data->hw_config.max_height) {
+ width = logo_w;
+ height = logo_h;
+
+ rbase_addr = XV_MIX_CTRL_ADDR_HWREG_LOGOR_V_BASE;
+ gbase_addr = XV_MIX_CTRL_ADDR_HWREG_LOGOG_V_BASE;
+ bbase_addr = XV_MIX_CTRL_ADDR_HWREG_LOGOB_V_BASE;
+ abase_addr = XV_MIX_CTRL_ADDR_HWREG_LOGOA_V_BASE;
+
+ aligned_pix_cnt = pixel_cnt - unaligned_pix_cnt;
+
+ for (x = 0; x < aligned_pix_cnt; x += 4) {
+ rword = (u32)r_buffer[x] |
+ (((u32)r_buffer[x + 1]) << 8) |
+ (((u32)r_buffer[x + 2]) << 16) |
+ (((u32)r_buffer[x + 3]) << 24);
+
+ gword = (u32)g_buffer[x] |
+ (((u32)g_buffer[x + 1]) << 8) |
+ (((u32)g_buffer[x + 2]) << 16) |
+ (((u32)g_buffer[x + 3]) << 24);
+
+ bword = (u32)b_buffer[x] |
+ (((u32)b_buffer[x + 1]) << 8) |
+ (((u32)b_buffer[x + 2]) << 16) |
+ (((u32)b_buffer[x + 3]) << 24);
+
+ if (mixer->logo_pixel_alpha_enabled) {
+ aword = (u32)a_buffer[x] |
+ (((u32)a_buffer[x + 1]) << 8) |
+ (((u32)a_buffer[x + 2]) << 16) |
+ (((u32)a_buffer[x + 3]) << 24);
+ }
+
+ reg_writel(reg_base_addr, (rbase_addr + x), rword);
+ reg_writel(reg_base_addr, (gbase_addr + x), gword);
+ reg_writel(reg_base_addr, (bbase_addr + x), bword);
+
+ if (mixer->logo_pixel_alpha_enabled)
+ reg_writel(reg_base_addr,
+ (abase_addr + x), aword);
+ }
+
+ if (unaligned_pix_cnt) {
+ rword = 0;
+ gword = 0;
+ bword = 0;
+
+ switch (unaligned_pix_cnt) {
+ case 3:
+ rword = rword |
+ (((u32)r_buffer[aligned_pix_cnt + 2]) << 16);
+ gword = gword |
+ (((u32)g_buffer[aligned_pix_cnt + 2]) << 16);
+ bword = bword |
+ (((u32)b_buffer[aligned_pix_cnt + 2]) << 16);
+ break;
+
+ case 2:
+ rword = rword |
+ (((u32)r_buffer[aligned_pix_cnt + 1]) << 8);
+ gword = gword |
+ (((u32)g_buffer[aligned_pix_cnt + 1]) << 8);
+ bword = bword |
+ (((u32)b_buffer[aligned_pix_cnt + 1]) << 8);
+ break;
+
+ case 1:
+ rword = rword |
+ ((u32)r_buffer[aligned_pix_cnt]);
+ gword = gword |
+ ((u32)g_buffer[aligned_pix_cnt]);
+ bword = bword |
+ ((u32)b_buffer[aligned_pix_cnt]);
+ }
+
+ reg_writel(reg_base_addr,
+ (rbase_addr + aligned_pix_cnt), rword);
+ reg_writel(reg_base_addr,
+ (gbase_addr + aligned_pix_cnt), gword);
+ reg_writel(reg_base_addr,
+ (bbase_addr + aligned_pix_cnt), bword);
+ }
+
+ curr_x_pos = mixer_layer_x_pos(layer_data);
+ curr_y_pos = mixer_layer_y_pos(layer_data);
+
+ status = xilinx_mixer_set_layer_window(mixer, XVMIX_LAYER_LOGO,
+ curr_x_pos, curr_y_pos,
+ logo_w, logo_h, 0);
+ } else {
+ status = -EINVAL;
+ }
+ return status;
+}
+
+struct xv_mixer_layer_data
+*xilinx_mixer_get_layer_data(struct xv_mixer *mixer, enum xv_mixer_layer_id id)
+{
+ int i;
+ struct xv_mixer_layer_data *layer_data;
+
+ for (i = 0; i <= (mixer->layer_cnt - 1); i++) {
+ layer_data = &mixer->layer_data[i];
+ if (layer_data->id == id)
+ return layer_data;
+ }
+ return NULL;
+}
diff --git a/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_regs.h b/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_regs.h
new file mode 100644
index 00000000000000..be0e9d165fd423
--- /dev/null
+++ b/drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_regs.h
@@ -0,0 +1,639 @@
+/*
+ * (C) Copyright 2016 - 2017, Xilinx, Inc.
+ *
+ * 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.
+ */
+
+/* ==============================================================
+ * File generated by Vivado(TM) HLS - High-Level Synthesis from C,
+ * C++ and SystemC
+ * Version: 2016.1
+ * Copyright (C) 2016,2017 Xilinx Inc. All rights reserved.
+ *
+ * ==============================================================
+
+ * CTRL
+ * 0x00000 : Control signals
+ * bit 0 - ap_start (Read/Write/COH)
+ * bit 1 - ap_done (Read/COR)
+ * bit 2 - ap_idle (Read)
+ * bit 3 - ap_ready (Read)
+ * bit 7 - auto_restart (Read/Write)
+ * others - reserved
+ * 0x00004 : Global Interrupt Enable Register
+ * bit 0 - Global Interrupt Enable (Read/Write)
+ * others - reserved
+ * 0x00008 : IP Interrupt Enable Register (Read/Write)
+ * bit 0 - Channel 0 (ap_done)
+ * bit 1 - Channel 1 (ap_ready)
+ * others - reserved
+ * 0x0000c : IP Interrupt Status Register (Read/TOW)
+ * bit 0 - Channel 0 (ap_done)
+ * bit 1 - Channel 1 (ap_ready)
+ * others - reserved
+ * 0x00010 : Data signal of HwReg_width
+ * bit 15~0 - HwReg_width[15:0] (Read/Write)
+ * others - reserved
+ * 0x00014 : reserved
+ * 0x00018 : Data signal of HwReg_height
+ * bit 15~0 - HwReg_height[15:0] (Read/Write)
+ * others - reserved
+ * 0x0001c : reserved
+ * 0x00020 : Data signal of HwReg_video_format
+ * bit 15~0 - HwReg_video_format[15:0] (Read/Write)
+ * others - reserved
+ * 0x00024 : reserved
+ * 0x00028 : Data signal of HwReg_background_Y_R
+ * bit 15~0 - HwReg_background_Y_R[15:0] (Read/Write)
+ * others - reserved
+ * 0x0002c : reserved
+ * 0x00030 : Data signal of HwReg_background_U_G
+ * bit 15~0 - HwReg_background_U_G[15:0] (Read/Write)
+ * others - reserved
+ * 0x00034 : reserved
+ * 0x00038 : Data signal of HwReg_background_V_B
+ * bit 15~0 - HwReg_background_V_B[15:0] (Read/Write)
+ * others - reserved
+ * 0x0003c : reserved
+ * 0x00040 : Data signal of HwReg_layerEnable
+ * bit 15~0 - HwReg_layerEnable[15:0] (Read/Write)
+ * others - reserved
+ * 0x00044 : reserved
+ * 0x00048 : Data signal of HwReg_layer1_V
+ * bit 31~0 - HwReg_layer1_V[31:0] (Read/Write)
+ * 0x0004c : reserved
+ * 0x00050 : Data signal of HwReg_layer2_V
+ * bit 31~0 - HwReg_layer2_V[31:0] (Read/Write)
+ * 0x00054 : reserved
+ * 0x00058 : Data signal of HwReg_layer3_V
+ * bit 31~0 - HwReg_layer3_V[31:0] (Read/Write)
+ * 0x0005c : reserved
+ * 0x00060 : Data signal of HwReg_layer4_V
+ * bit 31~0 - HwReg_layer4_V[31:0] (Read/Write)
+ * 0x00064 : reserved
+ * 0x00068 : Data signal of HwReg_layer5_V
+ * bit 31~0 - HwReg_layer5_V[31:0] (Read/Write)
+ * 0x0006c : reserved
+ * 0x00070 : Data signal of HwReg_layer6_V
+ * bit 31~0 - HwReg_layer6_V[31:0] (Read/Write)
+ * 0x00074 : reserved
+ * 0x00078 : Data signal of HwReg_layer7_V
+ * bit 31~0 - HwReg_layer7_V[31:0] (Read/Write)
+ * 0x0007c : reserved
+ * 0x00080 : Data signal of HwReg_layerAlpha_0
+ * bit 15~0 - HwReg_layerAlpha_0[15:0] (Read/Write)
+ * others - reserved
+ * 0x00084 : reserved
+ * 0x00088 : Data signal of HwReg_layerAlpha_1
+ * bit 15~0 - HwReg_layerAlpha_1[15:0] (Read/Write)
+ * others - reserved
+ * 0x0008c : reserved
+ * 0x00090 : Data signal of HwReg_layerAlpha_2
+ * bit 15~0 - HwReg_layerAlpha_2[15:0] (Read/Write)
+ * others - reserved
+ * 0x00094 : reserved
+ * 0x00098 : Data signal of HwReg_layerAlpha_3
+ * bit 15~0 - HwReg_layerAlpha_3[15:0] (Read/Write)
+ * others - reserved
+ * 0x0009c : reserved
+ * 0x000a0 : Data signal of HwReg_layerAlpha_4
+ * bit 15~0 - HwReg_layerAlpha_4[15:0] (Read/Write)
+ * others - reserved
+ * 0x000a4 : reserved
+ * 0x000a8 : Data signal of HwReg_layerAlpha_5
+ * bit 15~0 - HwReg_layerAlpha_5[15:0] (Read/Write)
+ * others - reserved
+ * 0x000ac : reserved
+ * 0x000b0 : Data signal of HwReg_layerAlpha_6
+ * bit 15~0 - HwReg_layerAlpha_6[15:0] (Read/Write)
+ * others - reserved
+ * 0x000b4 : reserved
+ * 0x000b8 : Data signal of HwReg_layerAlpha_7
+ * bit 15~0 - HwReg_layerAlpha_7[15:0] (Read/Write)
+ * others - reserved
+ * 0x000bc : reserved
+ * 0x000c0 : Data signal of HwReg_layerStartX_0
+ * bit 15~0 - HwReg_layerStartX_0[15:0] (Read/Write)
+ * others - reserved
+ * 0x000c4 : reserved
+ * 0x000c8 : Data signal of HwReg_layerStartX_1
+ * bit 15~0 - HwReg_layerStartX_1[15:0] (Read/Write)
+ * others - reserved
+ * 0x000cc : reserved
+ * 0x000d0 : Data signal of HwReg_layerStartX_2
+ * bit 15~0 - HwReg_layerStartX_2[15:0] (Read/Write)
+ * others - reserved
+ * 0x000d4 : reserved
+ * 0x000d8 : Data signal of HwReg_layerStartX_3
+ * bit 15~0 - HwReg_layerStartX_3[15:0] (Read/Write)
+ * others - reserved
+ * 0x000dc : reserved
+ * 0x000e0 : Data signal of HwReg_layerStartX_4
+ * bit 15~0 - HwReg_layerStartX_4[15:0] (Read/Write)
+ * others - reserved
+ * 0x000e4 : reserved
+ * 0x000e8 : Data signal of HwReg_layerStartX_5
+ * bit 15~0 - HwReg_layerStartX_5[15:0] (Read/Write)
+ * others - reserved
+ * 0x000ec : reserved
+ * 0x000f0 : Data signal of HwReg_layerStartX_6
+ * bit 15~0 - HwReg_layerStartX_6[15:0] (Read/Write)
+ * others - reserved
+ * 0x000f4 : reserved
+ * 0x000f8 : Data signal of HwReg_layerStartX_7
+ * bit 15~0 - HwReg_layerStartX_7[15:0] (Read/Write)
+ * others - reserved
+ * 0x000fc : reserved
+ * 0x00100 : Data signal of HwReg_layerStartY_0
+ * bit 15~0 - HwReg_layerStartY_0[15:0] (Read/Write)
+ * others - reserved
+ * 0x00104 : reserved
+ * 0x00108 : Data signal of HwReg_layerStartY_1
+ * bit 15~0 - HwReg_layerStartY_1[15:0] (Read/Write)
+ * others - reserved
+ * 0x0010c : reserved
+ * 0x00110 : Data signal of HwReg_layerStartY_2
+ * bit 15~0 - HwReg_layerStartY_2[15:0] (Read/Write)
+ * others - reserved
+ * 0x00114 : reserved
+ * 0x00118 : Data signal of HwReg_layerStartY_3
+ * bit 15~0 - HwReg_layerStartY_3[15:0] (Read/Write)
+ * others - reserved
+ * 0x0011c : reserved
+ * 0x00120 : Data signal of HwReg_layerStartY_4
+ * bit 15~0 - HwReg_layerStartY_4[15:0] (Read/Write)
+ * others - reserved
+ * 0x00124 : reserved
+ * 0x00128 : Data signal of HwReg_layerStartY_5
+ * bit 15~0 - HwReg_layerStartY_5[15:0] (Read/Write)
+ * others - reserved
+ * 0x0012c : reserved
+ * 0x00130 : Data signal of HwReg_layerStartY_6
+ * bit 15~0 - HwReg_layerStartY_6[15:0] (Read/Write)
+ * others - reserved
+ * 0x00134 : reserved
+ * 0x00138 : Data signal of HwReg_layerStartY_7
+ * bit 15~0 - HwReg_layerStartY_7[15:0] (Read/Write)
+ * others - reserved
+ * 0x0013c : reserved
+ * 0x00140 : Data signal of HwReg_layerWidth_0
+ * bit 15~0 - HwReg_layerWidth_0[15:0] (Read/Write)
+ * others - reserved
+ * 0x00144 : reserved
+ * 0x00148 : Data signal of HwReg_layerWidth_1
+ * bit 15~0 - HwReg_layerWidth_1[15:0] (Read/Write)
+ * others - reserved
+ * 0x0014c : reserved
+ * 0x00150 : Data signal of HwReg_layerWidth_2
+ * bit 15~0 - HwReg_layerWidth_2[15:0] (Read/Write)
+ * others - reserved
+ * 0x00154 : reserved
+ * 0x00158 : Data signal of HwReg_layerWidth_3
+ * bit 15~0 - HwReg_layerWidth_3[15:0] (Read/Write)
+ * others - reserved
+ * 0x0015c : reserved
+ * 0x00160 : Data signal of HwReg_layerWidth_4
+ * bit 15~0 - HwReg_layerWidth_4[15:0] (Read/Write)
+ * others - reserved
+ * 0x00164 : reserved
+ * 0x00168 : Data signal of HwReg_layerWidth_5
+ * bit 15~0 - HwReg_layerWidth_5[15:0] (Read/Write)
+ * others - reserved
+ * 0x0016c : reserved
+ * 0x00170 : Data signal of HwReg_layerWidth_6
+ * bit 15~0 - HwReg_layerWidth_6[15:0] (Read/Write)
+ * others - reserved
+ * 0x00174 : reserved
+ * 0x00178 : Data signal of HwReg_layerWidth_7
+ * bit 15~0 - HwReg_layerWidth_7[15:0] (Read/Write)
+ * others - reserved
+ * 0x0017c : reserved
+ * 0x00180 : Data signal of HwReg_layerHeight_0
+ * bit 15~0 - HwReg_layerHeight_0[15:0] (Read/Write)
+ * others - reserved
+ * 0x00184 : reserved
+ * 0x00188 : Data signal of HwReg_layerHeight_1
+ * bit 15~0 - HwReg_layerHeight_1[15:0] (Read/Write)
+ * others - reserved
+ * 0x0018c : reserved
+ * 0x00190 : Data signal of HwReg_layerHeight_2
+ * bit 15~0 - HwReg_layerHeight_2[15:0] (Read/Write)
+ * others - reserved
+ * 0x00194 : reserved
+ * 0x00198 : Data signal of HwReg_layerHeight_3
+ * bit 15~0 - HwReg_layerHeight_3[15:0] (Read/Write)
+ * others - reserved
+ * 0x0019c : reserved
+ * 0x001a0 : Data signal of HwReg_layerHeight_4
+ * bit 15~0 - HwReg_layerHeight_4[15:0] (Read/Write)
+ * others - reserved
+ * 0x001a4 : reserved
+ * 0x001a8 : Data signal of HwReg_layerHeight_5
+ * bit 15~0 - HwReg_layerHeight_5[15:0] (Read/Write)
+ * others - reserved
+ * 0x001ac : reserved
+ * 0x001b0 : Data signal of HwReg_layerHeight_6
+ * bit 15~0 - HwReg_layerHeight_6[15:0] (Read/Write)
+ * others - reserved
+ * 0x001b4 : reserved
+ * 0x001b8 : Data signal of HwReg_layerHeight_7
+ * bit 15~0 - HwReg_layerHeight_7[15:0] (Read/Write)
+ * others - reserved
+ * 0x001bc : reserved
+ * 0x001c0 : Data signal of HwReg_layerScaleFactor_0
+ * bit 7~0 - HwReg_layerScaleFactor_0[7:0] (Read/Write)
+ * others - reserved
+ * 0x001c4 : reserved
+ * 0x001c8 : Data signal of HwReg_layerScaleFactor_1
+ * bit 7~0 - HwReg_layerScaleFactor_1[7:0] (Read/Write)
+ * others - reserved
+ * 0x001cc : reserved
+ * 0x001d0 : Data signal of HwReg_layerScaleFactor_2
+ * bit 7~0 - HwReg_layerScaleFactor_2[7:0] (Read/Write)
+ * others - reserved
+ * 0x001d4 : reserved
+ * 0x001d8 : Data signal of HwReg_layerScaleFactor_3
+ * bit 7~0 - HwReg_layerScaleFactor_3[7:0] (Read/Write)
+ * others - reserved
+ * 0x001dc : reserved
+ * 0x001e0 : Data signal of HwReg_layerScaleFactor_4
+ * bit 7~0 - HwReg_layerScaleFactor_4[7:0] (Read/Write)
+ * others - reserved
+ * 0x001e4 : reserved
+ * 0x001e8 : Data signal of HwReg_layerScaleFactor_5
+ * bit 7~0 - HwReg_layerScaleFactor_5[7:0] (Read/Write)
+ * others - reserved
+ * 0x001ec : reserved
+ * 0x001f0 : Data signal of HwReg_layerScaleFactor_6
+ * bit 7~0 - HwReg_layerScaleFactor_6[7:0] (Read/Write)
+ * others - reserved
+ * 0x001f4 : reserved
+ * 0x001f8 : Data signal of HwReg_layerScaleFactor_7
+ * bit 7~0 - HwReg_layerScaleFactor_7[7:0] (Read/Write)
+ * others - reserved
+ * 0x001fc : reserved
+ * 0x00200 : Data signal of HwReg_layerVideoFormat_0
+ * bit 7~0 - HwReg_layerVideoFormat_0[7:0] (Read/Write)
+ * others - reserved
+ * 0x00204 : reserved
+ * 0x00208 : Data signal of HwReg_layerVideoFormat_1
+ * bit 7~0 - HwReg_layerVideoFormat_1[7:0] (Read/Write)
+ * others - reserved
+ * 0x0020c : reserved
+ * 0x00210 : Data signal of HwReg_layerVideoFormat_2
+ * bit 7~0 - HwReg_layerVideoFormat_2[7:0] (Read/Write)
+ * others - reserved
+ * 0x00214 : reserved
+ * 0x00218 : Data signal of HwReg_layerVideoFormat_3
+ * bit 7~0 - HwReg_layerVideoFormat_3[7:0] (Read/Write)
+ * others - reserved
+ * 0x0021c : reserved
+ * 0x00220 : Data signal of HwReg_layerVideoFormat_4
+ * bit 7~0 - HwReg_layerVideoFormat_4[7:0] (Read/Write)
+ * others - reserved
+ * 0x00224 : reserved
+ * 0x00228 : Data signal of HwReg_layerVideoFormat_5
+ * bit 7~0 - HwReg_layerVideoFormat_5[7:0] (Read/Write)
+ * others - reserved
+ * 0x0022c : reserved
+ * 0x00230 : Data signal of HwReg_layerVideoFormat_6
+ * bit 7~0 - HwReg_layerVideoFormat_6[7:0] (Read/Write)
+ * others - reserved
+ * 0x00234 : reserved
+ * 0x00238 : Data signal of HwReg_layerVideoFormat_7
+ * bit 7~0 - HwReg_layerVideoFormat_7[7:0] (Read/Write)
+ * others - reserved
+ * 0x0023c : reserved
+ * 0x00240 : Data signal of HwReg_logoStartX
+ * bit 15~0 - HwReg_logoStartX[15:0] (Read/Write)
+ * others - reserved
+ * 0x00244 : reserved
+ * 0x00248 : Data signal of HwReg_logoStartY
+ * bit 15~0 - HwReg_logoStartY[15:0] (Read/Write)
+ * others - reserved
+ * 0x0024c : reserved
+ * 0x00250 : Data signal of HwReg_logoWidth
+ * bit 15~0 - HwReg_logoWidth[15:0] (Read/Write)
+ * others - reserved
+ * 0x00254 : reserved
+ * 0x00258 : Data signal of HwReg_logoHeight
+ * bit 15~0 - HwReg_logoHeight[15:0] (Read/Write)
+ * others - reserved
+ * 0x0025c : reserved
+ * 0x00260 : Data signal of HwReg_logoScaleFactor
+ * bit 15~0 - HwReg_logoScaleFactor[15:0] (Read/Write)
+ * others - reserved
+ * 0x00264 : reserved
+ * 0x00268 : Data signal of HwReg_logoAlpha
+ * bit 15~0 - HwReg_logoAlpha[15:0] (Read/Write)
+ * others - reserved
+ * 0x0026c : reserved
+ * 0x00270 : Data signal of HwReg_layerStride_0
+ * bit 15~0 - HwReg_layerStride_0[15:0] (Read/Write)
+ * others - reserved
+ * 0x00274 : reserved
+ * 0x00278 : Data signal of HwReg_layerStride_1
+ * bit 15~0 - HwReg_layerStride_1[15:0] (Read/Write)
+ * others - reserved
+ * 0x0027c : reserved
+ * 0x00280 : Data signal of HwReg_layerStride_2
+ * bit 15~0 - HwReg_layerStride_2[15:0] (Read/Write)
+ * others - reserved
+ * 0x00284 : reserved
+ * 0x00288 : Data signal of HwReg_layerStride_3
+ * bit 15~0 - HwReg_layerStride_3[15:0] (Read/Write)
+ * others - reserved
+ * 0x0028c : reserved
+ * 0x00290 : Data signal of HwReg_layerStride_4
+ * bit 15~0 - HwReg_layerStride_4[15:0] (Read/Write)
+ * others - reserved
+ * 0x00294 : reserved
+ * 0x00298 : Data signal of HwReg_layerStride_5
+ * bit 15~0 - HwReg_layerStride_5[15:0] (Read/Write)
+ * others - reserved
+ * 0x0029c : reserved
+ * 0x002a0 : Data signal of HwReg_layerStride_6
+ * bit 15~0 - HwReg_layerStride_6[15:0] (Read/Write)
+ * others - reserved
+ * 0x002a4 : reserved
+ * 0x002a8 : Data signal of HwReg_layerStride_7
+ * bit 15~0 - HwReg_layerStride_7[15:0] (Read/Write)
+ * others - reserved
+ * 0x002ac : reserved
+ * 0x002b0 : Data signal of HwReg_logoClrKeyMin_R
+ * bit 7~0 - HwReg_logoClrKeyMin_R[7:0] (Read/Write)
+ * others - reserved
+ * 0x002b4 : reserved
+ * 0x002b8 : Data signal of HwReg_logoClrKeyMin_G
+ * bit 7~0 - HwReg_logoClrKeyMin_G[7:0] (Read/Write)
+ * others - reserved
+ * 0x002bc : reserved
+ * 0x002c0 : Data signal of HwReg_logoClrKeyMin_B
+ * bit 7~0 - HwReg_logoClrKeyMin_B[7:0] (Read/Write)
+ * others - reserved
+ * 0x002c4 : reserved
+ * 0x002c8 : Data signal of HwReg_logoClrKeyMax_R
+ * bit 7~0 - HwReg_logoClrKeyMax_R[7:0] (Read/Write)
+ * others - reserved
+ * 0x002cc : reserved
+ * 0x002d0 : Data signal of HwReg_logoClrKeyMax_G
+ * bit 7~0 - HwReg_logoClrKeyMax_G[7:0] (Read/Write)
+ * others - reserved
+ * 0x002d4 : reserved
+ * 0x002d8 : Data signal of HwReg_logoClrKeyMax_B
+ * bit 7~0 - HwReg_logoClrKeyMax_B[7:0] (Read/Write)
+ * others - reserved
+ * 0x002dc : reserved
+ * 0x10000 ~
+ * 0x13fff : Memory 'HwReg_logoR_V' (4096 * 16b)
+ * Word n : bit [15: 0] - HwReg_logoR_V[2n]
+ * bit [31:16] - HwReg_logoR_V[2n+1]
+ * 0x20000 ~
+ * 0x23fff : Memory 'HwReg_logoG_V' (4096 * 16b)
+ * Word n : bit [15: 0] - HwReg_logoG_V[2n]
+ * bit [31:16] - HwReg_logoG_V[2n+1]
+ * 0x30000 ~
+ * 0x33fff : Memory 'HwReg_logoB_V' (4096 * 16b)
+ * Word n : bit [15: 0] - HwReg_logoB_V[2n]
+ * bit [31:16] - HwReg_logoB_V[2n+1]
+ * (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write,
+ * COH = Clear on Handshake)
+ */
+
+#include <linux/io.h>
+
+#ifndef __XV_MIXER_REGS__
+#define __XV_MIXER_REGS__
+
+static inline void reg_writel(void __iomem *base, int offset, u32 val)
+{
+ writel(val, base + offset);
+}
+
+/* io read operations */
+static inline u32 reg_readl(void __iomem *base, int offset)
+{
+ return readl(base + offset);
+}
+
+/************************** Constant Definitions *****************************/
+#define XVMIX_MAX_SUPPORTED_LAYERS (9)
+#define XVMIX_MAX_BPC (16)
+#define XVMIX_MAX_BG_COLOR_BITS (0xFFFFFFFFFFFF)
+#define XVMIX_ALPHA_MIN (0)
+#define XVMIX_ALPHA_MAX (256)
+#define XVMIX_LAYER_WIDTH_MIN (64)
+#define XVMIX_LAYER_HEIGHT_MIN XVMIX_LAYER_WIDTH_MIN
+#define XVMIX_LOGO_LAYER_WIDTH_MIN (32)
+#define XVMIX_LOGO_LAYER_HEIGHT_MIN XVMIX_LOGO_LAYER_WIDTH_MIN
+#define XVMIX_LOGO_LAYER_WIDTH_MAX (256)
+#define XVMIX_LOGO_LAYER_HEIGHT_MAX XVMIX_LOGO_LAYER_WIDTH_MAX
+#define XVMIX_IRQ_DONE_MASK (0x01)
+#define XVMIX_IRQ_READY_MASK (0x02)
+
+/**************************** Register Data **********************************/
+#define XV_MIX_CTRL_ADDR_AP_CTRL 0x00000
+#define XV_MIX_CTRL_ADDR_GIE 0x00004
+#define XV_MIX_CTRL_ADDR_IER 0x00008
+#define XV_MIX_CTRL_ADDR_ISR 0x0000c
+#define XV_MIX_CTRL_ADDR_HWREG_WIDTH_DATA 0x00010
+#define XV_MIX_CTRL_BITS_HWREG_WIDTH_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_HEIGHT_DATA 0x00018
+#define XV_MIX_CTRL_BITS_HWREG_HEIGHT_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_VIDEO_FORMAT_DATA 0x00020
+#define XV_MIX_CTRL_BITS_HWREG_VIDEO_FORMAT_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_BACKGROUND_Y_R_DATA 0x00028
+#define XV_MIX_CTRL_BITS_HWREG_BACKGROUND_Y_R_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_BACKGROUND_U_G_DATA 0x00030
+#define XV_MIX_CTRL_BITS_HWREG_BACKGROUND_U_G_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_BACKGROUND_V_B_DATA 0x00038
+#define XV_MIX_CTRL_BITS_HWREG_BACKGROUND_V_B_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERENABLE_DATA 0x00040
+#define XV_MIX_CTRL_BITS_HWREG_LAYERENABLE_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER1_V_DATA 0x00048
+#define XV_MIX_CTRL_BITS_HWREG_LAYER1_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER2_V_DATA 0x00050
+#define XV_MIX_CTRL_BITS_HWREG_LAYER2_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER3_V_DATA 0x00058
+#define XV_MIX_CTRL_BITS_HWREG_LAYER3_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER4_V_DATA 0x00060
+#define XV_MIX_CTRL_BITS_HWREG_LAYER4_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER5_V_DATA 0x00068
+#define XV_MIX_CTRL_BITS_HWREG_LAYER5_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER6_V_DATA 0x00070
+#define XV_MIX_CTRL_BITS_HWREG_LAYER6_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYER7_V_DATA 0x00078
+#define XV_MIX_CTRL_BITS_HWREG_LAYER7_V_DATA 32
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_0_DATA 0x00080
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_0_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_1_DATA 0x00088
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_1_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_2_DATA 0x00090
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_2_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_3_DATA 0x00098
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_3_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_4_DATA 0x000a0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_4_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_5_DATA 0x000a8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_5_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_6_DATA 0x000b0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_6_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERALPHA_7_DATA 0x000b8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERALPHA_7_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_0_DATA 0x000c0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_0_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_1_DATA 0x000c8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_1_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_2_DATA 0x000d0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_2_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_3_DATA 0x000d8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_3_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_4_DATA 0x000e0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_4_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_5_DATA 0x000e8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_5_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_6_DATA 0x000f0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_6_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTX_7_DATA 0x000f8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTX_7_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_0_DATA 0x00100
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_0_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_1_DATA 0x00108
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_1_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_2_DATA 0x00110
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_2_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_3_DATA 0x00118
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_3_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_4_DATA 0x00120
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_4_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_5_DATA 0x00128
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_5_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_6_DATA 0x00130
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_6_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSTARTY_7_DATA 0x00138
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSTARTY_7_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_0_DATA 0x00140
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_0_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_1_DATA 0x00148
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_1_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_2_DATA 0x00150
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_2_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_3_DATA 0x00158
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_3_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_4_DATA 0x00160
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_4_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_5_DATA 0x00168
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_5_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_6_DATA 0x00170
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_6_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERWIDTH_7_DATA 0x00178
+#define XV_MIX_CTRL_BITS_HWREG_LAYERWIDTH_7_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_0_DATA 0x00180
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_0_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_1_DATA 0x00188
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_1_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_2_DATA 0x00190
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_2_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_3_DATA 0x00198
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_3_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_4_DATA 0x001a0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_4_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_5_DATA 0x001a8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_5_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_6_DATA 0x001b0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_6_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERHEIGHT_7_DATA 0x001b8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERHEIGHT_7_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_0_DATA 0x001c0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_0_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_1_DATA 0x001c8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_1_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_2_DATA 0x001d0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_2_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_3_DATA 0x001d8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_3_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_4_DATA 0x001e0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_4_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_5_DATA 0x001e8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_5_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_6_DATA 0x001f0
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_6_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERSCALEFACTOR_7_DATA 0x001f8
+#define XV_MIX_CTRL_BITS_HWREG_LAYERSCALEFACTOR_7_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_0_DATA 0x00200
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_0_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_1_DATA 0x00208
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_1_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_2_DATA 0x00210
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_2_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_3_DATA 0x00218
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_3_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_4_DATA 0x00220
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_4_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_5_DATA 0x00228
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_5_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_6_DATA 0x00230
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_6_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LAYERVIDEOFORMAT_7_DATA 0x00238
+#define XV_MIX_CTRL_BITS_HWREG_LAYERVIDEOFORMAT_7_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOSTARTX_DATA 0x00240
+#define XV_MIX_CTRL_BITS_HWREG_LOGOSTARTX_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOSTARTY_DATA 0x00248
+#define XV_MIX_CTRL_BITS_HWREG_LOGOSTARTY_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOWIDTH_DATA 0x00250
+#define XV_MIX_CTRL_BITS_HWREG_LOGOWIDTH_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOHEIGHT_DATA 0x00258
+#define XV_MIX_CTRL_BITS_HWREG_LOGOHEIGHT_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOSCALEFACTOR_DATA 0x00260
+#define XV_MIX_CTRL_BITS_HWREG_LOGOSCALEFACTOR_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOALPHA_DATA 0x00268
+#define XV_MIX_CTRL_BITS_HWREG_LOGOALPHA_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_0_DATA 0x00270
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_0_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_1_DATA 0x00278
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_1_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_2_DATA 0x00280
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_2_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_3_DATA 0x00288
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_3_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_4_DATA 0x00290
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_4_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_5_DATA 0x00298
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_5_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_6_DATA 0x002a0
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_6_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_STRIDE_7_DATA 0x002a8
+#define XV_MIX_CTRL_BITS_HWREG_STRIDE_7_DATA 16
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_R_DATA 0x002b0
+#define XV_MIX_CTRL_BITS_HWREG_LOGOCLRKEYMIN_R_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_G_DATA 0x002b8
+#define XV_MIX_CTRL_BITS_HWREG_LOGOCLRKEYMIN_G_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMIN_B_DATA 0x002c0
+#define XV_MIX_CTRL_BITS_HWREG_LOGOCLRKEYMIN_B_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMAX_R_DATA 0x002c8
+#define XV_MIX_CTRL_BITS_HWREG_LOGOCLRKEYMAX_R_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMAX_G_DATA 0x002d0
+#define XV_MIX_CTRL_BITS_HWREG_LOGOCLRKEYMAX_G_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOCLRKEYMAX_B_DATA 0x002d8
+#define XV_MIX_CTRL_BITS_HWREG_LOGOCLRKEYMAX_B_DATA 8
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOR_V_BASE 0x10000
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOR_V_HIGH 0x13fff
+#define XV_MIX_CTRL_WIDTH_HWREG_LOGOR_V 16
+#define XV_MIX_CTRL_DEPTH_HWREG_LOGOR_V 4096
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOG_V_BASE 0x20000
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOG_V_HIGH 0x23fff
+#define XV_MIX_CTRL_WIDTH_HWREG_LOGOG_V 16
+#define XV_MIX_CTRL_DEPTH_HWREG_LOGOG_V 4096
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOB_V_BASE 0x30000
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOB_V_HIGH 0x33fff
+#define XV_MIX_CTRL_WIDTH_HWREG_LOGOB_V 16
+#define XV_MIX_CTRL_DEPTH_HWREG_LOGOB_V 4096
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOA_V_BASE 0x40000
+#define XV_MIX_CTRL_ADDR_HWREG_LOGOA_V_HIGH 0x43fff
+#define XV_MIX_CTRL_WIDTH_HWREG_LOGOA_V 16
+#define XV_MIX_CTRL_DEPTH_HWREG_LOGOA_V 4096
+
+#endif /* __XV_MIXER_REGS__ */
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_connector.c b/drivers/gpu/drm/xilinx/xilinx_drm_connector.c
index ad76dbc29aa9f1..146d59fe9fa24e 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_connector.c
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_connector.c
@@ -107,7 +107,7 @@ xilinx_drm_connector_detect(struct drm_connector *base_connector, bool force)
if (force && (status != connector_status_connected))
status = encoder_sfuncs->detect(encoder, base_connector);
- DRM_DEBUG_KMS("status: %d\n", status);
+ DRM_DEBUG_KMS("encoder_sfuncs->detect call status: %d\n", status);
return status;
}
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c b/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c
index 723bcc47e2a67b..322a2cd236eb3c 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c
@@ -32,11 +32,13 @@
#include "xilinx_drm_dp_sub.h"
#include "xilinx_drm_drv.h"
#include "xilinx_drm_plane.h"
+#include "crtc/mixer/drm/xilinx_drm_mixer.h"
#include "xilinx_cresample.h"
#include "xilinx_rgb2yuv.h"
#include "xilinx_vtc.h"
+
struct xilinx_drm_crtc {
struct drm_crtc base;
struct xilinx_cresample *cresample;
@@ -53,6 +55,10 @@ struct xilinx_drm_crtc {
#define to_xilinx_crtc(x) container_of(x, struct xilinx_drm_crtc, base)
+static struct drm_plane *
+xilinx_find_plane(struct xilinx_drm_plane_manager *manager,
+ enum drm_plane_type type);
+
/* set crtc dpms */
static void xilinx_drm_crtc_dpms(struct drm_crtc *base_crtc, int dpms)
{
@@ -118,8 +124,8 @@ static void xilinx_drm_crtc_prepare(struct drm_crtc *base_crtc)
/* apply mode to crtc pipe */
static void xilinx_drm_crtc_commit(struct drm_crtc *base_crtc)
{
- xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_ON);
xilinx_drm_plane_commit(base_crtc->primary);
+ xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_ON);
}
/* fix mode */
@@ -151,7 +157,7 @@ static int xilinx_drm_crtc_mode_set(struct drm_crtc *base_crtc,
/* set pixel clock */
ret = clk_set_rate(crtc->pixel_clock, adjusted_mode->clock * 1000);
if (ret) {
- DRM_ERROR("failed to set a pixel clock\n");
+ DRM_ERROR("failed to set a pixel clock. ret code = %d\n", ret);
return ret;
}
@@ -191,7 +197,7 @@ static int xilinx_drm_crtc_mode_set(struct drm_crtc *base_crtc,
adjusted_mode->hdisplay,
adjusted_mode->vdisplay);
- /* configure a plane: vdma and osd layer */
+ /* configure a plane: vdma and osd|mixer layer */
xilinx_drm_plane_manager_mode_set(crtc->plane_manager,
adjusted_mode->hdisplay,
adjusted_mode->vdisplay);
@@ -392,14 +398,31 @@ void xilinx_drm_crtc_enable_vblank(struct drm_crtc *base_crtc)
{
struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
- if (crtc->vtc)
+ if (crtc->plane_manager->mixer) {
+ struct xilinx_drm_mixer *mixer = crtc->plane_manager->mixer;
+
+ if (mixer->mixer_hw.intrpts_enabled) {
+ xilinx_drm_mixer_set_intr_handler(
+ mixer,
+ xilinx_drm_crtc_vblank_handler,
+ base_crtc);
+ return;
+ }
+ }
+
+ if (crtc->vtc) {
xilinx_vtc_enable_vblank_intr(crtc->vtc,
xilinx_drm_crtc_vblank_handler,
base_crtc);
- if (crtc->dp_sub)
+ return;
+ }
+
+ if (crtc->dp_sub) {
xilinx_drm_dp_sub_enable_vblank(crtc->dp_sub,
xilinx_drm_crtc_vblank_handler,
base_crtc);
+ return;
+ }
}
/* disable vblank interrupt */
@@ -433,6 +456,24 @@ unsigned int xilinx_drm_crtc_get_max_width(struct drm_crtc *base_crtc)
return xilinx_drm_plane_get_max_width(base_crtc->primary);
}
+/* check max height */
+unsigned int xilinx_drm_crtc_get_max_height(struct drm_crtc *base_crtc)
+{
+ return xilinx_drm_plane_get_max_height(base_crtc->primary);
+}
+
+/* check max cursor width */
+unsigned int xilinx_drm_crtc_get_max_cursor_width(struct drm_crtc *base_crtc)
+{
+ return xilinx_drm_plane_get_max_cursor_width(base_crtc->primary);
+}
+
+/* check max cursor height */
+unsigned int xilinx_drm_crtc_get_max_cursor_height(struct drm_crtc *base_crtc)
+{
+ return xilinx_drm_plane_get_max_cursor_height(base_crtc->primary);
+}
+
/* check format */
bool xilinx_drm_crtc_check_format(struct drm_crtc *base_crtc, uint32_t fourcc)
{
@@ -470,7 +511,8 @@ static struct drm_crtc_funcs xilinx_drm_crtc_funcs = {
struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm)
{
struct xilinx_drm_crtc *crtc;
- struct drm_plane *primary_plane;
+ struct drm_plane *primary_plane = NULL;
+ struct drm_plane *cursor_plane = NULL;
struct device_node *sub_node;
int possible_crtcs = 1;
int ret;
@@ -512,6 +554,7 @@ struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm)
/* create a primary plane. there's only one crtc now */
primary_plane = xilinx_drm_plane_create_primary(crtc->plane_manager,
possible_crtcs);
+
if (IS_ERR(primary_plane)) {
DRM_ERROR("failed to create a primary plane for crtc\n");
ret = PTR_ERR(primary_plane);
@@ -562,9 +605,22 @@ struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm)
crtc->dpms = DRM_MODE_DPMS_OFF;
+ /* permit flexible placement of primary plane among planes## in dts */
+ if (primary_plane->type != DRM_PLANE_TYPE_PRIMARY)
+ primary_plane = xilinx_find_plane(crtc->plane_manager,
+ DRM_PLANE_TYPE_PRIMARY);
+
+ if (!primary_plane)
+ return ERR_PTR(-ENODEV);
+
+ cursor_plane = xilinx_find_plane(crtc->plane_manager,
+ DRM_PLANE_TYPE_CURSOR);
+
/* initialize drm crtc */
- ret = drm_crtc_init_with_planes(drm, &crtc->base, primary_plane,
- NULL, &xilinx_drm_crtc_funcs, NULL);
+ ret = drm_crtc_init_with_planes(drm, &crtc->base,
+ primary_plane, cursor_plane,
+ &xilinx_drm_crtc_funcs,
+ NULL);
if (ret) {
DRM_ERROR("failed to initialize crtc\n");
goto err_pixel_clk;
@@ -582,3 +638,19 @@ err_plane:
xilinx_drm_plane_remove_manager(crtc->plane_manager);
return ERR_PTR(ret);
}
+
+static struct drm_plane *
+xilinx_find_plane(struct xilinx_drm_plane_manager *manager,
+ enum drm_plane_type type)
+{
+ int i;
+
+ for (i = 0; i < manager->num_planes; i++) {
+ struct xilinx_drm_plane *p = manager->planes[i];
+
+ if (p && (p->base.type == type))
+ return &p->base;
+ }
+
+ return NULL;
+}
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_crtc.h b/drivers/gpu/drm/xilinx/xilinx_drm_crtc.h
index 3566e0eba0360f..29cd638a606fb5 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_crtc.h
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_crtc.h
@@ -29,6 +29,9 @@ void xilinx_drm_crtc_cancel_page_flip(struct drm_crtc *base_crtc,
void xilinx_drm_crtc_restore(struct drm_crtc *base_crtc);
unsigned int xilinx_drm_crtc_get_max_width(struct drm_crtc *base_crtc);
+unsigned int xilinx_drm_crtc_get_max_height(struct drm_crtc *base_crtc);
+unsigned int xilinx_drm_crtc_get_max_cursor_width(struct drm_crtc *base_crtc);
+unsigned int xilinx_drm_crtc_get_max_cursor_height(struct drm_crtc *base_crtc);
bool xilinx_drm_crtc_check_format(struct drm_crtc *base_crtc, uint32_t fourcc);
uint32_t xilinx_drm_crtc_get_format(struct drm_crtc *base_crtc);
unsigned int xilinx_drm_crtc_get_align(struct drm_crtc *base_crtc);
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_drv.c b/drivers/gpu/drm/xilinx/xilinx_drm_drv.c
index 7a99f132dba131..e0d96b7ad1356e 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_drv.c
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_drv.c
@@ -197,7 +197,21 @@ static void xilinx_drm_mode_config_init(struct drm_device *drm)
drm->mode_config.max_width =
xilinx_drm_crtc_get_max_width(private->crtc);
- drm->mode_config.max_height = 4096;
+
+ drm->mode_config.max_height =
+ xilinx_drm_crtc_get_max_height(private->crtc);
+
+ if (drm->mode_config.max_height <= 0)
+ drm->mode_config.max_height = 4096;
+
+ if (drm->mode_config.max_width <= 0)
+ drm->mode_config.max_width = 4096;
+
+ drm->mode_config.cursor_width =
+ xilinx_drm_crtc_get_max_cursor_width(private->crtc);
+
+ drm->mode_config.cursor_height =
+ xilinx_drm_crtc_get_max_cursor_height(private->crtc);
drm->mode_config.funcs = &xilinx_drm_mode_config_funcs;
}
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c b/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c
index 51126ddef13ffa..989a8241a7c510 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_encoder.c
@@ -186,7 +186,7 @@ struct drm_encoder *xilinx_drm_encoder_create(struct drm_device *drm,
i2c_driver = to_i2c_driver(i2c_slv->dev.driver);
drm_i2c_driver = to_drm_i2c_encoder_driver(i2c_driver);
if (!drm_i2c_driver) {
- DRM_ERROR("failed to initialize i2c slave\n");
+ DRM_ERROR("failed to init i2c slave, deferring\n");
ret = -EPROBE_DEFER;
goto err_out;
}
@@ -197,13 +197,13 @@ struct drm_encoder *xilinx_drm_encoder_create(struct drm_device *drm,
} else {
platform_slv = of_find_device_by_node(node);
if (!platform_slv) {
- DRM_DEBUG_KMS("failed to get an encoder slv\n");
+ DRM_DEBUG_KMS("No encoder slv device, deferring\n");
return ERR_PTR(-EPROBE_DEFER);
}
device_driver = platform_slv->dev.driver;
if (!device_driver) {
- DRM_DEBUG_KMS("failed to get device driver\n");
+ DRM_DEBUG_KMS("No encoder slv driver, deferring\n");
return ERR_PTR(-EPROBE_DEFER);
}
@@ -211,7 +211,7 @@ struct drm_encoder *xilinx_drm_encoder_create(struct drm_device *drm,
drm_platform_driver =
to_drm_platform_encoder_driver(platform_driver);
if (!drm_platform_driver) {
- DRM_ERROR("failed to initialize platform slave\n");
+ DRM_ERROR("failed to init platform slave, deferring\n");
ret = -EPROBE_DEFER;
goto err_out;
}
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_plane.c b/drivers/gpu/drm/xilinx/xilinx_drm_plane.c
index 2646763b172c10..715c46cd64813d 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_plane.c
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_plane.c
@@ -1,9 +1,10 @@
/*
* Xilinx DRM plane driver for Xilinx
*
- * Copyright (C) 2013 Xilinx, Inc.
+ * Copyright (C) 2013,2016,2017 Xilinx, Inc.
*
* Author: Hyun Woo Kwon <hyunk@xilinx.com>
+ * Jeffrey Mouroux <jmouroux@xilinx.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -15,114 +16,28 @@
* GNU General Public License for more details.
*/
-#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drmP.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
+/* drm component libs */
#include "xilinx_drm_dp_sub.h"
#include "xilinx_drm_drv.h"
#include "xilinx_drm_fb.h"
#include "xilinx_drm_plane.h"
+/* hardware layer libs */
+#include "crtc/mixer/drm/xilinx_drm_mixer.h"
#include "xilinx_cresample.h"
#include "xilinx_osd.h"
#include "xilinx_rgb2yuv.h"
-#define MAX_NUM_SUB_PLANES 4
-
-/**
- * struct xilinx_drm_plane_dma - Xilinx drm plane VDMA object
- *
- * @chan: dma channel
- * @xt: dma interleaved configuration template
- * @sgl: data chunk for dma_interleaved_template
- * @is_active: flag if the DMA is active
- */
-struct xilinx_drm_plane_dma {
- struct dma_chan *chan;
- struct dma_interleaved_template xt;
- struct data_chunk sgl[1];
- bool is_active;
-};
-
-/**
- * struct xilinx_drm_plane - Xilinx drm plane object
- *
- * @base: base drm plane object
- * @id: plane id
- * @dpms: current dpms level
- * @zpos: user requested z-position value
- * @prio: actual layer priority
- * @alpha: alpha value
- * @alpha_enable: alpha enable value
- * @primary: flag for primary plane
- * @format: pixel format
- * @dma: dma object
- * @rgb2yuv: rgb2yuv instance
- * @cresample: cresample instance
- * @osd_layer: osd layer
- * @dp_layer: DisplayPort subsystem layer
- * @manager: plane manager
- */
-struct xilinx_drm_plane {
- struct drm_plane base;
- int id;
- int dpms;
- unsigned int zpos;
- unsigned int prio;
- unsigned int alpha;
- unsigned int alpha_enable;
- bool primary;
- uint32_t format;
- struct xilinx_drm_plane_dma dma[MAX_NUM_SUB_PLANES];
- struct xilinx_rgb2yuv *rgb2yuv;
- struct xilinx_cresample *cresample;
- struct xilinx_osd_layer *osd_layer;
- struct xilinx_drm_dp_sub_layer *dp_layer;
- struct xilinx_drm_plane_manager *manager;
-};
-
-#define MAX_PLANES 8
-
-/**
- * struct xilinx_drm_plane_manager - Xilinx drm plane manager object
- *
- * @drm: drm device
- * @node: plane device node
- * @osd: osd instance
- * @dp_sub: DisplayPort subsystem instance
- * @num_planes: number of available planes
- * @format: video format
- * @max_width: maximum width
- * @zpos_prop: z-position(priority) property
- * @alpha_prop: alpha value property
- * @alpha_enable_prop: alpha enable property
- * @default_alpha: default alpha value
- * @planes: xilinx drm planes
- */
-struct xilinx_drm_plane_manager {
- struct drm_device *drm;
- struct device_node *node;
- struct xilinx_osd *osd;
- struct xilinx_drm_dp_sub *dp_sub;
- int num_planes;
- uint32_t format;
- int max_width;
- struct drm_property *zpos_prop;
- struct drm_property *alpha_prop;
- struct drm_property *alpha_enable_prop;
- unsigned int default_alpha;
- struct xilinx_drm_plane *planes[MAX_PLANES];
-};
-
-#define to_xilinx_plane(x) container_of(x, struct xilinx_drm_plane, base)
-
/* set plane dpms */
void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
{
@@ -175,6 +90,8 @@ void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
xilinx_osd_enable_rue(manager->osd);
}
+ if (manager->mixer)
+ xilinx_drm_mixer_plane_dpms(plane, dpms);
break;
default:
@@ -188,6 +105,8 @@ void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
xilinx_osd_enable_rue(manager->osd);
}
+ if (manager->mixer)
+ xilinx_drm_mixer_plane_dpms(plane, dpms);
if (plane->cresample) {
xilinx_cresample_disable(plane->cresample);
@@ -255,8 +174,9 @@ int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
{
struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
struct drm_gem_cma_object *obj;
- size_t offset;
+ size_t offset = 0;
unsigned int hsub, vsub, i;
+ int ret;
DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
@@ -269,7 +189,7 @@ int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h);
DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n",
- src_w, crtc_x, src_h, crtc_y);
+ src_w, crtc_x, src_h, crtc_y);
DRM_DEBUG_KMS("bpp: %d\n", fb->bits_per_pixel / 8);
hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
@@ -316,9 +236,14 @@ int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
xilinx_osd_enable_rue(plane->manager->osd);
}
- if (plane->manager->dp_sub) {
- int ret;
+ if (plane->manager->mixer) {
+ ret = xilinx_drm_mixer_set_plane(plane, fb, crtc_x, crtc_y,
+ src_x, src_y, src_w, src_h);
+ if (ret)
+ return ret;
+ }
+ if (plane->manager->dp_sub) {
ret = xilinx_drm_dp_sub_layer_check_size(plane->manager->dp_sub,
plane->dp_layer,
src_w, src_h);
@@ -357,11 +282,12 @@ static int xilinx_drm_plane_update(struct drm_plane *base_plane,
return ret;
}
- /* make sure a plane is on */
- xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_ON);
/* apply the new fb addr */
xilinx_drm_plane_commit(base_plane);
+ /* make sure a plane is on */
+ xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_ON);
+
return 0;
}
@@ -394,6 +320,9 @@ static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
xilinx_osd_layer_put(plane->osd_layer);
}
+ if (plane->manager->mixer)
+ xilinx_drm_mixer_layer_disable(plane);
+
if (plane->manager->dp_sub) {
xilinx_drm_dp_sub_layer_disable(plane->manager->dp_sub,
plane->dp_layer);
@@ -516,14 +445,25 @@ static int xilinx_drm_plane_set_property(struct drm_plane *base_plane,
struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
struct xilinx_drm_plane_manager *manager = plane->manager;
- if (property == manager->zpos_prop)
+ if (property == manager->zpos_prop) {
xilinx_drm_plane_set_zpos(base_plane, val);
- else if (property == manager->alpha_prop)
+
+ } else if (property == manager->alpha_prop) {
xilinx_drm_plane_set_alpha(base_plane, val);
- else if (property == manager->alpha_enable_prop)
+
+ } else if (property == manager->alpha_enable_prop) {
xilinx_drm_plane_enable_alpha(base_plane, val);
- else
+
+ } else if (manager->mixer) {
+ int ret;
+
+ ret = xilinx_drm_mixer_set_plane_property(plane,
+ property, val);
+ if (ret)
+ return ret;
+ } else {
return -EINVAL;
+ }
drm_object_property_set_value(&base_plane->base, property, val);
@@ -545,6 +485,30 @@ int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane)
return plane->manager->max_width;
}
+/* get a plane max height */
+int xilinx_drm_plane_get_max_height(struct drm_plane *base_plane)
+{
+ struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
+
+ return plane->manager->max_height;
+}
+
+/* get a plane max width */
+int xilinx_drm_plane_get_max_cursor_width(struct drm_plane *base_plane)
+{
+ struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
+
+ return plane->manager->max_cursor_width;
+}
+
+/* get a plane max height */
+int xilinx_drm_plane_get_max_cursor_height(struct drm_plane *base_plane)
+{
+ struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
+
+ return plane->manager->max_cursor_height;
+}
+
/* check if format is supported */
bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager,
uint32_t format)
@@ -579,6 +543,8 @@ void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager)
struct xilinx_drm_plane *plane;
unsigned int i;
+ if (!manager)
+ return;
/*
* Reinitialize property default values as they get reset by DPMS OFF
* operation. User will read the correct default values later, and
@@ -587,19 +553,28 @@ void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager)
for (i = 0; i < manager->num_planes; i++) {
plane = manager->planes[i];
+ if (!plane)
+ continue;
+
+ if (manager->mixer)
+ xilinx_drm_mixer_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+
plane->prio = plane->zpos = plane->id;
+
if (manager->zpos_prop)
drm_object_property_set_value(&plane->base.base,
manager->zpos_prop,
plane->prio);
plane->alpha = manager->default_alpha;
+
if (manager->alpha_prop)
drm_object_property_set_value(&plane->base.base,
manager->alpha_prop,
plane->alpha);
plane->alpha_enable = true;
+
if (manager->alpha_enable_prop)
drm_object_property_set_value(&plane->base.base,
manager->alpha_enable_prop, true);
@@ -625,6 +600,14 @@ unsigned int xilinx_drm_plane_get_align(struct drm_plane *base_plane)
{
struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
+ if (!plane->dma[0].chan) {
+ if (plane->manager->mixer) {
+ struct xilinx_drm_mixer *m = plane->manager->mixer;
+
+ return 1 << get_xilinx_mixer_mem_align(m);
+ }
+ }
+
return 1 << plane->dma[0].chan->device->copy_align;
}
@@ -664,10 +647,13 @@ static void xilinx_drm_plane_attach_property(struct drm_plane *base_plane)
manager->alpha_prop,
manager->default_alpha);
drm_object_attach_property(&base_plane->base,
- manager->alpha_enable_prop, false);
+ manager->alpha_enable_prop, false);
+
+ plane->alpha_enable = true;
}
- plane->alpha_enable = true;
+ if (manager->mixer)
+ xilinx_drm_mixer_attach_plane_prop(plane);
}
/**
@@ -695,11 +681,18 @@ void xilinx_drm_plane_manager_dpms(struct xilinx_drm_plane_manager *manager,
xilinx_osd_enable_rue(manager->osd);
}
+ if (manager->mixer)
+ xilinx_drm_mixer_dpms(manager->mixer, dpms);
+
break;
+
default:
if (manager->osd)
xilinx_osd_reset(manager->osd);
+ if (manager->mixer)
+ xilinx_drm_mixer_dpms(manager->mixer, dpms);
+
if (manager->dp_sub)
xilinx_drm_dp_sub_disable(manager->dp_sub);
@@ -733,6 +726,7 @@ xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
char name[16];
struct device_node *plane_node;
struct device_node *sub_node;
+ struct device_node *layer_node;
enum drm_plane_type type;
uint32_t fmt_in = -1;
uint32_t fmt_out = -1;
@@ -771,6 +765,9 @@ xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
plane->alpha = manager->default_alpha;
plane->dpms = DRM_MODE_DPMS_OFF;
plane->format = -1;
+
+ type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+
DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
@@ -864,6 +861,25 @@ xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
plane->format = manager->format;
}
+ if (manager->mixer) {
+ type = DRM_PLANE_TYPE_OVERLAY;
+
+ layer_node =
+ of_parse_phandle(plane_node, "xlnx,mixer-layer", 0);
+
+ ret = xilinx_drm_create_mixer_layer_plane(manager, plane,
+ layer_node);
+
+ if (ret)
+ goto err_init;
+
+ if (plane->mixer_layer == manager->mixer->hw_logo_layer)
+ type = DRM_PLANE_TYPE_CURSOR;
+
+ if (plane->mixer_layer == manager->mixer->drm_primary_layer)
+ type = DRM_PLANE_TYPE_PRIMARY;
+ }
+
if (manager->dp_sub) {
plane->dp_layer = xilinx_drm_dp_sub_layer_get(manager->dp_sub,
primary);
@@ -897,7 +913,6 @@ xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
plane->format = manager->format;
/* initialize drm plane */
- type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(manager->drm, &plane->base,
possible_crtcs, &xilinx_drm_plane_funcs,
fmts ? fmts : &plane->format,
@@ -926,6 +941,10 @@ err_init:
xilinx_osd_layer_disable(plane->osd_layer);
xilinx_osd_layer_put(plane->osd_layer);
}
+
+ if (manager->mixer)
+ xilinx_drm_mixer_layer_disable(plane);
+
err_dma:
for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
if (plane->dma[i].chan)
@@ -979,11 +998,40 @@ int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager,
static int
xilinx_drm_plane_init_manager(struct xilinx_drm_plane_manager *manager)
{
- unsigned int format;
+ uint32_t format;
uint32_t drm_format;
int ret = 0;
- if (manager->osd) {
+ if (manager->mixer) {
+ struct xilinx_drm_mixer *mixer = manager->mixer;
+
+ manager->num_planes = get_num_mixer_planes(mixer);
+ manager->max_width = get_mixer_max_width(mixer);
+ manager->max_height = get_mixer_max_height(mixer);
+
+ format = get_mixer_vid_out_fmt(mixer);
+
+ ret = xilinx_drm_mixer_fmt_to_drm_fmt(format, &drm_format);
+
+ /* JPM TODO We comply with manager device tree format but
+ * we'll want to just clobber that device tree setting with the
+ * mixer setting if a mixer is the central crtc object,
+ * eventually
+ */
+ if (ret || (drm_format != manager->format)) {
+ dev_err(manager->drm->dev,
+ "Plane mgr vid format != mixer vid format\n");
+ return -EINVAL;
+ }
+
+ if (mixer->hw_logo_layer) {
+ manager->max_cursor_width =
+ get_mixer_max_logo_width(mixer);
+ manager->max_cursor_height =
+ get_mixer_max_logo_height(mixer);
+ }
+
+ } else if (manager->osd) {
manager->num_planes = xilinx_osd_get_num_layers(manager->osd);
manager->max_width = xilinx_osd_get_max_width(manager->osd);
@@ -1039,6 +1087,17 @@ xilinx_drm_plane_probe_manager(struct drm_device *drm)
manager->drm = drm;
+ /* Mixer addition */
+ sub_node = of_parse_phandle(dev->of_node, "xlnx,mixer", 0);
+ if (sub_node) {
+ manager->mixer = xilinx_drm_mixer_probe(dev, sub_node, manager);
+ of_node_put(sub_node);
+ if (IS_ERR(manager->mixer)) {
+ of_node_put(manager->node);
+ return ERR_CAST(manager->mixer);
+ }
+ }
+
/* probe an OSD. proceed even if there's no OSD */
sub_node = of_parse_phandle(dev->of_node, "xlnx,osd", 0);
if (sub_node) {
diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_plane.h b/drivers/gpu/drm/xilinx/xilinx_drm_plane.h
index c55868c62865b2..b33e09999db4dd 100644
--- a/drivers/gpu/drm/xilinx/xilinx_drm_plane.h
+++ b/drivers/gpu/drm/xilinx/xilinx_drm_plane.h
@@ -17,13 +17,122 @@
#ifndef _XILINX_DRM_PLANE_H_
#define _XILINX_DRM_PLANE_H_
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <linux/of_dma.h>
struct drm_crtc;
struct drm_plane;
+#define MAX_NUM_SUB_PLANES 4
+
+/**
+ * struct xilinx_drm_plane_dma - Xilinx drm plane VDMA object
+ *
+ * @chan: dma channel
+ * @xt: dma interleaved configuration template
+ * @sgl: data chunk for dma_interleaved_template
+ * @is_active: flag if the DMA is active
+ */
+struct xilinx_drm_plane_dma {
+ struct dma_chan *chan;
+ struct dma_interleaved_template xt;
+ struct data_chunk sgl[1];
+ bool is_active;
+};
+
+/**
+ * struct xilinx_drm_plane - Xilinx drm plane object
+ *
+ * @base: base drm plane object
+ * @id: plane id
+ * @dpms: current dpms level
+ * @zpos: user requested z-position value
+ * @prio: actual layer priority
+ * @alpha: alpha value
+ * @alpha_enable: alpha enable value
+ * @primary: flag for primary plane
+ * @format: pixel format
+ * @dma: dma object
+ * @rgb2yuv: rgb2yuv instance
+ * @cresample: cresample instance
+ * @osd_layer: osd layer
+ * @mixer_layer: video mixer hardware layer data instance
+ * @dp_layer: DisplayPort subsystem layer
+ * @manager: plane manager
+ */
+struct xilinx_drm_plane {
+ struct drm_plane base;
+ int id;
+ int dpms;
+ unsigned int zpos;
+ unsigned int prio;
+ unsigned int alpha;
+ unsigned int alpha_enable;
+ bool primary;
+ uint32_t format;
+ struct xilinx_drm_plane_dma dma[MAX_NUM_SUB_PLANES];
+ struct xilinx_rgb2yuv *rgb2yuv;
+ struct xilinx_cresample *cresample;
+ struct xilinx_osd_layer *osd_layer;
+ struct xv_mixer_layer_data *mixer_layer;
+ struct xilinx_drm_dp_sub_layer *dp_layer;
+ struct xilinx_drm_plane_manager *manager;
+};
+
+#ifdef __XLNX_DRM_MIXER__
+#define MAX_PLANES XVMIX_MAX_SUPPORTED_LAYERS
+#else
+#define MAX_PLANES 8
+#endif
+
+/**
+ * struct xilinx_drm_plane_manager - Xilinx drm plane manager object
+ *
+ * @drm: drm device
+ * @node: plane device node
+ * @osd: osd instance
+ * @mixer: mixer IP instance
+ * @dp_sub: DisplayPort subsystem instance
+ * @num_planes: number of available planes
+ * @format: video format
+ * @max_width: maximum crtc primary layer width
+ * @max_height: maximum crtc primary layer height
+ * @max_cursor_width: maximum pixel size for cursor layer width
+ * @max_cursor_height: maximum pixel size for cursor layer height
+ * @zpos_prop: z-position(priority) property
+ * @alpha_prop: alpha value property
+ * @default_alpha: default alpha value
+ * @planes: xilinx drm planes
+ */
+struct xilinx_drm_plane_manager {
+ struct drm_device *drm;
+ struct device_node *node;
+ struct xilinx_osd *osd;
+ struct xilinx_drm_mixer *mixer;
+ struct xilinx_drm_dp_sub *dp_sub;
+ int num_planes;
+ int max_planes;
+ uint32_t format;
+ int max_width;
+ int max_height;
+ int max_cursor_width;
+ int max_cursor_height;
+ struct drm_property *zpos_prop;
+ struct drm_property *alpha_prop;
+ struct drm_property *scale_prop;
+ struct drm_property *alpha_enable_prop;
+ unsigned int default_alpha;
+ struct xilinx_drm_plane *planes[MAX_PLANES];
+};
+
+#define to_xilinx_plane(x) container_of(x, struct xilinx_drm_plane, base)
+
/* plane operations */
void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms);
+
void xilinx_drm_plane_commit(struct drm_plane *base_plane);
+
int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
@@ -31,7 +140,15 @@ int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane);
+
+int xilinx_drm_plane_get_max_height(struct drm_plane *base_plane);
+
+int xilinx_drm_plane_get_max_cursor_width(struct drm_plane *base_plane);
+
+int xilinx_drm_plane_get_max_cursor_height(struct drm_plane *base_plane);
+
uint32_t xilinx_drm_plane_get_format(struct drm_plane *base_plane);
+
unsigned int xilinx_drm_plane_get_align(struct drm_plane *base_plane);
/* plane manager operations */
@@ -56,6 +173,7 @@ void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager);
struct xilinx_drm_plane_manager *
xilinx_drm_plane_probe_manager(struct drm_device *drm);
+
void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager);
#endif /* _XILINX_DRM_PLANE_H_ */