| /* |
| * 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>"; |
| } |
| } |
| EXPORT_SYMBOL(sti_layer_to_str); |
| |
| 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; |
| } |
| EXPORT_SYMBOL(sti_layer_create); |
| |
| 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); |
| } |