blob: e5521ba41bfc9dcfe5f20eb04ac12991e6759899 [file] [log] [blame]
/*
* Copyright (C) 2017 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/device.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <drm/drm_fourcc.h>
#include <video/imx-dcss.h>
#include "dcss-prv.h"
#define USE_CTXLD
#define DCSS_SCALER_CTRL 0x00
#define SCALER_EN BIT(0)
#define REPEAT_EN BIT(4)
#define SCALE2MEM_EN BIT(8)
#define MEM2OFIFO_EN BIT(12)
#define DCSS_SCALER_OFIFO_CTRL 0x04
#define OFIFO_LOW_THRES_POS 0
#define OFIFO_LOW_THRES_MASK GENMASK(9, 0)
#define OFIFO_HIGH_THRES_POS 16
#define OFIFO_HIGH_THRES_MASK GENMASK(25, 16)
#define UNDERRUN_DETECT_CLR BIT(26)
#define LOW_THRES_DETECT_CLR BIT(27)
#define HIGH_THRES_DETECT_CLR BIT(28)
#define UNDERRUN_DETECT_EN BIT(29)
#define LOW_THRES_DETECT_EN BIT(30)
#define HIGH_THRES_DETECT_EN BIT(31)
#define DCSS_SCALER_SDATA_CTRL 0x08
#define YUV_EN BIT(0)
#define RTRAM_8LINES BIT(1)
#define Y_UV_BYTE_SWAP BIT(4)
#define A2R10G10B10_FORMAT_POS 8
#define A2R10G10B10_FORMAT_MASK GENMASK(11, 8)
#define DCSS_SCALER_BIT_DEPTH 0x0C
#define LUM_BIT_DEPTH_POS 0
#define LUM_BIT_DEPTH_MASK GENMASK(1, 0)
#define CHR_BIT_DEPTH_POS 4
#define CHR_BIT_DEPTH_MASK GENMASK(5, 4)
#define DCSS_SCALER_SRC_FORMAT 0x10
#define DCSS_SCALER_DST_FORMAT 0x14
#define FORMAT_MASK GENMASK(1, 0)
#define DCSS_SCALER_SRC_LUM_RES 0x18
#define DCSS_SCALER_SRC_CHR_RES 0x1C
#define DCSS_SCALER_DST_LUM_RES 0x20
#define DCSS_SCALER_DST_CHR_RES 0x24
#define WIDTH_POS 0
#define WIDTH_MASK GENMASK(11, 0)
#define HEIGHT_POS 16
#define HEIGHT_MASK GENMASK(27, 16)
#define DCSS_SCALER_V_LUM_START 0x48
#define V_START_MASK GENMASK(15, 0)
#define DCSS_SCALER_V_LUM_INC 0x4C
#define V_INC_MASK GENMASK(15, 0)
#define DCSS_SCALER_H_LUM_START 0x50
#define H_START_MASK GENMASK(18, 0)
#define DCSS_SCALER_H_LUM_INC 0x54
#define H_INC_MASK GENMASK(15, 0)
#define DCSS_SCALER_V_CHR_START 0x58
#define DCSS_SCALER_V_CHR_INC 0x5C
#define DCSS_SCALER_H_CHR_START 0x60
#define DCSS_SCALER_H_CHR_INC 0x64
#define DCSS_SCALER_COEF_VLUM 0x80
#define DCSS_SCALER_COEF_HLUM 0x140
#define DCSS_SCALER_COEF_VCHR 0x200
#define DCSS_SCALER_COEF_HCHR 0x300
static struct dcss_debug_reg scaler_debug_reg[] = {
DCSS_DBG_REG(DCSS_SCALER_CTRL),
DCSS_DBG_REG(DCSS_SCALER_OFIFO_CTRL),
DCSS_DBG_REG(DCSS_SCALER_SDATA_CTRL),
DCSS_DBG_REG(DCSS_SCALER_BIT_DEPTH),
DCSS_DBG_REG(DCSS_SCALER_SRC_FORMAT),
DCSS_DBG_REG(DCSS_SCALER_DST_FORMAT),
DCSS_DBG_REG(DCSS_SCALER_SRC_LUM_RES),
DCSS_DBG_REG(DCSS_SCALER_SRC_CHR_RES),
DCSS_DBG_REG(DCSS_SCALER_DST_LUM_RES),
DCSS_DBG_REG(DCSS_SCALER_DST_CHR_RES),
DCSS_DBG_REG(DCSS_SCALER_V_LUM_START),
DCSS_DBG_REG(DCSS_SCALER_V_LUM_INC),
DCSS_DBG_REG(DCSS_SCALER_H_LUM_START),
DCSS_DBG_REG(DCSS_SCALER_H_LUM_INC),
DCSS_DBG_REG(DCSS_SCALER_V_CHR_START),
DCSS_DBG_REG(DCSS_SCALER_V_CHR_INC),
DCSS_DBG_REG(DCSS_SCALER_H_CHR_START),
DCSS_DBG_REG(DCSS_SCALER_H_CHR_INC),
};
struct dcss_scaler_ch {
void __iomem *base_reg;
u32 base_ofs;
u32 ctx_id;
u32 sdata_ctrl;
u32 scaler_ctrl;
u32 pix_format;
};
struct dcss_scaler_priv {
struct dcss_soc *dcss;
struct dcss_scaler_ch ch[3];
int ch_using_wrscl;
};
static void dcss_scaler_write(struct dcss_scaler_priv *scl, int ch_num,
u32 val, u32 ofs)
{
#if !defined(USE_CTXLD)
dcss_writel(val, scl->ch[ch_num].base_reg + ofs);
#else
dcss_ctxld_write(scl->dcss, scl->ch[ch_num].ctx_id,
val, scl->ch[ch_num].base_ofs + ofs);
#endif
}
#ifdef CONFIG_DEBUG_FS
void dcss_scaler_dump_regs(struct seq_file *s, void *data)
{
struct dcss_soc *dcss = data;
int i, j;
for (i = 0; i < 3; i++) {
seq_printf(s, ">> Dumping SCALER CH %d:\n", i);
for (j = 0; j < ARRAY_SIZE(scaler_debug_reg); j++) {
seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
scaler_debug_reg[j].name,
scaler_debug_reg[j].ofs,
dcss_readl(dcss->scaler_priv->ch[i].base_reg +
scaler_debug_reg[j].ofs));
}
}
}
#endif
static int dcss_scaler_ch_init_all(struct dcss_soc *dcss,
unsigned long scaler_base)
{
struct dcss_scaler_priv *scaler = dcss->scaler_priv;
struct dcss_scaler_ch *ch;
int i;
for (i = 0; i < 3; i++) {
ch = &scaler->ch[i];
ch->base_ofs = scaler_base + i * 0x400;
ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
if (!ch->base_reg) {
dev_err(dcss->dev, "scaler: unable to remap ch base\n");
return -ENOMEM;
}
#if defined(USE_CTXLD)
ch->ctx_id = CTX_SB_HP;
#endif
}
return 0;
}
int dcss_scaler_init(struct dcss_soc *dcss, unsigned long scaler_base)
{
struct dcss_scaler_priv *scaler;
scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL);
if (!scaler)
return -ENOMEM;
dcss->scaler_priv = scaler;
scaler->dcss = dcss;
scaler->ch_using_wrscl = -1;
return dcss_scaler_ch_init_all(dcss, scaler_base);
}
void dcss_scaler_exit(struct dcss_soc *dcss)
{
struct dcss_scaler_priv *scaler = dcss->scaler_priv;
int ch_no;
for (ch_no = 0; ch_no < 3; ch_no++) {
struct dcss_scaler_ch *ch = &scaler->ch[ch_no];
dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
}
}
void dcss_scaler_enable(struct dcss_soc *dcss, int ch_num, bool en)
{
struct dcss_scaler_priv *scaler = dcss->scaler_priv;
struct dcss_scaler_ch *ch = &scaler->ch[ch_num];
u32 scaler_ctrl;
if (scaler->ch_using_wrscl == ch_num) {
if (en) {
scaler_ctrl = SCALE2MEM_EN | MEM2OFIFO_EN | REPEAT_EN;
} else {
dcss_wrscl_enable(dcss, false);
dcss_rdsrc_enable(dcss, false);
scaler->ch_using_wrscl = -1;
scaler_ctrl = 0;
}
} else {
scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
}
if (en)
dcss_scaler_write(dcss->scaler_priv, ch_num, ch->sdata_ctrl,
DCSS_SCALER_SDATA_CTRL);
if (ch->scaler_ctrl != scaler_ctrl)
dcss_scaler_write(dcss->scaler_priv, ch_num, scaler_ctrl,
DCSS_SCALER_CTRL);
ch->scaler_ctrl = scaler_ctrl;
}
EXPORT_SYMBOL(dcss_scaler_enable);
static void dcss_scaler_yuv_enable(struct dcss_soc *dcss, int ch_num, bool en)
{
struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
ch->sdata_ctrl &= ~YUV_EN;
ch->sdata_ctrl |= en ? YUV_EN : 0;
}
static void dcss_scaler_rtr_8lines_enable(struct dcss_soc *dcss, int ch_num,
bool en)
{
struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
ch->sdata_ctrl &= ~RTRAM_8LINES;
ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
}
static void dcss_scaler_bit_depth_set(struct dcss_soc *dcss, int ch_num,
int depth)
{
u32 val;
val = depth == 30 ? 2 : 0;
dcss_scaler_write(dcss->scaler_priv, ch_num,
((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
DCSS_SCALER_BIT_DEPTH);
}
enum buffer_format {
BUF_FMT_YUV420,
BUF_FMT_YUV422,
BUF_FMT_ARGB8888_YUV444,
};
static void dcss_scaler_format_set(struct dcss_soc *dcss, int ch_num,
enum buffer_format src_fmt,
enum buffer_format dst_fmt)
{
dcss_scaler_write(dcss->scaler_priv, ch_num, src_fmt,
DCSS_SCALER_SRC_FORMAT);
dcss_scaler_write(dcss->scaler_priv, ch_num, dst_fmt,
DCSS_SCALER_DST_FORMAT);
}
static void dcss_scaler_res_set(struct dcss_soc *dcss, int ch_num,
int src_xres, int src_yres,
int dst_xres, int dst_yres,
u32 pix_format)
{
u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
lsrc_xres = csrc_xres = src_xres;
lsrc_yres = csrc_yres = src_yres;
ldst_xres = cdst_xres = dst_xres;
ldst_yres = cdst_yres = dst_yres;
if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU)
csrc_xres >>= 1;
else if (pix_format == DRM_FORMAT_NV12 ||
pix_format == DRM_FORMAT_NV21 ||
pix_format == DRM_FORMAT_P010) {
csrc_xres >>= 1;
csrc_yres >>= 1;
}
dcss_scaler_write(dcss->scaler_priv, ch_num,
(((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
(((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
DCSS_SCALER_SRC_LUM_RES);
dcss_scaler_write(dcss->scaler_priv, ch_num,
(((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
(((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
DCSS_SCALER_SRC_CHR_RES);
dcss_scaler_write(dcss->scaler_priv, ch_num,
(((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
(((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
DCSS_SCALER_DST_LUM_RES);
dcss_scaler_write(dcss->scaler_priv, ch_num,
(((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
(((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
DCSS_SCALER_DST_CHR_RES);
}
#define max_downscale(ratio) ((ratio) << 13)
#define max_upscale(ratio) ((1 << 13) / (ratio))
struct dcss_scaler_ratios {
u16 downscale;
u16 upscale;
};
static const struct dcss_scaler_ratios dcss_scaler_ratios[] = {
{max_downscale(3), max_upscale(5)},
{max_downscale(5), max_upscale(7)},
{max_downscale(5), max_upscale(7)},
};
static const struct dcss_scaler_ratios dcss_scaler_wrscl_ratios[] = {
{max_downscale(5), max_upscale(5)},
{max_downscale(7), max_upscale(7)},
{max_downscale(7), max_upscale(7)},
};
static bool dcss_scaler_fractions_set(struct dcss_soc *dcss, int ch_num,
int src_xres, int src_yres,
int dst_xres, int dst_yres,
u32 pix_format)
{
u32 l_vinc, l_hinc, c_vinc, c_hinc;
l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
c_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
c_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
c_hinc >>= 1;
} else if (pix_format == DRM_FORMAT_NV12 ||
pix_format == DRM_FORMAT_NV21 ||
pix_format == DRM_FORMAT_P010) {
c_hinc >>= 1;
c_vinc >>= 1;
}
dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
DCSS_SCALER_V_LUM_START);
dcss_scaler_write(dcss->scaler_priv, ch_num, l_vinc,
DCSS_SCALER_V_LUM_INC);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
DCSS_SCALER_H_LUM_START);
dcss_scaler_write(dcss->scaler_priv, ch_num, l_hinc,
DCSS_SCALER_H_LUM_INC);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
DCSS_SCALER_V_CHR_START);
dcss_scaler_write(dcss->scaler_priv, ch_num, c_vinc,
DCSS_SCALER_V_CHR_INC);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
DCSS_SCALER_H_CHR_START);
dcss_scaler_write(dcss->scaler_priv, ch_num, c_hinc,
DCSS_SCALER_H_CHR_INC);
/* return if WR_SCL is needed to scale */
return l_vinc > dcss_scaler_ratios[ch_num].downscale ||
l_vinc < dcss_scaler_ratios[ch_num].upscale ||
l_hinc > dcss_scaler_ratios[ch_num].downscale ||
l_hinc < dcss_scaler_ratios[ch_num].upscale;
}
bool dcss_scaler_can_scale(struct dcss_soc *dcss, int ch_num,
int src_xres, int src_yres,
int dst_xres, int dst_yres)
{
struct dcss_scaler_priv *scaler = dcss->scaler_priv;
u32 vscale_fp, hscale_fp;
const struct dcss_scaler_ratios *ratios_map = dcss_scaler_ratios;
/* Convert to fixed point. Easier to work with. */
vscale_fp = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
hscale_fp = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
if (scaler->ch_using_wrscl == -1 || scaler->ch_using_wrscl == ch_num)
ratios_map = dcss_scaler_wrscl_ratios;
return vscale_fp <= ratios_map[ch_num].downscale &&
vscale_fp >= ratios_map[ch_num].upscale &&
hscale_fp <= ratios_map[ch_num].downscale &&
hscale_fp >= ratios_map[ch_num].upscale;
}
EXPORT_SYMBOL(dcss_scaler_can_scale);
static void dcss_scaler_coef_clr(struct dcss_soc *dcss, int ch_num)
{
int i;
for (i = 0; i < 48; i++) {
dcss_scaler_write(dcss->scaler_priv, ch_num,
0, DCSS_SCALER_COEF_VLUM + i * 4);
dcss_scaler_write(dcss->scaler_priv, ch_num,
0, DCSS_SCALER_COEF_HLUM + i * 4);
dcss_scaler_write(dcss->scaler_priv, ch_num,
0, DCSS_SCALER_COEF_VCHR + i * 4);
dcss_scaler_write(dcss->scaler_priv, ch_num,
0, DCSS_SCALER_COEF_HCHR + i * 4);
}
}
static void dcss_scaler_rgb_coef_set(struct dcss_soc *dcss, int ch_num)
{
int i;
dcss_scaler_coef_clr(dcss, ch_num);
for (i = 0; i < 16; i++) {
u32 ofs = (16 + i) * sizeof(u32);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
DCSS_SCALER_COEF_VLUM + ofs);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
DCSS_SCALER_COEF_HLUM + ofs);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
DCSS_SCALER_COEF_VCHR + ofs);
dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
DCSS_SCALER_COEF_HCHR + ofs);
}
}
static u32 dcss_scaler_yuv_coef[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040300, 0x05532208,
0x0413120a, 0x0312f80d, 0x0242d310, 0x01a2a614, 0x01327117, 0x00d2361b,
0x0091f81f, 0x0b923600, 0x07b27101, 0x0402a601, 0x00a2d302, 0x0da2f803,
0x0af31204, 0x08b32205, 0x00000000, 0x0b000000, 0x0f001000, 0x0a001000,
0x0a002000, 0x00003000, 0x0b004000, 0x09006000, 0x08009000, 0x0d000000,
0x03000000, 0x0a000000, 0x04000000, 0x01000000, 0x01000000, 0x05000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040000, 0x05432008,
0x0403100a, 0x0302f50d, 0x0242d110, 0x01a2a413, 0x01326f17, 0x00d2351b,
0x0091f71f, 0x0b823500, 0x07a26f01, 0x03f2a401, 0x0092d102, 0x0d92f503,
0x0af31004, 0x08b32005, 0x00000000, 0x0b000000, 0x0f001000, 0x09001000,
0x09002000, 0x0f003000, 0x0a004000, 0x08006000, 0x07009000, 0x0d000000,
0x03000000, 0x0a000000, 0x04000000, 0x00000000, 0x00000000, 0x04000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040300, 0x05532208,
0x0413120a, 0x0312f80d, 0x0242d310, 0x01a2a614, 0x01327117, 0x00d2361b,
0x0091f81f, 0x0b923600, 0x07b27101, 0x0402a601, 0x00a2d302, 0x0da2f803,
0x0af31204, 0x08b32205, 0x00000000, 0x0b000000, 0x0f001000, 0x0a001000,
0x0a002000, 0x00003000, 0x0b004000, 0x09006000, 0x08009000, 0x0d000000,
0x03000000, 0x0a000000, 0x04000000, 0x01000000, 0x01000000, 0x05000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040000, 0x05432008,
0x0403100a, 0x0302f50d, 0x0242d110, 0x01a2a413, 0x01326f17, 0x00d2351b,
0x0091f71f, 0x0b823500, 0x07a26f01, 0x03f2a401, 0x0092d102, 0x0d92f503,
0x0af31004, 0x08b32005, 0x00000000, 0x0b000000, 0x0f001000, 0x09001000,
0x09002000, 0x0f003000, 0x0a004000, 0x08006000, 0x07009000, 0x0d000000,
0x03000000, 0x0a000000, 0x04000000, 0x00000000, 0x00000000, 0x04000000,
};
static void dcss_scaler_yuv_coef_set(struct dcss_soc *dcss, int ch_num)
{
int i;
for (i = 0; i < 48; i++) {
dcss_scaler_write(dcss->scaler_priv, ch_num,
dcss_scaler_yuv_coef[i],
DCSS_SCALER_COEF_VLUM + i * sizeof(u32));
dcss_scaler_write(dcss->scaler_priv, ch_num,
dcss_scaler_yuv_coef[48 + i],
DCSS_SCALER_COEF_HLUM + i * sizeof(u32));
dcss_scaler_write(dcss->scaler_priv, ch_num,
dcss_scaler_yuv_coef[2 * 48 + i],
DCSS_SCALER_COEF_VCHR + i * sizeof(u32));
dcss_scaler_write(dcss->scaler_priv, ch_num,
dcss_scaler_yuv_coef[3 * 48 + i],
DCSS_SCALER_COEF_HCHR + i * sizeof(u32));
}
}
static void dcss_scaler_set_rgb10_order(struct dcss_soc *dcss, int ch_num,
u32 pix_format)
{
struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
enum dcss_color_space dcss_cs;
unsigned int pixel_depth;
int bpp;
u32 a2r10g10b10_format;
dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
if (dcss_cs != DCSS_COLORSPACE_RGB)
return;
drm_fb_get_bpp_depth(pix_format, &pixel_depth, &bpp);
ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
if (pixel_depth != 30)
return;
switch (pix_format) {
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_XRGB2101010:
a2r10g10b10_format = 0;
break;
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_XBGR2101010:
a2r10g10b10_format = 5;
break;
case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_RGBX1010102:
a2r10g10b10_format = 6;
break;
case DRM_FORMAT_BGRA1010102:
case DRM_FORMAT_BGRX1010102:
a2r10g10b10_format = 11;
break;
default:
a2r10g10b10_format = 0;
break;
}
ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
}
static void dcss_scaler_setup_path(struct dcss_soc *dcss, int ch_num,
u32 pix_format, int dst_xres,
int dst_yres, u32 vrefresh_hz,
bool wrscl_needed)
{
struct dcss_scaler_priv *scaler = dcss->scaler_priv;
u32 base_addr;
/* nothing to do if WRSCL path is needed but it's already used */
if (wrscl_needed && scaler->ch_using_wrscl != -1 &&
scaler->ch_using_wrscl != ch_num)
return;
if (!wrscl_needed) {
/* Channel has finished using WRSCL. Release WRSCL/RDSRC. */
if (scaler->ch_using_wrscl == ch_num) {
dcss_wrscl_enable(dcss, false);
dcss_rdsrc_enable(dcss, false);
scaler->ch_using_wrscl = -1;
}
return;
}
base_addr = dcss_wrscl_setup(dcss, pix_format, vrefresh_hz,
dst_xres, dst_yres);
dcss_rdsrc_setup(dcss, pix_format, dst_xres, dst_yres,
base_addr);
dcss_wrscl_enable(dcss, true);
dcss_rdsrc_enable(dcss, true);
scaler->ch_using_wrscl = ch_num;
}
void dcss_scaler_setup(struct dcss_soc *dcss, int ch_num, u32 pix_format,
int src_xres, int src_yres, int dst_xres, int dst_yres,
u32 vrefresh_hz)
{
struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
enum dcss_color_space dcss_cs;
int planes;
unsigned int pixel_depth;
bool rtr_8line_en = false;
u32 bpp;
enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
bool wrscl_needed = false;
dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
planes = drm_format_num_planes(pix_format);
if (dcss_cs == DCSS_COLORSPACE_YUV) {
dcss_scaler_yuv_enable(dcss, ch_num, true);
if (pix_format == DRM_FORMAT_NV12 ||
pix_format == DRM_FORMAT_NV21 ||
pix_format == DRM_FORMAT_P010) {
rtr_8line_en = true;
src_format = BUF_FMT_YUV420;
} else if (pix_format == DRM_FORMAT_UYVY ||
pix_format == DRM_FORMAT_VYUY ||
pix_format == DRM_FORMAT_YUYV ||
pix_format == DRM_FORMAT_YVYU) {
src_format = BUF_FMT_YUV422;
}
if (pix_format != ch->pix_format)
dcss_scaler_yuv_coef_set(dcss, ch_num);
if (pix_format == DRM_FORMAT_P010)
pixel_depth = 30;
} else if (dcss_cs == DCSS_COLORSPACE_RGB) {
dcss_scaler_yuv_enable(dcss, ch_num, false);
drm_fb_get_bpp_depth(pix_format, &pixel_depth, &bpp);
if (pix_format != ch->pix_format)
dcss_scaler_rgb_coef_set(dcss, ch_num);
}
dcss_scaler_rtr_8lines_enable(dcss, ch_num, rtr_8line_en);
dcss_scaler_bit_depth_set(dcss, ch_num, pixel_depth);
dcss_scaler_set_rgb10_order(dcss, ch_num, pix_format);
dcss_scaler_format_set(dcss, ch_num, src_format, dst_format);
dcss_scaler_res_set(dcss, ch_num, src_xres, src_yres,
dst_xres, dst_yres, pix_format);
wrscl_needed = dcss_scaler_fractions_set(dcss, ch_num, src_xres,
src_yres, dst_xres,
dst_yres, pix_format);
dcss_scaler_setup_path(dcss, ch_num, pix_format, dst_xres,
dst_yres, vrefresh_hz, wrscl_needed);
ch->pix_format = pix_format;
}
EXPORT_SYMBOL(dcss_scaler_setup);