diff options
author | Jeffrey Mouroux <jmouroux@xilinx.com> | 2017-05-08 17:03:25 -0700 |
---|---|---|
committer | Jeffrey Mouroux <jmouroux@xilinx.com> | 2017-06-28 12:54:02 -0700 |
commit | d359779442ffc9727fbb0108d40f8158e8f6a55b (patch) | |
tree | f47fe65cc3d30bc5b0fede4b6cc2f5b85d80d25f | |
parent | 78e25c06fdf8d0897a22d1cf15c6fd4b545eb57c (diff) | |
download | linux-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/Makefile | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.c | 1083 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/crtc/mixer/drm/xilinx_drm_mixer.h | 363 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_data.h | 476 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_hw.c | 897 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/crtc/mixer/hw/xilinx_mixer_regs.h | 639 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_connector.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_crtc.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_crtc.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_drv.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_encoder.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_plane.c | 271 | ||||
-rw-r--r-- | drivers/gpu/drm/xilinx/xilinx_drm_plane.h | 118 |
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_ */ |