summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDhaval Patel <pdhaval@quicinc.com>2016-09-20 16:00:22 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-09-20 16:00:22 -0700
commit04495f87647dafca1c86c78a915108b16bdcd3b4 (patch)
tree7018385f5f0e70e6eb75901aabc8c8eec5022777 /drivers/gpu
parentcbecc661e13a6a91b5bc9012a4545369a3cbacff (diff)
parent92d7d5765ce84b96ac3c3577cfb7b151547e7e3c (diff)
Merge "drm/msm/sde: add OT support for source pipe and writeback" into dev/msm-4.4-drm_kms
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/Makefile1
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c27
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h99
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c134
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_mdss.h1
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_top.c29
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_top.h10
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_vbif.c165
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_vbif.h90
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c223
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.h23
-rw-r--r--drivers/gpu/drm/msm/sde/sde_plane.c50
-rw-r--r--drivers/gpu/drm/msm/sde/sde_trace.h20
13 files changed, 855 insertions, 17 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index ca16fa5b1767..b8a2df8c16b3 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_DRM_MSM) += sde/sde_hw_catalog.o \
sde/sde_hw_pingpong.o \
sde/sde_hw_top.o \
sde/sde_hw_interrupts.o \
+ sde/sde_hw_vbif.o \
sde/sde_formats.o
obj-$(CONFIG_DRM_MSM) += display-manager/display_manager.o
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 1adf5533ea87..e935db7845fe 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -51,6 +51,31 @@ static enum sde_intr_type sde_encoder_phys_wb_get_intr_type(
}
/**
+ * sde_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
+ * @phys_enc: Pointer to physical encoder
+ */
+static void sde_encoder_phys_wb_set_ot_limit(
+ struct sde_encoder_phys *phys_enc)
+{
+ struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+ struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
+ struct sde_vbif_set_ot_params ot_params;
+
+ memset(&ot_params, 0, sizeof(ot_params));
+ ot_params.xin_id = hw_wb->caps->xin_id;
+ ot_params.num = hw_wb->idx - WB_0;
+ ot_params.width = wb_enc->wb_roi.w;
+ ot_params.height = wb_enc->wb_roi.h;
+ ot_params.is_wfd = true;
+ ot_params.frame_rate = phys_enc->cached_mode.vrefresh;
+ ot_params.vbif_idx = hw_wb->caps->vbif_idx;
+ ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
+ ot_params.rd = false;
+
+ sde_vbif_set_ot_limit(phys_enc->sde_kms, &ot_params);
+}
+
+/**
* sde_encoder_phys_wb_set_traffic_shaper - set traffic shaper for writeback
* @phys_enc: Pointer to physical encoder
*/
@@ -438,6 +463,8 @@ static void sde_encoder_phys_wb_setup(
SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->pixel_format,
fb->modifier[0]);
+ sde_encoder_phys_wb_set_ot_limit(phys_enc);
+
sde_encoder_phys_wb_set_traffic_shaper(phys_enc);
sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index e84558e35d2e..85aa6b671258 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -191,6 +191,16 @@ enum {
};
/**
+ * VBIF sub-blocks and features
+ * @SDE_VBIF_QOS_OTLIM VBIF supports OT Limit
+ * @SDE_VBIF_MAX maximum value
+ */
+enum {
+ SDE_VBIF_QOS_OTLIM = 0x1,
+ SDE_VBIF_MAX
+};
+
+/**
* MACRO SDE_HW_BLK_INFO - information of HW blocks inside SDE
* @id: enum identifying this block
* @base: register base offset to mdss
@@ -339,15 +349,50 @@ struct sde_mdss_base_cfg {
SDE_HW_BLK_INFO;
};
+/**
+ * sde_clk_ctrl_type - Defines top level clock control signals
+ */
+enum sde_clk_ctrl_type {
+ SDE_CLK_CTRL_NONE,
+ SDE_CLK_CTRL_VIG0,
+ SDE_CLK_CTRL_VIG1,
+ SDE_CLK_CTRL_VIG2,
+ SDE_CLK_CTRL_VIG3,
+ SDE_CLK_CTRL_VIG4,
+ SDE_CLK_CTRL_RGB0,
+ SDE_CLK_CTRL_RGB1,
+ SDE_CLK_CTRL_RGB2,
+ SDE_CLK_CTRL_RGB3,
+ SDE_CLK_CTRL_DMA0,
+ SDE_CLK_CTRL_DMA1,
+ SDE_CLK_CTRL_CURSOR0,
+ SDE_CLK_CTRL_CURSOR1,
+ SDE_CLK_CTRL_WB0,
+ SDE_CLK_CTRL_WB1,
+ SDE_CLK_CTRL_WB2,
+ SDE_CLK_CTRL_MAX,
+};
+
+/* struct sde_clk_ctrl_reg : Clock control register
+ * @reg_off: register offset
+ * @bit_off: bit offset
+ */
+struct sde_clk_ctrl_reg {
+ u32 reg_off;
+ u32 bit_off;
+};
+
/* struct sde_mdp_cfg : MDP TOP-BLK instance info
* @id: index identifying this block
* @base: register base offset to mdss
* @features bit mask identifying sub-blocks/features
* @highest_bank_bit: UBWC parameter
+ * @clk_ctrls clock control register definition
*/
struct sde_mdp_cfg {
SDE_HW_BLK_INFO;
u32 highest_bank_bit;
+ struct sde_clk_ctrl_reg clk_ctrls[SDE_CLK_CTRL_MAX];
};
/* struct sde_mdp_cfg : MDP TOP-BLK instance info
@@ -365,10 +410,14 @@ struct sde_ctl_cfg {
* @base register offset of this block
* @features bit mask identifying sub-blocks/features
* @sblk: SSPP sub-blocks information
+ * @xin_id: bus client identifier
+ * @clk_ctrl clock control identifier
*/
struct sde_sspp_cfg {
SDE_HW_BLK_INFO;
const struct sde_sspp_sub_blks *sblk;
+ u32 xin_id;
+ enum sde_clk_ctrl_type clk_ctrl;
};
/**
@@ -451,11 +500,17 @@ struct sde_intf_cfg {
* @features bit mask identifying sub-blocks/features
* @sblk sub-block information
* @format_list: Pointer to list of supported formats
+ * @vbif_idx vbif identifier
+ * @xin_id client interface identifier
+ * @clk_ctrl clock control identifier
*/
struct sde_wb_cfg {
SDE_HW_BLK_INFO;
const struct sde_wb_sub_blocks *sblk;
const struct sde_format_extended *format_list;
+ u32 vbif_idx;
+ u32 xin_id;
+ enum sde_clk_ctrl_type clk_ctrl;
};
/**
@@ -469,6 +524,47 @@ struct sde_ad_cfg {
};
/**
+ * struct sde_vbif_dynamic_ot_cfg - dynamic OT setting
+ * @pps pixel per seconds
+ * @ot_limit OT limit to use up to specified pixel per second
+ */
+struct sde_vbif_dynamic_ot_cfg {
+ u64 pps;
+ u32 ot_limit;
+};
+
+/**
+ * struct sde_vbif_dynamic_ot_tbl - dynamic OT setting table
+ * @count length of cfg
+ * @cfg pointer to array of configuration settings with
+ * ascending requirements
+ */
+struct sde_vbif_dynamic_ot_tbl {
+ u32 count;
+ const struct sde_vbif_dynamic_ot_cfg *cfg;
+};
+
+/**
+ * struct sde_vbif_cfg - information of VBIF blocks
+ * @id enum identifying this block
+ * @base register offset of this block
+ * @features bit mask identifying sub-blocks/features
+ * @ot_rd_limit default OT read limit
+ * @ot_wr_limit default OT write limit
+ * @xin_halt_timeout maximum time (in usec) for xin to halt
+ * @dynamic_ot_rd_tbl dynamic OT read configuration table
+ * @dynamic_ot_wr_tbl dynamic OT write configuration table
+ */
+struct sde_vbif_cfg {
+ SDE_HW_BLK_INFO;
+ u32 default_ot_rd_limit;
+ u32 default_ot_wr_limit;
+ u32 xin_halt_timeout;
+ struct sde_vbif_dynamic_ot_tbl dynamic_ot_rd_tbl;
+ struct sde_vbif_dynamic_ot_tbl dynamic_ot_wr_tbl;
+};
+
+/**
* struct sde_mdss_cfg - information of MDSS HW
* This is the main catalog data structure representing
* this HW version. Contains number of instances,
@@ -509,6 +605,9 @@ struct sde_mdss_cfg {
u32 ad_count;
struct sde_ad_cfg ad[MAX_BLOCKS];
+
+ u32 vbif_count;
+ struct sde_vbif_cfg vbif[MAX_BLOCKS];
/* Add additional block data structures here */
};
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
index d8c6fa38b60d..a397d67cac26 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -62,6 +62,9 @@
#define DECIMATION_17X_MAX_H 4
#define DECIMATION_17X_MAX_V 4
+#define RES_1080p ((u64)(1088*1920))
+#define RES_UHD ((u64)(3840*2160))
+
static const struct sde_format_extended plane_formats[] = {
{DRM_FORMAT_ARGB8888, 0},
{DRM_FORMAT_ABGR8888, 0},
@@ -372,6 +375,12 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.maxlinewidth = 4096,
};
+ static const struct sde_vbif_dynamic_ot_cfg dynamic_ot_cfg[] = {
+ {RES_1080p * 30, 2},
+ {RES_1080p * 60, 4},
+ {RES_UHD * 30, 16},
+ };
+
/* Setup Register maps and defaults */
*cfg = (struct sde_mdss_cfg){
.mdss_count = 1,
@@ -381,7 +390,38 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.mdp_count = 1,
.mdp = {
{.id = MDP_TOP, .base = 0x00001000, .features = 0,
- .highest_bank_bit = 0x2},
+ .highest_bank_bit = 0x2,
+ .clk_ctrls[SDE_CLK_CTRL_VIG0] = {
+ .reg_off = 0x2AC, .bit_off = 0},
+ .clk_ctrls[SDE_CLK_CTRL_VIG1] = {
+ .reg_off = 0x2B4, .bit_off = 0},
+ .clk_ctrls[SDE_CLK_CTRL_VIG2] = {
+ .reg_off = 0x2BC, .bit_off = 0},
+ .clk_ctrls[SDE_CLK_CTRL_VIG3] = {
+ .reg_off = 0x2C4, .bit_off = 0},
+ .clk_ctrls[SDE_CLK_CTRL_RGB0] = {
+ .reg_off = 0x2AC, .bit_off = 4},
+ .clk_ctrls[SDE_CLK_CTRL_RGB1] = {
+ .reg_off = 0x2B4, .bit_off = 4},
+ .clk_ctrls[SDE_CLK_CTRL_RGB2] = {
+ .reg_off = 0x2BC, .bit_off = 4},
+ .clk_ctrls[SDE_CLK_CTRL_RGB3] = {
+ .reg_off = 0x2C4, .bit_off = 4},
+ .clk_ctrls[SDE_CLK_CTRL_DMA0] = {
+ .reg_off = 0x2AC, .bit_off = 8},
+ .clk_ctrls[SDE_CLK_CTRL_DMA1] = {
+ .reg_off = 0x2B4, .bit_off = 8},
+ .clk_ctrls[SDE_CLK_CTRL_CURSOR0] = {
+ .reg_off = 0x3A8, .bit_off = 16},
+ .clk_ctrls[SDE_CLK_CTRL_CURSOR1] = {
+ .reg_off = 0x3B0, .bit_off = 16},
+ .clk_ctrls[SDE_CLK_CTRL_WB0] = {
+ .reg_off = 0x2BC, .bit_off = 8},
+ .clk_ctrls[SDE_CLK_CTRL_WB1] = {
+ .reg_off = 0x2BC, .bit_off = 12},
+ .clk_ctrls[SDE_CLK_CTRL_WB2] = {
+ .reg_off = 0x2BC, .bit_off = 16},
+ },
},
.ctl_count = 5,
.ctl = {
@@ -403,32 +443,56 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.sspp_count = 12,
.sspp = {
{.id = SSPP_VIG0, .base = 0x00005000,
- .features = VIG_17X_MASK, .sblk = &vig_layer},
+ .features = VIG_17X_MASK, .sblk = &vig_layer,
+ .xin_id = 0,
+ .clk_ctrl = SDE_CLK_CTRL_VIG0},
{.id = SSPP_VIG1, .base = 0x00007000,
- .features = VIG_17X_MASK, .sblk = &vig_layer},
+ .features = VIG_17X_MASK, .sblk = &vig_layer,
+ .xin_id = 4,
+ .clk_ctrl = SDE_CLK_CTRL_VIG1},
{.id = SSPP_VIG2, .base = 0x00009000,
- .features = VIG_17X_MASK, .sblk = &vig_layer},
+ .features = VIG_17X_MASK, .sblk = &vig_layer,
+ .xin_id = 8,
+ .clk_ctrl = SDE_CLK_CTRL_VIG2},
{.id = SSPP_VIG3, .base = 0x0000b000,
- .features = VIG_17X_MASK, .sblk = &vig_layer},
+ .features = VIG_17X_MASK, .sblk = &vig_layer,
+ .xin_id = 12,
+ .clk_ctrl = SDE_CLK_CTRL_VIG3},
{.id = SSPP_RGB0, .base = 0x00015000,
- .features = RGB_17X_MASK, .sblk = &layer},
+ .features = RGB_17X_MASK, .sblk = &layer,
+ .xin_id = 1,
+ .clk_ctrl = SDE_CLK_CTRL_RGB0},
{.id = SSPP_RGB1, .base = 0x00017000,
- .features = RGB_17X_MASK, .sblk = &layer},
+ .features = RGB_17X_MASK, .sblk = &layer,
+ .xin_id = 5,
+ .clk_ctrl = SDE_CLK_CTRL_RGB1},
{.id = SSPP_RGB2, .base = 0x00019000,
- .features = RGB_17X_MASK, .sblk = &layer},
+ .features = RGB_17X_MASK, .sblk = &layer,
+ .xin_id = 9,
+ .clk_ctrl = SDE_CLK_CTRL_RGB2},
{.id = SSPP_RGB3, .base = 0x0001B000,
- .features = RGB_17X_MASK, .sblk = &layer},
+ .features = RGB_17X_MASK, .sblk = &layer,
+ .xin_id = 13,
+ .clk_ctrl = SDE_CLK_CTRL_RGB3},
{.id = SSPP_DMA0, .base = 0x00025000,
- .features = DMA_17X_MASK, .sblk = &dma},
+ .features = DMA_17X_MASK, .sblk = &dma,
+ .xin_id = 2,
+ .clk_ctrl = SDE_CLK_CTRL_DMA0},
{.id = SSPP_DMA1, .base = 0x00027000,
- .features = DMA_17X_MASK, .sblk = &dma},
+ .features = DMA_17X_MASK, .sblk = &dma,
+ .xin_id = 10,
+ .clk_ctrl = SDE_CLK_CTRL_DMA1},
{.id = SSPP_CURSOR0, .base = 0x00035000,
- .features = CURSOR_17X_MASK, .sblk = &cursor},
+ .features = CURSOR_17X_MASK, .sblk = &cursor,
+ .xin_id = 7,
+ .clk_ctrl = SDE_CLK_CTRL_CURSOR0},
{.id = SSPP_CURSOR1, .base = 0x00037000,
- .features = CURSOR_17X_MASK, .sblk = &cursor},
+ .features = CURSOR_17X_MASK, .sblk = &cursor,
+ .xin_id = 7,
+ .clk_ctrl = SDE_CLK_CTRL_CURSOR1},
},
.mixer_count = 6,
.mixer = {
@@ -517,21 +581,59 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
{.id = WB_0, .base = 0x00065000,
.features = WB01_17X_MASK,
.sblk = &wb0,
- .format_list = wb0_formats},
+ .format_list = wb0_formats,
+ .vbif_idx = VBIF_NRT,
+ .xin_id = 3,
+ .clk_ctrl = SDE_CLK_CTRL_WB0},
{.id = WB_1, .base = 0x00065800,
.features = WB01_17X_MASK,
.sblk = &wb0,
- .format_list = wb0_formats},
+ .format_list = wb0_formats,
+ .vbif_idx = VBIF_NRT,
+ .xin_id = 11,
+ .clk_ctrl = SDE_CLK_CTRL_WB1},
{.id = WB_2, .base = 0x00066000,
.features = WB2_17X_MASK,
.sblk = &wb2,
- .format_list = wb2_formats},
+ .format_list = wb2_formats,
+ .vbif_idx = VBIF_NRT,
+ .xin_id = 6,
+ .clk_ctrl = SDE_CLK_CTRL_WB2},
},
.ad_count = 2,
.ad = {
{.id = AD_0, .base = 0x00079000},
{.id = AD_1, .base = 0x00079800},
},
+ .vbif_count = 2,
+ .vbif = {
+ {.id = VBIF_0,
+ .base = 0, /* 0x000B0000 */
+ .features = BIT(SDE_VBIF_QOS_OTLIM),
+ .default_ot_rd_limit = 32,
+ .default_ot_wr_limit = 16,
+ .xin_halt_timeout = 0x4000,
+ .dynamic_ot_rd_tbl = {
+ .count = ARRAY_SIZE(dynamic_ot_cfg),
+ .cfg = dynamic_ot_cfg},
+ .dynamic_ot_wr_tbl = {
+ .count = ARRAY_SIZE(dynamic_ot_cfg),
+ .cfg = dynamic_ot_cfg},
+ },
+ {.id = VBIF_1,
+ .base = 0, /* 0x000B8000 */
+ .features = BIT(SDE_VBIF_QOS_OTLIM),
+ .default_ot_rd_limit = 32,
+ .default_ot_wr_limit = 16,
+ .xin_halt_timeout = 0x4000,
+ .dynamic_ot_rd_tbl = {
+ .count = ARRAY_SIZE(dynamic_ot_cfg),
+ .cfg = dynamic_ot_cfg},
+ .dynamic_ot_wr_tbl = {
+ .count = ARRAY_SIZE(dynamic_ot_cfg),
+ .cfg = dynamic_ot_cfg},
+ },
+ },
};
return 0;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index db16e9b3bbb0..2f3aa9a81433 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -426,5 +426,6 @@ struct sde_mdss_color {
#define SDE_DBG_MASK_SSPP (1 << 7)
#define SDE_DBG_MASK_WB (1 << 8)
#define SDE_DBG_MASK_TOP (1 << 9)
+#define SDE_DBG_MASK_VBIF (1 << 10)
#endif /* _SDE_HW_MDSS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 9e31187a9849..8feca9b56b81 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -108,12 +108,41 @@ static void sde_hw_setup_traffic_shaper(struct sde_hw_mdp *mdp,
SDE_REG_WRITE(c, offset, ts_control);
}
+static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
+ enum sde_clk_ctrl_type clk_ctrl, bool enable)
+{
+ struct sde_hw_blk_reg_map *c = &mdp->hw;
+ u32 reg_off, bit_off;
+ u32 reg_val, new_val;
+ bool clk_forced_on;
+
+ if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
+ return false;
+
+ reg_off = mdp->cap->clk_ctrls[clk_ctrl].reg_off;
+ bit_off = mdp->cap->clk_ctrls[clk_ctrl].bit_off;
+
+ reg_val = SDE_REG_READ(c, reg_off);
+
+ if (enable)
+ new_val = reg_val | BIT(bit_off);
+ else
+ new_val = reg_val & ~BIT(bit_off);
+
+ SDE_REG_WRITE(c, reg_off, new_val);
+
+ clk_forced_on = !(reg_val & BIT(bit_off));
+
+ return clk_forced_on;
+}
+
static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
unsigned long cap)
{
ops->setup_split_pipe = sde_hw_setup_split_pipe_control;
ops->setup_cdm_output = sde_hw_setup_cdm_output;
ops->setup_traffic_shaper = sde_hw_setup_traffic_shaper;
+ ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
}
static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index d310afd75096..7359a77bc954 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -93,6 +93,16 @@ struct sde_hw_mdp_ops {
*/
void (*setup_traffic_shaper)(struct sde_hw_mdp *mdp,
struct traffic_shaper_cfg *cfg);
+
+ /**
+ * setup_clk_force_ctrl - set clock force control
+ * @mdp: mdp top context driver
+ * @clk_ctrl: clock to be controlled
+ * @enable: force on enable
+ * @return: if the clock is forced-on by this function
+ */
+ bool (*setup_clk_force_ctrl)(struct sde_hw_mdp *mdp,
+ enum sde_clk_ctrl_type clk_ctrl, bool enable);
};
struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
new file mode 100644
index 000000000000..76473fa879c5
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
@@ -0,0 +1,165 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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 "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_vbif.h"
+
+#define VBIF_VERSION 0x0000
+#define VBIF_CLK_FORCE_CTRL0 0x0008
+#define VBIF_CLK_FORCE_CTRL1 0x000C
+#define VBIF_QOS_REMAP_00 0x0020
+#define VBIF_QOS_REMAP_01 0x0024
+#define VBIF_QOS_REMAP_10 0x0028
+#define VBIF_QOS_REMAP_11 0x002C
+#define VBIF_WRITE_GATHTER_EN 0x00AC
+#define VBIF_IN_RD_LIM_CONF0 0x00B0
+#define VBIF_IN_RD_LIM_CONF1 0x00B4
+#define VBIF_IN_RD_LIM_CONF2 0x00B8
+#define VBIF_IN_WR_LIM_CONF0 0x00C0
+#define VBIF_IN_WR_LIM_CONF1 0x00C4
+#define VBIF_IN_WR_LIM_CONF2 0x00C8
+#define VBIF_OUT_RD_LIM_CONF0 0x00D0
+#define VBIF_OUT_WR_LIM_CONF0 0x00D4
+#define VBIF_XIN_HALT_CTRL0 0x0200
+#define VBIF_XIN_HALT_CTRL1 0x0204
+
+static void sde_hw_set_limit_conf(struct sde_hw_vbif *vbif,
+ u32 xin_id, bool rd, u32 limit)
+{
+ struct sde_hw_blk_reg_map *c = &vbif->hw;
+ u32 reg_val;
+ u32 reg_off;
+ u32 bit_off;
+
+ if (rd)
+ reg_off = VBIF_IN_RD_LIM_CONF0;
+ else
+ reg_off = VBIF_IN_WR_LIM_CONF0;
+
+ reg_off += (xin_id / 4) * 4;
+ bit_off = (xin_id % 4) * 8;
+ reg_val = SDE_REG_READ(c, reg_off);
+ reg_val &= ~(0xFF << bit_off);
+ reg_val |= (limit) << bit_off;
+ SDE_REG_WRITE(c, reg_off, reg_val);
+}
+
+static u32 sde_hw_get_limit_conf(struct sde_hw_vbif *vbif,
+ u32 xin_id, bool rd)
+{
+ struct sde_hw_blk_reg_map *c = &vbif->hw;
+ u32 reg_val;
+ u32 reg_off;
+ u32 bit_off;
+ u32 limit;
+
+ if (rd)
+ reg_off = VBIF_IN_RD_LIM_CONF0;
+ else
+ reg_off = VBIF_IN_WR_LIM_CONF0;
+
+ reg_off += (xin_id / 4) * 4;
+ bit_off = (xin_id % 4) * 8;
+ reg_val = SDE_REG_READ(c, reg_off);
+ limit = (reg_val >> bit_off) & 0xFF;
+
+ return limit;
+}
+
+static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif,
+ u32 xin_id, bool enable)
+{
+ struct sde_hw_blk_reg_map *c = &vbif->hw;
+ u32 reg_val;
+
+ reg_val = SDE_REG_READ(c, VBIF_XIN_HALT_CTRL0);
+
+ if (enable)
+ reg_val |= BIT(xin_id);
+ else
+ reg_val &= ~BIT(xin_id);
+
+ SDE_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val);
+}
+
+static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif,
+ u32 xin_id)
+{
+ struct sde_hw_blk_reg_map *c = &vbif->hw;
+ u32 reg_val;
+
+ reg_val = SDE_REG_READ(c, VBIF_XIN_HALT_CTRL1);
+
+ return (reg_val & BIT(xin_id)) ? true : false;
+}
+
+static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops,
+ unsigned long cap)
+{
+ ops->set_limit_conf = sde_hw_set_limit_conf;
+ ops->get_limit_conf = sde_hw_get_limit_conf;
+ ops->set_halt_ctrl = sde_hw_set_halt_ctrl;
+ ops->get_halt_ctrl = sde_hw_get_halt_ctrl;
+}
+
+static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif,
+ const struct sde_mdss_cfg *m,
+ void __iomem *addr,
+ struct sde_hw_blk_reg_map *b)
+{
+ int i;
+
+ for (i = 0; i < m->vbif_count; i++) {
+ if (vbif == m->vbif[i].id) {
+ b->base_off = addr;
+ b->blk_off = m->vbif[i].base;
+ b->hwversion = m->hwversion;
+ b->log_mask = SDE_DBG_MASK_VBIF;
+ return &m->vbif[i];
+ }
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx,
+ void __iomem *addr,
+ const struct sde_mdss_cfg *m)
+{
+ struct sde_hw_vbif *c;
+ const struct sde_vbif_cfg *cfg;
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return ERR_PTR(-ENOMEM);
+
+ cfg = _top_offset(idx, m, addr, &c->hw);
+ if (IS_ERR_OR_NULL(cfg)) {
+ kfree(c);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * Assign ops
+ */
+ c->idx = idx;
+ c->cap = cfg;
+ _setup_vbif_ops(&c->ops, c->cap->features);
+
+ return c;
+}
+
+void sde_hw_vbif_destroy(struct sde_hw_vbif *vbif)
+{
+ kfree(vbif);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
new file mode 100644
index 000000000000..de7fac0ed8f2
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _SDE_HW_VBIF_H
+#define _SDE_HW_VBIF_H
+
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hw_util.h"
+
+struct sde_hw_vbif;
+
+/**
+ * struct sde_hw_vbif_ops : Interface to the VBIF hardware driver functions
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_vbif_ops {
+ /**
+ * set_limit_conf - set transaction limit config
+ * @vbif: vbif context driver
+ * @xin_id: client interface identifier
+ * @rd: true for read limit; false for write limit
+ * @limit: outstanding transaction limit
+ */
+ void (*set_limit_conf)(struct sde_hw_vbif *vbif,
+ u32 xin_id, bool rd, u32 limit);
+
+ /**
+ * get_limit_conf - get transaction limit config
+ * @vbif: vbif context driver
+ * @xin_id: client interface identifier
+ * @rd: true for read limit; false for write limit
+ * @return: outstanding transaction limit
+ */
+ u32 (*get_limit_conf)(struct sde_hw_vbif *vbif,
+ u32 xin_id, bool rd);
+
+ /**
+ * set_halt_ctrl - set halt control
+ * @vbif: vbif context driver
+ * @xin_id: client interface identifier
+ * @enable: halt control enable
+ */
+ void (*set_halt_ctrl)(struct sde_hw_vbif *vbif,
+ u32 xin_id, bool enable);
+
+ /**
+ * get_halt_ctrl - get halt control
+ * @vbif: vbif context driver
+ * @xin_id: client interface identifier
+ * @return: halt control enable
+ */
+ bool (*get_halt_ctrl)(struct sde_hw_vbif *vbif,
+ u32 xin_id);
+};
+
+struct sde_hw_vbif {
+ /* base */
+ struct sde_hw_blk_reg_map hw;
+
+ /* vbif */
+ enum sde_vbif idx;
+ const struct sde_vbif_cfg *cap;
+
+ /* ops */
+ struct sde_hw_vbif_ops ops;
+};
+
+/**
+ * sde_hw_vbif_init - initializes the vbif driver for the passed interface idx
+ * @idx: Interface index for which driver object is required
+ * @addr: Mapped register io address of MDSS
+ * @m: Pointer to mdss catalog data
+ */
+struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx,
+ void __iomem *addr,
+ const struct sde_mdss_cfg *m);
+
+void sde_hw_vbif_destroy(struct sde_hw_vbif *vbif);
+
+#endif /*_SDE_HW_VBIF_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index a255303a109b..c8fe90ac2c5a 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+
#include <drm/drm_crtc.h>
#include <linux/debugfs.h>
@@ -20,6 +22,7 @@
#include "sde_hw_mdss.h"
#include "sde_hw_util.h"
#include "sde_hw_intf.h"
+#include "sde_hw_vbif.h"
#define CREATE_TRACE_POINTS
#include "sde_trace.h"
@@ -324,6 +327,14 @@ static void sde_preclose(struct msm_kms *kms, struct drm_file *file)
static void sde_destroy(struct msm_kms *kms)
{
struct sde_kms *sde_kms = to_sde_kms(kms);
+ int i;
+
+ for (i = 0; i < sde_kms->catalog->vbif_count; i++) {
+ u32 vbif_idx = sde_kms->catalog->vbif[i].id;
+
+ if ((vbif_idx < VBIF_MAX) && sde_kms->hw_vbif[vbif_idx])
+ sde_hw_vbif_destroy(sde_kms->hw_vbif[vbif_idx]);
+ }
sde_debugfs_destroy(sde_kms);
sde_irq_domain_fini(sde_kms);
@@ -359,6 +370,198 @@ static void core_hw_rev_init(struct sde_kms *sde_kms)
sde_kms->core_rev = readl_relaxed(sde_kms->mmio + 0x0);
}
+/**
+ * _sde_vbif_wait_for_xin_halt - wait for the xin to halt
+ * @vbif: Pointer to hardware vbif driver
+ * @xin_id: Client interface identifier
+ * @return: 0 if success; error code otherwise
+ */
+static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id)
+{
+ ktime_t timeout;
+ bool status;
+ int rc;
+
+ if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) {
+ SDE_ERROR("invalid arguments vbif %d\n", vbif != 0);
+ return -EINVAL;
+ }
+
+ timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout);
+ for (;;) {
+ status = vbif->ops.get_halt_ctrl(vbif, xin_id);
+ if (status)
+ break;
+ if (ktime_compare_safe(ktime_get(), timeout) > 0) {
+ status = vbif->ops.get_halt_ctrl(vbif, xin_id);
+ break;
+ }
+ usleep_range(501, 1000);
+ }
+
+ if (!status) {
+ rc = -ETIMEDOUT;
+ SDE_ERROR("VBIF %d client %d not halting. TIMEDOUT.\n",
+ vbif->idx - VBIF_0, xin_id);
+ } else {
+ rc = 0;
+ SDE_DEBUG("VBIF %d client %d is halted\n",
+ vbif->idx - VBIF_0, xin_id);
+ }
+
+ return rc;
+}
+
+/**
+ * _sde_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters
+ * @vbif: Pointer to hardware vbif driver
+ * @ot_lim: Pointer to OT limit to be modified
+ * @params: Pointer to usecase parameters
+ */
+static void _sde_vbif_apply_dynamic_ot_limit(struct sde_hw_vbif *vbif,
+ u32 *ot_lim, struct sde_vbif_set_ot_params *params)
+{
+ u64 pps;
+ const struct sde_vbif_dynamic_ot_tbl *tbl;
+ u32 i;
+
+ if (!vbif || !(vbif->cap->features & BIT(SDE_VBIF_QOS_OTLIM)))
+ return;
+
+ /* Dynamic OT setting done only for WFD */
+ if (!params->is_wfd)
+ return;
+
+ pps = params->frame_rate;
+ pps *= params->width;
+ pps *= params->height;
+
+ tbl = params->rd ? &vbif->cap->dynamic_ot_rd_tbl :
+ &vbif->cap->dynamic_ot_wr_tbl;
+
+ for (i = 0; i < tbl->count; i++) {
+ if (pps <= tbl->cfg[i].pps) {
+ *ot_lim = tbl->cfg[i].ot_limit;
+ break;
+ }
+ }
+
+ SDE_DEBUG("vbif:%d xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n",
+ vbif->idx - VBIF_0, params->xin_id,
+ params->width, params->height, params->frame_rate,
+ pps, *ot_lim);
+}
+
+/**
+ * _sde_vbif_get_ot_limit - get OT based on usecase & configuration parameters
+ * @vbif: Pointer to hardware vbif driver
+ * @params: Pointer to usecase parameters
+ * @return: OT limit
+ */
+static u32 _sde_vbif_get_ot_limit(struct sde_hw_vbif *vbif,
+ struct sde_vbif_set_ot_params *params)
+{
+ u32 ot_lim = 0;
+ u32 val;
+
+ if (!vbif || !vbif->cap) {
+ SDE_ERROR("invalid arguments vbif %d\n", vbif != 0);
+ return -EINVAL;
+ }
+
+ if (vbif->cap->default_ot_wr_limit && !params->rd)
+ ot_lim = vbif->cap->default_ot_wr_limit;
+ else if (vbif->cap->default_ot_rd_limit && params->rd)
+ ot_lim = vbif->cap->default_ot_rd_limit;
+
+ /*
+ * If default ot is not set from dt/catalog,
+ * then do not configure it.
+ */
+ if (ot_lim == 0)
+ goto exit;
+
+ /* Modify the limits if the target and the use case requires it */
+ _sde_vbif_apply_dynamic_ot_limit(vbif, &ot_lim, params);
+
+ if (vbif && vbif->ops.get_limit_conf) {
+ val = vbif->ops.get_limit_conf(vbif,
+ params->xin_id, params->rd);
+ if (val == ot_lim)
+ ot_lim = 0;
+ }
+
+exit:
+ SDE_DEBUG("vbif:%d xin:%d ot_lim:%d\n",
+ vbif->idx - VBIF_0, params->xin_id, ot_lim);
+ return ot_lim;
+}
+
+/**
+ * sde_vbif_set_ot_limit - set OT based on usecase & configuration parameters
+ * @vbif: Pointer to hardware vbif driver
+ * @params: Pointer to usecase parameters
+ *
+ * Note this function would block waiting for bus halt.
+ */
+void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,
+ struct sde_vbif_set_ot_params *params)
+{
+ struct sde_hw_vbif *vbif = NULL;
+ struct sde_hw_mdp *mdp;
+ bool forced_on = false;
+ u32 ot_lim;
+ int ret, i;
+
+ if (!sde_kms) {
+ SDE_ERROR("invalid arguments\n");
+ return;
+ }
+ mdp = sde_kms->hw_mdp;
+
+ for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
+ if (sde_kms->hw_vbif[i] &&
+ sde_kms->hw_vbif[i]->idx == params->vbif_idx)
+ vbif = sde_kms->hw_vbif[i];
+ }
+
+ if (!vbif || !mdp) {
+ SDE_ERROR("invalid arguments vbif %d mdp %d\n",
+ vbif != 0, mdp != 0);
+ return;
+ }
+
+ if (!mdp->ops.setup_clk_force_ctrl ||
+ !vbif->ops.set_limit_conf ||
+ !vbif->ops.set_halt_ctrl)
+ return;
+
+ ot_lim = _sde_vbif_get_ot_limit(vbif, params) & 0xFF;
+
+ if (ot_lim == 0)
+ goto exit;
+
+ trace_sde_perf_set_ot(params->num, params->xin_id, ot_lim,
+ params->vbif_idx);
+
+ forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true);
+
+ vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim);
+
+ vbif->ops.set_halt_ctrl(vbif, params->xin_id, true);
+
+ ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id);
+ if (ret)
+ MSM_EVT(sde_kms->dev, vbif->idx, params->xin_id);
+
+ vbif->ops.set_halt_ctrl(vbif, params->xin_id, false);
+
+ if (forced_on)
+ mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
+exit:
+ return;
+}
+
int sde_mmu_init(struct sde_kms *sde_kms)
{
struct msm_mmu *mmu;
@@ -463,6 +666,7 @@ struct msm_kms *sde_kms_init(struct drm_device *dev)
{
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
+ int i;
int rc;
if (!dev) {
@@ -519,6 +723,25 @@ struct msm_kms *sde_kms_init(struct drm_device *dev)
if (rc)
goto catalog_err;
+ for (i = 0; i < sde_kms->catalog->vbif_count; i++) {
+ u32 vbif_idx = sde_kms->catalog->vbif[i].id;
+
+ sde_kms->hw_vbif[i] = sde_hw_vbif_init(vbif_idx,
+ sde_kms->vbif[vbif_idx], sde_kms->catalog);
+ if (IS_ERR_OR_NULL(sde_kms->hw_vbif[vbif_idx])) {
+ SDE_ERROR("failed to init vbif %d\n", vbif_idx);
+ sde_kms->hw_vbif[vbif_idx] = NULL;
+ goto catalog_err;
+ }
+ }
+
+ sde_kms->hw_mdp = sde_rm_get_mdp(&sde_kms->rm);
+ if (IS_ERR_OR_NULL(sde_kms->hw_mdp)) {
+ SDE_ERROR("failed to get hw_mdp\n");
+ sde_kms->hw_mdp = NULL;
+ goto catalog_err;
+ }
+
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
/*
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 460491e5f4c7..e8a69888e800 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -140,6 +140,9 @@ struct sde_kms {
struct sde_irq irq_obj;
struct sde_rm rm;
+
+ struct sde_hw_vbif *hw_vbif[VBIF_MAX];
+ struct sde_hw_mdp *hw_mdp;
};
struct vsync_info {
@@ -149,6 +152,18 @@ struct vsync_info {
#define to_sde_kms(x) container_of(x, struct sde_kms, base)
+struct sde_vbif_set_ot_params {
+ u32 xin_id;
+ u32 num;
+ u32 width;
+ u32 height;
+ u32 frame_rate;
+ bool rd;
+ bool is_wfd;
+ u32 vbif_idx;
+ u32 clk_ctrl;
+};
+
struct sde_plane_state {
struct drm_plane_state base;
@@ -618,4 +633,12 @@ enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder);
*/
void sde_encoders_init(struct drm_device *dev);
+/**
+ * sde_vbif_set_ot_limit - set OT limit for vbif client
+ * @sde_kms: SDE handler
+ * @params: Pointer to OT configuration parameters
+ */
+void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,
+ struct sde_vbif_set_ot_params *params);
+
#endif /* __sde_kms_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 12de055d82ed..f62428602c3a 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -407,6 +407,52 @@ static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
&psde->pipe_qos_cfg);
}
+/**
+ * _sde_plane_set_ot_limit - set OT limit for the given plane
+ * @plane: Pointer to drm plane
+ * @crtc: Pointer to drm crtc
+ */
+static void _sde_plane_set_ot_limit(struct drm_plane *plane,
+ struct drm_crtc *crtc)
+{
+ struct sde_plane *psde;
+ struct sde_vbif_set_ot_params ot_params;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+
+ if (!plane || !plane->dev || !crtc) {
+ SDE_ERROR("invalid arguments plane %d crtc %d\n",
+ plane != 0, crtc != 0);
+ return;
+ }
+
+ priv = plane->dev->dev_private;
+ if (!priv || !priv->kms) {
+ SDE_ERROR("invalid KMS reference\n");
+ return;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+ psde = to_sde_plane(plane);
+ if (!psde->pipe_hw) {
+ SDE_ERROR("invalid pipe reference\n");
+ return;
+ }
+
+ memset(&ot_params, 0, sizeof(ot_params));
+ ot_params.xin_id = psde->pipe_hw->cap->xin_id;
+ ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
+ ot_params.width = psde->pipe_cfg.src_rect.w;
+ ot_params.height = psde->pipe_cfg.src_rect.h;
+ ot_params.is_wfd = !psde->is_rt_pipe;
+ ot_params.frame_rate = crtc->mode.vrefresh;
+ ot_params.vbif_idx = VBIF_RT;
+ ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
+ ot_params.rd = true;
+
+ sde_vbif_set_ot_limit(sde_kms, &ot_params);
+}
+
/* helper to update a state's input fence pointer from the property */
static void _sde_plane_set_input_fence(struct drm_plane *plane,
struct sde_plane_state *pstate, uint64_t fd)
@@ -1115,8 +1161,10 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
_sde_plane_set_qos_lut(plane, fb);
_sde_plane_set_danger_lut(plane, fb);
- if (plane->type != DRM_PLANE_TYPE_CURSOR)
+ if (plane->type != DRM_PLANE_TYPE_CURSOR) {
_sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
+ _sde_plane_set_ot_limit(plane, crtc);
+ }
return 0;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index ba1181cc6119..950145cb69bb 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -72,6 +72,26 @@ TRACE_EVENT(sde_perf_set_danger_luts,
__entry->safe_lut)
);
+TRACE_EVENT(sde_perf_set_ot,
+ TP_PROTO(u32 pnum, u32 xin_id, u32 rd_lim, u32 vbif_idx),
+ TP_ARGS(pnum, xin_id, rd_lim, vbif_idx),
+ TP_STRUCT__entry(
+ __field(u32, pnum)
+ __field(u32, xin_id)
+ __field(u32, rd_lim)
+ __field(u32, vbif_idx)
+ ),
+ TP_fast_assign(
+ __entry->pnum = pnum;
+ __entry->xin_id = xin_id;
+ __entry->rd_lim = rd_lim;
+ __entry->vbif_idx = vbif_idx;
+ ),
+ TP_printk("pnum:%d xin_id:%d ot:%d vbif:%d",
+ __entry->pnum, __entry->xin_id, __entry->rd_lim,
+ __entry->vbif_idx)
+)
+
#endif /* _SDE_TRACE_H_ */
/* This part must be outside protection */