diff options
author | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 12:17:53 -0700 |
---|---|---|
committer | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 15:44:42 -0700 |
commit | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch) | |
tree | 1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/drivers/gpu/drm/rcar-du/rcar_du_plane.c | |
parent | 98260f3884f4a202f9ca5eabed40b1354c489b29 (diff) |
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base.
It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and
the base is:
commit 0917f823c59692d751951bf5ea699a2d1e2f26a2
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Sat Jul 25 12:13:34 2015 +0200
Prepare v4.1.3-rt3
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
We lose all the git history this way and it's not good. We
should apply another opnfv project repo in future.
Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/drivers/gpu/drm/rcar-du/rcar_du_plane.c')
-rw-r--r-- | kernel/drivers/gpu/drm/rcar-du/rcar_du_plane.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/kernel/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/kernel/drivers/gpu/drm/rcar-du/rcar_du_plane.c new file mode 100644 index 000000000..210e5c3fd --- /dev/null +++ b/kernel/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -0,0 +1,460 @@ +/* + * rcar_du_plane.c -- R-Car Display Unit Planes + * + * Copyright (C) 2013-2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * 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/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_plane_helper.h> + +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_plane.h" +#include "rcar_du_regs.h" + +#define RCAR_DU_COLORKEY_NONE (0 << 24) +#define RCAR_DU_COLORKEY_SOURCE (1 << 24) +#define RCAR_DU_COLORKEY_MASK (1 << 24) + +static u32 rcar_du_plane_read(struct rcar_du_group *rgrp, + unsigned int index, u32 reg) +{ + return rcar_du_read(rgrp->dev, + rgrp->mmio_offset + index * PLANE_OFF + reg); +} + +static void rcar_du_plane_write(struct rcar_du_group *rgrp, + unsigned int index, u32 reg, u32 data) +{ + rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg, + data); +} + +static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane) +{ + struct rcar_du_plane_state *state = + to_rcar_du_plane_state(plane->plane.state); + struct drm_framebuffer *fb = plane->plane.state->fb; + struct rcar_du_group *rgrp = plane->group; + unsigned int src_x = state->state.src_x >> 16; + unsigned int src_y = state->state.src_y >> 16; + unsigned int index = state->hwindex; + struct drm_gem_cma_object *gem; + bool interlaced; + u32 mwr; + + interlaced = state->state.crtc->state->adjusted_mode.flags + & DRM_MODE_FLAG_INTERLACE; + + /* Memory pitch (expressed in pixels). Must be doubled for interlaced + * operation with 32bpp formats. + */ + if (state->format->planes == 2) + mwr = fb->pitches[0]; + else + mwr = fb->pitches[0] * 8 / state->format->bpp; + + if (interlaced && state->format->bpp == 32) + mwr *= 2; + + rcar_du_plane_write(rgrp, index, PnMWR, mwr); + + /* The Y position is expressed in raster line units and must be doubled + * for 32bpp formats, according to the R8A7790 datasheet. No mention of + * doubling the Y position is found in the R8A7779 datasheet, but the + * rule seems to apply there as well. + * + * Despite not being documented, doubling seem not to be needed when + * operating in interlaced mode. + * + * Similarly, for the second plane, NV12 and NV21 formats seem to + * require a halved Y position value, in both progressive and interlaced + * modes. + */ + rcar_du_plane_write(rgrp, index, PnSPXR, src_x); + rcar_du_plane_write(rgrp, index, PnSPYR, src_y * + (!interlaced && state->format->bpp == 32 ? 2 : 1)); + + gem = drm_fb_cma_get_gem_obj(fb, 0); + rcar_du_plane_write(rgrp, index, PnDSA0R, gem->paddr + fb->offsets[0]); + + if (state->format->planes == 2) { + index = (index + 1) % 8; + + rcar_du_plane_write(rgrp, index, PnMWR, fb->pitches[0]); + + rcar_du_plane_write(rgrp, index, PnSPXR, src_x); + rcar_du_plane_write(rgrp, index, PnSPYR, src_y * + (state->format->bpp == 16 ? 2 : 1) / 2); + + gem = drm_fb_cma_get_gem_obj(fb, 1); + rcar_du_plane_write(rgrp, index, PnDSA0R, + gem->paddr + fb->offsets[1]); + } +} + +static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane, + unsigned int index) +{ + struct rcar_du_plane_state *state = + to_rcar_du_plane_state(plane->plane.state); + struct rcar_du_group *rgrp = plane->group; + u32 colorkey; + u32 pnmr; + + /* The PnALPHAR register controls alpha-blending in 16bpp formats + * (ARGB1555 and XRGB1555). + * + * For ARGB, set the alpha value to 0, and enable alpha-blending when + * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255. + * + * For XRGB, set the alpha value to the plane-wide alpha value and + * enable alpha-blending regardless of the X bit value. + */ + if (state->format->fourcc != DRM_FORMAT_XRGB1555) + rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0); + else + rcar_du_plane_write(rgrp, index, PnALPHAR, + PnALPHAR_ABIT_X | state->alpha); + + pnmr = PnMR_BM_MD | state->format->pnmr; + + /* Disable color keying when requested. YUV formats have the + * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying + * automatically. + */ + if ((state->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE) + pnmr |= PnMR_SPIM_TP_OFF; + + /* For packed YUV formats we need to select the U/V order. */ + if (state->format->fourcc == DRM_FORMAT_YUYV) + pnmr |= PnMR_YCDF_YUYV; + + rcar_du_plane_write(rgrp, index, PnMR, pnmr); + + switch (state->format->fourcc) { + case DRM_FORMAT_RGB565: + colorkey = ((state->colorkey & 0xf80000) >> 8) + | ((state->colorkey & 0x00fc00) >> 5) + | ((state->colorkey & 0x0000f8) >> 3); + rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); + break; + + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + colorkey = ((state->colorkey & 0xf80000) >> 9) + | ((state->colorkey & 0x00f800) >> 6) + | ((state->colorkey & 0x0000f8) >> 3); + rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); + break; + + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + rcar_du_plane_write(rgrp, index, PnTC3R, + PnTC3R_CODE | (state->colorkey & 0xffffff)); + break; + } +} + +static void __rcar_du_plane_setup(struct rcar_du_plane *plane, + unsigned int index) +{ + struct rcar_du_plane_state *state = + to_rcar_du_plane_state(plane->plane.state); + struct rcar_du_group *rgrp = plane->group; + u32 ddcr2 = PnDDCR2_CODE; + u32 ddcr4; + + /* Data format + * + * The data format is selected by the DDDF field in PnMR and the EDF + * field in DDCR4. + */ + ddcr4 = rcar_du_plane_read(rgrp, index, PnDDCR4); + ddcr4 &= ~PnDDCR4_EDF_MASK; + ddcr4 |= state->format->edf | PnDDCR4_CODE; + + rcar_du_plane_setup_mode(plane, index); + + if (state->format->planes == 2) { + if (state->hwindex != index) { + if (state->format->fourcc == DRM_FORMAT_NV12 || + state->format->fourcc == DRM_FORMAT_NV21) + ddcr2 |= PnDDCR2_Y420; + + if (state->format->fourcc == DRM_FORMAT_NV21) + ddcr2 |= PnDDCR2_NV21; + + ddcr2 |= PnDDCR2_DIVU; + } else { + ddcr2 |= PnDDCR2_DIVY; + } + } + + rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); + rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); + + /* Destination position and size */ + rcar_du_plane_write(rgrp, index, PnDSXR, plane->plane.state->crtc_w); + rcar_du_plane_write(rgrp, index, PnDSYR, plane->plane.state->crtc_h); + rcar_du_plane_write(rgrp, index, PnDPXR, plane->plane.state->crtc_x); + rcar_du_plane_write(rgrp, index, PnDPYR, plane->plane.state->crtc_y); + + /* Wrap-around and blinking, disabled */ + rcar_du_plane_write(rgrp, index, PnWASPR, 0); + rcar_du_plane_write(rgrp, index, PnWAMWR, 4095); + rcar_du_plane_write(rgrp, index, PnBTR, 0); + rcar_du_plane_write(rgrp, index, PnMLR, 0); +} + +void rcar_du_plane_setup(struct rcar_du_plane *plane) +{ + struct rcar_du_plane_state *state = + to_rcar_du_plane_state(plane->plane.state); + + __rcar_du_plane_setup(plane, state->hwindex); + if (state->format->planes == 2) + __rcar_du_plane_setup(plane, (state->hwindex + 1) % 8); + + rcar_du_plane_setup_fb(plane); +} + +static int rcar_du_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state); + struct rcar_du_plane *rplane = to_rcar_plane(plane); + struct rcar_du_device *rcdu = rplane->group->dev; + + if (!state->fb || !state->crtc) { + rstate->format = NULL; + return 0; + } + + if (state->src_w >> 16 != state->crtc_w || + state->src_h >> 16 != state->crtc_h) { + dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__); + return -EINVAL; + } + + rstate->format = rcar_du_format_info(state->fb->pixel_format); + if (rstate->format == NULL) { + dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__, + state->fb->pixel_format); + return -EINVAL; + } + + return 0; +} + +static void rcar_du_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct rcar_du_plane *rplane = to_rcar_plane(plane); + + if (plane->state->crtc) + rcar_du_plane_setup(rplane); +} + +static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { + .atomic_check = rcar_du_plane_atomic_check, + .atomic_update = rcar_du_plane_atomic_update, +}; + +static void rcar_du_plane_reset(struct drm_plane *plane) +{ + struct rcar_du_plane_state *state; + + if (plane->state && plane->state->fb) + drm_framebuffer_unreference(plane->state->fb); + + kfree(plane->state); + plane->state = NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return; + + state->hwindex = -1; + state->alpha = 255; + state->colorkey = RCAR_DU_COLORKEY_NONE; + state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; + + plane->state = &state->state; + plane->state->plane = plane; +} + +static struct drm_plane_state * +rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) +{ + struct rcar_du_plane_state *state; + struct rcar_du_plane_state *copy; + + state = to_rcar_du_plane_state(plane->state); + copy = kmemdup(state, sizeof(*state), GFP_KERNEL); + if (copy == NULL) + return NULL; + + if (copy->state.fb) + drm_framebuffer_reference(copy->state.fb); + + return ©->state; +} + +static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (state->fb) + drm_framebuffer_unreference(state->fb); + + kfree(to_rcar_du_plane_state(state)); +} + +static int rcar_du_plane_atomic_set_property(struct drm_plane *plane, + struct drm_plane_state *state, + struct drm_property *property, + uint64_t val) +{ + struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state); + struct rcar_du_plane *rplane = to_rcar_plane(plane); + struct rcar_du_group *rgrp = rplane->group; + + if (property == rgrp->planes.alpha) + rstate->alpha = val; + else if (property == rgrp->planes.colorkey) + rstate->colorkey = val; + else if (property == rgrp->planes.zpos) + rstate->zpos = val; + else + return -EINVAL; + + return 0; +} + +static int rcar_du_plane_atomic_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, struct drm_property *property, + uint64_t *val) +{ + const struct rcar_du_plane_state *rstate = + container_of(state, const struct rcar_du_plane_state, state); + struct rcar_du_plane *rplane = to_rcar_plane(plane); + struct rcar_du_group *rgrp = rplane->group; + + if (property == rgrp->planes.alpha) + *val = rstate->alpha; + else if (property == rgrp->planes.colorkey) + *val = rstate->colorkey; + else if (property == rgrp->planes.zpos) + *val = rstate->zpos; + else + return -EINVAL; + + return 0; +} + +static const struct drm_plane_funcs rcar_du_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = rcar_du_plane_reset, + .set_property = drm_atomic_helper_plane_set_property, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state, + .atomic_destroy_state = rcar_du_plane_atomic_destroy_state, + .atomic_set_property = rcar_du_plane_atomic_set_property, + .atomic_get_property = rcar_du_plane_atomic_get_property, +}; + +static const uint32_t formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_UYVY, + DRM_FORMAT_YUYV, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, +}; + +int rcar_du_planes_init(struct rcar_du_group *rgrp) +{ + struct rcar_du_planes *planes = &rgrp->planes; + struct rcar_du_device *rcdu = rgrp->dev; + unsigned int num_planes; + unsigned int num_crtcs; + unsigned int crtcs; + unsigned int i; + int ret; + + planes->alpha = + drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255); + if (planes->alpha == NULL) + return -ENOMEM; + + /* The color key is expressed as an RGB888 triplet stored in a 32-bit + * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0) + * or enable source color keying (1). + */ + planes->colorkey = + drm_property_create_range(rcdu->ddev, 0, "colorkey", + 0, 0x01ffffff); + if (planes->colorkey == NULL) + return -ENOMEM; + + planes->zpos = + drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7); + if (planes->zpos == NULL) + return -ENOMEM; + + /* Create one primary plane per in this group CRTC and seven overlay + * planes. + */ + num_crtcs = min(rcdu->num_crtcs - 2 * rgrp->index, 2U); + num_planes = num_crtcs + 7; + + crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index)); + + for (i = 0; i < num_planes; ++i) { + enum drm_plane_type type = i < num_crtcs + ? DRM_PLANE_TYPE_PRIMARY + : DRM_PLANE_TYPE_OVERLAY; + struct rcar_du_plane *plane = &planes->planes[i]; + + plane->group = rgrp; + + ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs, + &rcar_du_plane_funcs, formats, + ARRAY_SIZE(formats), type); + if (ret < 0) + return ret; + + drm_plane_helper_add(&plane->plane, + &rcar_du_plane_helper_funcs); + + if (type == DRM_PLANE_TYPE_PRIMARY) + continue; + + drm_object_attach_property(&plane->plane.base, + planes->alpha, 255); + drm_object_attach_property(&plane->plane.base, + planes->colorkey, + RCAR_DU_COLORKEY_NONE); + drm_object_attach_property(&plane->plane.base, + planes->zpos, 1); + } + + return 0; +} |