blob: b482b2e75e7f6368f208e1b921a38973924aa231 [file] [log] [blame]
/*
* Copyright 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 <video/dpu.h>
#include "dpu-prv.h"
#define BASEADDRESS(n) (0x10 + (n) * 0x28)
#define SOURCEBUFFERATTRIBUTES(n) (0x14 + (n) * 0x28)
#define SOURCEBUFFERDIMENSION(n) (0x18 + (n) * 0x28)
#define COLORCOMPONENTBITS(n) (0x1C + (n) * 0x28)
#define COLORCOMPONENTSHIFT(n) (0x20 + (n) * 0x28)
#define LAYEROFFSET(n) (0x24 + (n) * 0x28)
#define CLIPWINDOWOFFSET(n) (0x28 + (n) * 0x28)
#define CLIPWINDOWDIMENSIONS(n) (0x2C + (n) * 0x28)
#define CONSTANTCOLOR(n) (0x30 + (n) * 0x28)
#define LAYERPROPERTY(n) (0x34 + (n) * 0x28)
void fetchunit_get_dprc(struct dpu_fetchunit *fu, void *data)
{
if (WARN_ON(!fu))
return;
fu->dprc = data;
}
EXPORT_SYMBOL_GPL(fetchunit_get_dprc);
void fetchunit_shden(struct dpu_fetchunit *fu, bool enable)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, STATICCONTROL);
if (enable)
val |= SHDEN;
else
val &= ~SHDEN;
dpu_fu_write(fu, val, STATICCONTROL);
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_shden);
void fetchunit_baddr_autoupdate(struct dpu_fetchunit *fu, u8 layer_mask)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, STATICCONTROL);
val &= ~BASEADDRESSAUTOUPDATE_MASK;
val |= BASEADDRESSAUTOUPDATE(layer_mask);
dpu_fu_write(fu, val, STATICCONTROL);
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_baddr_autoupdate);
void fetchunit_shdldreq_sticky(struct dpu_fetchunit *fu, u8 layer_mask)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, STATICCONTROL);
val &= ~SHDLDREQSTICKY_MASK;
val |= SHDLDREQSTICKY(layer_mask);
dpu_fu_write(fu, val, STATICCONTROL);
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_shdldreq_sticky);
void fetchunit_set_burstlength(struct dpu_fetchunit *fu,
unsigned int x_offset, unsigned int mt_w,
int bpp, dma_addr_t baddr, bool use_prefetch)
{
struct dpu_soc *dpu = fu->dpu;
unsigned int burst_size, burst_length;
bool nonzero_mod = !!mt_w;
u32 val;
if (use_prefetch) {
/* consider PRG x offset to calculate buffer address */
if (nonzero_mod)
baddr += (x_offset % mt_w) * (bpp / 8);
/*
* address TKT343664:
* fetch unit base address has to align to burst size
*/
burst_size = 1 << (ffs(baddr) - 1);
burst_size = round_up(burst_size, 8);
burst_size = min(burst_size, 128U);
burst_length = burst_size / 8;
} else {
burst_length = 16;
}
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, BURSTBUFFERMANAGEMENT);
val &= ~SETBURSTLENGTH_MASK;
val |= SETBURSTLENGTH(burst_length);
dpu_fu_write(fu, val, BURSTBUFFERMANAGEMENT);
mutex_unlock(&fu->mutex);
dev_dbg(dpu->dev, "%s%d burst length is %u\n",
fu->name, fu->id, burst_length);
}
EXPORT_SYMBOL_GPL(fetchunit_set_burstlength);
void fetchunit_set_baseaddress(struct dpu_fetchunit *fu, unsigned int width,
unsigned int x_offset, unsigned int y_offset,
unsigned int mt_w, unsigned int mt_h,
int bpp, dma_addr_t baddr)
{
unsigned int burst_size, stride;
bool nonzero_mod = !!mt_w;
if (nonzero_mod) {
/* consider PRG x offset to calculate buffer address */
baddr += (x_offset % mt_w) * (bpp / 8);
/*
* address TKT343664:
* fetch unit base address has to align to burst size
*/
burst_size = 1 << (ffs(baddr) - 1);
burst_size = round_up(burst_size, 8);
burst_size = min(burst_size, 128U);
stride = width * (bpp >> 3);
/*
* address TKT339017:
* fixup for burst size vs stride mismatch
*/
stride = round_up(stride + round_up(baddr % 8, 8), burst_size);
/* consider PRG y offset to calculate buffer address */
baddr += (y_offset % mt_h) * stride;
}
mutex_lock(&fu->mutex);
dpu_fu_write(fu, baddr, BASEADDRESS(fu->sub_id));
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_set_baseaddress);
void fetchunit_set_src_bpp(struct dpu_fetchunit *fu, int bpp)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id));
val &= ~0x3f0000;
val |= BITSPERPIXEL(bpp);
dpu_fu_write(fu, val, SOURCEBUFFERATTRIBUTES(fu->sub_id));
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_set_src_bpp);
/*
* The arguments width and bpp are valid only when use_prefetch is true.
* For fetcheco, since the pixel format has to be NV12 or NV21 when
* use_prefetch is true, we assume width stands for how many UV we have
* in bytes for one line, while bpp should be 8bits for every U or V component.
*/
void fetchunit_set_src_stride(struct dpu_fetchunit *fu,
unsigned int width, unsigned int x_offset,
unsigned int mt_w, int bpp, unsigned int stride,
dma_addr_t baddr, bool use_prefetch)
{
unsigned int burst_size;
bool nonzero_mod = !!mt_w;
u32 val;
if (use_prefetch) {
/* consider PRG x offset to calculate buffer address */
if (nonzero_mod)
baddr += (x_offset % mt_w) * (bpp / 8);
/*
* address TKT343664:
* fetch unit base address has to align to burst size
*/
burst_size = 1 << (ffs(baddr) - 1);
burst_size = round_up(burst_size, 8);
burst_size = min(burst_size, 128U);
stride = width * (bpp >> 3);
/*
* address TKT339017:
* fixup for burst size vs stride mismatch
*/
if (nonzero_mod)
stride = round_up(stride + round_up(baddr % 8, 8),
burst_size);
else
stride = round_up(stride, burst_size);
}
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id));
val &= ~0xffff;
val |= STRIDE(stride);
dpu_fu_write(fu, val, SOURCEBUFFERATTRIBUTES(fu->sub_id));
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_set_src_stride);
void fetchunit_enable_src_buf(struct dpu_fetchunit *fu)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
val |= SOURCEBUFFERENABLE;
dpu_fu_write(fu, val, LAYERPROPERTY(fu->sub_id));
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_enable_src_buf);
void fetchunit_disable_src_buf(struct dpu_fetchunit *fu)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
val &= ~SOURCEBUFFERENABLE;
dpu_fu_write(fu, val, LAYERPROPERTY(fu->sub_id));
mutex_unlock(&fu->mutex);
}
EXPORT_SYMBOL_GPL(fetchunit_disable_src_buf);
bool fetchunit_is_enabled(struct dpu_fetchunit *fu)
{
u32 val;
mutex_lock(&fu->mutex);
val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
mutex_unlock(&fu->mutex);
return !!(val & SOURCEBUFFERENABLE);
}
EXPORT_SYMBOL_GPL(fetchunit_is_enabled);
unsigned int fetchunit_get_stream_id(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return DPU_PLANE_SRC_DISABLED;
return fu->stream_id;
}
EXPORT_SYMBOL_GPL(fetchunit_get_stream_id);
void fetchunit_set_stream_id(struct dpu_fetchunit *fu, unsigned int id)
{
if (WARN_ON(!fu))
return;
switch (id) {
case DPU_PLANE_SRC_TO_DISP_STREAM0:
case DPU_PLANE_SRC_TO_DISP_STREAM1:
case DPU_PLANE_SRC_DISABLED:
fu->stream_id = id;
break;
default:
WARN_ON(1);
}
}
EXPORT_SYMBOL_GPL(fetchunit_set_stream_id);
void fetchunit_pin_off(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return;
fu->pin_off = true;
}
EXPORT_SYMBOL_GPL(fetchunit_pin_off);
void fetchunit_unpin_off(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return;
fu->pin_off = false;
}
EXPORT_SYMBOL_GPL(fetchunit_unpin_off);
bool fetchunit_is_pinned_off(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return false;
return fu->pin_off;
}
EXPORT_SYMBOL_GPL(fetchunit_is_pinned_off);
bool fetchunit_is_fetchdecode(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return false;
return fu->type == FU_T_FD;
}
EXPORT_SYMBOL_GPL(fetchunit_is_fetchdecode);
bool fetchunit_is_fetcheco(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return false;
return fu->type == FU_T_FE;
}
EXPORT_SYMBOL_GPL(fetchunit_is_fetcheco);
bool fetchunit_is_fetchlayer(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return false;
return fu->type == FU_T_FL;
}
EXPORT_SYMBOL_GPL(fetchunit_is_fetchlayer);
bool fetchunit_is_fetchwarp(struct dpu_fetchunit *fu)
{
if (WARN_ON(!fu))
return false;
return fu->type == FU_T_FW;
}
EXPORT_SYMBOL_GPL(fetchunit_is_fetchwarp);