From 8d91c1e411f55d7ea91b1183a2e9f8088fb4d5be Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 15 Dec 2015 14:52:16 -0300 Subject: Linux-libre 4.3.2-gnu --- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | 262 ++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c (limited to 'drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c') diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c new file mode 100644 index 000000000..d1e300dcd --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c @@ -0,0 +1,262 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * Freescale DCU drm device driver + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_dcu_drm_drv.h" +#include "fsl_dcu_drm_plane.h" + +static int fsl_dcu_drm_plane_index(struct drm_plane *plane) +{ + struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; + unsigned int total_layer = fsl_dev->soc->total_layer; + unsigned int index; + + index = drm_plane_index(plane); + if (index < total_layer) + return total_layer - index - 1; + + dev_err(fsl_dev->dev, "No more layer left\n"); + return -EINVAL; +} + +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_framebuffer *fb = state->fb; + + switch (fb->pixel_format) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_YUV422: + return 0; + default: + return -EINVAL; + } +} + +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; + unsigned int value; + int index, ret; + + index = fsl_dcu_drm_plane_index(plane); + if (index < 0) + return; + + ret = regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value); + if (ret) + dev_err(fsl_dev->dev, "read DCU_INT_MASK failed\n"); + value &= ~DCU_LAYER_EN; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value); + if (ret) + dev_err(fsl_dev->dev, "set DCU register failed\n"); +} + +static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) + +{ + struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = plane->state->fb; + struct drm_gem_cma_object *gem; + unsigned int alpha, bpp; + int index, ret; + + if (!fb) + return; + + index = fsl_dcu_drm_plane_index(plane); + if (index < 0) + return; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + + switch (fb->pixel_format) { + case DRM_FORMAT_RGB565: + bpp = FSL_DCU_RGB565; + alpha = 0xff; + break; + case DRM_FORMAT_RGB888: + bpp = FSL_DCU_RGB888; + alpha = 0xff; + break; + case DRM_FORMAT_ARGB8888: + bpp = FSL_DCU_ARGB8888; + alpha = 0xff; + break; + case DRM_FORMAT_BGRA4444: + bpp = FSL_DCU_ARGB4444; + alpha = 0xff; + break; + case DRM_FORMAT_ARGB1555: + bpp = FSL_DCU_ARGB1555; + alpha = 0xff; + break; + case DRM_FORMAT_YUV422: + bpp = FSL_DCU_YUV422; + alpha = 0xff; + break; + default: + return; + } + + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1), + DCU_LAYER_HEIGHT(state->crtc_h) | + DCU_LAYER_WIDTH(state->crtc_w)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2), + DCU_LAYER_POSY(state->crtc_y) | + DCU_LAYER_POSX(state->crtc_x)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, + DCU_CTRLDESCLN(index, 3), gem->paddr); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), + DCU_LAYER_EN | + DCU_LAYER_TRANS(alpha) | + DCU_LAYER_BPP(bpp) | + DCU_LAYER_AB(0)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5), + DCU_LAYER_CKMAX_R(0xFF) | + DCU_LAYER_CKMAX_G(0xFF) | + DCU_LAYER_CKMAX_B(0xFF)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6), + DCU_LAYER_CKMIN_R(0) | + DCU_LAYER_CKMIN_G(0) | + DCU_LAYER_CKMIN_B(0)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8), + DCU_LAYER_FG_FCOLOR(0)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9), + DCU_LAYER_BG_BCOLOR(0)); + if (ret) + goto set_failed; + if (!strcmp(fsl_dev->soc->name, "ls1021a")) { + ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10), + DCU_LAYER_POST_SKIP(0) | + DCU_LAYER_PRE_SKIP(0)); + if (ret) + goto set_failed; + } + ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_DCU_MODE_MASK, + DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); + if (ret) + goto set_failed; + ret = regmap_write(fsl_dev->regmap, + DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); + if (ret) + goto set_failed; + return; + +set_failed: + dev_err(fsl_dev->dev, "set DCU register failed\n"); +} + +static void +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) +{ +} + +static int +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) +{ + return 0; +} + +static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = { + .atomic_check = fsl_dcu_drm_plane_atomic_check, + .atomic_disable = fsl_dcu_drm_plane_atomic_disable, + .atomic_update = fsl_dcu_drm_plane_atomic_update, + .cleanup_fb = fsl_dcu_drm_plane_cleanup_fb, + .prepare_fb = fsl_dcu_drm_plane_prepare_fb, +}; + +static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane) +{ + drm_plane_cleanup(plane); +} + +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = { + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .destroy = fsl_dcu_drm_plane_destroy, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = drm_atomic_helper_plane_reset, + .update_plane = drm_atomic_helper_update_plane, +}; + +static const u32 fsl_dcu_drm_plane_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_YUV422, +}; + +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev) +{ + struct drm_plane *primary; + int ret; + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (!primary) { + DRM_DEBUG_KMS("Failed to allocate primary plane\n"); + return NULL; + } + + /* possible_crtc's will be filled in later by crtc_init */ + ret = drm_universal_plane_init(dev, primary, 0, + &fsl_dcu_drm_plane_funcs, + fsl_dcu_drm_plane_formats, + ARRAY_SIZE(fsl_dcu_drm_plane_formats), + DRM_PLANE_TYPE_PRIMARY); + if (ret) { + kfree(primary); + primary = NULL; + } + drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs); + + return primary; +} -- cgit v1.2.3-54-g00ecf