summaryrefslogtreecommitdiff
path: root/drivers/gpu/imx/dcss/dcss-hdr10.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/imx/dcss/dcss-hdr10.c')
-rw-r--r--drivers/gpu/imx/dcss/dcss-hdr10.c656
1 files changed, 656 insertions, 0 deletions
diff --git a/drivers/gpu/imx/dcss/dcss-hdr10.c b/drivers/gpu/imx/dcss/dcss-hdr10.c
new file mode 100644
index 000000000000..d5888936034f
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-hdr10.c
@@ -0,0 +1,656 @@
+/*
+ * 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)
+{
+ int bpp;
+ 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:
+ drm_fb_get_bpp_depth(pix_format, &depth, &bpp);
+ 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);