1
0
Fork 0

MLK-21509-4 drm/imx: dpu: crc: Add user-configurable CRC region(ROI) support

This patch adds user-configurable CRC region support.
The users may choose a region of interest(ROI) as the CRC source
(i.e., the CRC evaluation window) via the debugfs control node.
The ROI cannot exceed the display region as indicated by
drm_crtc_state->adjusted_mode.  The users may write a string in
the fashion of "roi:x1,y1,x2,y2" to the node to specify the ROI
within the display region.  The inclusive position at (x1, y1)
indicates the upper left of the region, while the exclusive
position at (x2, y2) indicates the lower right of the region.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
Reviewed-by: Robby Cai <robby.cai@nxp.com>
5.4-rM2-2.2.x-imx-squashed
Liu Ying 2020-07-07 15:38:52 +08:00
parent ba2b101d1f
commit aa6fda9c4e
5 changed files with 185 additions and 23 deletions

View File

@ -19,8 +19,25 @@
#include <linux/interrupt.h>
#include <linux/types.h>
#include <video/dpu.h>
#include "dpu-crc.h"
#include "dpu-crtc.h"
static inline void get_left(struct drm_rect *r, struct drm_display_mode *m)
{
r->x1 = 0;
r->y1 = 0;
r->x2 = m->hdisplay >> 1;
r->y2 = m->vdisplay;
}
static inline void get_right(struct drm_rect *r, struct drm_display_mode *m)
{
r->x1 = m->hdisplay >> 1;
r->y1 = 0;
r->x2 = m->hdisplay;
r->y2 = m->vdisplay;
}
static void
dpu_enable_signature_roi(struct dpu_signature *sig, struct drm_rect *roi)
{
@ -37,12 +54,64 @@ static void dpu_disable_signature(struct dpu_signature *sig)
signature_eval_win(sig, 0, false);
}
static int dpu_crc_parse_source(const char *source_name, enum dpu_crc_source *s)
/*
* Supported modes and source names:
* 1) auto mode:
* "auto" should be selected as the source name.
* The evaluation window is the same to the display region as
* indicated by drm_crtc_state->adjusted_mode.
*
* 2) region of interest(ROI) mode:
* "roi:x1,y1,x2,y2" should be selected as the source name.
* The region of interest is defined by the inclusive upper left
* position at (x1, y1) and the exclusive lower right position
* at (x2, y2), see struct drm_rect for the same idea.
* The evaluation window is the region of interest.
*/
static int
dpu_crc_parse_source(const char *source_name, enum dpu_crc_source *s,
struct drm_rect *roi)
{
static const char roi_prefix[] = "roi:";
if (!source_name) {
*s = DPU_CRC_SRC_NONE;
} else if (!strcmp(source_name, "auto")) {
*s = DPU_CRC_SRC_FRAMEGEN;
} else if (strstarts(source_name, roi_prefix)) {
char *options, *opt;
int len = strlen(roi_prefix);
int params[4];
int i = 0, ret;
options = kstrdup(source_name + len, GFP_KERNEL);
while ((opt = strsep(&options, ",")) != NULL) {
if (i > 4)
return -EINVAL;
ret = kstrtouint(opt, 10, &params[i]);
if (ret < 0)
return ret;
if (params[i] < 0)
return -EINVAL;
i++;
}
if (i != 4)
return -EINVAL;
roi->x1 = params[0];
roi->y1 = params[1];
roi->x2 = params[2];
roi->y2 = params[3];
if (!drm_rect_visible(roi))
return -EINVAL;
*s = DPU_CRC_SRC_FRAMEGEN_ROI;
} else {
return -EINVAL;
}
@ -56,10 +125,11 @@ int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct imx_crtc_state *imx_crtc_state;
struct dpu_crtc_state *dcstate;
struct drm_rect roi;
enum dpu_crc_source source;
int ret;
if (dpu_crc_parse_source(source_name, &source) < 0) {
if (dpu_crc_parse_source(source_name, &source, &roi) < 0) {
dev_dbg(dpu_crtc->dev, "unknown source %s\n", source_name);
return -EINVAL;
}
@ -83,10 +153,11 @@ int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
struct drm_modeset_acquire_ctx ctx;
struct drm_crtc_state *crtc_state;
struct drm_atomic_state *state;
struct drm_rect roi = {0, 0, 0, 0};
enum dpu_crc_source source;
int ret;
if (dpu_crc_parse_source(source_name, &source) < 0) {
if (dpu_crc_parse_source(source_name, &source, &roi) < 0) {
dev_dbg(dpu_crtc->dev, "unknown source %s\n", source_name);
return -EINVAL;
}
@ -118,6 +189,7 @@ retry:
}
dcstate->crc.source = source;
dpu_copy_roi(&roi, &dcstate->crc.roi);
dpu_crtc->use_dual_crc = dcstate->use_pc;
ret = drm_atomic_commit(state);
@ -161,9 +233,12 @@ irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
crcs[2] = dpu_crtc->crc_red;
crcs[1] = dpu_crtc->crc_green;
crcs[0] = dpu_crtc->crc_blue;
if (!dual_crc ||
(dual_crc && dpu_crtc->dual_crc_flag != DPU_DUAL_CRC_FLAG_RIGHT)) {
crcs[2] = dpu_crtc->crc_red;
crcs[1] = dpu_crtc->crc_green;
crcs[0] = dpu_crtc->crc_blue;
}
if (dual_crc && dpu_crtc->stream_id == 0) {
ret = wait_for_completion_timeout(&dpu_crtc->aux_crc_done,
@ -172,9 +247,11 @@ irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id)
dev_warn(dpu_crtc->dev,
"wait for auxiliary CRC done timeout\n");
crcs[5] = aux_dpu_crtc->crc_red;
crcs[4] = aux_dpu_crtc->crc_green;
crcs[3] = aux_dpu_crtc->crc_blue;
if (dpu_crtc->dual_crc_flag != DPU_DUAL_CRC_FLAG_LEFT) {
crcs[5] = aux_dpu_crtc->crc_red;
crcs[4] = aux_dpu_crtc->crc_green;
crcs[3] = aux_dpu_crtc->crc_blue;
}
}
drm_crtc_add_crc_entry(&dpu_crtc->base, false, 0, crcs);
@ -183,7 +260,8 @@ irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id)
}
void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
enum dpu_crc_source source)
enum dpu_crc_source source,
struct drm_rect *roi)
{
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct dpu_crtc *aux_dpu_crtc = dpu_crtc_get_aux_dpu_crtc(dpu_crtc);
@ -191,8 +269,11 @@ void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
struct completion *shdld_done;
struct drm_rect roi;
struct drm_rect left, right;
struct drm_rect r, aux_r, clip;
bool dual_crc = dpu_crtc->use_dual_crc;
bool use_left, use_right;
int half_hdisplay;
unsigned long ret;
if (source == DPU_CRC_SRC_NONE)
@ -204,23 +285,57 @@ void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
if (dpu_crtc->crc_is_enabled)
return;
/* region of interest */
roi.x1 = 0;
roi.y1 = 0;
roi.x2 = dual_crc ? mode->hdisplay >> 1 : mode->hdisplay;
roi.y2 = mode->vdisplay;
if (dual_crc) {
half_hdisplay = mode->hdisplay >> 1;
get_left(&left, mode);
get_right(&right, mode);
dpu_copy_roi(&left, &clip);
if (drm_rect_intersect(&clip, roi)) {
dpu_copy_roi(&clip, &r);
use_left = true;
} else {
dpu_copy_roi(&left, &r);
use_left = false;
}
if (drm_rect_intersect(&right, roi)) {
right.x1 -= half_hdisplay;
right.x2 -= half_hdisplay;
dpu_copy_roi(&right, &aux_r);
use_right = true;
} else {
dpu_copy_roi(&left, &aux_r);
use_right = false;
}
if (use_left && !use_right) {
dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_LEFT;
} else if (!use_left && use_right) {
dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_RIGHT;
} else if (use_left && use_right) {
dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_DUAL;
} else {
dpu_crtc->dual_crc_flag = DPU_DUAL_CRC_FLAG_ERR_NONE;
dev_err(dpu_crtc->dev, "error flag for dual CRC\n");
return;
}
} else {
dpu_copy_roi(roi, &r);
}
enable_irq(dpu_crtc->crc_valid_irq);
enable_irq(dpu_crtc->crc_shdld_irq);
disengcfg_sig_select(dpu_crtc->dec, DEC_SIG_SEL_FRAMEGEN);
dpu_enable_signature_roi(dpu_crtc->sig, &roi);
dpu_enable_signature_roi(dpu_crtc->sig, &r);
if (dual_crc) {
aux_dpu_crtc->use_dual_crc = dual_crc;
enable_irq(aux_dpu_crtc->crc_valid_irq);
enable_irq(aux_dpu_crtc->crc_shdld_irq);
disengcfg_sig_select(dpu_crtc->aux_dec, DEC_SIG_SEL_FRAMEGEN);
dpu_enable_signature_roi(dpu_crtc->aux_sig, &roi);
dpu_enable_signature_roi(dpu_crtc->aux_sig, &aux_r);
}
shdld_done = &dpu_crtc->crc_shdld_done;
@ -242,7 +357,8 @@ void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
dpu_crtc->crc_is_enabled = true;
dev_dbg(dpu_crtc->dev, "enable CRC source\n");
dev_dbg(dpu_crtc->dev, "enable CRC source %d, ROI:" DRM_RECT_FMT "\n",
source, DRM_RECT_ARG(roi));
}
void dpu_crtc_disable_crc_source(struct drm_crtc *crtc, bool dual_crc)

View File

@ -17,6 +17,13 @@
#include "dpu-crtc.h"
enum {
DPU_DUAL_CRC_FLAG_DUAL,
DPU_DUAL_CRC_FLAG_LEFT,
DPU_DUAL_CRC_FLAG_RIGHT,
DPU_DUAL_CRC_FLAG_ERR_NONE,
};
static inline bool to_enable_dpu_crc(struct dpu_crtc_state *new_dcstate,
struct dpu_crtc_state *old_dcstate)
{
@ -31,13 +38,22 @@ static inline bool to_disable_dpu_crc(struct dpu_crtc_state *new_dcstate,
new_dcstate->crc.source == DPU_CRC_SRC_NONE;
}
static inline void dpu_copy_roi(struct drm_rect *from, struct drm_rect *to)
{
to->x1 = from->x1;
to->y1 = from->y1;
to->x2 = from->x2;
to->y2 = from->y2;
}
#ifdef CONFIG_DEBUG_FS
int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
size_t *values_cnt);
int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name);
irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id);
void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
enum dpu_crc_source source);
enum dpu_crc_source source,
struct drm_rect *roi);
void dpu_crtc_disable_crc_source(struct drm_crtc *crtc, bool dual_crc);
#else
#define dpu_crtc_verify_crc_source NULL
@ -47,7 +63,8 @@ irqreturn_t dpu_crc_valid_irq_threaded_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
void dpu_crtc_enable_crc_source(struct drm_crtc *crtc,
enum dpu_crc_source source)
enum dpu_crc_source source,
struct drm_rect *roi)
{
}
void dpu_crtc_disable_crc_source(struct drm_crtc *crtc, bool dual_crc)

View File

@ -282,7 +282,8 @@ static void dpu_crtc_atomic_enable(struct drm_crtc *crtc,
}
if (dcstate->crc.source != DPU_CRC_SRC_NONE)
dpu_crtc_enable_crc_source(crtc, dcstate->crc.source);
dpu_crtc_enable_crc_source(crtc,
dcstate->crc.source, &dcstate->crc.roi);
}
static void dpu_crtc_atomic_disable(struct drm_crtc *crtc,
@ -438,6 +439,10 @@ static void dpu_drm_crtc_reset(struct drm_crtc *crtc)
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state) {
state->crc.source = DPU_CRC_SRC_NONE;
state->crc.roi.x1 = 0;
state->crc.roi.y1 = 0;
state->crc.roi.x2 = 0;
state->crc.roi.y2 = 0;
crtc->state = &state->imx_crtc_state.base;
crtc->state->crtc = crtc;
@ -474,6 +479,7 @@ dpu_drm_crtc_duplicate_state(struct drm_crtc *crtc)
state = to_dpu_crtc_state(imx_crtc_state);
copy->use_pc = state->use_pc;
copy->crc.source = state->crc.source;
dpu_copy_roi(&state->crc.roi, &copy->crc.roi);
return &copy->imx_crtc_state.base;
}
@ -626,6 +632,25 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
to_enable_dpu_crc(dcstate, old_dcstate))
return -EINVAL;
if (crtc_state->enable && dcstate->crc.source == DPU_CRC_SRC_FRAMEGEN) {
dcstate->crc.roi.x1 = 0;
dcstate->crc.roi.y1 = 0;
dcstate->crc.roi.x2 = mode->hdisplay;
dcstate->crc.roi.y2 = mode->vdisplay;
}
if (crtc_state->enable && dcstate->crc.source != DPU_CRC_SRC_NONE) {
if (dcstate->crc.roi.x1 < 0 || dcstate->crc.roi.y1 < 0)
return -EINVAL;
if (dcstate->crc.roi.x2 > mode->hdisplay ||
dcstate->crc.roi.y2 > mode->vdisplay)
return -EINVAL;
if (!drm_rect_visible(&dcstate->crc.roi))
return -EINVAL;
}
/*
* cache the plane states so that the planes can be disabled in
* ->atomic_begin.
@ -958,7 +983,8 @@ again2:
}
if (!need_modeset && to_enable_dpu_crc(dcstate, old_dcstate))
dpu_crtc_enable_crc_source(crtc, dcstate->crc.source);
dpu_crtc_enable_crc_source(crtc,
dcstate->crc.source, &dcstate->crc.roi);
}
static void dpu_crtc_mode_set_nofb(struct drm_crtc *crtc)

View File

@ -82,10 +82,12 @@ struct dpu_crtc {
u32 crc_red;
u32 crc_green;
u32 crc_blue;
u32 dual_crc_flag;
};
struct dpu_crc {
enum dpu_crc_source source;
struct drm_rect roi;
};
struct dpu_crtc_state {

View File

@ -335,6 +335,7 @@ enum {
enum dpu_crc_source {
DPU_CRC_SRC_NONE,
DPU_CRC_SRC_FRAMEGEN,
DPU_CRC_SRC_FRAMEGEN_ROI,
};
struct dpu_fetchunit;