forked from Minki/linux
4fdbc678fe
High Quality Video Data Plane is hardware IP dedicated to video rendering. Compare to GPD (graphic planes) it have better scaler capabilities. HQVDP use VID layer to push data into hardware compositor without going into DDR. From data flow point of view HQVDP and VID are nested so HQVPD update/disable VID. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
212 lines
4.3 KiB
C
212 lines
4.3 KiB
C
/*
|
|
* Copyright (C) STMicroelectronics SA 2014
|
|
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
|
|
* Fabien Dessenne <fabien.dessenne@st.com>
|
|
* for STMicroelectronics.
|
|
* License terms: GNU General Public License (GPL), version 2
|
|
*/
|
|
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm_gem_cma_helper.h>
|
|
#include <drm/drm_fb_cma_helper.h>
|
|
|
|
#include "sti_compositor.h"
|
|
#include "sti_cursor.h"
|
|
#include "sti_gdp.h"
|
|
#include "sti_hqvdp.h"
|
|
#include "sti_layer.h"
|
|
#include "sti_vid.h"
|
|
|
|
const char *sti_layer_to_str(struct sti_layer *layer)
|
|
{
|
|
switch (layer->desc) {
|
|
case STI_GDP_0:
|
|
return "GDP0";
|
|
case STI_GDP_1:
|
|
return "GDP1";
|
|
case STI_GDP_2:
|
|
return "GDP2";
|
|
case STI_GDP_3:
|
|
return "GDP3";
|
|
case STI_VID_0:
|
|
return "VID0";
|
|
case STI_VID_1:
|
|
return "VID1";
|
|
case STI_CURSOR:
|
|
return "CURSOR";
|
|
case STI_HQVDP_0:
|
|
return "HQVDP0";
|
|
default:
|
|
return "<UNKNOWN LAYER>";
|
|
}
|
|
}
|
|
|
|
struct sti_layer *sti_layer_create(struct device *dev, int desc,
|
|
void __iomem *baseaddr)
|
|
{
|
|
|
|
struct sti_layer *layer = NULL;
|
|
|
|
switch (desc & STI_LAYER_TYPE_MASK) {
|
|
case STI_GDP:
|
|
layer = sti_gdp_create(dev, desc);
|
|
break;
|
|
case STI_VID:
|
|
layer = sti_vid_create(dev);
|
|
break;
|
|
case STI_CUR:
|
|
layer = sti_cursor_create(dev);
|
|
break;
|
|
case STI_VDP:
|
|
layer = sti_hqvdp_create(dev);
|
|
break;
|
|
}
|
|
|
|
if (!layer) {
|
|
DRM_ERROR("Failed to create layer\n");
|
|
return NULL;
|
|
}
|
|
|
|
layer->desc = desc;
|
|
layer->dev = dev;
|
|
layer->regs = baseaddr;
|
|
|
|
layer->ops->init(layer);
|
|
|
|
DRM_DEBUG_DRIVER("%s created\n", sti_layer_to_str(layer));
|
|
|
|
return layer;
|
|
}
|
|
|
|
int sti_layer_prepare(struct sti_layer *layer,
|
|
struct drm_crtc *crtc,
|
|
struct drm_framebuffer *fb,
|
|
struct drm_display_mode *mode, int mixer_id,
|
|
int dest_x, int dest_y, int dest_w, int dest_h,
|
|
int src_x, int src_y, int src_w, int src_h)
|
|
{
|
|
int ret;
|
|
unsigned int i;
|
|
struct drm_gem_cma_object *cma_obj;
|
|
|
|
if (!layer || !fb || !mode) {
|
|
DRM_ERROR("Null fb, layer or mode\n");
|
|
return 1;
|
|
}
|
|
|
|
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
|
if (!cma_obj) {
|
|
DRM_ERROR("Can't get CMA GEM object for fb\n");
|
|
return 1;
|
|
}
|
|
|
|
layer->crtc = crtc;
|
|
layer->fb = fb;
|
|
layer->mode = mode;
|
|
layer->mixer_id = mixer_id;
|
|
layer->dst_x = dest_x;
|
|
layer->dst_y = dest_y;
|
|
layer->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x);
|
|
layer->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y);
|
|
layer->src_x = src_x;
|
|
layer->src_y = src_y;
|
|
layer->src_w = src_w;
|
|
layer->src_h = src_h;
|
|
layer->format = fb->pixel_format;
|
|
layer->vaddr = cma_obj->vaddr;
|
|
layer->paddr = cma_obj->paddr;
|
|
for (i = 0; i < 4; i++) {
|
|
layer->pitches[i] = fb->pitches[i];
|
|
layer->offsets[i] = fb->offsets[i];
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n",
|
|
sti_layer_to_str(layer),
|
|
layer->mixer_id);
|
|
DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
|
|
sti_layer_to_str(layer),
|
|
layer->dst_w, layer->dst_h, layer->dst_x, layer->dst_y,
|
|
layer->src_w, layer->src_h, layer->src_x,
|
|
layer->src_y);
|
|
|
|
DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
|
|
(char *)&layer->format, (unsigned long)layer->paddr);
|
|
|
|
if (!layer->ops->prepare)
|
|
goto err_no_prepare;
|
|
|
|
ret = layer->ops->prepare(layer, !layer->enabled);
|
|
if (!ret)
|
|
layer->enabled = true;
|
|
|
|
return ret;
|
|
|
|
err_no_prepare:
|
|
DRM_ERROR("Cannot prepare\n");
|
|
return 1;
|
|
}
|
|
|
|
int sti_layer_commit(struct sti_layer *layer)
|
|
{
|
|
if (!layer)
|
|
return 1;
|
|
|
|
if (!layer->ops->commit)
|
|
goto err_no_commit;
|
|
|
|
return layer->ops->commit(layer);
|
|
|
|
err_no_commit:
|
|
DRM_ERROR("Cannot commit\n");
|
|
return 1;
|
|
}
|
|
|
|
int sti_layer_disable(struct sti_layer *layer)
|
|
{
|
|
int ret;
|
|
|
|
DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
|
|
if (!layer)
|
|
return 1;
|
|
|
|
if (!layer->enabled)
|
|
return 0;
|
|
|
|
if (!layer->ops->disable)
|
|
goto err_no_disable;
|
|
|
|
ret = layer->ops->disable(layer);
|
|
if (!ret)
|
|
layer->enabled = false;
|
|
else
|
|
DRM_ERROR("Disable failed\n");
|
|
|
|
return ret;
|
|
|
|
err_no_disable:
|
|
DRM_ERROR("Cannot disable\n");
|
|
return 1;
|
|
}
|
|
|
|
const uint32_t *sti_layer_get_formats(struct sti_layer *layer)
|
|
{
|
|
if (!layer)
|
|
return NULL;
|
|
|
|
if (!layer->ops->get_formats)
|
|
return NULL;
|
|
|
|
return layer->ops->get_formats(layer);
|
|
}
|
|
|
|
unsigned int sti_layer_get_nb_formats(struct sti_layer *layer)
|
|
{
|
|
if (!layer)
|
|
return 0;
|
|
|
|
if (!layer->ops->get_nb_formats)
|
|
return 0;
|
|
|
|
return layer->ops->get_nb_formats(layer);
|
|
}
|