MLK-17634-8: drm: imx: dcss: read HDR10 LUTs/CSCs from FW file
authorLaurentiu Palcu <laurentiu.palcu@nxp.com>
Mon, 22 Jan 2018 07:50:23 +0000 (09:50 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
drivers/gpu/drm/imx/dcss/dcss-plane.c
drivers/gpu/imx/dcss/dcss-common.c
drivers/gpu/imx/dcss/dcss-dpr.c
drivers/gpu/imx/dcss/dcss-dtrc.c
drivers/gpu/imx/dcss/dcss-hdr10.c
include/video/imx-dcss.h

index e0c858e..87e5fbf 100644 (file)
@@ -303,7 +303,7 @@ static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
                }
 
                dcss_dtrc_set_format_mod(dcss_plane->dcss, dcss_plane->ch_num,
-                                        fb->modifier);
+                                        pix_format, fb->modifier);
                dcss_dtrc_addr_set(dcss_plane->dcss, dcss_plane->ch_num,
                                   p1_ba, p2_ba, dcss_plane->dtrc_table_ofs_val);
                break;
@@ -364,6 +364,7 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
        u32 src_w, src_h, adj_w, adj_h;
        struct drm_rect disp, crtc, src, old_src;
        u32 scaler_w, scaler_h;
+       struct dcss_hdr10_pipe_cfg ipipe_cfg, opipe_cfg;
 
        if (!state->fb)
                return;
@@ -446,13 +447,20 @@ static void dcss_plane_atomic_update(struct drm_plane *plane,
                          crtc.y2 - crtc.y1,
                          drm_mode_vrefresh(&crtc_state->mode));
 
-       /*
-        * TODO: retrieve the output colorspace format from somewhere... For
-        * now, assume RGB.
-        */
-       dcss_hdr10_pipe_csc_setup(dcss_plane->dcss, dcss_plane->ch_num,
-                                 dcss_drm_fourcc_to_colorspace(pixel_format),
-                                 DCSS_COLORSPACE_RGB);
+       ipipe_cfg.pixel_format = pixel_format;
+       ipipe_cfg.nl = NL_REC709;
+       ipipe_cfg.pr = PR_LIMITED;
+       ipipe_cfg.g = G_REC709;
+
+       /* FIXME: where do I get the output pipe pixel format? */
+
+       opipe_cfg.pixel_format = DRM_FORMAT_ARGB8888;
+       opipe_cfg.nl = NL_REC709;
+       opipe_cfg.pr = PR_LIMITED;
+       opipe_cfg.g = G_REC2020;
+
+       dcss_hdr10_setup(dcss_plane->dcss, dcss_plane->ch_num,
+                        &ipipe_cfg, &opipe_cfg);
 
        dcss_dtg_plane_pos_set(dcss_plane->dcss, dcss_plane->ch_num,
                               crtc.x1, crtc.y1,
index 072f0ff..24738c0 100644 (file)
@@ -98,6 +98,7 @@ enum dcss_color_space dcss_drm_fourcc_to_colorspace(u32 drm_fourcc)
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_P010:
                return DCSS_COLORSPACE_YUV;
        default:
                return DCSS_COLORSPACE_UNKNOWN;
@@ -510,7 +511,6 @@ static int dcss_resume(struct device *dev)
        dcss_clocks_enable(dcss, true);
 
        dcss_blkctl_cfg(dcss);
-       dcss_hdr10_cfg(dcss);
 
        dcss_ctxld_resume(dcss);
 
@@ -550,7 +550,6 @@ static int dcss_runtime_resume(struct device *dev)
        dcss_clocks_enable(dcss, true);
 
        dcss_blkctl_cfg(dcss);
-       dcss_hdr10_cfg(dcss);
 
        dcss_ctxld_resume(dcss);
 
index b3639cf..aa11ba3 100644 (file)
@@ -239,6 +239,9 @@ static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
 
        pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
 
+       if (pix_format == DRM_FORMAT_P010)
+               pix_wide *= 10 / 8;
+
        div_64byte_mod = pix_wide % pix_in_64byte;
        offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
 
index 3dfcfc0..2a9bc48 100644 (file)
@@ -298,6 +298,7 @@ void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
 
        ch = &dtrc->ch[ch_num];
 
+
        dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_DYDSADDR);
        dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_DCDSADDR);
 
@@ -329,6 +330,7 @@ void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
        u32 crop_w, crop_h, crop_orig_w, crop_orig_h;
        int bank;
        u32 old_xres, old_yres, xres, yres;
+       u32 pix_depth;
 
        if (ch_num == 0)
                return;
@@ -339,6 +341,7 @@ void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
 
        bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
 
+       pix_depth = ch->pix_format == DRM_FORMAT_P010 ? 10 : 8;
        old_xres = old_src->x2 - old_src->x1;
        old_yres = old_src->y2 - old_src->y1;
        xres = src->x2 - src->x1;
@@ -397,14 +400,14 @@ void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
        ch->dctl |= CROPPING_EN;
 
 exit:
-       dcss_dtrc_write(dtrc, ch_num, xres * yres,
+       dcss_dtrc_write(dtrc, ch_num, xres * yres * pix_depth / 8,
                        DCSS_DTRC_SYSEA);
-       dcss_dtrc_write(dtrc, ch_num, xres * yres,
+       dcss_dtrc_write(dtrc, ch_num, xres * yres * pix_depth / 8,
                        DTRC_F1_OFS + DCSS_DTRC_SYSEA);
 
-       dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres / 2,
+       dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres * pix_depth / 8 / 2,
                        DCSS_DTRC_SUVSEA);
-       dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres / 2,
+       dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres * pix_depth / 8 / 2,
                        DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
 
        src->x2 = src->x1 + xres;
@@ -470,7 +473,7 @@ void dcss_dtrc_enable(struct dcss_soc *dcss, int ch_num, bool enable)
 
        fdctl = ch->dctl & ~(PIX_DEPTH_8BIT_EN | COMPRESSION_DIS);
 
-       fdctl |= PIX_DEPTH_8BIT_EN;
+       fdctl |= ch->pix_format == DRM_FORMAT_P010 ? 0 : PIX_DEPTH_8BIT_EN;
 
        if (ch->format_modifier != DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED)
                fdctl |= COMPRESSION_DIS;
@@ -501,7 +504,8 @@ bool dcss_dtrc_is_running(struct dcss_soc *dcss, int ch_num)
        return ch->running;
 }
 
-void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num, u64 modifier)
+void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num,
+                             u32 pix_format, u64 modifier)
 {
        struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
        struct dcss_dtrc_ch *ch;
@@ -513,6 +517,7 @@ void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num, u64 modifier)
 
        ch = &dtrc->ch[ch_num];
 
+       ch->pix_format = pix_format;
        ch->format_modifier = modifier;
 }
 EXPORT_SYMBOL(dcss_dtrc_set_format_mod);
index 049e006..b28e00b 100644 (file)
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/seq_file.h>
+#include <linux/firmware.h>
+#include <drm/drm_fourcc.h>
 
 #include <video/imx-dcss.h>
 #include "dcss-prv.h"
-#include "dcss-tables.h"
 
 #define USE_CTXLD
 
@@ -36,6 +37,7 @@
 #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 DCSS_HDR10_CSC_OMAX2           0x70
 #define   POST_CLIP_MASK               GENMASK(9, 0)
 
-#define HDR10_LUT_MAX_ENTRIES          1024
-#define HDR10_CSC_MAX_REGS             28
+#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_OPIPE_DESC_POS           4
+#define HDR10_OPIPE_DESC_MASK          GENMASK(19, 4)
+/* Input pipe config descriptor */
+#define HDR10_IPIPE_DESC_POS           20
+#define HDR10_IPIPE_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;
 
-       u32 old_in_cs;
-       u32 old_out_cs;
+       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[] = {
@@ -188,6 +248,17 @@ void dcss_hdr10_dump_regs(struct seq_file *s, void *data)
                                           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));
                }
        }
 }
@@ -199,8 +270,8 @@ static void dcss_hdr10_csc_fill(struct dcss_soc *dcss, int ch_num,
 {
        int i;
        u32 csc_base_ofs[] = {
-               DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_H00,
-               DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_H00,
+               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++) {
@@ -210,40 +281,43 @@ static void dcss_hdr10_csc_fill(struct dcss_soc *dcss, int ch_num,
        }
 }
 
-static void dcss_hdr10_lut_fill(struct dcss_soc *dcss, int ch_num,
-                               int comp, u16 *map)
+static void dcss_hdr10_lut_fill(struct dcss_soc *dcss, int ch_num, u32 *map)
 {
-       int i;
-       u32 lut_base_ofs;
-
-       lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
-
-       for (i = 0; i < HDR10_LUT_MAX_ENTRIES; i++) {
-               u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
+       int i, comp;
+       u32 lut_base_ofs, ctrl_ofs, lut_entries;
 
-               dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
+       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;
        }
-}
 
-void dcss_hdr10_cfg(struct dcss_soc *dcss)
-{
-       struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
-       struct dcss_hdr10_ch *ch;
-       int i;
-       u16 *lut;
+       if (ch_num != OPIPE_CH_NO)
+               dcss_hdr10_write(dcss, ch_num, *map++, ctrl_ofs);
 
-       for (i = 0; i < 4; i++) {
-               ch = &hdr10->ch[i];
+       for (comp = 0; comp < 3; comp++) {
+               lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
 
-               lut = i < 3 ? dcss_hdr10_comp_lut : dcss_hdr10_opipe;
+               if (ch_num == OPIPE_CH_NO) {
+                       dcss_hdr10_write(dcss, ch_num, map[0], lut_base_ofs);
+                       lut_base_ofs += 4;
+               }
 
-               dcss_hdr10_lut_fill(dcss, i, 0, lut);
-               dcss_hdr10_lut_fill(dcss, i, 1, lut);
-               dcss_hdr10_lut_fill(dcss, i, 2, lut);
+               for (i = 0; i < lut_entries; i++) {
+                       u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
 
-               ch->old_out_cs = DCSS_COLORSPACE_UNKNOWN;
-               ch->old_in_cs = DCSS_COLORSPACE_UNKNOWN;
+                       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,
@@ -264,20 +338,184 @@ static int dcss_hdr10_ch_init_all(struct dcss_soc *dcss,
                        return -ENOMEM;
                }
 
+               ch->old_cfg_desc = HDR10_DESC_INVALID;
+
 #if defined(USE_CTXLD)
                ch->ctx_id = CTX_SB_HP;
 #endif
        }
 
-#ifndef CONFIG_PM
-       dcss_hdr10_cfg(dcss);
-#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;
+       u32 *tbl = NULL;
+
+       list_for_each(node, head) {
+               tbl_node = container_of(node, struct dcss_hdr10_tbl_node, node);
+
+               if ((tbl_node->tbl_descriptor & desc) == desc)
+                       tbl = tbl_node->tbl_data;
+       }
+
+       return tbl;
+}
+
+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 + 2;
+       }
+}
+
+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");
+}
+
+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);
@@ -287,6 +525,20 @@ int dcss_hdr10_init(struct dcss_soc *dcss, unsigned long hdr10_base)
        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;
+       }
+
+       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;
+       }
+
        return dcss_hdr10_ch_init_all(dcss, hdr10_base);
 }
 
@@ -294,56 +546,91 @@ void dcss_hdr10_exit(struct dcss_soc *dcss)
 {
 }
 
-static void dcss_hdr10_csc_en(struct dcss_soc *dcss, int ch_num,
-                             enum dcss_hdr10_csc csc_to_en, bool en)
+static u32 dcss_hdr10_get_bpc(u32 pix_format)
 {
-       u32 ctrl_reg[] = {
-               DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_CONTROL,
-               DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_CONTROL,
-       };
+       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;
+       }
 
-       dcss_hdr10_write(dcss, ch_num, en ? CSC_EN | CSC_ALL_PIX_EN : 0,
-                        ctrl_reg[csc_to_en]);
+       return bpc;
 }
 
-static void dcss_hdr10_cs2rgb_setup(struct dcss_soc *dcss, int ch_num,
-                                   enum dcss_color_space in_cs)
+static u32 dcss_hdr10_pipe_desc(struct dcss_hdr10_pipe_cfg *pipe_cfg)
 {
-       if (in_cs == DCSS_COLORSPACE_YUV) {
-               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCA,
-                                   dcss_hdr10_yuv2rgb_csca);
-               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCA, true);
-               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCB,
-                                   dcss_hdr10_yuv2rgb_cscb);
-               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCB, true);
-       } else {
-               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCA,
-                                   dcss_hdr10_rgb2rgb_csca);
-               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCA, true);
-               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCB,
-                                   dcss_hdr10_rgb2rgb_cscb);
-               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCB, true);
-       }
+       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);
+       opipe_desc = dcss_hdr10_pipe_desc(opipe_cfg);
 
-       dcss_hdr10_write(dcss, ch_num, LUT_ENABLE | LUT_EN_FOR_ALL_PELS,
-                        DCSS_HDR10_LUT_CONTROL);
-       dcss_hdr10_write(dcss, OPIPE_CH_NO,
-                        LTNL_EN_FOR_ALL_PELS | FIX2FLT_EN_FOR_ALL_PELS,
-                        DCSS_HDR10_LTNL);
+       return (ipipe_desc & 0xFFFF) |
+              (opipe_desc & 0xFFFF) << 16;
 }
 
-void dcss_hdr10_pipe_csc_setup(struct dcss_soc *dcss, int ch_num,
-                              enum dcss_color_space in_cs,
-                              enum dcss_color_space out_cs)
+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 cs_chgd = (in_cs != ch->old_in_cs) || (out_cs != ch->old_out_cs);
+       bool pipe_cfg_chgd;
+       u32 *csca, *cscb, *lut;
+
+       pipe_cfg_chgd = ch->old_cfg_desc != desc;
+
+       if (!pipe_cfg_chgd)
+               return;
 
-       if (out_cs == DCSS_COLORSPACE_RGB && cs_chgd)
-               dcss_hdr10_cs2rgb_setup(dcss, ch_num, in_cs);
+       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_in_cs = in_cs;
-       ch->old_out_cs = out_cs;
+       ch->old_cfg_desc = desc;
 }
-EXPORT_SYMBOL(dcss_hdr10_pipe_csc_setup);
 
+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);
+       dcss_hdr10_pipe_setup(dcss, OPIPE_CH_NO, desc);
+}
+EXPORT_SYMBOL(dcss_hdr10_setup);
index bb48b3c..a8fd32a 100644 (file)
@@ -91,9 +91,37 @@ bool dcss_scaler_can_scale(struct dcss_soc *dcss, int ch_num,
 int dcss_ctxld_enable(struct dcss_soc *dcss);
 
 /* HDR10 */
-void dcss_hdr10_pipe_csc_setup(struct dcss_soc *dcss, int ch_num,
-                              enum dcss_color_space in_cs,
-                              enum dcss_color_space out_cs);
+enum dcss_hdr10_nonlinearity {
+       NL_REC2084,
+       NL_REC709,
+       NL_BT1886,
+       NL_2100HLG,
+       NL_SRGB,
+};
+
+enum dcss_hdr10_pixel_range {
+       PR_LIMITED,
+       PR_FULL,
+};
+
+enum dcss_hdr10_gamut {
+       G_REC2020,
+       G_REC709,
+       G_REC601_NTSC,
+       G_REC601_PAL,
+       G_ADOBE_ARGB,
+};
+
+struct dcss_hdr10_pipe_cfg {
+       u32 pixel_format;
+       enum dcss_hdr10_nonlinearity nl;
+       enum dcss_hdr10_pixel_range pr;
+       enum dcss_hdr10_gamut g;
+};
+
+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);
 
 /* DTRC */
 void dcss_dtrc_bypass(struct dcss_soc *dcss, int ch_num);
@@ -102,7 +130,8 @@ void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
 void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
                        uint64_t dec_table_ofs);
 void dcss_dtrc_enable(struct dcss_soc *dcss, int ch_num, bool enable);
-void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num, u64 modifier);
+void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num,
+                             u32 pix_format, u64 modifier);
 
 enum dcss_color_space {
        DCSS_COLORSPACE_RGB,