ソースを参照

disp: msm: sde: add dnsc_blur HW block support

Downscale blur HW block support is added from MDSS 9.x. The block
can be used to downscale the layer mixer output before feeding it to
the writeback block. It can be used for both writeback & concurrent
writeback usecases. Add hw files and the respective blocks in sw to
program the downscale blur block.

Change-Id: Ic5787e1655eff5ef0960b7569e48d2f35d23bfc9
Signed-off-by: Veera Sundaram Sankaran <[email protected]>
Veera Sundaram Sankaran 4 年 前
コミット
37ab0f2419
6 ファイル変更436 行追加0 行削除
  1. 1 0
      msm/Kbuild
  2. 44 0
      msm/sde/sde_hw_catalog.h
  3. 275 0
      msm/sde/sde_hw_dnsc_blur.c
  4. 89 0
      msm/sde/sde_hw_dnsc_blur.h
  5. 10 0
      msm/sde/sde_hw_mdss.h
  6. 17 0
      msm/sde/sde_rm.c

+ 1 - 0
msm/Kbuild

@@ -172,6 +172,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
 				 sde/sde_hw_qdss.o \
 				 sde_dsc_helper.o \
 				 sde_vdc_helper.o \
+				 sde/sde_hw_dnsc_blur.o \
 				 sde/sde_hw_rc.o
 
 msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \

+ 44 - 0
msm/sde/sde_hw_catalog.h

@@ -486,6 +486,18 @@ enum {
 	SDE_VDC_MAX
 };
 
+/**
+ * Downscale Blur sub-blocks/features
+ * @SDE_DNSC_BLUR_GAUS_LUT      Downscale Blur Gaussian LUT sub block
+ * @SDE_DNSC_BLUR_DITHER        Downscale Blur Dither sub block
+ * @SDE_DNSC_BLUR_MAX
+ */
+enum {
+	SDE_DNSC_BLUR_GAUS_LUT,
+	SDE_DNSC_BLUR_DITHER,
+	SDE_DNSC_BLUR_MAX
+};
+
 /**
  * CTL sub-blocks
  * @SDE_CTL_SPLIT_DISPLAY       CTL supports video mode split display
@@ -788,6 +800,14 @@ struct sde_vdc_blk {
 	SDE_HW_SUBBLK_INFO;
 };
 
+/**
+ * struct sde_dnsc_blur_blk : Downscale Blur sub-blk information
+ * @info:   HW register and features supported by this sub-blk
+ */
+struct sde_dnsc_blur_blk {
+	SDE_HW_SUBBLK_INFO;
+};
+
 /**
  * struct sde_format_extended - define sde specific pixel format+modifier
  * @fourcc_format: Base FOURCC pixel format code
@@ -999,6 +1019,16 @@ struct sde_vdc_sub_blks {
 	struct sde_vdc_blk ctl;
 };
 
+/**
+ * struct sde_dnsc_blur_sub_blks : Downscale Blur sub-blks
+ * @gaus_lut: Gaussian coef LUT register offset(relative to Downscale Blur base)
+ * @dither: Dither register offset(relative to Downscale Blur base)
+ */
+struct sde_dnsc_blur_sub_blks {
+	struct sde_dnsc_blur_blk gaus_lut;
+	struct sde_dnsc_blur_blk dither;
+};
+
 struct sde_wb_sub_blocks {
 	u32 maxlinewidth;
 	u32 maxlinewidth_linear;
@@ -1309,6 +1339,18 @@ struct sde_cdm_cfg   {
 	unsigned long wb_connect;
 };
 
+/**
+ * struct sde_dnsc_blur_cfg - information of Downscale Blur blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ * @sblk               sub-blocks associated with Downscale Blur
+ */
+struct sde_dnsc_blur_cfg   {
+	SDE_HW_BLK_INFO;
+	struct sde_dnsc_blur_sub_blks *sblk;
+};
+
 /**
  * struct sde_intf_cfg - information of timing engine blocks
  * @id                 enum identifying this block
@@ -1740,6 +1782,8 @@ struct sde_mdss_cfg {
 	struct sde_vdc_cfg vdc[MAX_BLOCKS];
 	u32 cdm_count;
 	struct sde_cdm_cfg cdm[MAX_BLOCKS];
+	u32 dnsc_blur_count;
+	struct sde_dnsc_blur_cfg dnsc_blur[MAX_BLOCKS];
 	u32 intf_count;
 	struct sde_intf_cfg intf[MAX_BLOCKS];
 	u32 wb_count;

+ 275 - 0
msm/sde/sde_hw_dnsc_blur.c

@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#include "sde_hw_mdss.h"
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_dnsc_blur.h"
+#include "sde_dbg.h"
+#include "sde_kms.h"
+
+#define DNSC_BLUR_OP_MODE		0x0
+#define DNSC_BLUR_BLUR_RATIO_H		0x4
+#define DNSC_BLUR_BLUR_RATIO_V		0x8
+#define DNSC_BLUR_PCMN_PHASE_INIT_H	0xC
+#define DNSC_BLUR_PCMN_PHASE_STEP_H	0x10
+#define DNSC_BLUR_PCMN_PHASE_INIT_V	0x14
+#define DNSC_BLUR_PCMN_PHASE_STEP_V	0x18
+#define DNSC_BLUR_OUT_IMG_SIZE		0x1C
+#define DNSC_BLUR_GAUS_COEF_LUT_SEL	0x20
+#define DNSC_BLUR_MUX			0x24
+#define DNSC_BLUR_SRC_IMG_SIZE		0x28
+
+#define DNSC_BLUR_GAUS_COEF_LUT_H0	0x0
+#define DNSC_BLUR_GAUS_COEF_LUT_V0	0x100
+#define DNSC_BLUR_GAUS_COEF_LUT_H1	0x200
+#define DNSC_BLUR_GAUS_COEF_LUT_V1	0x300
+
+#define DNSC_BLUR_DITHER_OP_MODE	0x0
+#define DNSC_BLUR_DITHER_BITDEPTH	0x4
+#define DNSC_BLUR_DITHER_MATRIX_ROW0	0x8
+
+/* DNSC_BLUR_OP_MODE bits */
+#define DNSC_BLUR_OPMODE_ENABLE		BIT(0)
+#define DNSC_BLUR_OPMODE_DWNS_H_EN	BIT(1)
+#define DNSC_BLUR_OPMODE_DWNS_V_EN	BIT(2)
+#define DNSC_BLUR_OPMODE_PCMN_H		BIT(8)
+#define DNSC_BLUR_OPMODE_PCMN_V		BIT(12)
+#define DNSC_BLUR_OPMODE_OUT_RND_8B_EN	BIT(16)
+
+static struct sde_dnsc_blur_cfg *_dnsc_blur_offset(enum sde_dnsc_blur idx,
+		struct sde_mdss_cfg *m, void __iomem *addr, struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->dnsc_blur_count; i++) {
+		if (idx == m->dnsc_blur[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->dnsc_blur[i].base;
+			b->length = m->dnsc_blur[i].len;
+			b->hw_rev = m->hw_rev;
+			b->log_mask = SDE_DBG_MASK_DNSC_BLUR;
+			return &m->dnsc_blur[i];
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int _dnsc_blur_subblk_offset(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+		int s_id, u32 *base)
+{
+	const struct sde_dnsc_blur_sub_blks *sblk;
+
+	sblk = hw_dnsc_blur->caps->sblk;
+
+	switch (s_id) {
+	case SDE_DNSC_BLUR_GAUS_LUT:
+		*base = sblk->gaus_lut.base;
+		break;
+	case SDE_DNSC_BLUR_DITHER:
+		*base = sblk->dither.base;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void _sde_hw_dnsc_blur_gaus_lut_setup(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+		struct sde_drm_dnsc_blur_cfg *cfg, u32 lut_sel)
+{
+	struct sde_hw_blk_reg_map *hw = &hw_dnsc_blur->hw;
+	u32 lut_off, base;
+	int i;
+
+	if (_dnsc_blur_subblk_offset(hw_dnsc_blur, SDE_DNSC_BLUR_GAUS_LUT, &base))
+		return;
+
+	SDE_REG_WRITE(hw, DNSC_BLUR_GAUS_COEF_LUT_SEL, lut_sel);
+
+	if (cfg->flags_h & DNSC_BLUR_GAUS_FILTER) {
+		lut_off = lut_sel ? DNSC_BLUR_GAUS_COEF_LUT_H1 : DNSC_BLUR_GAUS_COEF_LUT_H0;
+		for (i = 0; i < DNSC_BLUR_COEF_NUM; i++)
+			SDE_REG_WRITE(hw, lut_off + (i * 0x4) + base, cfg->coef_hori[i]);
+	}
+
+	if (cfg->flags_v & DNSC_BLUR_GAUS_FILTER) {
+		lut_off = lut_sel ? DNSC_BLUR_GAUS_COEF_LUT_V1 : DNSC_BLUR_GAUS_COEF_LUT_V0;
+		for (i = 0; i < DNSC_BLUR_COEF_NUM; i++)
+			SDE_REG_WRITE(hw, lut_off + (i * 0x4) + base, cfg->coef_vert[i]);
+	}
+}
+
+static void _sde_hw_dnsc_blur_filter_setup(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+		struct sde_drm_dnsc_blur_cfg *cfg, u32 lut_sel)
+{
+	struct sde_hw_blk_reg_map *hw = &hw_dnsc_blur->hw;
+	u32 val;
+
+	/* PCMN */
+	if (cfg->flags_h & DNSC_BLUR_PCMN_FILTER) {
+		SDE_REG_WRITE(hw, DNSC_BLUR_PCMN_PHASE_INIT_H, cfg->phase_init_h);
+		SDE_REG_WRITE(hw, DNSC_BLUR_PCMN_PHASE_STEP_H, cfg->phase_step_h);
+	}
+
+	if (cfg->flags_v & DNSC_BLUR_PCMN_FILTER) {
+		SDE_REG_WRITE(hw, DNSC_BLUR_PCMN_PHASE_INIT_V, cfg->phase_init_v);
+		SDE_REG_WRITE(hw, DNSC_BLUR_PCMN_PHASE_STEP_V, cfg->phase_step_v);
+	}
+
+	/* Gaussian */
+	if (cfg->flags_h & DNSC_BLUR_GAUS_FILTER) {
+		val = (cfg->norm_h << 16) | cfg->ratio_h;
+		SDE_REG_WRITE(hw, DNSC_BLUR_BLUR_RATIO_H, val);
+	}
+
+	if (cfg->flags_v & DNSC_BLUR_GAUS_FILTER) {
+		val = (cfg->norm_v << 16) | cfg->ratio_v;
+		SDE_REG_WRITE(hw, DNSC_BLUR_BLUR_RATIO_V, val);
+	}
+
+	if ((cfg->flags_v | cfg->flags_h) & DNSC_BLUR_GAUS_FILTER)
+		_sde_hw_dnsc_blur_gaus_lut_setup(hw_dnsc_blur, cfg, lut_sel);
+}
+
+static void _sde_hw_dnsc_blur_setup(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+		struct sde_drm_dnsc_blur_cfg *cfg, u32 lut_sel)
+{
+	struct sde_hw_blk_reg_map *hw = &hw_dnsc_blur->hw;
+	u32 opmode = 0;
+
+	/* disable, when no scaling involved */
+	if (!cfg || !(cfg->flags & DNSC_BLUR_EN)) {
+		SDE_REG_WRITE(hw, DNSC_BLUR_OP_MODE, 0x0);
+		return;
+	}
+
+	opmode = DNSC_BLUR_OPMODE_ENABLE;
+	opmode |= (cfg->flags & DNSC_BLUR_RND_8B_EN) ? DNSC_BLUR_OPMODE_OUT_RND_8B_EN : 0;
+
+	if (cfg->flags_h) {
+		opmode |= DNSC_BLUR_OPMODE_DWNS_H_EN;
+		opmode |= (cfg->flags_h & DNSC_BLUR_PCMN_FILTER) ? DNSC_BLUR_OPMODE_PCMN_H : 0;
+	}
+
+	if (cfg->flags_v) {
+		opmode |= DNSC_BLUR_OPMODE_DWNS_V_EN;
+		opmode |= (cfg->flags_v & DNSC_BLUR_PCMN_FILTER) ? DNSC_BLUR_OPMODE_PCMN_V : 0;
+	}
+
+	_sde_hw_dnsc_blur_filter_setup(hw_dnsc_blur, cfg, lut_sel);
+
+	SDE_REG_WRITE(hw, DNSC_BLUR_OP_MODE, opmode);
+	SDE_REG_WRITE(hw, DNSC_BLUR_OUT_IMG_SIZE, (cfg->dst_height << 16) | cfg->dst_width);
+	SDE_REG_WRITE(hw, DNSC_BLUR_SRC_IMG_SIZE, (cfg->src_height << 16) | cfg->src_width);
+}
+
+static void _sde_hw_dnsc_blur_dither_setup(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+		struct sde_drm_dnsc_blur_cfg *cfg)
+{
+	struct sde_hw_blk_reg_map *hw = &hw_dnsc_blur->hw;
+	int i;
+	u32 base, data, offset;
+
+	if (_dnsc_blur_subblk_offset(hw_dnsc_blur, SDE_DNSC_BLUR_DITHER, &base))
+		return;
+
+	/* disable case */
+	if (!cfg || !(cfg->flags & DNSC_BLUR_DITHER_EN)) {
+		SDE_REG_WRITE(hw, DNSC_BLUR_DITHER_OP_MODE + base, 0x0);
+		return;
+	}
+
+	data = (dither_depth_map[cfg->c0_bitdepth] & REG_MASK(2)) |
+			((dither_depth_map[cfg->c1_bitdepth] & REG_MASK(2)) << 2) |
+			((dither_depth_map[cfg->c2_bitdepth] & REG_MASK(2)) << 4) |
+			((dither_depth_map[cfg->c3_bitdepth] & REG_MASK(2)) << 6) |
+			((cfg->temporal_en) ? (1 << 8) : 0);
+	SDE_REG_WRITE(hw, DNSC_BLUR_DITHER_BITDEPTH + base, data);
+
+	offset = DNSC_BLUR_DITHER_MATRIX_ROW0;
+	for (i = 0; i < DNSC_BLUR_DITHER_MATRIX_SZ - 3; i += 4) {
+		data = (cfg->dither_matrix[i] & REG_MASK(4)) |
+				((cfg->dither_matrix[i + 1] & REG_MASK(4)) << 4) |
+				((cfg->dither_matrix[i + 2] & REG_MASK(4)) << 8) |
+				((cfg->dither_matrix[i + 3] & REG_MASK(4)) << 12);
+		SDE_REG_WRITE(hw, base + offset, data);
+		offset += 4;
+	}
+
+	data = BIT(0);
+	data |= (cfg->dither_flags & DNSC_BLUR_DITHER_LUMA_MODE) ? BIT(4) : 0;
+	SDE_REG_WRITE(hw, DNSC_BLUR_DITHER_OP_MODE + base, data);
+}
+
+static void _sde_hw_dnsc_blur_bind_pingpong_blk(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+		bool enable, const enum sde_pingpong pp)
+{
+	struct sde_hw_blk_reg_map *hw = &hw_dnsc_blur->hw;
+	int mux_cfg;
+
+	if (enable && (pp < PINGPONG_0 || pp >= PINGPONG_MAX))
+		return;
+
+	mux_cfg = enable ? (pp - PINGPONG_0) & 0x7 : 0xF;
+	SDE_REG_WRITE(hw, DNSC_BLUR_MUX, mux_cfg);
+}
+
+static void _setup_dnsc_blur_ops(struct sde_hw_dnsc_blur_ops *ops, unsigned long features)
+{
+	ops->setup_dnsc_blur = _sde_hw_dnsc_blur_setup;
+	ops->setup_dither = _sde_hw_dnsc_blur_dither_setup;
+	ops->bind_pingpong_blk = _sde_hw_dnsc_blur_bind_pingpong_blk;
+}
+
+struct sde_hw_blk_reg_map *sde_hw_dnsc_blur_init(enum sde_dnsc_blur idx,
+		void __iomem *addr, struct sde_mdss_cfg *m)
+{
+	struct sde_hw_dnsc_blur *c;
+	struct sde_dnsc_blur_cfg *cfg;
+
+	if (!addr || !m)
+		return ERR_PTR(-EINVAL);
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _dnsc_blur_offset(idx, m, addr, &c->hw);
+	if (IS_ERR_OR_NULL(cfg)) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	c->idx = idx;
+	c->caps = cfg;
+	_setup_dnsc_blur_ops(&c->ops, c->caps->features);
+
+	sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+			c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
+	if (cfg->sblk->gaus_lut.base && cfg->sblk->gaus_lut.len)
+		sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->sblk->gaus_lut.name,
+				c->hw.blk_off + cfg->sblk->gaus_lut.base,
+				c->hw.blk_off + cfg->sblk->gaus_lut.base +
+					cfg->sblk->gaus_lut.len, c->hw.xin_id);
+
+	if (cfg->sblk->dither.base && cfg->sblk->dither.len)
+		sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->sblk->dither.name,
+				c->hw.blk_off + cfg->sblk->dither.base,
+				c->hw.blk_off + cfg->sblk->dither.base +
+					cfg->sblk->dither.len, c->hw.xin_id);
+
+	return &c->hw;
+}
+
+void sde_hw_dnsc_blur_destroy(struct sde_hw_blk_reg_map *hw)
+{
+	if (hw)
+		kfree(to_sde_hw_dnsc_blur(hw));
+}
+

+ 89 - 0
msm/sde/sde_hw_dnsc_blur.h

@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _SDE_HW_DNSC_BLUR_H
+#define _SDE_HW_DNSC_BLUR_H
+
+#include <drm/sde_drm.h>
+#include <drm/msm_drm_pp.h>
+
+#include "sde_hw_mdss.h"
+
+struct sde_hw_dnsc_blur;
+
+/**
+ * sde_hw_dnsc_blur_ops - interface to the DNSC_BLUR HW driver functions
+ * Caller must call the init function to the dnsc_blur hw context for dnsc_blur
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_dnsc_blur_ops {
+	/**
+	 * setup_dnsc_blur - downscale blur block setup
+	 * @hw_dnsc_blur: Pointer to dnsc_blur context
+	 * @cfg : Pointer to dnsc_blur configs
+	 * @lut_sel: LUT index for Gausian filter
+	 */
+	void (*setup_dnsc_blur)(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+			struct sde_drm_dnsc_blur_cfg *cfg, u32 lut_sel);
+
+	/**
+	 * setup_dither - Dither programming
+	 * @hw_dnsc_blur: Pointer to dnsc_blur context
+	 * @cfg : Pointer to dnsc_blur configs
+	 */
+	void (*setup_dither)(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+			struct sde_drm_dnsc_blur_cfg *cfg);
+
+	/**
+	 * bind_pingpong_blk - connection with pingpong block which feeds pixels
+	 * to downscale blur block
+	 * @hw_dnsc_blur: Pointer to dnsc_blur context
+	 * @enable: Boolean to indicate enable/disable of the binding
+	 * @pp: Pingpong block idx for binding
+	 */
+	void (*bind_pingpong_blk)(struct sde_hw_dnsc_blur *hw_dnsc_blur,
+			bool enable, const enum sde_pingpong pp);
+};
+
+/**
+ * struct sde_hw_dnsc_blur - downscale blur description
+ * @hw: Block hardware details
+ * @caps: Pointer to block capabilities
+ * @idx: Downscale Blur index
+ * @ops: Pointer to operations for this block
+ */
+struct sde_hw_dnsc_blur {
+	struct sde_hw_blk_reg_map hw;
+	const struct sde_dnsc_blur_cfg *caps;
+	enum sde_dnsc_blur idx;
+	struct sde_hw_dnsc_blur_ops ops;
+};
+
+/**
+ * to_sde_hw_dnsc_blur - convert base hw object to sde_hw_dnsc_blur to container
+ * @hw: Pointer to base hardware block register map object
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_dnsc_blur *to_sde_hw_dnsc_blur(struct sde_hw_blk_reg_map *hw)
+{
+	return container_of(hw, struct sde_hw_dnsc_blur, hw);
+}
+
+/**
+ * sde_hw_dnsc_blur_init - initializes the dnsc_blur hw driver object
+ * @idx: dnsc_blur index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m: pointer to mdss catalog data
+ */
+struct sde_hw_blk_reg_map *sde_hw_dnsc_blur_init(enum sde_dnsc_blur idx,
+		void __iomem *addr, struct sde_mdss_cfg *m);
+
+/**
+ * sde_hw_dnsc_blur_destroy - destroys dnsc_blur driver context
+ * @hw: Pointer to hardware block register map object
+ */
+void sde_hw_dnsc_blur_destroy(struct sde_hw_blk_reg_map *hw);
+
+#endif /*_SDE_HW_DNSC_BLUR_H */

+ 10 - 0
msm/sde/sde_hw_mdss.h

@@ -9,6 +9,9 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 
+#include <drm/sde_drm.h>
+#include <drm/msm_drm_pp.h>
+
 #include "msm_drv.h"
 
 #define SDE_DBG_NAME			"sde"
@@ -121,6 +124,7 @@ enum sde_hw_blk_type {
 	SDE_HW_BLK_VDC,
 	SDE_HW_BLK_MERGE_3D,
 	SDE_HW_BLK_QDSS,
+	SDE_HW_BLK_DNSC_BLUR,
 	SDE_HW_BLK_MAX,
 };
 
@@ -251,6 +255,11 @@ enum sde_cdm {
 	CDM_MAX
 };
 
+enum sde_dnsc_blur {
+	DNSC_BLUR_0 = 1,
+	DNSC_BLUR__MAX
+};
+
 enum sde_pingpong {
 	PINGPONG_0 = 1,
 	PINGPONG_1,
@@ -598,6 +607,7 @@ struct sde_mdss_color {
 #define SDE_DBG_MASK_SID      (1 << 15)
 #define SDE_DBG_MASK_QDSS     (1 << 16)
 #define SDE_DBG_MASK_VDC      (1 << 17)
+#define SDE_DBG_MASK_DNSC_BLUR  (1 << 18)
 
 /**
  * struct sde_hw_cp_cfg: hardware dspp/lm feature payload.

+ 17 - 0
msm/sde/sde_rm.c

@@ -20,6 +20,7 @@
 #include "sde_crtc.h"
 #include "sde_hw_qdss.h"
 #include "sde_vbif.h"
+#include "sde_hw_dnsc_blur.h"
 
 #define RESERVED_BY_OTHER(h, r) \
 	(((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id)) ||\
@@ -120,6 +121,7 @@ char sde_hw_blk_str[SDE_HW_BLK_MAX][SDE_HW_BLK_NAME_LEN] = {
 	"vdc",
 	"merge_3d",
 	"qdss",
+	"dnsc_blur"
 };
 
 /**
@@ -544,6 +546,9 @@ static void _sde_rm_hw_destroy(enum sde_hw_blk_type type, struct sde_hw_blk_reg_
 	case SDE_HW_BLK_QDSS:
 		sde_hw_qdss_destroy(hw);
 		break;
+	case SDE_HW_BLK_DNSC_BLUR:
+		sde_hw_dnsc_blur_destroy(hw);
+		break;
 	case SDE_HW_BLK_SSPP:
 		/* SSPPs are not managed by the resource manager */
 	case SDE_HW_BLK_TOP:
@@ -641,6 +646,9 @@ static int _sde_rm_hw_blk_create(
 	case SDE_HW_BLK_QDSS:
 		hw = sde_hw_qdss_init(id, mmio, cat);
 		break;
+	case SDE_HW_BLK_DNSC_BLUR:
+		hw = sde_hw_dnsc_blur_init(id, mmio, cat);
+		break;
 	case SDE_HW_BLK_SSPP:
 		/* SSPPs are not managed by the resource manager */
 	case SDE_HW_BLK_TOP:
@@ -776,6 +784,15 @@ static int _sde_rm_hw_blk_create_new(struct sde_rm *rm,
 		}
 	}
 
+	for (i = 0; i < cat->dnsc_blur_count; i++) {
+		rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DNSC_BLUR,
+				cat->dnsc_blur[i].id, &cat->dnsc_blur[i]);
+		if (rc) {
+			SDE_ERROR("failed: dnsc_blur hw not available\n");
+			goto fail;
+		}
+	}
+
 	for (i = 0; i < cat->qdss_count; i++) {
 		rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_QDSS,
 				cat->qdss[i].id, &cat->qdss[i]);