diff options
| author | Dhaval Patel <pdhaval@quicinc.com> | 2016-09-20 16:00:22 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-09-20 16:00:22 -0700 |
| commit | 04495f87647dafca1c86c78a915108b16bdcd3b4 (patch) | |
| tree | 7018385f5f0e70e6eb75901aabc8c8eec5022777 /drivers/gpu | |
| parent | cbecc661e13a6a91b5bc9012a4545369a3cbacff (diff) | |
| parent | 92d7d5765ce84b96ac3c3577cfb7b151547e7e3c (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/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 27 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_catalog.h | 99 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c | 134 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_top.c | 29 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_top.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_vbif.c | 165 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_vbif.h | 90 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 223 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.h | 23 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_plane.c | 50 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_trace.h | 20 |
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 */ |
