blob: 7dad29acf2e1d2db0f5e823980640a271c8b0c21 [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/io.h>
#include <linux/firmware.h>
#include <drm/drm_fourcc.h>
#include <video/imx-dcss.h>
#include "dcss-prv.h"
#define USE_TBL_HEADER
#ifdef USE_TBL_HEADER
#include "dcss-hdr10-tables.h"
#endif
#define USE_CTXLD
#define DCSS_HDR10_A0_LUT 0x0000
#define DCSS_HDR10_A1_LUT 0x1000
#define DCSS_HDR10_A2_LUT 0x2000
/* one CSCA and CSCB for each channel(pipe) */
#define DCSS_HDR10_CSCA_BASE 0x3000
#define DCSS_HDR10_CSCB_BASE 0x3800
/* one CSCO for all channels(pipes) */
#define DCSS_HDR10_CSCO_BASE 0x3000
#define DCSS_HDR10_LUT_CONTROL (DCSS_HDR10_CSCA_BASE + 0x80)
#define LUT_ENABLE BIT(0)
#define LUT_EN_FOR_ALL_PELS BIT(1)
#define LUT_BYPASS BIT(15)
#define DCSS_HDR10_FL2FX (DCSS_HDR10_CSCB_BASE + 0x74)
#define DCSS_HDR10_LTNL (DCSS_HDR10_CSCO_BASE + 0x74)
#define LTNL_PASS_THRU BIT(0)
#define FIX2FLT_DISABLE BIT(1)
#define LTNL_EN_FOR_ALL_PELS BIT(2)
#define FIX2FLT_EN_FOR_ALL_PELS BIT(3)
/* following offsets are relative to CSC(A|B|O)_BASE */
#define DCSS_HDR10_CSC_CONTROL 0x00
#define CSC_EN BIT(0)
#define CSC_ALL_PIX_EN BIT(1)
#define CSC_BYPASS BIT(15)
#define DCSS_HDR10_CSC_H00 0x04
#define DCSS_HDR10_CSC_H10 0x08
#define DCSS_HDR10_CSC_H20 0x0C
#define DCSS_HDR10_CSC_H01 0x10
#define DCSS_HDR10_CSC_H11 0x14
#define DCSS_HDR10_CSC_H21 0x18
#define DCSS_HDR10_CSC_H02 0x1C
#define DCSS_HDR10_CSC_H12 0x20
#define DCSS_HDR10_CSC_H22 0x24
#define H_COEF_MASK GENMASK(15, 0)
#define DCSS_HDR10_CSC_IO0 0x28
#define DCSS_HDR10_CSC_IO1 0x2C
#define DCSS_HDR10_CSC_IO2 0x30
#define PRE_OFFSET_MASK GENMASK(9, 0)
#define DCSS_HDR10_CSC_IO_MIN0 0x34
#define DCSS_HDR10_CSC_IO_MIN1 0x38
#define DCSS_HDR10_CSC_IO_MIN2 0x3C
#define DCSS_HDR10_CSC_IO_MAX0 0x40
#define DCSS_HDR10_CSC_IO_MAX1 0x44
#define DCSS_HDR10_CSC_IO_MAX2 0x48
#define IO_CLIP_MASK GENMASK(9, 0)
#define DCSS_HDR10_CSC_NORM 0x4C
#define NORM_MASK GENMASK(4, 0)
#define DCSS_HDR10_CSC_OO0 0x50
#define DCSS_HDR10_CSC_OO1 0x54
#define DCSS_HDR10_CSC_OO2 0x58
#define POST_OFFSET_MASK GENMASK(27, 0)
#define DCSS_HDR10_CSC_OMIN0 0x5C
#define DCSS_HDR10_CSC_OMIN1 0x60
#define DCSS_HDR10_CSC_OMIN2 0x64
#define DCSS_HDR10_CSC_OMAX0 0x68
#define DCSS_HDR10_CSC_OMAX1 0x6C
#define DCSS_HDR10_CSC_OMAX2 0x70
#define POST_CLIP_MASK GENMASK(9, 0)
#define HDR10_IPIPE_LUT_MAX_ENTRIES 1024
#define HDR10_OPIPE_LUT_MAX_ENTRIES 1023
#define HDR10_CSC_MAX_REGS 29
#define OPIPE_CH_NO 3
/* Pipe config descriptor */
/* bits per component */
#define HDR10_BPC_POS 0
#define HDR10_BPC_MASK GENMASK(1, 0)
/* colorspace */
#define HDR10_CS_POS 2
#define HDR10_CS_MASK GENMASK(3, 2)
/* nonlinearity type */
#define HDR10_NL_POS 4
#define HDR10_NL_MASK GENMASK(8, 4)
/* pixel range */
#define HDR10_PR_POS 9
#define HDR10_PR_MASK GENMASK(10, 9)
/* gamut type */
#define HDR10_G_POS 11
#define HDR10_G_MASK GENMASK(15, 11)
/* FW Table Descriptor */
#define HDR10_TT_LUT BIT(0)
#define HDR10_TT_CSCA BIT(1)
#define HDR10_TT_CSCB BIT(2)
/* Pipe type */
#define HDR10_PT_OUTPUT BIT(3)
/* Output pipe config descriptor */
#define HDR10_IPIPE_DESC_POS 4
#define HDR10_IPIPE_DESC_MASK GENMASK(19, 4)
/* Input pipe config descriptor */
#define HDR10_OPIPE_DESC_POS 20
#define HDR10_OPIPE_DESC_MASK GENMASK(35, 20)
/* config invalid */
#define HDR10_DESC_INVALID BIT(63)
enum dcss_hdr10_csc {
HDR10_CSCA,
HDR10_CSCB,
};
struct dcss_hdr10_tbl_node {
u64 tbl_descriptor;
u32 *tbl_data;
struct list_head node;
};
struct dcss_hdr10_opipe_tbls {
struct list_head lut;
struct list_head csc;
};
struct dcss_hdr10_ipipe_tbls {
struct list_head lut;
struct list_head csca;
struct list_head cscb;
};
struct dcss_hdr10_ch {
void __iomem *base_reg;
u32 base_ofs;
u32 ctx_id;
u64 old_cfg_desc;
};
struct dcss_hdr10_priv {
struct dcss_soc *dcss;
struct dcss_hdr10_ch ch[4]; /* 4th channel is, actually, OPIPE */
struct dcss_hdr10_ipipe_tbls *ipipe_tbls;
struct dcss_hdr10_opipe_tbls *opipe_tbls;
u8 *fw_data;
u32 fw_size;
};
static struct dcss_debug_reg hdr10_debug_reg[] = {
DCSS_DBG_REG(DCSS_HDR10_CSC_CONTROL),
DCSS_DBG_REG(DCSS_HDR10_CSC_H00),
DCSS_DBG_REG(DCSS_HDR10_CSC_H10),
DCSS_DBG_REG(DCSS_HDR10_CSC_H20),
DCSS_DBG_REG(DCSS_HDR10_CSC_H01),
DCSS_DBG_REG(DCSS_HDR10_CSC_H11),
DCSS_DBG_REG(DCSS_HDR10_CSC_H21),
DCSS_DBG_REG(DCSS_HDR10_CSC_H02),
DCSS_DBG_REG(DCSS_HDR10_CSC_H12),
DCSS_DBG_REG(DCSS_HDR10_CSC_H22),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO0),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO1),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO2),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN0),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN1),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN2),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX0),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX1),
DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX2),
DCSS_DBG_REG(DCSS_HDR10_CSC_NORM),
DCSS_DBG_REG(DCSS_HDR10_CSC_OO0),
DCSS_DBG_REG(DCSS_HDR10_CSC_OO1),
DCSS_DBG_REG(DCSS_HDR10_CSC_OO2),
DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN0),
DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN1),
DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN2),
DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX0),
DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX1),
DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX2),
};
static void dcss_hdr10_write(struct dcss_soc *dcss, u32 ch_num,
u32 val, u32 ofs)
{
struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
#if !defined(USE_CTXLD)
dcss_writel(val, hdr10->ch[ch_num].base_reg + ofs);
#else
dcss_ctxld_write(dcss, hdr10->ch[ch_num].ctx_id, val,
hdr10->ch[ch_num].base_ofs + ofs);
#endif
}
#ifdef CONFIG_DEBUG_FS
void dcss_hdr10_dump_regs(struct seq_file *s, void *data)
{
struct dcss_soc *dcss = data;
int ch, csc, r;
int csc_no;
for (ch = 0; ch < 4; ch++) {
void __iomem *csc_base = dcss->hdr10_priv->ch[ch].base_reg +
DCSS_HDR10_CSCA_BASE;
if (ch < 3) {
seq_printf(s, ">> Dumping HDR10 CH %d:\n", ch);
csc_no = 2;
} else {
seq_puts(s, ">> Dumping HDR10 OPIPE:\n");
csc_no = 1;
}
for (csc = 0; csc < csc_no; csc++) {
csc_base += csc * 0x800;
if (ch < 3)
seq_printf(s, "\t>> Dumping CSC%s of CH %d:\n",
csc ? "B" : "A", ch);
else
seq_puts(s, "\t>> Dumping CSC of OPIPE:\n");
for (r = 0; r < ARRAY_SIZE(hdr10_debug_reg); r++)
seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
hdr10_debug_reg[r].name,
hdr10_debug_reg[r].ofs,
dcss_readl(csc_base +
hdr10_debug_reg[r].ofs));
if (csc == 0 && ch != 3)
seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
"DCSS_HDR10_LUT_CONTROL",
0x80, dcss_readl(csc_base + 0x80));
if (csc == 1 || ch == 3)
seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
ch == 3 ? "DCSS_HDR10_LTNL" :
"DCSS_HDR10_FL2FX",
0x74, dcss_readl(csc_base + 0x74));
}
}
}
#endif
static void dcss_hdr10_csc_fill(struct dcss_soc *dcss, int ch_num,
enum dcss_hdr10_csc csc_to_use,
u32 *map)
{
int i;
u32 csc_base_ofs[] = {
DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_CONTROL,
DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_CONTROL,
};
for (i = 0; i < HDR10_CSC_MAX_REGS; i++) {
u32 reg_ofs = csc_base_ofs[csc_to_use] + i * sizeof(u32);
dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
}
}
static void dcss_hdr10_lut_fill(struct dcss_soc *dcss, int ch_num, u32 *map)
{
int i, comp;
u32 lut_base_ofs, ctrl_ofs, lut_entries;
if (ch_num == OPIPE_CH_NO) {
ctrl_ofs = DCSS_HDR10_LTNL;
lut_entries = HDR10_OPIPE_LUT_MAX_ENTRIES;
} else {
ctrl_ofs = DCSS_HDR10_LUT_CONTROL;
lut_entries = HDR10_IPIPE_LUT_MAX_ENTRIES;
}
if (ch_num != OPIPE_CH_NO)
dcss_hdr10_write(dcss, ch_num, *map++, ctrl_ofs);
for (comp = 0; comp < 3; comp++) {
lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
if (ch_num == OPIPE_CH_NO) {
dcss_hdr10_write(dcss, ch_num, map[0], lut_base_ofs);
lut_base_ofs += 4;
}
for (i = 0; i < lut_entries; i++) {
u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
}
}
map += lut_entries;
if (ch_num != OPIPE_CH_NO)
dcss_hdr10_write(dcss, ch_num, *map, DCSS_HDR10_FL2FX);
else
dcss_hdr10_write(dcss, ch_num, *map, ctrl_ofs);
}
static int dcss_hdr10_ch_init_all(struct dcss_soc *dcss,
unsigned long hdr10_base)
{
struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
struct dcss_hdr10_ch *ch;
int i;
for (i = 0; i < 4; i++) {
ch = &hdr10->ch[i];
ch->base_ofs = hdr10_base + i * 0x4000;
ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_16K);
if (!ch->base_reg) {
dev_err(dcss->dev, "hdr10: unable to remap ch base\n");
return -ENOMEM;
}
ch->old_cfg_desc = HDR10_DESC_INVALID;
#if defined(USE_CTXLD)
ch->ctx_id = CTX_SB_HP;
#endif
}
return 0;
}
static u32 *dcss_hdr10_find_tbl(u64 desc, struct list_head *head)
{
struct list_head *node;
struct dcss_hdr10_tbl_node *tbl_node;
list_for_each(node, head) {
tbl_node = container_of(node, struct dcss_hdr10_tbl_node, node);
if ((tbl_node->tbl_descriptor & desc) == desc)
return tbl_node->tbl_data;
}
return NULL;
}
static int dcss_hdr10_get_tbls(struct dcss_hdr10_priv *hdr10, bool input,
u64 desc, u32 **lut, u32 **csca, u32 **cscb)
{
struct list_head *lut_list, *csca_list, *cscb_list;
lut_list = input ? &hdr10->ipipe_tbls->lut : &hdr10->opipe_tbls->lut;
csca_list = input ? &hdr10->ipipe_tbls->csca : &hdr10->opipe_tbls->csc;
cscb_list = input ? &hdr10->ipipe_tbls->cscb : NULL;
*lut = dcss_hdr10_find_tbl(desc, lut_list);
*csca = dcss_hdr10_find_tbl(desc, csca_list);
*cscb = NULL;
if (cscb_list)
*cscb = dcss_hdr10_find_tbl(desc, cscb_list);
return 0;
}
static void dcss_hdr10_write_pipe_tbls(struct dcss_soc *dcss, int ch_num,
u32 *lut, u32 *csca, u32 *cscb)
{
if (csca)
dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCA, csca);
if (ch_num != OPIPE_CH_NO && cscb)
dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCB, cscb);
if (lut)
dcss_hdr10_lut_fill(dcss, ch_num, lut);
}
static void dcss_hdr10_tbl_add(struct dcss_hdr10_priv *hdr10, u64 desc, u32 sz,
u32 *data)
{
struct device *dev = hdr10->dcss->dev;
struct dcss_hdr10_tbl_node *node;
node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
if (!node) {
dev_err(dev, "hdr10: cannot alloc memory for table node.\n");
return;
}
/* we don't need to store the table type and pipe type */
node->tbl_descriptor = desc >> 4;
node->tbl_data = data;
if (!(desc & HDR10_PT_OUTPUT)) {
if (desc & HDR10_TT_LUT)
list_add(&node->node, &hdr10->ipipe_tbls->lut);
else if (desc & HDR10_TT_CSCA)
list_add(&node->node, &hdr10->ipipe_tbls->csca);
else if (desc & HDR10_TT_CSCB)
list_add(&node->node, &hdr10->ipipe_tbls->cscb);
return;
}
if (desc & HDR10_TT_LUT)
list_add(&node->node, &hdr10->opipe_tbls->lut);
else if (desc & HDR10_TT_CSCA)
list_add(&node->node, &hdr10->opipe_tbls->csc);
}
static void dcss_hdr10_parse_fw_data(struct dcss_hdr10_priv *hdr10)
{
u32 *data = (u32 *)hdr10->fw_data;
u32 remaining = hdr10->fw_size / sizeof(u32);
u64 tbl_desc;
u32 tbl_size;
while (remaining) {
tbl_desc = *((u64 *)data);
data += 2;
tbl_size = *data++;
dcss_hdr10_tbl_add(hdr10, tbl_desc, tbl_size, data);
data += tbl_size;
remaining -= tbl_size + 3;
}
}
#ifndef USE_TBL_HEADER
static void dcss_hdr10_fw_handler(const struct firmware *fw, void *context)
{
struct dcss_hdr10_priv *hdr10 = context;
int i;
if (!fw) {
dev_err(hdr10->dcss->dev, "hdr10: DCSS FW load failed.\n");
return;
}
/* we need to keep the tables for the entire life of the driver */
hdr10->fw_data = devm_kzalloc(hdr10->dcss->dev, fw->size, GFP_KERNEL);
if (!hdr10->fw_data) {
dev_err(hdr10->dcss->dev, "hdr10: cannot alloc FW memory.\n");
return;
}
memcpy(hdr10->fw_data, fw->data, fw->size);
hdr10->fw_size = fw->size;
release_firmware(fw);
dcss_hdr10_parse_fw_data(hdr10);
for (i = 0; i < 4; i++) {
u32 *lut, *csca, *cscb;
struct dcss_hdr10_ch *ch = &hdr10->ch[i];
bool is_input_pipe = i != OPIPE_CH_NO ? true : false;
if (ch->old_cfg_desc != HDR10_DESC_INVALID) {
dcss_hdr10_get_tbls(hdr10, is_input_pipe,
ch->old_cfg_desc, &lut,
&csca, &cscb);
dcss_hdr10_write_pipe_tbls(hdr10->dcss, i, lut,
csca, cscb);
}
}
dev_info(hdr10->dcss->dev, "hdr10: DCSS FW loaded successfully\n");
}
#endif
static int dcss_hdr10_tbls_init(struct dcss_hdr10_priv *hdr10)
{
struct device *dev = hdr10->dcss->dev;
hdr10->ipipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->ipipe_tbls),
GFP_KERNEL);
if (!hdr10->ipipe_tbls)
return -ENOMEM;
INIT_LIST_HEAD(&hdr10->ipipe_tbls->lut);
INIT_LIST_HEAD(&hdr10->ipipe_tbls->csca);
INIT_LIST_HEAD(&hdr10->ipipe_tbls->cscb);
hdr10->opipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->opipe_tbls),
GFP_KERNEL);
if (!hdr10->opipe_tbls)
return -ENOMEM;
INIT_LIST_HEAD(&hdr10->opipe_tbls->lut);
INIT_LIST_HEAD(&hdr10->opipe_tbls->csc);
return 0;
}
int dcss_hdr10_init(struct dcss_soc *dcss, unsigned long hdr10_base)
{
int ret;
struct dcss_hdr10_priv *hdr10;
hdr10 = devm_kzalloc(dcss->dev, sizeof(*hdr10), GFP_KERNEL);
if (!hdr10)
return -ENOMEM;
dcss->hdr10_priv = hdr10;
hdr10->dcss = dcss;
ret = dcss_hdr10_tbls_init(hdr10);
if (ret < 0) {
dev_err(dcss->dev, "hdr10: Cannot init table lists.\n");
return ret;
}
#ifndef USE_TBL_HEADER
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "dcss.fw",
dcss->dev, GFP_KERNEL, hdr10,
dcss_hdr10_fw_handler);
if (ret < 0) {
dev_err(dcss->dev, "hdr10: Cannot async load DCSS FW.\n");
return ret;
}
#else
hdr10->fw_data = (u8 *)dcss_hdr10_tables;
hdr10->fw_size = sizeof(dcss_hdr10_tables);
dcss_hdr10_parse_fw_data(hdr10);
#endif
return dcss_hdr10_ch_init_all(dcss, hdr10_base);
}
void dcss_hdr10_exit(struct dcss_soc *dcss)
{
}
static u32 dcss_hdr10_get_bpc(u32 pix_format)
{
u32 depth, bpc;
switch (pix_format) {
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
bpc = 8;
break;
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
bpc = 8;
break;
case DRM_FORMAT_P010:
bpc = 10;
break;
default:
depth = drm_format_info(pix_format)->depth;
bpc = depth == 30 ? 10 : 8;
break;
}
return bpc;
}
static u32 dcss_hdr10_pipe_desc(struct dcss_hdr10_pipe_cfg *pipe_cfg)
{
u32 bpc, cs, desc;
bpc = dcss_hdr10_get_bpc(pipe_cfg->pixel_format);
cs = dcss_drm_fourcc_to_colorspace(pipe_cfg->pixel_format);
desc = bpc == 10 ? 2 << HDR10_BPC_POS : 1 << HDR10_BPC_POS;
desc |= cs == DCSS_COLORSPACE_YUV ? 2 << HDR10_CS_POS :
1 << HDR10_CS_POS;
desc |= ((1 << pipe_cfg->nl) << HDR10_NL_POS) & HDR10_NL_MASK;
desc |= ((1 << pipe_cfg->pr) << HDR10_PR_POS) & HDR10_PR_MASK;
desc |= ((1 << pipe_cfg->g) << HDR10_G_POS) & HDR10_G_MASK;
return desc;
}
static u64 dcss_hdr10_get_desc(struct dcss_hdr10_pipe_cfg *ipipe_cfg,
struct dcss_hdr10_pipe_cfg *opipe_cfg)
{
u32 ipipe_desc, opipe_desc;
ipipe_desc = dcss_hdr10_pipe_desc(ipipe_cfg) & (~HDR10_BPC_MASK);
ipipe_desc |= 2 << HDR10_BPC_POS;
opipe_desc = dcss_hdr10_pipe_desc(opipe_cfg);
return (ipipe_desc & 0xFFFF) |
(opipe_desc & 0xFFFF) << 16;
}
static void dcss_hdr10_pipe_setup(struct dcss_soc *dcss, int ch_num,
u64 desc)
{
struct dcss_hdr10_ch *ch = &dcss->hdr10_priv->ch[ch_num];
bool pipe_cfg_chgd;
u32 *csca, *cscb, *lut;
pipe_cfg_chgd = ch->old_cfg_desc != desc;
if (!pipe_cfg_chgd)
return;
dcss_hdr10_get_tbls(dcss->hdr10_priv, ch_num != OPIPE_CH_NO,
desc, &lut, &csca, &cscb);
dcss_hdr10_write_pipe_tbls(dcss, ch_num, lut, csca, cscb);
ch->old_cfg_desc = desc;
}
void dcss_hdr10_setup(struct dcss_soc *dcss, int ch_num,
struct dcss_hdr10_pipe_cfg *ipipe_cfg,
struct dcss_hdr10_pipe_cfg *opipe_cfg)
{
u64 desc = dcss_hdr10_get_desc(ipipe_cfg, opipe_cfg);
dcss_hdr10_pipe_setup(dcss, ch_num, desc);
/*
* Input pipe configuration doesn't matter for configuring the output
* pipe. So, will just mask off the input part of the descriptor.
*/
dcss_hdr10_pipe_setup(dcss, OPIPE_CH_NO, desc | 0xfffe);
}
EXPORT_SYMBOL(dcss_hdr10_setup);