summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLiu Ying <victor.liu@nxp.com>2019-04-13 15:59:39 +0800
committerLiu Ying <victor.liu@nxp.com>2019-05-07 14:45:49 +0800
commit0ed040a467ef98187f4893183c58d5cfd0f0e2bd (patch)
treed16e339c4c5a92407bbf88e3971b50cb3fa3b755 /drivers
parenta7469b05e8e99b8845f13fec29dc282e12f13804 (diff)
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> (cherry picked from commit 1d3b253e11f0d09f9956abb587962a751cd34b5f)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-crc.c166
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-crc.h21
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-crtc.c30
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-crtc.h2
4 files changed, 194 insertions, 25 deletions
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crc.c b/drivers/gpu/drm/imx/dpu/dpu-crc.c
index 4fe0af59eb3d..042c4f5fa3a8 100644
--- a/drivers/gpu/drm/imx/dpu/dpu-crc.c
+++ b/drivers/gpu/drm/imx/dpu/dpu-crc.c
@@ -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,6 +54,71 @@ static void dpu_disable_signature(struct dpu_signature *sig)
signature_eval_win(sig, 0, false);
}
+/*
+ * 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)
+{
+ 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;
+ }
+
+ return 0;
+}
+
int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
size_t *values_cnt)
{
@@ -44,14 +126,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 (!source_name) {
- source = DPU_CRC_SRC_NONE;
- } else if (!strcmp(source_name, "auto")) {
- source = DPU_CRC_SRC_FRAMEGEN;
- } else {
+ if (dpu_crc_parse_source(source_name, &source, &roi) < 0) {
dev_dbg(dpu_crtc->dev, "unknown source %s\n", source_name);
return -EINVAL;
}
@@ -76,6 +155,7 @@ retry:
imx_crtc_state = to_imx_crtc_state(crtc_state);
dcstate = to_dpu_crtc_state(imx_crtc_state);
dcstate->crc.source = source;
+ dpu_copy_roi(&roi, &dcstate->crc.roi);
dpu_crtc->use_dual_crc = dcstate->use_pc;
*values_cnt = dpu_crtc->use_dual_crc ? 6 : 3;
@@ -120,9 +200,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,
@@ -131,9 +214,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);
@@ -142,7 +227,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);
@@ -150,8 +236,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)
@@ -163,23 +252,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;
@@ -201,7 +324,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)
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crc.h b/drivers/gpu/drm/imx/dpu/dpu-crc.h
index 6eda099dfcaa..55253eda6d51 100644
--- a/drivers/gpu/drm/imx/dpu/dpu-crc.h
+++ b/drivers/gpu/drm/imx/dpu/dpu-crc.h
@@ -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,12 +38,21 @@ 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_set_crc_source(struct drm_crtc *crtc, const char *source_name,
size_t *values_cnt);
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_set_crc_source NULL
@@ -45,7 +61,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)
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crtc.c b/drivers/gpu/drm/imx/dpu/dpu-crtc.c
index 4cea669d7bb8..83e8eb9d6aec 100644
--- a/drivers/gpu/drm/imx/dpu/dpu-crtc.c
+++ b/drivers/gpu/drm/imx/dpu/dpu-crtc.c
@@ -257,7 +257,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,
@@ -322,6 +323,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;
@@ -358,6 +363,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;
}
@@ -496,6 +502,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.
@@ -797,7 +822,8 @@ again:
}
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)
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crtc.h b/drivers/gpu/drm/imx/dpu/dpu-crtc.h
index 1c82cd0e5d19..3652da2199a4 100644
--- a/drivers/gpu/drm/imx/dpu/dpu-crtc.h
+++ b/drivers/gpu/drm/imx/dpu/dpu-crtc.h
@@ -76,10 +76,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 {