This patch adds constframe_framedimenstions_copy_prim() helper support so that callers may may copy frame dimensions from a primary constframe to the relevant secondary constframe. Signed-off-by: Liu Ying <victor.liu@nxp.com>
281 lines
5.9 KiB
C
281 lines
5.9 KiB
C
/*
|
|
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
|
* Copyright 2017-2018 NXP
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/types.h>
|
|
#include <video/dpu.h>
|
|
#include "dpu-prv.h"
|
|
|
|
static unsigned int safety_stream_cf_color = 0x0;
|
|
module_param(safety_stream_cf_color, uint, 0444);
|
|
MODULE_PARM_DESC(safety_stream_cf_color,
|
|
"Safety stream constframe color in hex(0xRRGGBBAA) [default=0x00000000]");
|
|
|
|
#define FRAMEDIMENSIONS 0xC
|
|
#define WIDTH(w) (((w) - 1) & 0x3FFF)
|
|
#define HEIGHT(h) ((((h) - 1) & 0x3FFF) << 16)
|
|
#define CONSTANTCOLOR 0x10
|
|
#define RED(r) (((r) & 0xFF) << 24)
|
|
#define GREEN(g) (((g) & 0xFF) << 16)
|
|
#define BLUE(b) (((b) & 0xFF) << 8)
|
|
#define ALPHA(a) ((a) & 0xFF)
|
|
#define CONTROLTRIGGER 0x14
|
|
#define START 0x18
|
|
#define STATUS 0x1C
|
|
|
|
static const shadow_load_req_t cf_shdlreqs[] = {
|
|
SHLDREQID_CONSTFRAME0, SHLDREQID_CONSTFRAME1,
|
|
SHLDREQID_CONSTFRAME4, SHLDREQID_CONSTFRAME5,
|
|
};
|
|
|
|
struct dpu_constframe {
|
|
void __iomem *pec_base;
|
|
void __iomem *base;
|
|
struct mutex mutex;
|
|
int id;
|
|
bool inuse;
|
|
struct dpu_soc *dpu;
|
|
shadow_load_req_t shdlreq;
|
|
};
|
|
|
|
static inline u32 dpu_cf_read(struct dpu_constframe *cf, unsigned int offset)
|
|
{
|
|
return readl(cf->base + offset);
|
|
}
|
|
|
|
static inline void dpu_cf_write(struct dpu_constframe *cf, u32 value,
|
|
unsigned int offset)
|
|
{
|
|
writel(value, cf->base + offset);
|
|
}
|
|
|
|
void constframe_shden(struct dpu_constframe *cf, bool enable)
|
|
{
|
|
u32 val;
|
|
|
|
val = enable ? SHDEN : 0;
|
|
|
|
mutex_lock(&cf->mutex);
|
|
dpu_cf_write(cf, val, STATICCONTROL);
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(constframe_shden);
|
|
|
|
void constframe_framedimensions(struct dpu_constframe *cf, unsigned int w,
|
|
unsigned int h)
|
|
{
|
|
u32 val;
|
|
|
|
val = WIDTH(w) | HEIGHT(h);
|
|
|
|
mutex_lock(&cf->mutex);
|
|
dpu_cf_write(cf, val, FRAMEDIMENSIONS);
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(constframe_framedimensions);
|
|
|
|
void constframe_framedimensions_copy_prim(struct dpu_constframe *cf)
|
|
{
|
|
struct dpu_constframe *prim_cf = NULL;
|
|
unsigned int prim_id;
|
|
int i;
|
|
u32 val;
|
|
|
|
if (cf->id != 0 && cf->id != 1) {
|
|
dev_warn(cf->dpu->dev, "ConstFrame%d is not a secondary one\n",
|
|
cf->id);
|
|
return;
|
|
}
|
|
|
|
prim_id = cf->id + 4;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
|
|
if (cf_ids[i] == prim_id)
|
|
prim_cf = cf->dpu->cf_priv[i];
|
|
|
|
if (!prim_cf) {
|
|
dev_warn(cf->dpu->dev, "cannot find ConstFrame%d's primary peer\n",
|
|
cf->id);
|
|
return;
|
|
}
|
|
|
|
mutex_lock(&cf->mutex);
|
|
val = dpu_cf_read(prim_cf, FRAMEDIMENSIONS);
|
|
dpu_cf_write(cf, val, FRAMEDIMENSIONS);
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(constframe_framedimensions_copy_prim);
|
|
|
|
void constframe_constantcolor(struct dpu_constframe *cf, unsigned int r,
|
|
unsigned int g, unsigned int b, unsigned int a)
|
|
{
|
|
u32 val;
|
|
|
|
val = RED(r) | GREEN(g) | BLUE(b) | ALPHA(a);
|
|
|
|
mutex_lock(&cf->mutex);
|
|
dpu_cf_write(cf, val, CONSTANTCOLOR);
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(constframe_constantcolor);
|
|
|
|
void constframe_controltrigger(struct dpu_constframe *cf, bool trigger)
|
|
{
|
|
u32 val;
|
|
|
|
val = trigger ? SHDTOKGEN : 0;
|
|
|
|
mutex_lock(&cf->mutex);
|
|
dpu_cf_write(cf, val, CONTROLTRIGGER);
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(constframe_controltrigger);
|
|
|
|
shadow_load_req_t constframe_to_shdldreq_t(struct dpu_constframe *cf)
|
|
{
|
|
shadow_load_req_t t = 0;
|
|
|
|
switch (cf->id) {
|
|
case 0:
|
|
t = SHLDREQID_CONSTFRAME0;
|
|
break;
|
|
case 1:
|
|
t = SHLDREQID_CONSTFRAME1;
|
|
break;
|
|
case 4:
|
|
t = SHLDREQID_CONSTFRAME4;
|
|
break;
|
|
case 5:
|
|
t = SHLDREQID_CONSTFRAME5;
|
|
break;
|
|
}
|
|
|
|
return t;
|
|
}
|
|
EXPORT_SYMBOL_GPL(constframe_to_shdldreq_t);
|
|
|
|
struct dpu_constframe *dpu_cf_get(struct dpu_soc *dpu, int id)
|
|
{
|
|
struct dpu_constframe *cf;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
|
|
if (cf_ids[i] == id)
|
|
break;
|
|
|
|
if (i == ARRAY_SIZE(cf_ids))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
cf = dpu->cf_priv[i];
|
|
|
|
mutex_lock(&cf->mutex);
|
|
|
|
if (cf->inuse) {
|
|
mutex_unlock(&cf->mutex);
|
|
return ERR_PTR(-EBUSY);
|
|
}
|
|
|
|
cf->inuse = true;
|
|
|
|
mutex_unlock(&cf->mutex);
|
|
|
|
return cf;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dpu_cf_get);
|
|
|
|
void dpu_cf_put(struct dpu_constframe *cf)
|
|
{
|
|
mutex_lock(&cf->mutex);
|
|
|
|
cf->inuse = false;
|
|
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(dpu_cf_put);
|
|
|
|
struct dpu_constframe *dpu_aux_cf_peek(struct dpu_constframe *cf)
|
|
{
|
|
unsigned int aux_id = cf->id ^ 1;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
|
|
if (cf_ids[i] == aux_id)
|
|
return cf->dpu->cf_priv[i];
|
|
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dpu_aux_cf_peek);
|
|
|
|
void _dpu_cf_init(struct dpu_soc *dpu, unsigned int id)
|
|
{
|
|
struct dpu_constframe *cf;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
|
|
if (cf_ids[i] == id)
|
|
break;
|
|
|
|
if (WARN_ON(i == ARRAY_SIZE(cf_ids)))
|
|
return;
|
|
|
|
cf = dpu->cf_priv[i];
|
|
|
|
constframe_shden(cf, true);
|
|
|
|
if (id == 4 || id == 5) {
|
|
mutex_lock(&cf->mutex);
|
|
dpu_cf_write(cf, safety_stream_cf_color, CONSTANTCOLOR);
|
|
mutex_unlock(&cf->mutex);
|
|
}
|
|
}
|
|
|
|
int dpu_cf_init(struct dpu_soc *dpu, unsigned int id,
|
|
unsigned long pec_base, unsigned long base)
|
|
{
|
|
struct dpu_constframe *cf;
|
|
int i;
|
|
|
|
cf = devm_kzalloc(dpu->dev, sizeof(*cf), GFP_KERNEL);
|
|
if (!cf)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
|
|
if (cf_ids[i] == id)
|
|
break;
|
|
|
|
dpu->cf_priv[i] = cf;
|
|
|
|
cf->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
|
|
if (!cf->pec_base)
|
|
return -ENOMEM;
|
|
|
|
cf->base = devm_ioremap(dpu->dev, base, SZ_32);
|
|
if (!cf->base)
|
|
return -ENOMEM;
|
|
|
|
cf->dpu = dpu;
|
|
cf->id = id;
|
|
cf->shdlreq = cf_shdlreqs[i];
|
|
|
|
mutex_init(&cf->mutex);
|
|
|
|
_dpu_cf_init(dpu, id);
|
|
|
|
return 0;
|
|
}
|