提交 cb2025d2 编写于 作者: L Laurent Pinchart

drm/rcar-du: Introduce CRTCs groups

The R8A7779 DU is split in per-CRTC resources (scan-out engine, blending
unit, timings generator, ...) and device-global resources (start/stop
control, planes, ...) shared between the two CRTCs.

The R8A7790 introduced a third CRTC with its own set of global resources
This would be modeled as two separate DU device instances if it wasn't
for a handful or resources that are shared between the three CRTCs
(mostly related to input and output routing). For this reason the
R8A7790 DU must be modeled as a single device with three CRTCs, two sets
of "semi-global" resources, and a few device-global resources.

Introduce a new rcar_du_group driver-specific object, without any real
counterpart in the DU documentation, that models those semi-global
resources.
Signed-off-by: NLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
上级 7fe99fda
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
rcar-du-drm-y := rcar_du_crtc.o \
rcar_du_drv.o \
rcar_du_encoder.o \
rcar_du_group.o \
rcar_du_kms.o \
rcar_du_lvdscon.o \
rcar_du_plane.o \
......
......@@ -30,21 +30,21 @@
static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
struct rcar_du_device *rcdu = rcrtc->group->dev;
return rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
}
static void rcar_du_crtc_write(struct rcar_du_crtc *rcrtc, u32 reg, u32 data)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
struct rcar_du_device *rcdu = rcrtc->group->dev;
rcar_du_write(rcdu, rcrtc->mmio_offset + reg, data);
}
static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
struct rcar_du_device *rcdu = rcrtc->group->dev;
rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr);
......@@ -52,7 +52,7 @@ static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr)
static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
struct rcar_du_device *rcdu = rcrtc->group->dev;
rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set);
......@@ -61,7 +61,7 @@ static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set)
static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
u32 clr, u32 set)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
struct rcar_du_device *rcdu = rcrtc->group->dev;
u32 value = rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set);
......@@ -69,14 +69,13 @@ static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
int ret;
ret = clk_prepare_enable(rcrtc->clock);
if (ret < 0)
return ret;
ret = rcar_du_get(rcdu);
ret = rcar_du_group_get(rcrtc->group);
if (ret < 0)
clk_disable_unprepare(rcrtc->clock);
......@@ -85,17 +84,14 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
rcar_du_put(rcdu);
rcar_du_group_put(rcrtc->group);
clk_disable_unprepare(rcrtc->clock);
}
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{
struct drm_crtc *crtc = &rcrtc->crtc;
struct rcar_du_device *rcdu = crtc->dev->dev_private;
const struct drm_display_mode *mode = &crtc->mode;
const struct drm_display_mode *mode = &rcrtc->crtc.mode;
struct rcar_du_device *rcdu = rcrtc->group->dev;
unsigned long clk;
u32 value;
u32 div;
......@@ -136,7 +132,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
static void rcar_du_crtc_set_routing(struct rcar_du_crtc *rcrtc)
{
struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
struct rcar_du_device *rcdu = rcrtc->group->dev;
u32 dorcr = rcar_du_read(rcdu, DORCR);
dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK);
......@@ -153,36 +149,6 @@ static void rcar_du_crtc_set_routing(struct rcar_du_crtc *rcrtc)
rcar_du_write(rcdu, DORCR, dorcr);
}
static void __rcar_du_start_stop(struct rcar_du_device *rcdu, bool start)
{
rcar_du_write(rcdu, DSYSR,
(rcar_du_read(rcdu, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
(start ? DSYSR_DEN : DSYSR_DRES));
}
static void rcar_du_start_stop(struct rcar_du_device *rcdu, bool start)
{
/* Many of the configuration bits are only updated when the display
* reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some
* of those bits could be pre-configured, but others (especially the
* bits related to plane assignment to display timing controllers) need
* to be modified at runtime.
*
* Restart the display controller if a start is requested. Sorry for the
* flicker. It should be possible to move most of the "DRES-update" bits
* setup to driver initialization time and minimize the number of cases
* when the display controller will have to be restarted.
*/
if (start) {
if (rcdu->used_crtcs++ != 0)
__rcar_du_start_stop(rcdu, false);
__rcar_du_start_stop(rcdu, true);
} else {
if (--rcdu->used_crtcs == 0)
__rcar_du_start_stop(rcdu, false);
}
}
void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output)
{
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
......@@ -195,8 +161,8 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output)
void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
{
struct rcar_du_device *rcdu = crtc->dev->dev_private;
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
struct rcar_du_device *rcdu = rcrtc->group->dev;
struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
unsigned int num_planes = 0;
unsigned int prio = 0;
......@@ -204,8 +170,8 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
u32 dptsr = 0;
u32 dspr = 0;
for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcdu->planes.planes[i];
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
unsigned int j;
if (plane->crtc != &rcrtc->crtc || !plane->enabled)
......@@ -254,10 +220,8 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
*/
if (value != dptsr) {
rcar_du_write(rcdu, DPTSR, dptsr);
if (rcdu->used_crtcs) {
__rcar_du_start_stop(rcdu, false);
__rcar_du_start_stop(rcdu, true);
}
if (rcrtc->group->used_crtcs)
rcar_du_group_restart(rcrtc->group);
}
}
......@@ -267,7 +231,6 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
{
struct drm_crtc *crtc = &rcrtc->crtc;
struct rcar_du_device *rcdu = crtc->dev->dev_private;
unsigned int i;
if (rcrtc->started)
......@@ -284,14 +247,14 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
rcar_du_crtc_set_display_timing(rcrtc);
rcar_du_crtc_set_routing(rcrtc);
mutex_lock(&rcdu->planes.lock);
mutex_lock(&rcrtc->group->planes.lock);
rcrtc->plane->enabled = true;
rcar_du_crtc_update_planes(crtc);
mutex_unlock(&rcdu->planes.lock);
mutex_unlock(&rcrtc->group->planes.lock);
/* Setup planes. */
for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcdu->planes.planes[i];
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
if (plane->crtc != crtc || !plane->enabled)
continue;
......@@ -305,7 +268,7 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
*/
rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
rcar_du_start_stop(rcdu, true);
rcar_du_group_start_stop(rcrtc->group, true);
rcrtc->started = true;
}
......@@ -313,22 +276,21 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
{
struct drm_crtc *crtc = &rcrtc->crtc;
struct rcar_du_device *rcdu = crtc->dev->dev_private;
if (!rcrtc->started)
return;
mutex_lock(&rcdu->planes.lock);
mutex_lock(&rcrtc->group->planes.lock);
rcrtc->plane->enabled = false;
rcar_du_crtc_update_planes(crtc);
mutex_unlock(&rcdu->planes.lock);
mutex_unlock(&rcrtc->group->planes.lock);
/* Select switch sync mode. This stops display operation and configures
* the HSYNC and VSYNC signals as inputs.
*/
rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
rcar_du_start_stop(rcdu, false);
rcar_du_group_start_stop(rcrtc->group, false);
rcrtc->started = false;
}
......@@ -406,8 +368,8 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
int x, int y,
struct drm_framebuffer *old_fb)
{
struct rcar_du_device *rcdu = crtc->dev->dev_private;
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
struct rcar_du_device *rcdu = rcrtc->group->dev;
const struct rcar_du_format_info *format;
int ret;
......@@ -583,8 +545,9 @@ static const struct drm_crtc_funcs crtc_funcs = {
.page_flip = rcar_du_crtc_page_flip,
};
int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index)
int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
{
struct rcar_du_device *rcdu = rgrp->dev;
struct platform_device *pdev = to_platform_device(rcdu->dev);
struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
struct drm_crtc *crtc = &rcrtc->crtc;
......@@ -608,10 +571,11 @@ int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index)
return PTR_ERR(rcrtc->clock);
}
rcrtc->group = rgrp;
rcrtc->mmio_offset = index ? DISP2_REG_OFFSET : 0;
rcrtc->index = index;
rcrtc->dpms = DRM_MODE_DPMS_OFF;
rcrtc->plane = &rcdu->planes.planes[index];
rcrtc->plane = &rgrp->planes.planes[index];
rcrtc->plane->crtc = crtc;
......
......@@ -19,7 +19,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
struct rcar_du_device;
struct rcar_du_group;
struct rcar_du_plane;
struct rcar_du_crtc {
......@@ -34,10 +34,11 @@ struct rcar_du_crtc {
unsigned int outputs;
int dpms;
struct rcar_du_group *group;
struct rcar_du_plane *plane;
};
int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index);
int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index);
void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable);
void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
struct drm_file *file);
......
......@@ -28,52 +28,6 @@
#include "rcar_du_kms.h"
#include "rcar_du_regs.h"
/* -----------------------------------------------------------------------------
* Core device operations
*/
/*
* rcar_du_get - Acquire a reference to the DU
*
* Acquiring the first reference setups core registers. A reference must be
* held before accessing any hardware registers.
*
* This function must be called with the DRM mode_config lock held.
*
* Return 0 in case of success or a negative error code otherwise.
*/
int rcar_du_get(struct rcar_du_device *rcdu)
{
if (rcdu->use_count)
goto done;
/* Enable extended features */
rcar_du_write(rcdu, DEFR, DEFR_CODE | DEFR_DEFE);
rcar_du_write(rcdu, DEFR2, DEFR2_CODE | DEFR2_DEFE2G);
rcar_du_write(rcdu, DEFR3, DEFR3_CODE | DEFR3_DEFE3);
rcar_du_write(rcdu, DEFR4, DEFR4_CODE);
rcar_du_write(rcdu, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
/* Use DS1PR and DS2PR to configure planes priorities and connects the
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
*/
rcar_du_write(rcdu, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
done:
rcdu->use_count++;
return 0;
}
/*
* rcar_du_put - Release a reference to the DU
*
* This function must be called with the DRM mode_config lock held.
*/
void rcar_du_put(struct rcar_du_device *rcdu)
{
--rcdu->use_count;
}
/* -----------------------------------------------------------------------------
* DRM operations
*/
......
......@@ -18,11 +18,12 @@
#include <linux/platform_data/rcar-du.h>
#include "rcar_du_crtc.h"
#include "rcar_du_plane.h"
#include "rcar_du_group.h"
struct clk;
struct device;
struct drm_device;
struct rcar_du_device;
#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */
......@@ -40,15 +41,13 @@ struct rcar_du_device {
const struct rcar_du_device_info *info;
void __iomem *mmio;
unsigned int use_count;
struct drm_device *ddev;
struct rcar_du_crtc crtcs[2];
unsigned int used_crtcs;
unsigned int num_crtcs;
struct rcar_du_planes planes;
struct rcar_du_group group;
};
static inline bool rcar_du_has(struct rcar_du_device *rcdu,
......@@ -57,9 +56,6 @@ static inline bool rcar_du_has(struct rcar_du_device *rcdu,
return rcdu->info->features & feature;
}
int rcar_du_get(struct rcar_du_device *rcdu);
void rcar_du_put(struct rcar_du_device *rcdu);
static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg)
{
return ioread32(rcdu->mmio + reg);
......
/*
* rcar_du_group.c -- R-Car Display Unit Channels Pair
*
* Copyright (C) 2013 Renesas 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.
*/
/*
* The R8A7779 DU is split in per-CRTC resources (scan-out engine, blending
* unit, timings generator, ...) and device-global resources (start/stop
* control, planes, ...) shared between the two CRTCs.
*
* The R8A7790 introduced a third CRTC with its own set of global resources.
* This would be modeled as two separate DU device instances if it wasn't for
* a handful or resources that are shared between the three CRTCs (mostly
* related to input and output routing). For this reason the R8A7790 DU must be
* modeled as a single device with three CRTCs, two sets of "semi-global"
* resources, and a few device-global resources.
*
* The rcar_du_group object is a driver specific object, without any real
* counterpart in the DU documentation, that models those semi-global resources.
*/
#include <linux/io.h>
#include "rcar_du_drv.h"
#include "rcar_du_group.h"
#include "rcar_du_regs.h"
static u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg)
{
return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg);
}
static void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data)
{
rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data);
}
static void rcar_du_group_setup(struct rcar_du_group *rgrp)
{
/* Enable extended features */
rcar_du_group_write(rgrp, DEFR, DEFR_CODE | DEFR_DEFE);
rcar_du_group_write(rgrp, DEFR2, DEFR2_CODE | DEFR2_DEFE2G);
rcar_du_group_write(rgrp, DEFR3, DEFR3_CODE | DEFR3_DEFE3);
rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE);
rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
/* Use DS1PR and DS2PR to configure planes priorities and connects the
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
*/
rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
}
/*
* rcar_du_group_get - Acquire a reference to the DU channels group
*
* Acquiring the first reference setups core registers. A reference must be held
* before accessing any hardware registers.
*
* This function must be called with the DRM mode_config lock held.
*
* Return 0 in case of success or a negative error code otherwise.
*/
int rcar_du_group_get(struct rcar_du_group *rgrp)
{
if (rgrp->use_count)
goto done;
rcar_du_group_setup(rgrp);
done:
rgrp->use_count++;
return 0;
}
/*
* rcar_du_group_put - Release a reference to the DU
*
* This function must be called with the DRM mode_config lock held.
*/
void rcar_du_group_put(struct rcar_du_group *rgrp)
{
--rgrp->use_count;
}
static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
{
rcar_du_group_write(rgrp, DSYSR,
(rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
(start ? DSYSR_DEN : DSYSR_DRES));
}
void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
{
/* Many of the configuration bits are only updated when the display
* reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some
* of those bits could be pre-configured, but others (especially the
* bits related to plane assignment to display timing controllers) need
* to be modified at runtime.
*
* Restart the display controller if a start is requested. Sorry for the
* flicker. It should be possible to move most of the "DRES-update" bits
* setup to driver initialization time and minimize the number of cases
* when the display controller will have to be restarted.
*/
if (start) {
if (rgrp->used_crtcs++ != 0)
__rcar_du_group_start_stop(rgrp, false);
__rcar_du_group_start_stop(rgrp, true);
} else {
if (--rgrp->used_crtcs == 0)
__rcar_du_group_start_stop(rgrp, false);
}
}
void rcar_du_group_restart(struct rcar_du_group *rgrp)
{
__rcar_du_group_start_stop(rgrp, false);
__rcar_du_group_start_stop(rgrp, true);
}
/*
* rcar_du_group.c -- R-Car Display Unit Planes and CRTCs Group
*
* Copyright (C) 2013 Renesas 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.
*/
#ifndef __RCAR_DU_GROUP_H__
#define __RCAR_DU_GROUP_H__
#include "rcar_du_plane.h"
struct rcar_du_device;
/*
* struct rcar_du_group - CRTCs and planes group
* @dev: the DU device
* @mmio_offset: registers offset in the device memory map
* @index: group index
* @use_count: number of users of the group (rcar_du_group_(get|put))
* @used_crtcs: number of CRTCs currently in use
* @planes: planes handled by the group
*/
struct rcar_du_group {
struct rcar_du_device *dev;
unsigned int mmio_offset;
unsigned int index;
unsigned int use_count;
unsigned int used_crtcs;
struct rcar_du_planes planes;
};
int rcar_du_group_get(struct rcar_du_group *rgrp);
void rcar_du_group_put(struct rcar_du_group *rgrp);
void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start);
void rcar_du_group_restart(struct rcar_du_group *rgrp);
#endif /* __RCAR_DU_GROUP_H__ */
......@@ -174,17 +174,20 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
rcdu->ddev->mode_config.max_height = 2047;
rcdu->ddev->mode_config.funcs = &rcar_du_mode_config_funcs;
ret = rcar_du_planes_init(rcdu);
rcdu->group.dev = rcdu;
rcdu->group.index = 0;
rcdu->group.used_crtcs = 0;
ret = rcar_du_planes_init(&rcdu->group);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) {
ret = rcar_du_crtc_create(rcdu, i);
ret = rcar_du_crtc_create(&rcdu->group, i);
if (ret < 0)
return ret;
}
rcdu->used_crtcs = 0;
rcdu->num_crtcs = i;
for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
......@@ -215,7 +218,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
encoder->possible_clones = 1 << 0;
}
ret = rcar_du_planes_register(rcdu);
ret = rcar_du_planes_register(&rcdu->group);
if (ret < 0)
return ret;
......
......@@ -36,71 +36,73 @@ static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
return container_of(plane, struct rcar_du_kms_plane, plane)->hwplane;
}
static u32 rcar_du_plane_read(struct rcar_du_device *rcdu,
static u32 rcar_du_plane_read(struct rcar_du_group *rgrp,
unsigned int index, u32 reg)
{
return rcar_du_read(rcdu, index * PLANE_OFF + reg);
return rcar_du_read(rgrp->dev,
rgrp->mmio_offset + index * PLANE_OFF + reg);
}
static void rcar_du_plane_write(struct rcar_du_device *rcdu,
static void rcar_du_plane_write(struct rcar_du_group *rgrp,
unsigned int index, u32 reg, u32 data)
{
rcar_du_write(rcdu, index * PLANE_OFF + reg, data);
rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg,
data);
}
int rcar_du_plane_reserve(struct rcar_du_plane *plane,
const struct rcar_du_format_info *format)
{
struct rcar_du_device *rcdu = plane->dev;
struct rcar_du_group *rgrp = plane->group;
unsigned int i;
int ret = -EBUSY;
mutex_lock(&rcdu->planes.lock);
mutex_lock(&rgrp->planes.lock);
for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
if (!(rcdu->planes.free & (1 << i)))
for (i = 0; i < ARRAY_SIZE(rgrp->planes.planes); ++i) {
if (!(rgrp->planes.free & (1 << i)))
continue;
if (format->planes == 1 ||
rcdu->planes.free & (1 << ((i + 1) % 8)))
rgrp->planes.free & (1 << ((i + 1) % 8)))
break;
}
if (i == ARRAY_SIZE(rcdu->planes.planes))
if (i == ARRAY_SIZE(rgrp->planes.planes))
goto done;
rcdu->planes.free &= ~(1 << i);
rgrp->planes.free &= ~(1 << i);
if (format->planes == 2)
rcdu->planes.free &= ~(1 << ((i + 1) % 8));
rgrp->planes.free &= ~(1 << ((i + 1) % 8));
plane->hwindex = i;
ret = 0;
done:
mutex_unlock(&rcdu->planes.lock);
mutex_unlock(&rgrp->planes.lock);
return ret;
}
void rcar_du_plane_release(struct rcar_du_plane *plane)
{
struct rcar_du_device *rcdu = plane->dev;
struct rcar_du_group *rgrp = plane->group;
if (plane->hwindex == -1)
return;
mutex_lock(&rcdu->planes.lock);
rcdu->planes.free |= 1 << plane->hwindex;
mutex_lock(&rgrp->planes.lock);
rgrp->planes.free |= 1 << plane->hwindex;
if (plane->format->planes == 2)
rcdu->planes.free |= 1 << ((plane->hwindex + 1) % 8);
mutex_unlock(&rcdu->planes.lock);
rgrp->planes.free |= 1 << ((plane->hwindex + 1) % 8);
mutex_unlock(&rgrp->planes.lock);
plane->hwindex = -1;
}
void rcar_du_plane_update_base(struct rcar_du_plane *plane)
{
struct rcar_du_device *rcdu = plane->dev;
struct rcar_du_group *rgrp = plane->group;
unsigned int index = plane->hwindex;
/* The Y position is expressed in raster line units and must be doubled
......@@ -111,18 +113,18 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
* Similarly, for the second plane, NV12 and NV21 formats seem to
* require a halved Y position value.
*/
rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x);
rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y *
rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
(plane->format->bpp == 32 ? 2 : 1));
rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[0]);
rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
if (plane->format->planes == 2) {
index = (index + 1) % 8;
rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x);
rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y *
rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
(plane->format->bpp == 16 ? 2 : 1) / 2);
rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[1]);
rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[1]);
}
}
......@@ -143,7 +145,7 @@ void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
unsigned int index)
{
struct rcar_du_device *rcdu = plane->dev;
struct rcar_du_group *rgrp = plane->group;
u32 colorkey;
u32 pnmr;
......@@ -157,9 +159,9 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
* enable alpha-blending regardless of the X bit value.
*/
if (plane->format->fourcc != DRM_FORMAT_XRGB1555)
rcar_du_plane_write(rcdu, index, PnALPHAR, PnALPHAR_ABIT_0);
rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0);
else
rcar_du_plane_write(rcdu, index, PnALPHAR,
rcar_du_plane_write(rgrp, index, PnALPHAR,
PnALPHAR_ABIT_X | plane->alpha);
pnmr = PnMR_BM_MD | plane->format->pnmr;
......@@ -175,14 +177,14 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
if (plane->format->fourcc == DRM_FORMAT_YUYV)
pnmr |= PnMR_YCDF_YUYV;
rcar_du_plane_write(rcdu, index, PnMR, pnmr);
rcar_du_plane_write(rgrp, index, PnMR, pnmr);
switch (plane->format->fourcc) {
case DRM_FORMAT_RGB565:
colorkey = ((plane->colorkey & 0xf80000) >> 8)
| ((plane->colorkey & 0x00fc00) >> 5)
| ((plane->colorkey & 0x0000f8) >> 3);
rcar_du_plane_write(rcdu, index, PnTC2R, colorkey);
rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
break;
case DRM_FORMAT_ARGB1555:
......@@ -190,12 +192,12 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
colorkey = ((plane->colorkey & 0xf80000) >> 9)
| ((plane->colorkey & 0x00f800) >> 6)
| ((plane->colorkey & 0x0000f8) >> 3);
rcar_du_plane_write(rcdu, index, PnTC2R, colorkey);
rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
break;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
rcar_du_plane_write(rcdu, index, PnTC3R,
rcar_du_plane_write(rgrp, index, PnTC3R,
PnTC3R_CODE | (plane->colorkey & 0xffffff));
break;
}
......@@ -204,7 +206,7 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
unsigned int index)
{
struct rcar_du_device *rcdu = plane->dev;
struct rcar_du_group *rgrp = plane->group;
u32 ddcr2 = PnDDCR2_CODE;
u32 ddcr4;
u32 mwr;
......@@ -214,7 +216,7 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
* The data format is selected by the DDDF field in PnMR and the EDF
* field in DDCR4.
*/
ddcr4 = rcar_du_plane_read(rcdu, index, PnDDCR4);
ddcr4 = rcar_du_plane_read(rgrp, index, PnDDCR4);
ddcr4 &= ~PnDDCR4_EDF_MASK;
ddcr4 |= plane->format->edf | PnDDCR4_CODE;
......@@ -235,8 +237,8 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
}
}
rcar_du_plane_write(rcdu, index, PnDDCR2, ddcr2);
rcar_du_plane_write(rcdu, index, PnDDCR4, ddcr4);
rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2);
rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4);
/* Memory pitch (expressed in pixels) */
if (plane->format->planes == 2)
......@@ -244,19 +246,19 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
else
mwr = plane->pitch * 8 / plane->format->bpp;
rcar_du_plane_write(rcdu, index, PnMWR, mwr);
rcar_du_plane_write(rgrp, index, PnMWR, mwr);
/* Destination position and size */
rcar_du_plane_write(rcdu, index, PnDSXR, plane->width);
rcar_du_plane_write(rcdu, index, PnDSYR, plane->height);
rcar_du_plane_write(rcdu, index, PnDPXR, plane->dst_x);
rcar_du_plane_write(rcdu, index, PnDPYR, plane->dst_y);
rcar_du_plane_write(rgrp, index, PnDSXR, plane->width);
rcar_du_plane_write(rgrp, index, PnDSYR, plane->height);
rcar_du_plane_write(rgrp, index, PnDPXR, plane->dst_x);
rcar_du_plane_write(rgrp, index, PnDPYR, plane->dst_y);
/* Wrap-around and blinking, disabled */
rcar_du_plane_write(rcdu, index, PnWASPR, 0);
rcar_du_plane_write(rcdu, index, PnWAMWR, 4095);
rcar_du_plane_write(rcdu, index, PnBTR, 0);
rcar_du_plane_write(rcdu, index, PnMLR, 0);
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)
......@@ -276,7 +278,7 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
uint32_t src_w, uint32_t src_h)
{
struct rcar_du_plane *rplane = to_rcar_plane(plane);
struct rcar_du_device *rcdu = plane->dev->dev_private;
struct rcar_du_device *rcdu = rplane->group->dev;
const struct rcar_du_format_info *format;
unsigned int nplanes;
int ret;
......@@ -319,26 +321,25 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
rcar_du_plane_compute_base(rplane, fb);
rcar_du_plane_setup(rplane);
mutex_lock(&rcdu->planes.lock);
mutex_lock(&rplane->group->planes.lock);
rplane->enabled = true;
rcar_du_crtc_update_planes(rplane->crtc);
mutex_unlock(&rcdu->planes.lock);
mutex_unlock(&rplane->group->planes.lock);
return 0;
}
static int rcar_du_plane_disable(struct drm_plane *plane)
{
struct rcar_du_device *rcdu = plane->dev->dev_private;
struct rcar_du_plane *rplane = to_rcar_plane(plane);
if (!rplane->enabled)
return 0;
mutex_lock(&rcdu->planes.lock);
mutex_lock(&rplane->group->planes.lock);
rplane->enabled = false;
rcar_du_crtc_update_planes(rplane->crtc);
mutex_unlock(&rcdu->planes.lock);
mutex_unlock(&rplane->group->planes.lock);
rcar_du_plane_release(rplane);
......@@ -380,9 +381,7 @@ static void rcar_du_plane_set_colorkey(struct rcar_du_plane *plane,
static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane,
unsigned int zpos)
{
struct rcar_du_device *rcdu = plane->dev;
mutex_lock(&rcdu->planes.lock);
mutex_lock(&plane->group->planes.lock);
if (plane->zpos == zpos)
goto done;
......@@ -393,21 +392,21 @@ static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane,
rcar_du_crtc_update_planes(plane->crtc);
done:
mutex_unlock(&rcdu->planes.lock);
mutex_unlock(&plane->group->planes.lock);
}
static int rcar_du_plane_set_property(struct drm_plane *plane,
struct drm_property *property,
uint64_t value)
{
struct rcar_du_device *rcdu = plane->dev->dev_private;
struct rcar_du_plane *rplane = to_rcar_plane(plane);
struct rcar_du_group *rgrp = rplane->group;
if (property == rcdu->planes.alpha)
if (property == rgrp->planes.alpha)
rcar_du_plane_set_alpha(rplane, value);
else if (property == rcdu->planes.colorkey)
else if (property == rgrp->planes.colorkey)
rcar_du_plane_set_colorkey(rplane, value);
else if (property == rcdu->planes.zpos)
else if (property == rgrp->planes.zpos)
rcar_du_plane_set_zpos(rplane, value);
else
return -EINVAL;
......@@ -435,37 +434,39 @@ static const uint32_t formats[] = {
DRM_FORMAT_NV16,
};
int rcar_du_planes_init(struct rcar_du_device *rcdu)
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 i;
mutex_init(&rcdu->planes.lock);
rcdu->planes.free = 0xff;
mutex_init(&planes->lock);
planes->free = 0xff;
rcdu->planes.alpha =
planes->alpha =
drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
if (rcdu->planes.alpha == NULL)
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).
*/
rcdu->planes.colorkey =
planes->colorkey =
drm_property_create_range(rcdu->ddev, 0, "colorkey",
0, 0x01ffffff);
if (rcdu->planes.colorkey == NULL)
if (planes->colorkey == NULL)
return -ENOMEM;
rcdu->planes.zpos =
planes->zpos =
drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
if (rcdu->planes.zpos == NULL)
if (planes->zpos == NULL)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcdu->planes.planes[i];
for (i = 0; i < ARRAY_SIZE(planes->planes); ++i) {
struct rcar_du_plane *plane = &planes->planes[i];
plane->dev = rcdu;
plane->group = rgrp;
plane->hwindex = -1;
plane->alpha = 255;
plane->colorkey = RCAR_DU_COLORKEY_NONE;
......@@ -475,8 +476,10 @@ int rcar_du_planes_init(struct rcar_du_device *rcdu)
return 0;
}
int rcar_du_planes_register(struct rcar_du_device *rcdu)
int rcar_du_planes_register(struct rcar_du_group *rgrp)
{
struct rcar_du_planes *planes = &rgrp->planes;
struct rcar_du_device *rcdu = rgrp->dev;
unsigned int i;
int ret;
......@@ -487,7 +490,7 @@ int rcar_du_planes_register(struct rcar_du_device *rcdu)
if (plane == NULL)
return -ENOMEM;
plane->hwplane = &rcdu->planes.planes[i + 2];
plane->hwplane = &planes->planes[i + 2];
plane->hwplane->zpos = 1;
ret = drm_plane_init(rcdu->ddev, &plane->plane,
......@@ -498,12 +501,12 @@ int rcar_du_planes_register(struct rcar_du_device *rcdu)
return ret;
drm_object_attach_property(&plane->plane.base,
rcdu->planes.alpha, 255);
planes->alpha, 255);
drm_object_attach_property(&plane->plane.base,
rcdu->planes.colorkey,
planes->colorkey,
RCAR_DU_COLORKEY_NONE);
drm_object_attach_property(&plane->plane.base,
rcdu->planes.zpos, 1);
planes->zpos, 1);
}
return 0;
......
......@@ -19,8 +19,8 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
struct rcar_du_device;
struct rcar_du_format_info;
struct rcar_du_group;
/* The RCAR DU has 8 hardware planes, shared between KMS planes and CRTCs. As
* using KMS planes requires at least one of the CRTCs being enabled, no more
......@@ -33,7 +33,7 @@ struct rcar_du_format_info;
#define RCAR_DU_NUM_SW_PLANES 9
struct rcar_du_plane {
struct rcar_du_device *dev;
struct rcar_du_group *group;
struct drm_crtc *crtc;
bool enabled;
......@@ -67,8 +67,8 @@ struct rcar_du_planes {
struct drm_property *zpos;
};
int rcar_du_planes_init(struct rcar_du_device *rcdu);
int rcar_du_planes_register(struct rcar_du_device *rcdu);
int rcar_du_planes_init(struct rcar_du_group *rgrp);
int rcar_du_planes_register(struct rcar_du_group *rgrp);
void rcar_du_plane_setup(struct rcar_du_plane *plane);
void rcar_du_plane_update_base(struct rcar_du_plane *plane);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部