[Freedreno] [PATCH v1 1/3] dt-bindings: phy: Add eDP PHY compatible for sc7280
Add compatible string for the supported eDP PHY on sc7280 platform. Signed-off-by: Sankeerth Billakanti --- Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 9076e19..a5850ff 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -16,7 +16,9 @@ description: properties: compatible: -const: qcom,sc8180x-edp-phy +enum: + - qcom,sc7280-edp-phy + - qcom,sc8180x-edp-phy reg: items: -- 2.7.4
[Freedreno] [PATCH v1 3/3] phy: qcom: Program SSC only if supported by sink
Some legacy eDP sinks may not support SSC. The support for SSC is indicated through an opts flag from the controller driver. This change will enable SSC only if the sink supports it. Signed-off-by: Sankeerth Billakanti --- drivers/phy/qualcomm/phy-qcom-edp.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 6d9404d..06ba609 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -335,9 +335,11 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x00, edp->tx0 + TXn_LANE_MODE_1); writel(0x00, edp->tx1 + TXn_LANE_MODE_1); - ret = qcom_edp_configure_ssc(edp); - if (ret) - return ret; + if (edp->dp_opts.ssc) { + ret = qcom_edp_configure_ssc(edp); + if (ret) + return ret; + } ret = qcom_edp_configure_pll(edp); if (ret) -- 2.7.4
[Freedreno] [PATCH v1 2/3] phy: qcom: Add support for eDP PHY on sc7280
The sc7280 platform supports native eDP controller and PHY. This change will add support for the eDP PHY on sc7280. Signed-off-by: Sankeerth Billakanti --- drivers/phy/qualcomm/phy-qcom-edp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 17d5653..6d9404d 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -654,6 +654,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) } static const struct of_device_id qcom_edp_phy_match_table[] = { + { .compatible = "qcom,sc7280-edp-phy" }, { .compatible = "qcom,sc8180x-edp-phy" }, { } }; -- 2.7.4
[Freedreno] [PATCH v1 0/3] Add support for eDP PHY on SC7280 platform
This series adds support for the eDP PHY on Qualcomm SC7280 platform. The changes are dependent on v4 of the new eDP PHY driver introduced by Bjorn: https://patchwork.kernel.org/project/linux-arm-msm/list/?series=575135 Sankeerth Billakanti (3): dt-bindings: phy: Add eDP PHY compatible for sc7280 phy: qcom: Add support for eDP PHY on sc7280 phy: qcom: Program SSC only if supported by sink Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml | 4 +++- drivers/phy/qualcomm/phy-qcom-edp.c | 9 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) -- 2.7.4
[Freedreno] [PATCH v3 13/13] drm/msm/dsi: Pass DSC params to drm_panel
When DSC is enabled, we need to pass the DSC parameters to panel driver as well, so add a dsc parameter in panel and set it when DSC is enabled Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/dsi/dsi_host.c | 16 +++- include/drm/drm_panel.h| 7 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 2c14c36f0b3d..3d5773fcf496 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -2159,11 +2159,25 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, struct msm_dsi_host *msm_host = to_msm_dsi_host(host); const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; struct msm_drm_private *priv; + struct drm_panel *panel; int ret; msm_host->dev = dev; + panel = msm_dsi_host_get_panel(&msm_host->base); priv = dev->dev_private; - priv->dsc = msm_host->dsc; + + if (panel && panel->dsc) { + struct msm_display_dsc_config *dsc = priv->dsc; + + if (!dsc) { + dsc = kzalloc(sizeof(*dsc), GFP_KERNEL); + if (!dsc) + return -ENOMEM; + dsc->drm = panel->dsc; + priv->dsc = dsc; + msm_host->dsc = dsc; + } + } ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K); if (ret) { diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 4602f833eb51..eb8ae9bf32ed 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -171,6 +171,13 @@ struct drm_panel { * Panel entry in registry. */ struct list_head list; + + /** +* @dsc: +* +* Panel DSC pps payload to be sent +*/ + struct drm_dsc_config *dsc; }; void drm_panel_init(struct drm_panel *panel, struct device *dev, -- 2.31.1
[Freedreno] [PATCH v3 12/13] drm/msm/dsi: Add support for DSC configuration
When DSC is enabled, we need to configure DSI registers accordingly and configure the respective stream compression registers. Add support to calculate the register setting based on DSC params and timing information and configure these registers. Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/dsi/dsi.xml.h | 10 +++ drivers/gpu/drm/msm/dsi/dsi_host.c | 113 - 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h index 49b551ad1bff..c1c85df58c4b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -706,4 +706,14 @@ static inline uint32_t DSI_VERSION_MAJOR(uint32_t val) #define REG_DSI_CPHY_MODE_CTRL 0x02d4 +#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL0x029c + +#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL2 0x02a0 + +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL 0x02a4 + +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2 0x02a8 + +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL3 0x02ac + #endif /* DSI_XML */ diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 31d385d8d834..2c14c36f0b3d 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -908,6 +908,20 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, dsi_write(msm_host, REG_DSI_CPHY_MODE_CTRL, BIT(0)); } +static int dsi_dsc_update_pic_dim(struct msm_display_dsc_config *dsc, + int pic_width, int pic_height) +{ + if (!dsc || !pic_width || !pic_height) { + pr_err("DSI: invalid input: pic_width: %d pic_height: %d\n", pic_width, pic_height); + return -EINVAL; + } + + dsc->drm->pic_width = pic_width; + dsc->drm->pic_height = pic_height; + + return 0; +} + static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) { struct drm_display_mode *mode = msm_host->mode; @@ -940,7 +954,68 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) hdisplay /= 2; } + if (msm_host->dsc) { + struct msm_display_dsc_config *dsc = msm_host->dsc; + + /* update dsc params with timing params */ + dsi_dsc_update_pic_dim(dsc, mode->hdisplay, mode->vdisplay); + DBG("Mode Width- %d x Height %d\n", dsc->drm->pic_width, dsc->drm->pic_height); + + /* we do the calculations for dsc parameters here so that +* panel can use these parameters +*/ + dsi_populate_dsc_params(dsc); + + /* Divide the display by 3 but keep back/font porch and +* pulse width same +*/ + h_total -= hdisplay; + hdisplay /= 3; + h_total += hdisplay; + ha_end = ha_start + hdisplay; + } + if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) { + if (msm_host->dsc) { + struct msm_display_dsc_config *dsc = msm_host->dsc; + u32 reg, intf_width, slice_per_intf; + u32 total_bytes_per_intf; + + /* first calculate dsc parameters and then program +* compress mode registers +*/ + intf_width = hdisplay; + slice_per_intf = DIV_ROUND_UP(intf_width, dsc->drm->slice_width); + + dsc->drm->slice_count = 1; + dsc->bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * 8, 8); + total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf; + + dsc->eol_byte_num = total_bytes_per_intf % 3; + dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc->bytes_per_pkt = dsc->bytes_in_slice * dsc->drm->slice_count; + dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count; + + reg = dsc->bytes_per_pkt << 16; + reg |= (0x0b << 8);/* dtype of compressed image */ + + /* pkt_per_line: +* 0 == 1 pkt +* 1 == 2 pkt +* 2 == 4 pkt +* 3 pkt is not supported +* above translates to ffs() - 1 +*/ + reg |= (ffs(dsc->pkt_per_line) - 1) << 6; + + dsc->eol_byte_num = total_bytes_per_intf % 3; + reg |= dsc->eol_byte_num << 4; + reg |= 1; + + dsi_write(msm_host, +
[Freedreno] [PATCH v3 11/13] drm/msm/dsi: add mode valid callback for dsi_mgr
Add a mode valid callback for dsi_mgr for checking mode being valid in case of DSC. For DSC the height and width needs to be multiple of slice, so we check that here Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/dsi/dsi.h | 2 ++ drivers/gpu/drm/msm/dsi/dsi_host.c| 26 ++ drivers/gpu/drm/msm/dsi/dsi_manager.c | 12 3 files changed, 40 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 569c8ff062ba..e7affab2fc1e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -115,6 +115,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, int msm_dsi_host_power_off(struct mipi_dsi_host *host); int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, const struct drm_display_mode *mode); +enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host, + const struct drm_display_mode *mode); struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host); unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host); struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 30c1e299aa52..31d385d8d834 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -2588,6 +2588,32 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, return 0; } +enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host, + const struct drm_display_mode *mode) +{ + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + struct msm_display_dsc_config *dsc = msm_host->dsc; + int pic_width = mode->hdisplay; + int pic_height = mode->vdisplay; + + if (!msm_host->dsc) + return MODE_OK; + + if (pic_width % dsc->drm->slice_width) { + pr_err("DSI: pic_width %d has to be multiple of slice %d\n", + pic_width, dsc->drm->slice_width); + return MODE_H_ILLEGAL; + } + + if (pic_height % dsc->drm->slice_height) { + pr_err("DSI: pic_height %d has to be multiple of slice %d\n", + pic_height, dsc->drm->slice_height); + return MODE_V_ILLEGAL; + } + + return MODE_OK; +} + struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host) { return of_drm_find_panel(to_msm_dsi_host(host)->device_node); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 20c4d650fd80..0ad8a53aaa0e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -579,6 +579,17 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode); } +static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + int id = dsi_mgr_bridge_get_id(bridge); + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + struct mipi_dsi_host *host = msm_dsi->host; + + return msm_dsi_host_check_dsc(host, mode); +} + static const struct drm_connector_funcs dsi_mgr_connector_funcs = { .detect = dsi_mgr_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -600,6 +611,7 @@ static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = { .disable = dsi_mgr_bridge_disable, .post_disable = dsi_mgr_bridge_post_disable, .mode_set = dsi_mgr_bridge_mode_set, + .mode_valid = dsi_mgr_bridge_mode_valid, }; /* initialize connector when we're connected to a drm_panel */ -- 2.31.1
[Freedreno] [PATCH v3 10/13] drm/msm/disp/dpu1: Add DSC support in RM
This add the bits in RM to enable the DSC blocks Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 66 + drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 1 + 3 files changed, 68 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 775bcbda860f..fd6672efb096 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -146,6 +146,7 @@ struct dpu_global_state { uint32_t ctl_to_enc_id[CTL_MAX - CTL_0]; uint32_t intf_to_enc_id[INTF_MAX - INTF_0]; uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0]; + uint32_t dsc_to_enc_id[DSC_MAX - DSC_0]; }; struct dpu_global_state diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index f9c83d6e427a..c9d0fc765aaf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -11,6 +11,7 @@ #include "dpu_hw_intf.h" #include "dpu_hw_dspp.h" #include "dpu_hw_merge3d.h" +#include "dpu_hw_dsc.h" #include "dpu_encoder.h" #include "dpu_trace.h" @@ -75,6 +76,14 @@ int dpu_rm_destroy(struct dpu_rm *rm) dpu_hw_intf_destroy(hw); } } + for (i = 0; i < ARRAY_SIZE(rm->dsc_blks); i++) { + struct dpu_hw_dsc *hw; + + if (rm->dsc_blks[i]) { + hw = to_dpu_hw_dsc(rm->dsc_blks[i]); + dpu_hw_dsc_destroy(hw); + } + } return 0; } @@ -221,6 +230,19 @@ int dpu_rm_init(struct dpu_rm *rm, rm->dspp_blks[dspp->id - DSPP_0] = &hw->base; } + for (i = 0; i < cat->dsc_count; i++) { + struct dpu_hw_dsc *hw; + const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; + + hw = dpu_hw_dsc_init(dsc->id, mmio, cat); + if (IS_ERR_OR_NULL(hw)) { + rc = PTR_ERR(hw); + DPU_ERROR("failed dsc object creation: err %d\n", rc); + goto fail; + } + rm->dsc_blks[dsc->id - DSC_0] = &hw->base; + } + return 0; fail: @@ -476,6 +498,7 @@ static int _dpu_rm_reserve_intf( } global_state->intf_to_enc_id[idx] = enc_id; + return 0; } @@ -500,6 +523,38 @@ static int _dpu_rm_reserve_intf_related_hw( return ret; } +static int _dpu_rm_reserve_dsc(struct dpu_rm *rm, + struct dpu_global_state *global_state, + struct drm_encoder *enc, + const struct msm_display_topology *top) +{ + struct msm_drm_private *priv; + int num_dsc = top->num_dsc; + int i; + + priv = enc->dev->dev_private; + + if (!priv) + return -EIO; + + /* check if DSC is supported */ + if (!priv->dsc) + return 0; + + /* check if DSC required are allocated or not */ + for (i = 0; i < num_dsc; i++) { + if (global_state->dsc_to_enc_id[i]) { + DPU_ERROR("DSC %d is already allocated\n", i); + return -EIO; + } + } + + for (i = 0; i < num_dsc; i++) + global_state->dsc_to_enc_id[i] = enc->base.id; + + return 0; +} + static int _dpu_rm_make_reservation( struct dpu_rm *rm, struct dpu_global_state *global_state, @@ -526,6 +581,10 @@ static int _dpu_rm_make_reservation( if (ret) return ret; + ret = _dpu_rm_reserve_dsc(rm, global_state, enc, &reqs->topology); + if (ret) + return ret; + return ret; } @@ -567,6 +626,8 @@ void dpu_rm_release(struct dpu_global_state *global_state, ARRAY_SIZE(global_state->ctl_to_enc_id), enc->base.id); _dpu_rm_clear_mapping(global_state->intf_to_enc_id, ARRAY_SIZE(global_state->intf_to_enc_id), enc->base.id); + _dpu_rm_clear_mapping(global_state->dsc_to_enc_id, + ARRAY_SIZE(global_state->dsc_to_enc_id), enc->base.id); } int dpu_rm_reserve( @@ -640,6 +701,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, hw_to_enc_id = global_state->dspp_to_enc_id; max_blks = ARRAY_SIZE(rm->dspp_blks); break; + case DPU_HW_BLK_DSC: + hw_blks = rm->dsc_blks; + hw_to_enc_id = global_state->dsc_to_enc_id; + max_blks = ARRAY_SIZE(rm->dsc_blks); + break; default: DPU_ERROR("blk type %d not managed by rm\n", type); return 0; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 1f12c8d5b8aa..278d2a510b80 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/ms
[Freedreno] [PATCH v3 09/13] drm/msm/disp/dpu1: Add support for DSC in topology
For DSC to work we typically need a 2,2,1 configuration. This should suffice for resolutions up to 4k. For more resolutions like 8k this won't work. Also, it is better to use 2 LMs and DSC instances as half width results in lesser power consumption as compared to single LM, DSC at full width. The panel has been tested only with 2,2,1 configuration, so for now we blindly create 2,2,1 topology when DSC is enabled Co-developed-by: Abhinav Kumar Signed-off-by: Abhinav Kumar Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 18 ++ drivers/gpu/drm/msm/msm_drv.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index f2ff8a504918..12f58de88ac7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -533,6 +533,8 @@ static struct msm_display_topology dpu_encoder_get_topology( struct drm_display_mode *mode) { struct msm_display_topology topology = {0}; + struct drm_encoder *drm_enc; + struct msm_drm_private *priv; int i, intf_count = 0; for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) @@ -567,8 +569,24 @@ static struct msm_display_topology dpu_encoder_get_topology( topology.num_enc = 0; topology.num_intf = intf_count; + drm_enc = &dpu_enc->base; + priv = drm_enc->dev->dev_private; + if (priv && priv->dsc) { + /* In case of Display Stream Compression DSC, we would use +* 2 encoders, 2 line mixers and 1 interface +* this is power optimal and can drive up to (including) 4k +* screens +*/ + topology.num_enc = 2; + topology.num_dsc = 2; + topology.num_intf = 1; + topology.num_lm = 2; + priv->dsc->dsc_mask = BIT(0) | BIT(1); + } + return topology; } + static int dpu_encoder_virt_atomic_check( struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index c4a588ad226e..d6b25d77700e 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -103,12 +103,14 @@ enum msm_event_wait { * @num_enc: number of compression encoder blocks used * @num_intf: number of interfaces the panel is mounted on * @num_dspp: number of dspp blocks used + * @num_dsc: number of Display Stream Compression (DSC) blocks used */ struct msm_display_topology { u32 num_lm; u32 num_enc; u32 num_intf; u32 num_dspp; + u32 num_dsc; }; /** -- 2.31.1
[Freedreno] [PATCH v3 08/13] drm/msm: Add missing structure documentation
Somehow documentation for dspp was missed, so add that Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/msm_drv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index de7cb65bfc52..c4a588ad226e 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -102,6 +102,7 @@ enum msm_event_wait { * @num_lm: number of layer mixers used * @num_enc: number of compression encoder blocks used * @num_intf: number of interfaces the panel is mounted on + * @num_dspp: number of dspp blocks used */ struct msm_display_topology { u32 num_lm; -- 2.31.1
[Freedreno] [PATCH v3 07/13] drm/msm/disp/dpu1: Add support for DSC in encoder
We need to configure the encoder for DSC configuration and calculate DSC parameters for the given timing so this patch adds that support by adding dpu_encoder_prep_dsc() which is invoked when DSC is enabled. Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 140 +++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index e7ee4cfb8461..f2ff8a504918 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -21,6 +21,7 @@ #include "dpu_hw_intf.h" #include "dpu_hw_ctl.h" #include "dpu_hw_dspp.h" +#include "dpu_hw_dsc.h" #include "dpu_formats.h" #include "dpu_encoder_phys.h" #include "dpu_crtc.h" @@ -136,6 +137,7 @@ enum dpu_enc_rc_states { * @cur_slave: As above but for the slave encoder. * @hw_pp: Handle to the pingpong blocks used for the display. No. * pingpong blocks can be different than num_phys_encs. + * @hw_dsc:Handle to the DSC blocks used for the display. * @intfs_swapped: Whether or not the phys_enc interfaces have been swapped * for partial update right-only cases, such as pingpong * split where virtual pingpong does not generate IRQs @@ -182,6 +184,7 @@ struct dpu_encoder_virt { struct dpu_encoder_phys *cur_master; struct dpu_encoder_phys *cur_slave; struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; bool intfs_swapped; @@ -972,7 +975,8 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL }; - int num_lm, num_ctl, num_pp; + struct dpu_hw_blk *hw_dsc[MAX_CHANNELS_PER_ENC]; + int num_lm, num_ctl, num_pp, num_dsc; int i, j; if (!drm_enc) { @@ -1030,6 +1034,14 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i]) : NULL; + if (priv->dsc) { + num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_DSC, + hw_dsc, ARRAY_SIZE(hw_dsc)); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) + dpu_enc->hw_dsc[i] = i < num_dsc ? to_dpu_hw_dsc(hw_dsc[i]) : NULL; + } + cstate = to_dpu_crtc_state(drm_crtc->state); for (i = 0; i < num_lm; i++) { @@ -1772,10 +1784,132 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) nsecs_to_jiffies(ktime_to_ns(wakeup_time))); } +static void +dpu_encoder_dsc_pclk_param_calc(struct msm_display_dsc_config *dsc, u32 width) +{ + int slice_count, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + + if (!dsc || !dsc->drm->slice_width || !dsc->drm->slice_count) { + DPU_ERROR("Invalid DSC/slices\n"); + return; + } + + slice_count = dsc->drm->slice_count; + slice_per_intf = DIV_ROUND_UP(width, dsc->drm->slice_width); + + /* +* If slice_count is greater than slice_per_intf then default to 1. +* This can happen during partial update. +*/ + if (slice_count > slice_per_intf) + slice_count = 1; + + bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * + dsc->drm->bits_per_pixel, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + dsc->eol_byte_num = total_bytes_per_intf % 3; + dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc->bytes_in_slice = bytes_in_slice; + dsc->bytes_per_pkt = bytes_in_slice * slice_count; + dsc->pkt_per_line = slice_per_intf / slice_count; +} + +static void +dpu_encoder_dsc_initial_line_calc(struct msm_display_dsc_config *dsc, + u32 enc_ip_width) +{ + int ssm_delay, total_pixels, soft_slice_per_enc; + + soft_slice_per_enc = enc_ip_width / dsc->drm->slice_width; + + /* +* minimum number of initial line pixels is a sum of: +* 1. sub-stream multiplexer delay (83 groups for 8bpc, +*91 for 10 bpc) * 3 +* 2. for two soft slice cases, add extra sub-stream multiplexer * 3 +* 3. the initial xmit delay +* 4. total pipeline delay through the "lock step" of encoder (47) +* 5. 6 additional pixels as the output of the rate buffer is +*48 bits wide +*/ + ssm_delay = ((dsc
[Freedreno] [PATCH v3 06/13] drm/msm/disp/dpu1: Add DSC support in hw_ctl
Later gens of hardware have DSC bits moved to hw_ctl, so configure these bits so that DSC would work there as well Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 36831457a91b..66b0c44118d8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -25,6 +25,8 @@ #define CTL_MERGE_3D_ACTIVE 0x0E4 #define CTL_INTF_ACTIVE 0x0F4 #define CTL_MERGE_3D_FLUSH0x100 +#define CTL_DSC_ACTIVE0x0E8 +#define CTL_DSC_FLUSH0x104 #define CTL_INTF_FLUSH0x110 #define CTL_INTF_MASTER 0x134 #define CTL_FETCH_PIPE_ACTIVE 0x0FC @@ -34,6 +36,7 @@ #define DPU_REG_RESET_TIMEOUT_US2000 #define MERGE_3D_IDX 23 +#define DSC_IDX22 #define INTF_IDX 31 #define CTL_INVALID_BIT 0x @@ -120,7 +123,6 @@ static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) { - if (ctx->pending_flush_mask & BIT(MERGE_3D_IDX)) DPU_REG_WRITE(&ctx->hw, CTL_MERGE_3D_FLUSH, ctx->pending_merge_3d_flush_mask); @@ -498,6 +500,9 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, u32 intf_active = 0; u32 mode_sel = 0; + if (cfg->dsc) + DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, cfg->dsc); + if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD) mode_sel |= BIT(17); @@ -509,6 +514,10 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, if (cfg->merge_3d) DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, BIT(cfg->merge_3d - MERGE_3D_0)); + if (cfg->dsc) { + DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, cfg->dsc); + DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc); + } } static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, -- 2.31.1
[Freedreno] [PATCH v3 05/13] drm/msm/disp/dpu1: Don't use DSC with mode_3d
We cannot enable mode_3d when we are using the DSC. So pass configuration to detect DSC is enabled and not enable mode_3d when we are using DSC We add a helper dpu_encoder_helper_get_dsc() to detect dsc enabled and pass this to .setup_intf_cfg() Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 11 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 2 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 3 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index e7270eb6b84b..efb85d595598 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -332,6 +332,17 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( return BLEND_3D_NONE; } +static inline bool dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc) +{ + struct drm_encoder *drm_enc = phys_enc->parent; + struct msm_drm_private *priv = drm_enc->dev->dev_private; + + if (priv->dsc) + return priv->dsc->dsc_mask; + + return 0; +} + /** * dpu_encoder_helper_split_config - split display configuration helper function * This helper function may be used by physical encoders to configure diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index 34a6940d12c5..f3f00f4d0193 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -70,6 +70,8 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg( intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD; intf_cfg.stream_sel = cmd_enc->stream_sel; intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + intf_cfg.dsc = dpu_encoder_helper_get_dsc(phys_enc); + ctl->ops.setup_intf_cfg(ctl, &intf_cfg); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 64740ddb983e..36831457a91b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -519,7 +519,8 @@ static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, intf_cfg |= (cfg->intf & 0xF) << 4; - if (cfg->mode_3d) { + /* In DSC we can't set merge, so check for dsc too */ + if (cfg->mode_3d && !cfg->dsc) { intf_cfg |= BIT(19); intf_cfg |= (cfg->mode_3d - 0x1) << 20; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 806c171e5df2..9847c9c46d6f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -40,6 +40,7 @@ struct dpu_hw_stage_cfg { * @merge_3d: 3d merge block used * @intf_mode_sel: Interface mode, cmd / vid * @stream_sel:Stream selection for multi-stream interfaces + * @dsc: DSC BIT masks */ struct dpu_hw_intf_cfg { enum dpu_intf intf; @@ -47,6 +48,7 @@ struct dpu_hw_intf_cfg { enum dpu_merge_3d merge_3d; enum dpu_ctl_mode_sel intf_mode_sel; int stream_sel; + unsigned int dsc; }; /** -- 2.31.1
[Freedreno] [PATCH v3 04/13] drm/msm/disp/dpu1: Add DSC for SDM845 to hw_catalog
This adds SDM845 DSC blocks into hw_catalog Reviewed-by: Dmitry Baryshkov Signed-off-by: Vinod Koul --- .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c| 20 +++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index ce6f32a919e5..c773bbe57b6b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -821,6 +821,24 @@ static const struct dpu_pingpong_cfg sc7280_pp[] = { PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), }; + +/* + * DSC sub blocks config + */ +#define DSC_BLK(_name, _id, _base) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0x140, \ + .features = 0, \ + } + +static struct dpu_dsc_cfg sdm845_dsc[] = { + DSC_BLK("dsc_0", DSC_0, 0x8), + DSC_BLK("dsc_1", DSC_1, 0x80400), + DSC_BLK("dsc_2", DSC_2, 0x80800), + DSC_BLK("dsc_3", DSC_3, 0x80c00), +}; + /* * INTF sub blocks config */ @@ -1124,6 +1142,8 @@ static void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg) .mixer = sdm845_lm, .pingpong_count = ARRAY_SIZE(sdm845_pp), .pingpong = sdm845_pp, + .dsc_count = ARRAY_SIZE(sdm845_dsc), + .dsc = sdm845_dsc, .intf_count = ARRAY_SIZE(sdm845_intf), .intf = sdm845_intf, .vbif_count = ARRAY_SIZE(sdm845_vbif), -- 2.31.1
[Freedreno] [PATCH v3 03/13] drm/msm/disp/dpu1: Add support for DSC in pingpong block
In SDM845, DSC can be enabled by writing to pingpong block registers, so add support for DSC in hw_pp Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Signed-off-by: Vinod Koul --- .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c | 32 +++ .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h | 14 2 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c index 55766c97c4c8..47c6ab6caf95 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -28,6 +28,9 @@ #define PP_FBC_MODE 0x034 #define PP_FBC_BUDGET_CTL 0x038 #define PP_FBC_LOSSY_MODE 0x03C +#define PP_DSC_MODE 0x0a0 +#define PP_DCE_DATA_IN_SWAP 0x0ac +#define PP_DCE_DATA_OUT_SWAP0x0c8 #define PP_DITHER_EN 0x000 #define PP_DITHER_BITDEPTH 0x004 @@ -245,6 +248,32 @@ static u32 dpu_hw_pp_get_line_count(struct dpu_hw_pingpong *pp) return line; } +static int dpu_hw_pp_dsc_enable(struct dpu_hw_pingpong *pp) +{ + struct dpu_hw_blk_reg_map *c = &pp->hw; + + DPU_REG_WRITE(c, PP_DSC_MODE, 1); + return 0; +} + +static void dpu_hw_pp_dsc_disable(struct dpu_hw_pingpong *pp) +{ + struct dpu_hw_blk_reg_map *c = &pp->hw; + + DPU_REG_WRITE(c, PP_DSC_MODE, 0); +} + +static int dpu_hw_pp_setup_dsc(struct dpu_hw_pingpong *pp) +{ + struct dpu_hw_blk_reg_map *pp_c = &pp->hw; + int data; + + data = DPU_REG_READ(pp_c, PP_DCE_DATA_OUT_SWAP); + data |= BIT(18); /* endian flip */ + DPU_REG_WRITE(pp_c, PP_DCE_DATA_OUT_SWAP, data); + return 0; +} + static void _setup_pingpong_ops(struct dpu_hw_pingpong *c, unsigned long features) { @@ -256,6 +285,9 @@ static void _setup_pingpong_ops(struct dpu_hw_pingpong *c, c->ops.get_autorefresh = dpu_hw_pp_get_autorefresh_config; c->ops.poll_timeout_wr_ptr = dpu_hw_pp_poll_timeout_wr_ptr; c->ops.get_line_count = dpu_hw_pp_get_line_count; + c->ops.setup_dsc = dpu_hw_pp_setup_dsc; + c->ops.enable_dsc = dpu_hw_pp_dsc_enable; + c->ops.disable_dsc = dpu_hw_pp_dsc_disable; if (test_bit(DPU_PINGPONG_DITHER, &features)) c->ops.setup_dither = dpu_hw_pp_setup_dither; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index 89d08a715c16..12758468d9ca 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -124,6 +124,20 @@ struct dpu_hw_pingpong_ops { */ void (*setup_dither)(struct dpu_hw_pingpong *pp, struct dpu_hw_dither_cfg *cfg); + /** +* Enable DSC +*/ + int (*enable_dsc)(struct dpu_hw_pingpong *pp); + + /** +* Disable DSC +*/ + void (*disable_dsc)(struct dpu_hw_pingpong *pp); + + /** +* Setup DSC +*/ + int (*setup_dsc)(struct dpu_hw_pingpong *pp); }; struct dpu_hw_merge_3d; -- 2.31.1
[Freedreno] [PATCH v3 02/13] drm/msm/disp/dpu1: Add support for DSC
Display Stream Compression (DSC) is one of the hw blocks in dpu, so add support by adding hw blocks for DSC Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/Makefile | 1 + .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h| 13 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c| 210 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h| 77 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 13 ++ 5 files changed, 314 insertions(+) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 40577f8856d8..7d7058f1f5c1 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -59,6 +59,7 @@ msm-y := \ disp/dpu1/dpu_formats.o \ disp/dpu1/dpu_hw_catalog.o \ disp/dpu1/dpu_hw_ctl.o \ + disp/dpu1/dpu_hw_dsc.o \ disp/dpu1/dpu_hw_interrupts.o \ disp/dpu1/dpu_hw_intf.o \ disp/dpu1/dpu_hw_lm.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 4ade44bbd37e..65f43fadcda0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -553,6 +553,16 @@ struct dpu_merge_3d_cfg { const struct dpu_merge_3d_sub_blks *sblk; }; +/** + * struct dpu_dsc_cfg - information of DSC blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + */ +struct dpu_dsc_cfg { + DPU_HW_BLK_INFO; +}; + /** * struct dpu_intf_cfg - information of timing engine blocks * @id enum identifying this block @@ -749,6 +759,9 @@ struct dpu_mdss_cfg { u32 merge_3d_count; const struct dpu_merge_3d_cfg *merge_3d; + u32 dsc_count; + struct dpu_dsc_cfg *dsc; + u32 intf_count; const struct dpu_intf_cfg *intf; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c new file mode 100644 index ..449d6f1dad28 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, Linaro Limited + */ + +#include "dpu_kms.h" +#include "dpu_hw_catalog.h" +#include "dpu_hwio.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_dsc.h" + +#define DSC_COMMON_MODE0x000 +#define DSC_ENC 0X004 +#define DSC_PICTURE 0x008 +#define DSC_SLICE 0x00C +#define DSC_CHUNK_SIZE 0x010 +#define DSC_DELAY 0x014 +#define DSC_SCALE_INITIAL 0x018 +#define DSC_SCALE_DEC_INTERVAL 0x01C +#define DSC_SCALE_INC_INTERVAL 0x020 +#define DSC_FIRST_LINE_BPG_OFFSET 0x024 +#define DSC_BPG_OFFSET 0x028 +#define DSC_DSC_OFFSET 0x02C +#define DSC_FLATNESS0x030 +#define DSC_RC_MODEL_SIZE 0x034 +#define DSC_RC 0x038 +#define DSC_RC_BUF_THRESH 0x03C +#define DSC_RANGE_MIN_QP0x074 +#define DSC_RANGE_MAX_QP0x0B0 +#define DSC_RANGE_BPG_OFFSET0x0EC + +static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc) +{ + struct dpu_hw_blk_reg_map *c = &dsc->hw; + + DPU_REG_WRITE(c, DSC_COMMON_MODE, 0); +} + +static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, + struct msm_display_dsc_config *dsc, u32 mode) +{ + struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; + u32 data, lsb, bpp; + u32 initial_lines = dsc->initial_lines; + bool is_cmd_mode = !(mode & DSC_MODE_VIDEO); + + DPU_REG_WRITE(c, DSC_COMMON_MODE, mode); + + if (is_cmd_mode) + initial_lines += 1; + + data = (initial_lines << 20); + data |= ((dsc->slice_last_group_size - 1) << 18); + /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ + data |= dsc->drm->bits_per_pixel << 12; + lsb = dsc->drm->bits_per_pixel % 4; + bpp = dsc->drm->bits_per_pixel / 4; + bpp *= 4; + bpp <<= 4; + bpp |= lsb; + + data |= bpp << 8; + data |= (dsc->drm->block_pred_enable << 7); + data |= (dsc->drm->line_buf_depth << 3); + data |= (dsc->drm->simple_422 << 2); + data |= (dsc->drm->convert_rgb << 1); + data |= dsc->drm->bits_per_component; + + DPU_REG_WRITE(c, DSC_ENC, data); + + data = dsc->drm->pic_width << 16; + data |= dsc->drm->pic_height; + DPU_REG_WRITE(c, DSC_PICTURE, data); + + data = dsc->drm->slice_width << 16; + data |= dsc->drm->slice_height; + DPU_REG_WRITE(c, DSC_SLICE, data); + + data = dsc->drm->slice_chunk_size << 16;
[Freedreno] [PATCH v3 01/13] drm/msm/dsi: add support for dsc data
Display Stream Compression (DSC) parameters need to be calculated. Add helpers and struct msm_display_dsc_config in msm_drv for this msm_display_dsc_config uses drm_dsc_config for DSC parameters. Signed-off-by: Vinod Koul --- drivers/gpu/drm/msm/dsi/dsi_host.c | 132 + drivers/gpu/drm/msm/msm_drv.h | 20 + 2 files changed, 152 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index f69a125f9559..30c1e299aa52 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -31,6 +31,8 @@ #define DSI_RESET_TOGGLE_DELAY_MS 20 +static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc); + static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { u32 ver; @@ -157,6 +159,7 @@ struct msm_dsi_host { struct regmap *sfpb; struct drm_display_mode *mode; + struct msm_display_dsc_config *dsc; /* connected device info */ struct device_node *device_node; @@ -1710,6 +1713,135 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host, return -EINVAL; } +static u32 dsi_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = { + 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, + 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e +}; + +/* only 8bpc, 8bpp added */ +static char min_qp[DSC_NUM_BUF_RANGES] = { + 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13 +}; + +static char max_qp[DSC_NUM_BUF_RANGES] = { + 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15 +}; + +static char bpg_offset[DSC_NUM_BUF_RANGES] = { + 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 +}; + +static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc) +{ + int mux_words_size; + int groups_per_line, groups_total; + int min_rate_buffer_size; + int hrd_delay; + int pre_num_extra_mux_bits, num_extra_mux_bits; + int slice_bits; + int target_bpp_x16; + int data; + int final_value, final_scale; + int i; + + dsc->drm->rc_model_size = 8192; + dsc->drm->first_line_bpg_offset = 12; + dsc->drm->rc_edge_factor = 6; + dsc->drm->rc_tgt_offset_high = 3; + dsc->drm->rc_tgt_offset_low = 3; + dsc->drm->simple_422 = 0; + dsc->drm->convert_rgb = 1; + dsc->drm->vbr_enable = 0; + + /* handle only bpp = bpc = 8 */ + for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++) + dsc->drm->rc_buf_thresh[i] = dsi_dsc_rc_buf_thresh[i]; + + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + dsc->drm->rc_range_params[i].range_min_qp = min_qp[i]; + dsc->drm->rc_range_params[i].range_max_qp = max_qp[i]; + dsc->drm->rc_range_params[i].range_bpg_offset = bpg_offset[i]; + } + + dsc->drm->initial_offset = 6144; /* Not bpp 12 */ + if (dsc->drm->bits_per_pixel != 8) + dsc->drm->initial_offset = 2048;/* bpp = 12 */ + + mux_words_size = 48;/* bpc == 8/10 */ + if (dsc->drm->bits_per_component == 12) + mux_words_size = 64; + + dsc->drm->initial_xmit_delay = 512; + dsc->drm->initial_scale_value = 32; + dsc->drm->first_line_bpg_offset = 12; + dsc->drm->line_buf_depth = dsc->drm->bits_per_component + 1; + + /* bpc 8 */ + dsc->drm->flatness_min_qp = 3; + dsc->drm->flatness_max_qp = 12; + dsc->det_thresh_flatness = 7 + 2 * (dsc->drm->bits_per_component - 8); + dsc->drm->rc_quant_incr_limit0 = 11; + dsc->drm->rc_quant_incr_limit1 = 11; + dsc->drm->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; + + /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of +* params are calculated +*/ + dsc->slice_last_group_size = 3 - (dsc->drm->slice_width % 3); + groups_per_line = DIV_ROUND_UP(dsc->drm->slice_width, 3); + dsc->drm->slice_chunk_size = dsc->drm->slice_width * dsc->drm->bits_per_pixel / 8; + if ((dsc->drm->slice_width * dsc->drm->bits_per_pixel) % 8) + dsc->drm->slice_chunk_size++; + + /* rbs-min */ + min_rate_buffer_size = dsc->drm->rc_model_size - dsc->drm->initial_offset + + dsc->drm->initial_xmit_delay * dsc->drm->bits_per_pixel + + groups_per_line * dsc->drm->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->drm->bits_per_pixel); + + dsc->drm->initial_dec_delay = hrd_delay - dsc->drm->initial_xmit_delay; + + dsc->drm->initial_scale_value = 8 * dsc->drm->rc_model_size / + (dsc->drm->rc_model_size - dsc->drm->initial_offset); + + slice_bits = 8 * dsc->drm->slice_chunk_size * dsc->drm->slice_height; + + groups_total = groups_per_line * dsc->drm->slice_height; + + data = dsc->drm->first_line_bpg_offset * 2
[Freedreno] [PATCH v3 00/13] drm/msm: Add Display Stream Compression Support
Display Stream Compression (DSC) compresses the display stream in host which is later decoded by panel. This series enables this for Qualcomm msm driver. This was tested on Google Pixel3 phone which use LGE SW43408 panel. The changes include DSC data and hardware block enabling for DPU1 then support in encoder. We also add support in DSI and introduce required topology changes. In order for panel to set the DSC parameters we add dsc in drm_panel and set it from the msm driver. We still have dsc as a globabl entity. I think while doing DP + DSC we should be able to update it, right now comprehending the requirements are bit difficult. Complete changes which enable this for Pixel3 along with panel driver (not part of this series) and DT changes can be found at: git.linaro.org/people/vinod.koul/kernel.git pixel/dsc_v3 Comments welcome! Changes since v2: - Fix comments by Dimitry except the dsc being global. - Move RM patch later for dependency on topology now - Add patch for mode valid callback for dsi_mgr - Add missing structure documentation patch - Fix errors in mode_3d changes - Rebase on v5.16-rc1 and test Changes since v1: - Fix various issues spotted by kbuildbot - Rebase to v5.15-rc3 - Remove unused fields and duplicate defines - Enable DSC blocks only when DSC is enabled - remove sdm845 feature mask, use 0 - Check for DSC in hw_ctl Changes since RFC: - Drop the DT binding patch as we derive the configuration from panel - Drop the drm api patch as we no longer need it (use pps drm api) - Fix comments raised by Dimitry - Add dsc parameters calculation from downstream Vinod Koul (13): drm/msm/dsi: add support for dsc data drm/msm/disp/dpu1: Add support for DSC drm/msm/disp/dpu1: Add support for DSC in pingpong block drm/msm/disp/dpu1: Add DSC for SDM845 to hw_catalog drm/msm/disp/dpu1: Don't use DSC with mode_3d drm/msm/disp/dpu1: Add DSC support in hw_ctl drm/msm/disp/dpu1: Add support for DSC in encoder drm/msm: Add missing structure documentation drm/msm/disp/dpu1: Add support for DSC in topology drm/msm/disp/dpu1: Add DSC support in RM drm/msm/dsi: add mode valid callback for dsi_mgr drm/msm/dsi: Add support for DSC configuration drm/msm/dsi: Pass DSC params to drm_panel drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 158 +- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 11 + .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 2 + .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c| 20 ++ .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h| 13 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c| 14 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h| 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c| 210 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h| 77 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 13 + .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c | 32 ++ .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h | 14 + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c| 66 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h| 1 + drivers/gpu/drm/msm/dsi/dsi.h | 2 + drivers/gpu/drm/msm/dsi/dsi.xml.h | 10 + drivers/gpu/drm/msm/dsi/dsi_host.c| 285 +- drivers/gpu/drm/msm/dsi/dsi_manager.c | 12 + drivers/gpu/drm/msm/msm_drv.h | 23 ++ include/drm/drm_panel.h | 7 + 22 files changed, 970 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h -- 2.31.1
Re: [Freedreno] [PATCH 2/2] drm/msm: Restore error return on invalid fence
On 11/15/2021 10:26 PM, Rob Clark wrote: On Mon, Nov 15, 2021 at 6:43 AM Akhil P Oommen wrote: On 11/12/2021 12:54 AM, Rob Clark wrote: From: Rob Clark When converting to use an idr to map userspace fence seqno values back to a dma_fence, we lost the error return when userspace passes seqno that is larger than the last submitted fence. Restore this check. Reported-by: Akhil P Oommen Fixes: a61acbbe9cf8 ("drm/msm: Track "seqno" fences by idr") Signed-off-by: Rob Clark --- Note: I will rebase "drm/msm: Handle fence rollover" on top of this, to simplify backporting this patch to stable kernels drivers/gpu/drm/msm/msm_drv.c| 6 ++ drivers/gpu/drm/msm/msm_gem_submit.c | 1 + drivers/gpu/drm/msm/msm_gpu.h| 3 +++ 3 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index cb14d997c174..56500eb5219e 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -967,6 +967,12 @@ static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id, struct dma_fence *fence; int ret; + if (fence_id > queue->last_fence) { But fence_id can wrap around and then this check won't be valid. that is correct, but see my note about rebasing "drm/msm: Handle fence rollover" on top of this patch, so this patch could be more easily cherry-picked to stable/lts branches BR, -R Missed that. Thanks. Reviewed-by: Akhil P Oommen -Akhil. -Akhil. + DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of %u)\n", + fence_id, queue->last_fence); + return -EINVAL; + } + /* * Map submitqueue scoped "seqno" (which is actually an idr key) * back to underlying dma-fence diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 151d19e4453c..a38f23be497d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -911,6 +911,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, drm_sched_entity_push_job(&submit->base, queue->entity); args->fence = submit->fence_id; + queue->last_fence = submit->fence_id; msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs); msm_process_post_deps(post_deps, args->nr_out_syncobjs, diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index bd4e0024033e..e73a5bb03544 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -376,6 +376,8 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, * @ring_nr: the ringbuffer used by this submitqueue, which is determined * by the submitqueue's priority * @faults:the number of GPU hangs associated with this submitqueue + * @last_fence: the sequence number of the last allocated fence (for error + * checking) * @ctx: the per-drm_file context associated with the submitqueue (ie. * which set of pgtables do submits jobs associated with the * submitqueue use) @@ -391,6 +393,7 @@ struct msm_gpu_submitqueue { u32 flags; u32 ring_nr; int faults; + uint32_t last_fence; struct msm_file_private *ctx; struct list_head node; struct idr fence_idr;
Re: [Freedreno] [PATCH igt v3 2/4] lib/igt_debugfs: Add helper for detecting debugfs files
On Mon, Nov 15, 2021 at 04:30:40PM -0800, Rob Clark wrote: > From: Rob Clark > > Add a helper that can be used with, for ex, igt_require() so that tests > can be skipped if the kernel is too old. > > Signed-off-by: Rob Clark Reviewed-by: Petri Latvala > --- > lib/igt_debugfs.c | 21 + > lib/igt_debugfs.h | 1 + > 2 files changed, 22 insertions(+) > > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c > index dd6f2995..7211c410 100644 > --- a/lib/igt_debugfs.c > +++ b/lib/igt_debugfs.c > @@ -307,6 +307,27 @@ int igt_debugfs_open(int device, const char *filename, > int mode) > return ret; > } > > +/** > + * igt_debugfs_exists: > + * @device: the drm device file fd > + * @filename: file name > + * @mode: mode bits as used by open() > + * > + * Test that the specified debugfs file exists and can be opened with the > + * requested mode. > + */ > +bool igt_debugfs_exists(int device, const char *filename, int mode) > +{ > + int fd = igt_debugfs_open(device, filename, mode); > + > + if (fd >= 0) { > + close(fd); > + return true; > + } > + > + return false; > +} > + > /** > * igt_debugfs_simple_read: > * @filename: file name > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h > index b4867681..37e85067 100644 > --- a/lib/igt_debugfs.h > +++ b/lib/igt_debugfs.h > @@ -39,6 +39,7 @@ int igt_debugfs_connector_dir(int device, char *conn_name, > int mode); > int igt_debugfs_pipe_dir(int device, int pipe, int mode); > > int igt_debugfs_open(int fd, const char *filename, int mode); > +bool igt_debugfs_exists(int fd, const char *filename, int mode); > void __igt_debugfs_read(int fd, const char *filename, char *buf, int size); > void __igt_debugfs_write(int fd, const char *filename, const char *buf, int > size); > int igt_debugfs_simple_read(int dir, const char *filename, char *buf, int > size); > -- > 2.33.1 >
Re: [Freedreno] [PATCH linux-next] drm/msm/dp: remove unneeded variable
Quoting cgel@gmail.com (2021-11-10 04:05:12) > From: Changcheng Deng > > Fix the following coccicheck review: > ./drivers/gpu/drm/msm/dp/dp_debug.c: Unneeded variable > > Remove unneeded variable used to store return value. > > Reported-by: Zeal Robot > Signed-off-by: Changcheng Deng > --- > drivers/gpu/drm/msm/dp/dp_debug.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c > b/drivers/gpu/drm/msm/dp/dp_debug.c > index 2f6247e80e9d..c5c75273d1e5 100644 > --- a/drivers/gpu/drm/msm/dp/dp_debug.c > +++ b/drivers/gpu/drm/msm/dp/dp_debug.c > @@ -365,7 +365,6 @@ static const struct file_operations test_active_fops = { > > static int dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor) Would be nice to make it void as well and then cleanup the caller. Can you do that too? > { > - int rc = 0; > struct dp_debug_private *debug = container_of(dp_debug, > struct dp_debug_private, dp_debug); >
Re: [Freedreno] [PATCH] drm/msm: Fix mmap to include VM_IO and VM_DONTDUMP
Quoting Douglas Anderson (2021-11-10 11:33:42) > In commit 510410bfc034 ("drm/msm: Implement mmap as GEM object > function") we switched to a new/cleaner method of doing things. That's > good, but we missed a little bit. > > Before that commit, we used to _first_ run through the > drm_gem_mmap_obj() case where `obj->funcs->mmap()` was NULL. That meant > that we ran: > > vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; > vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); > vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); > > ...and _then_ we modified those mappings with our own. Now that > `obj->funcs->mmap()` is no longer NULL we don't run the default > code. It looks like the fact that the vm_flags got VM_IO / VM_DONTDUMP > was important because we're now getting crashes on Chromebooks that > use ARC++ while logging out. Specifically a crash that looks like this > (this is on a 5.10 kernel w/ relevant backports but also seen on a > 5.15 kernel): > > Unable to handle kernel paging request at virtual address ffc00800 > Mem abort info: > ESR = 0x9606 > EC = 0x25: DABT (current EL), IL = 32 bits > SET = 0, FnV = 0 > EA = 0, S1PTW = 0 > Data abort info: > ISV = 0, ISS = 0x0006 > CM = 0, WnR = 0 > swapper pgtable: 4k pages, 39-bit VAs, pgdp=8293d000 > [ffc00800] pgd=0001002b3003, p4d=0001002b3003, > pud=0001002b3003, pmd= > Internal error: Oops: 9606 [#1] PREEMPT SMP > [...] > CPU: 7 PID: 15734 Comm: crash_dump64 Tainted: G W 5.10.67 #1 [...] > Hardware name: Qualcomm Technologies, Inc. sc7280 IDP SKU2 platform (DT) > pstate: 8049 (Nzcv daif +PAN -UAO -TCO BTYPE=--) > pc : __arch_copy_to_user+0xc0/0x30c > lr : copyout+0xac/0x14c > [...] > Call trace: >__arch_copy_to_user+0xc0/0x30c >copy_page_to_iter+0x1a0/0x294 >process_vm_rw_core+0x240/0x408 >process_vm_rw+0x110/0x16c >__arm64_sys_process_vm_readv+0x30/0x3c >el0_svc_common+0xf8/0x250 >do_el0_svc+0x30/0x80 >el0_svc+0x10/0x1c >el0_sync_handler+0x78/0x108 >el0_sync+0x184/0x1c0 > Code: f8408423 f80008c3 910020c6 36100082 (b8404423) > > Let's add the two flags back in. > > While we're at it, the fact that we aren't running the default means > that we _don't_ need to clear out VM_PFNMAP, so remove that and save > an instruction. > > NOTE: it was confirmed that VM_IO was the important flag to fix the > problem I was seeing, but adding back VM_DONTDUMP seems like a sane > thing to do so I'm doing that too. > > Fixes: 510410bfc034 ("drm/msm: Implement mmap as GEM object function") > Reported-by: Stephen Boyd > Signed-off-by: Douglas Anderson > --- Reviewed-by: Stephen Boyd Tested-by: Stephen Boyd
[Freedreno] [PATCH igt v3 4/4] msm: Add recovery tests
From: Rob Clark Add tests to exercise: 1. sw hangcheck timeout 2. gpu fault (hang) recovery 3. iova fault recovery Signed-off-by: Rob Clark --- lib/igt_msm.h| 3 + tests/meson.build| 1 + tests/msm_recovery.c | 174 +++ 3 files changed, 178 insertions(+) create mode 100644 tests/msm_recovery.c diff --git a/lib/igt_msm.h b/lib/igt_msm.h index 1a66c806..421d23ed 100644 --- a/lib/igt_msm.h +++ b/lib/igt_msm.h @@ -97,6 +97,9 @@ enum adreno_pm4_packet_type { enum adreno_pm4_type3_packets { CP_NOP = 16, + CP_WAIT_MEM_GTE = 20, + CP_WAIT_REG_MEM = 60, + CP_MEM_WRITE = 61, }; static inline unsigned diff --git a/tests/meson.build b/tests/meson.build index 0af3e03a..166e3494 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -60,6 +60,7 @@ test_progs = [ 'kms_vrr', 'kms_writeback', 'meta_test', + 'msm_recovery', 'msm_submit', 'panfrost_get_param', 'panfrost_gem_new', diff --git a/tests/msm_recovery.c b/tests/msm_recovery.c new file mode 100644 index ..890c543a --- /dev/null +++ b/tests/msm_recovery.c @@ -0,0 +1,174 @@ +/* + * Copyright © 2021 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "igt.h" +#include "igt_msm.h" + +static struct msm_device *dev; +static struct msm_bo *scratch_bo; +static uint32_t *scratch; + +/* + * Helpers for cmdstream packet building: + */ + +static void +wait_mem_gte(struct msm_cmd *cmd, uint32_t offset_dwords, uint32_t ref) +{ + msm_cmd_pkt7(cmd, CP_WAIT_MEM_GTE, 4); + msm_cmd_emit(cmd, 0); /* RESERVED */ + msm_cmd_bo (cmd, scratch_bo, offset_dwords * 4); /* POLL_ADDR_LO/HI */ + msm_cmd_emit(cmd, ref);/* REF */ +} + +static void +mem_write(struct msm_cmd *cmd, uint32_t offset_dwords, uint32_t val) +{ + msm_cmd_pkt7(cmd, CP_MEM_WRITE, 3); + msm_cmd_bo (cmd, scratch_bo, offset_dwords * 4); /* ADDR_LO/HI */ + msm_cmd_emit(cmd, val);/* VAL */ +} + +/* + * Helper to wait on a fence-fd: + */ +static void +wait_and_close(int fence_fd) +{ + poll(&(struct pollfd){fence_fd, POLLIN}, 1, -1); + close(fence_fd); +} + +/* + * Helper for hang tests. Emits multiple submits, with one in the middle + * that triggers a fault, and confirms that the submits before and after + * the faulting one execute properly, ie. that the driver properly manages + * to recover and re-queue the submits after the faulting submit; + */ +static void +do_hang_test(struct msm_pipe *pipe) +{ + struct msm_cmd *cmds[16]; + int fence_fds[ARRAY_SIZE(cmds)]; + + memset(scratch, 0, 0x1000); + + for (unsigned i = 0; i < ARRAY_SIZE(cmds); i++) { + struct msm_cmd *cmd = igt_msm_cmd_new(pipe, 0x1000); + + cmds[i] = cmd; + + /* +* Emit a packet to wait for scratch[0] to be >= 1 +* +* This lets us force the GPU to wait until all the cmdstream is +* queued up. +*/ + wait_mem_gte(cmd, 0, 1); + + if (i == 10) { + msm_cmd_emit(cmd, 0xdeaddead); + } + + /* Emit a packet to write scratch[1+i] = 2+i: */ + mem_write(cmd, 1+i, 2+i); + } + + for (unsigned i = 0; i < ARRAY_SIZE(cmds); i++) { + fence_fds[i] = igt_msm_cmd_submit(cmds[i]); + } + + usleep(1); + + /* Let the WAIT_MEM_GTE complete: */ + scratch[0] = 1; + + for (unsigned i = 0; i < ARRAY_SIZE(cmds); i++) { + wait_and_close(fence_fds[i]); + igt_msm_cmd_free(cmds[i]); + if (i == 10) + continue; + igt_assert_
[Freedreno] [PATCH igt v3 3/4] msm: Add helper for cmdstream building and submission
From: Rob Clark A pretty minimal subset compared to what a full gallium driver would need, but OTOH for igt tests we should only need to emit fairly basic command stream. Signed-off-by: Rob Clark --- lib/igt_msm.c | 102 ++ lib/igt_msm.h | 48 2 files changed, 150 insertions(+) diff --git a/lib/igt_msm.c b/lib/igt_msm.c index b9534164..e9cf588f 100644 --- a/lib/igt_msm.c +++ b/lib/igt_msm.c @@ -91,6 +91,19 @@ igt_msm_dev_close(struct msm_device *dev) free(dev); } +static uint64_t +get_iova(struct msm_bo *bo) +{ + struct drm_msm_gem_info req = { + .handle = bo->handle, + .info = MSM_INFO_GET_IOVA, + }; + + do_ioctl(bo->dev->fd, DRM_IOCTL_MSM_GEM_INFO, &req); + + return req.value; +} + /** * igt_msm_bo_new: * @dev: the device to allocate the BO from @@ -115,6 +128,7 @@ igt_msm_bo_new(struct msm_device *dev, size_t size, uint32_t flags) do_ioctl(dev->fd, DRM_IOCTL_MSM_GEM_NEW, &req); bo->handle = req.handle; + bo->iova = get_iova(bo); return bo; } @@ -209,3 +223,91 @@ igt_msm_pipe_close(struct msm_pipe *pipe) do_ioctl(pipe->dev->fd, DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE, &pipe->submitqueue_id); free(pipe); } + +/** + * igt_msm_cmd_new: + * @pipe: the submitqueue to submit cmdstream against + * @size: the size of requested cmdstream buffer + */ +struct msm_cmd * +igt_msm_cmd_new(struct msm_pipe *pipe, size_t size) +{ + struct msm_cmd *cmd = calloc(1, sizeof(*cmd)); + + cmd->pipe = pipe; + cmd->cmdstream_bo = igt_msm_bo_new(pipe->dev, size, MSM_BO_WC); + cmd->cur = igt_msm_bo_map(cmd->cmdstream_bo); + + __igt_msm_append_bo(cmd, cmd->cmdstream_bo); + + return cmd; +} + +static uint32_t +cmdstream_size(struct msm_cmd *cmd) +{ + uint8_t *start = igt_msm_bo_map(cmd->cmdstream_bo); + return (uint8_t *)cmd->cur - start; +} + +/** + * igt_msm_cmd_submit: + * @cmd: the command stream object to submit + * + * Returns dma-fence fd + */ +int +igt_msm_cmd_submit(struct msm_cmd *cmd) +{ + struct drm_msm_gem_submit_bo bos[cmd->nr_bos]; + struct drm_msm_gem_submit_cmd cmds[] = { + [0] = { + .type = MSM_SUBMIT_CMD_BUF, + .submit_idx = 0, + .size = cmdstream_size(cmd), + }, + }; + struct drm_msm_gem_submit req = { + .flags = cmd->pipe->pipe | MSM_SUBMIT_FENCE_FD_OUT, + .queueid = cmd->pipe->submitqueue_id, + .nr_cmds = ARRAY_SIZE(cmds), + .cmds= VOID2U64(cmds), + .nr_bos = ARRAY_SIZE(bos), + .bos = VOID2U64(bos), + }; + + for (unsigned i = 0; i < cmd->nr_bos; i++) { + bos[i] = (struct drm_msm_gem_submit_bo) { + .handle = cmd->bos[i]->handle, + .flags = MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE, + }; + } + + do_ioctl(cmd->pipe->dev->fd, DRM_IOCTL_MSM_GEM_SUBMIT, &req); + + return req.fence_fd; +} + +void +__igt_msm_append_bo(struct msm_cmd *cmd, struct msm_bo *bo) +{ + for (unsigned i = 0; i < cmd->nr_bos; i++) + if (cmd->bos[i] == bo) + return; + + assert((cmd->nr_bos + 1) < ARRAY_SIZE(cmd->bos)); + cmd->bos[cmd->nr_bos++] = bo; +} + +/** + * igt_msm_cmd_free: + * @cmd: the command stream object to free + * + * Free a command stream object + */ +void +igt_msm_cmd_free(struct msm_cmd *cmd) +{ + igt_msm_bo_free(cmd->cmdstream_bo); + free(cmd); +} diff --git a/lib/igt_msm.h b/lib/igt_msm.h index 99a099c1..1a66c806 100644 --- a/lib/igt_msm.h +++ b/lib/igt_msm.h @@ -24,6 +24,8 @@ #ifndef IGT_MSM_H #define IGT_MSM_H +#include "ioctl_wrappers.h" + #include "msm_drm.h" /** @@ -47,6 +49,7 @@ void igt_msm_dev_close(struct msm_device *dev); * @handle: the BO's GEM handle * @size: the BO's size * @map: the BO's memory mapping (if mapped) + * @iova: the BO's GPU address * * Helper wrapper for a GEM buffer object. */ @@ -55,6 +58,7 @@ struct msm_bo { int handle; uint32_t size; void *map; + uint64_t iova; }; struct msm_bo *igt_msm_bo_new(struct msm_device *dev, size_t size, uint32_t flags); @@ -136,6 +140,50 @@ pm4_pkt7_hdr(uint8_t opcode, uint16_t cnt) ((pm4_odd_parity_bit(opcode) << 23)); } +/** + * msm_cmd: + * @pipe: the submitqueue to submit cmdstream against + * @cmdstream_bo: the backing cmdstream buffer object + * @cur: pointer to current position in cmdstream + * + * Helper for building cmdstream and cmdstream submission + */ +struct msm_cmd { + struct msm_pipe *pipe; + struct msm_bo *cmdstream_bo; + uint32_t *cur; + uint32_t nr_bos; +
[Freedreno] [PATCH igt v3 2/4] lib/igt_debugfs: Add helper for detecting debugfs files
From: Rob Clark Add a helper that can be used with, for ex, igt_require() so that tests can be skipped if the kernel is too old. Signed-off-by: Rob Clark --- lib/igt_debugfs.c | 21 + lib/igt_debugfs.h | 1 + 2 files changed, 22 insertions(+) diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c index dd6f2995..7211c410 100644 --- a/lib/igt_debugfs.c +++ b/lib/igt_debugfs.c @@ -307,6 +307,27 @@ int igt_debugfs_open(int device, const char *filename, int mode) return ret; } +/** + * igt_debugfs_exists: + * @device: the drm device file fd + * @filename: file name + * @mode: mode bits as used by open() + * + * Test that the specified debugfs file exists and can be opened with the + * requested mode. + */ +bool igt_debugfs_exists(int device, const char *filename, int mode) +{ + int fd = igt_debugfs_open(device, filename, mode); + + if (fd >= 0) { + close(fd); + return true; + } + + return false; +} + /** * igt_debugfs_simple_read: * @filename: file name diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h index b4867681..37e85067 100644 --- a/lib/igt_debugfs.h +++ b/lib/igt_debugfs.h @@ -39,6 +39,7 @@ int igt_debugfs_connector_dir(int device, char *conn_name, int mode); int igt_debugfs_pipe_dir(int device, int pipe, int mode); int igt_debugfs_open(int fd, const char *filename, int mode); +bool igt_debugfs_exists(int fd, const char *filename, int mode); void __igt_debugfs_read(int fd, const char *filename, char *buf, int size); void __igt_debugfs_write(int fd, const char *filename, const char *buf, int size); int igt_debugfs_simple_read(int dir, const char *filename, char *buf, int size); -- 2.33.1
[Freedreno] [PATCH igt v3 0/4] msm: Add tests for gpu fault handling
From: Rob Clark The first patch adds a easy way to write debugfs files (needed to disable hw fault detection, so we can test the sw timeout fallback). The second adds some helpers for cmdstream building. And the third adds the new tests. v2: Fix headerdoc comments in first patch v3: Add helper to detect debugfs files and updated last patch to skip the one sub-test that depends on new debugfs when running on older kernels Rob Clark (4): lib/igt_debugfs: Add helper for writing debugfs files lib/igt_debugfs: Add helper for detecting debugfs files msm: Add helper for cmdstream building and submission msm: Add recovery tests lib/igt_debugfs.c| 38 ++ lib/igt_debugfs.h| 14 lib/igt_msm.c| 102 + lib/igt_msm.h| 51 + tests/meson.build| 1 + tests/msm_recovery.c | 174 +++ 6 files changed, 380 insertions(+) create mode 100644 tests/msm_recovery.c -- 2.33.1
[Freedreno] [PATCH igt v3 1/4] lib/igt_debugfs: Add helper for writing debugfs files
From: Rob Clark Signed-off-by: Rob Clark Reviewed-by: Petri Latvala --- lib/igt_debugfs.c | 17 + lib/igt_debugfs.h | 13 + 2 files changed, 30 insertions(+) diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c index a5bb95ca..dd6f2995 100644 --- a/lib/igt_debugfs.c +++ b/lib/igt_debugfs.c @@ -351,6 +351,23 @@ void __igt_debugfs_read(int fd, const char *filename, char *buf, int size) close(dir); } +/** + * __igt_debugfs_write: + * @fd: the drm device file fd + * @filename: file name + * @buf: buffer to be written to the debugfs file + * @size: size of the buffer + * + * This function opens the debugfs file, writes it, then closes the file. + */ +void __igt_debugfs_write(int fd, const char *filename, const char *buf, int size) +{ + int dir = igt_debugfs_dir(fd); + + igt_sysfs_write(dir, filename, buf, size); + close(dir); +} + /** * igt_debugfs_search: * @filename: file name diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h index d43ba6c6..b4867681 100644 --- a/lib/igt_debugfs.h +++ b/lib/igt_debugfs.h @@ -40,6 +40,7 @@ int igt_debugfs_pipe_dir(int device, int pipe, int mode); int igt_debugfs_open(int fd, const char *filename, int mode); void __igt_debugfs_read(int fd, const char *filename, char *buf, int size); +void __igt_debugfs_write(int fd, const char *filename, const char *buf, int size); int igt_debugfs_simple_read(int dir, const char *filename, char *buf, int size); bool igt_debugfs_search(int fd, const char *filename, const char *substring); @@ -54,6 +55,18 @@ bool igt_debugfs_search(int fd, const char *filename, const char *substring); #define igt_debugfs_read(fd, filename, buf) \ __igt_debugfs_read(fd, (filename), (buf), sizeof(buf)) +/** + * igt_debugfs_write: + * @fd: the drm device file fd + * @filename: name of the debugfs file + * @buf: buffer to be written to the debugfs file + * + * This is just a convenience wrapper for __igt_debugfs_write. See its + * documentation. + */ +#define igt_debugfs_write(fd, filename, buf) \ + __igt_debugfs_write(fd, (filename), (buf), sizeof(buf)) + /* * Pipe CRC */ -- 2.33.1
Re: [Freedreno] [PATCH v3] arm64: dts: qcom: sc7280: Add Display Port node
Quoting Kuogee Hsieh (2021-11-02 16:44:33) > From: Kuogee Hsieh > > Signed-off-by: Kuogee Hsieh > --- What tree is this based on? I don't see edp_phy upstream for sc7280 Otherwise, looks good to me. Reviewed-by: Stephen Boyd
Re: [Freedreno] [PATCH v4] drm/msm/dp: do not initialize phy until plugin interrupt received
On 2021-11-09 13:38, Kuogee Hsieh wrote: From: Kuogee Hsieh Current DP drivers have regulators, clocks, irq and phy are grouped together within a function and executed not in a symmetric manner. This increase difficulty of code maintenance and limited code scalability. This patch divided the driver life cycle of operation into four states, resume (including booting up), dongle plugin, dongle unplugged and suspend. Regulators, core clocks and irq are grouped together and enabled at resume (or booting up) so that the DP controller is armed and ready to receive HPD plugin interrupts. HPD plugin interrupt is generated when a dongle plugs into DUT (device under test). Once HPD plugin interrupt is received, DP controller will initialize phy so that dpcd read/write will function and following link training can be proceeded successfully. DP phy will be disabled after main link is teared down at end of unplugged HPD interrupt handle triggered by dongle unplugged out of DUT. Finally regulators, code clocks and irq are disabled at corresponding suspension. Changes in V2: -- removed unnecessary dp_ctrl NULL check -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs -- remove flip parameter out of dp_ctrl_irq_enable() -- add fixes tag Changes in V3: -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at dp_display_host_init() for eDP Changes in V4: -- rewording commit text to match this commit changes Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets") Signed-off-by: Kuogee Hsieh --- any more comments? drivers/gpu/drm/msm/dp/dp_ctrl.c| 87 - drivers/gpu/drm/msm/dp/dp_ctrl.h| 9 ++-- drivers/gpu/drm/msm/dp/dp_display.c | 83 ++- 3 files changed, 105 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 7ec155d..4788e8c 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1364,60 +1364,54 @@ static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl) return ret; } -int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset) +void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + dp_catalog_ctrl_reset(ctrl->catalog); + + dp_catalog_ctrl_enable_irq(ctrl->catalog, true); +} + +void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + dp_catalog_ctrl_reset(ctrl->catalog); + + dp_catalog_ctrl_enable_irq(ctrl->catalog, false); +} + +void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; struct dp_io *dp_io; struct phy *phy; - if (!dp_ctrl) { - DRM_ERROR("Invalid input data\n"); - return -EINVAL; - } - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); dp_io = &ctrl->parser->io; phy = dp_io->phy; - ctrl->dp_ctrl.orientation = flip; - - if (reset) - dp_catalog_ctrl_reset(ctrl->catalog); - - DRM_DEBUG_DP("flip=%d\n", flip); dp_catalog_ctrl_phy_reset(ctrl->catalog); phy_init(phy); - dp_catalog_ctrl_enable_irq(ctrl->catalog, true); - - return 0; } -/** - * dp_ctrl_host_deinit() - Uninitialize DP controller - * @dp_ctrl: Display Port Driver data - * - * Perform required steps to uninitialize DP controller - * and its resources. - */ -void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) +void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; struct dp_io *dp_io; struct phy *phy; - if (!dp_ctrl) { - DRM_ERROR("Invalid input data\n"); - return; - } - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); dp_io = &ctrl->parser->io; phy = dp_io->phy; - dp_catalog_ctrl_enable_irq(ctrl->catalog, false); + dp_catalog_ctrl_phy_reset(ctrl->catalog); phy_exit(phy); - - DRM_DEBUG_DP("Host deinitialized successfully\n"); } static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) @@ -1895,8 +1889,14 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) return ret; } + DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n", + (u32)(uintptr_t)phy, phy->init_count, phy->power_count); + phy_power_off(phy); + DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n", + (u32)(uintptr_t)phy, phy->init_count, phy->power_count); + /* aux channel down, reinit phy */ phy_exit(phy); phy_init(phy); @@ -1905,23 +1905,6 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctr
[Freedreno] [PATCH v4.5 12/14] dt-bindings: msm/dp: Add bindings for HDCP registers
From: Sean Paul This patch adds the bindings for the MSM DisplayPort HDCP registers which are required to write the HDCP key into the display controller as well as the registers to enable HDCP authentication/key exchange/encryption. We'll use a new compatible string for this since the fields are optional. Cc: Rob Herring Cc: Stephen Boyd Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-13-s...@poorly.run #v1 Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-13-s...@poorly.run #v2 Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-13-s...@poorly.run #v3 Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-13-s...@poorly.run #v4 Changes in v2: -Drop register range names (Stephen) -Fix yaml errors (Rob) Changes in v3: -Add new compatible string for dp-hdcp -Add descriptions to reg -Add minItems/maxItems to reg -Make reg depend on the new hdcp compatible string Changes in v4: -Rebase on Bjorn's multi-dp patchset Changes in v4.5: -Remove maxItems from reg (Rob) -Remove leading zeros in example (Rob) --- .../devicetree/bindings/display/msm/dp-controller.yaml | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index b36d74c1da7c..aff7d45ba6ed 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -21,12 +21,15 @@ properties: - qcom,sc8180x-edp reg: +minItems: 5 items: - description: ahb register block - description: aux register block - description: link register block - description: p0 register block - description: p1 register block + - description: (Optional) Registers for HDCP device key injection + - description: (Optional) Registers for HDCP TrustZone interaction interrupts: maxItems: 1 @@ -111,7 +114,9 @@ examples: <0xae90200 0x200>, <0xae90400 0xc00>, <0xae91000 0x400>, - <0xae91400 0x400>; + <0xae91400 0x400>, + <0xaed1000 0x174>, + <0xaee1000 0x2c>; interrupt-parent = <&mdss>; interrupts = <12>; clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, -- Sean Paul, Software Engineer, Google / Chromium OS
[Freedreno] [PATCH] drm/msm/adreno: Name the shadow buffer
From: Rob Clark This was the one GPU related kernel buffer which was not given a debug name. Let's fix that. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 2 ++ drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index ec8e043c9d38..a95977e8ad98 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -925,6 +925,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu) if (IS_ERR(a5xx_gpu->shadow)) return PTR_ERR(a5xx_gpu->shadow); + + msm_gem_object_set_name(a5xx_gpu->shadow_bo, "shadow"); } gpu_write64(gpu, REG_A5XX_CP_RB_RPTR_ADDR, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index dcde5eff931d..c6e7e7ca0482 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1068,6 +1068,8 @@ static int hw_init(struct msm_gpu *gpu) if (IS_ERR(a6xx_gpu->shadow)) return PTR_ERR(a6xx_gpu->shadow); + + msm_gem_object_set_name(a6xx_gpu->shadow_bo, "shadow"); } gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR_LO, -- 2.33.1
[Freedreno] [PATCH v3] drm/msm/dp: employ bridge mechanism for display enable and disable
Currently the msm_dp_*** functions implement the same sequence which would happen when drm_bridge is used. hence get rid of this intermediate layer and align with the drm_bridge usage to avoid customized implementation. Signed-off-by: Kuogee Hsieh Changes in v2: -- revise commit text -- rename dp_bridge to msm_dp_bridge -- delete empty functions Changes in 3: -- replace kzalloc() with devm_kzalloc() -- replace __dp_display_enable() with dp_display_enable() -- replace __dp_display_disable() with dp_display_disable() --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 21 --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 7 +++ drivers/gpu/drm/msm/dp/dp_display.c | 4 +- drivers/gpu/drm/msm/dp/dp_display.h | 1 + drivers/gpu/drm/msm/dp/dp_drm.c | 91 + drivers/gpu/drm/msm/msm_drv.h | 16 +++-- 6 files changed, 113 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 31050aa..c4e08c4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1003,9 +1003,6 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, trace_dpu_enc_mode_set(DRMID(drm_enc)); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) - msm_dp_display_mode_set(dpu_enc->dp, drm_enc, mode, adj_mode); - list_for_each_entry(conn_iter, connector_list, head) if (conn_iter->encoder == drm_enc) conn = conn_iter; @@ -1181,14 +1178,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) _dpu_encoder_virt_enable_helper(drm_enc); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - ret = msm_dp_display_enable(dpu_enc->dp, drm_enc); - if (ret) { - DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n", - ret); - goto out; - } - } dpu_enc->enabled = true; out: @@ -1214,11 +1203,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) /* wait for idle */ dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - if (msm_dp_display_pre_disable(dpu_enc->dp, drm_enc)) - DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n"); - } - dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); for (i = 0; i < dpu_enc->num_phys_encs; i++) { @@ -1243,11 +1227,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - if (msm_dp_display_disable(dpu_enc->dp, drm_enc)) - DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n"); - } - mutex_unlock(&dpu_enc->enc_lock); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 27d98b5..d16337f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -557,6 +557,13 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, encoder->base.id, rc); return rc; } + + rc = msm_dp_bridge_init(priv->dp[i], dev, encoder); + if (rc) { + DPU_ERROR("failed to setup DPU bridge %d: rc:%d\n", + encoder->base.id, rc); + return rc; + } } return rc; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 2f113ff..51770a4 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1674,8 +1674,8 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) } void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct dp_display_private *dp_display; diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 76f45f9..2237e80 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -13,6 +13,7 @@ struct msm_dp { struct drm_device *drm_dev; struct device *codec_dev; + struct drm_bridge *bridge; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_panel *drm_panel; diff --git a/
[Freedreno] [PATCH 5.15 261/917] drm/msm: prevent NULL dereference in msm_gpu_crashstate_capture()
From: Tim Gardner [ Upstream commit b220c154832c5cd0df34cbcbcc19d7135c16e823 ] Coverity complains of a possible NULL dereference: CID 120718 (#1 of 1): Dereference null return value (NULL_RETURNS) 23. dereference: Dereferencing a pointer that might be NULL state->bos when calling msm_gpu_crashstate_get_bo. [show details] 301msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, 302submit->bos[i].iova, submit->bos[i].flags); Fix this by employing the same state->bos NULL check as is used in the next for loop. Cc: Rob Clark Cc: Sean Paul Cc: David Airlie Cc: Daniel Vetter Cc: linux-arm-...@vger.kernel.org Cc: dri-de...@lists.freedesktop.org Cc: freedreno@lists.freedesktop.org Cc: linux-ker...@vger.kernel.org Signed-off-by: Tim Gardner Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210929162554.14295-1-tim.gard...@canonical.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 8a3a592da3a4d..2c46cd968ac4c 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -296,7 +296,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, state->bos = kcalloc(nr, sizeof(struct msm_gpu_state_bo), GFP_KERNEL); - for (i = 0; i < submit->nr_bos; i++) { + for (i = 0; state->bos && i < submit->nr_bos; i++) { if (should_dump(submit, i)) { msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, submit->bos[i].iova, submit->bos[i].flags); -- 2.33.0
Re: [Freedreno] [PATCH v2] drm/msm/dp: employ bridge mechanism for display enable and disable
On 11/6/2021 9:25 AM, Bjorn Andersson wrote: On Fri 05 Nov 16:22 CDT 2021, Kuogee Hsieh wrote: Currently the msm_dp_*** functions implement the same sequence which would happen when drm_bridge is used. hence get rid of this intermediate layer and align with the drm_bridge usage to avoid customized implementation. Signed-off-by: Kuogee Hsieh Changes in v2: -- revise commit text -- rename dp_bridge to msm_dp_bridge -- delete empty functions --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 21 --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 7 +++ drivers/gpu/drm/msm/dp/dp_display.c | 18 +++--- drivers/gpu/drm/msm/dp/dp_display.h | 1 + drivers/gpu/drm/msm/dp/dp_drm.c | 91 + drivers/gpu/drm/msm/msm_drv.h | 16 +++-- 6 files changed, 120 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 31050aa..c4e08c4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1003,9 +1003,6 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, trace_dpu_enc_mode_set(DRMID(drm_enc)); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) - msm_dp_display_mode_set(dpu_enc->dp, drm_enc, mode, adj_mode); - list_for_each_entry(conn_iter, connector_list, head) if (conn_iter->encoder == drm_enc) conn = conn_iter; @@ -1181,14 +1178,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) _dpu_encoder_virt_enable_helper(drm_enc); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - ret = msm_dp_display_enable(dpu_enc->dp, drm_enc); - if (ret) { - DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n", - ret); - goto out; - } - } dpu_enc->enabled = true; out: @@ -1214,11 +1203,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) /* wait for idle */ dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - if (msm_dp_display_pre_disable(dpu_enc->dp, drm_enc)) - DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n"); - } - dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); for (i = 0; i < dpu_enc->num_phys_encs; i++) { @@ -1243,11 +1227,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - if (msm_dp_display_disable(dpu_enc->dp, drm_enc)) - DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n"); - } - mutex_unlock(&dpu_enc->enc_lock); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 27d98b5..d16337f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -557,6 +557,13 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, encoder->base.id, rc); return rc; } + + rc = msm_dp_bridge_init(priv->dp[i], dev, encoder); + if (rc) { + DPU_ERROR("failed to setup DPU bridge %d: rc:%d\n", + encoder->base.id, rc); + return rc; + } } return rc; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index e41dd40..e9ea6ed 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -569,8 +569,8 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) return 0; }; -static int dp_display_enable(struct dp_display_private *dp, u32 data); -static int dp_display_disable(struct dp_display_private *dp, u32 data); +static int __dp_display_enable(struct dp_display_private *dp, u32 data); +static int __dp_display_disable(struct dp_display_private *dp, u32 data); Can you please help me understand why you're changing the name of these functions? static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) { @@ -855,7 +855,7 @@ static int dp_display_prepare(struct msm_dp *dp_display) return 0; } -static int dp_display_enable(struct dp_display_private *dp, u32 data) +static int __dp_display_enable(struct dp_display_private *dp, u32 data) { int rc = 0; @@ -898,7 +898,7 @@ static int dp_display_post_enable(struct msm_dp *dp_display) return 0; } -static int dp_display_disable(struct dp_display_private *dp, u32 data) +static int __dp_display_disable(st
[Freedreno] [PATCH 5.14 280/849] drm/msm: prevent NULL dereference in msm_gpu_crashstate_capture()
From: Tim Gardner [ Upstream commit b220c154832c5cd0df34cbcbcc19d7135c16e823 ] Coverity complains of a possible NULL dereference: CID 120718 (#1 of 1): Dereference null return value (NULL_RETURNS) 23. dereference: Dereferencing a pointer that might be NULL state->bos when calling msm_gpu_crashstate_get_bo. [show details] 301msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, 302submit->bos[i].iova, submit->bos[i].flags); Fix this by employing the same state->bos NULL check as is used in the next for loop. Cc: Rob Clark Cc: Sean Paul Cc: David Airlie Cc: Daniel Vetter Cc: linux-arm-...@vger.kernel.org Cc: dri-de...@lists.freedesktop.org Cc: freedreno@lists.freedesktop.org Cc: linux-ker...@vger.kernel.org Signed-off-by: Tim Gardner Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210929162554.14295-1-tim.gard...@canonical.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 0ebf7bc6ad097..8236989828ba3 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -404,7 +404,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, state->bos = kcalloc(nr, sizeof(struct msm_gpu_state_bo), GFP_KERNEL); - for (i = 0; i < submit->nr_bos; i++) { + for (i = 0; state->bos && i < submit->nr_bos; i++) { if (should_dump(submit, i)) { msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, submit->bos[i].iova, submit->bos[i].flags); -- 2.33.0
[Freedreno] [PATCH 5.10 218/575] drm/msm: prevent NULL dereference in msm_gpu_crashstate_capture()
From: Tim Gardner [ Upstream commit b220c154832c5cd0df34cbcbcc19d7135c16e823 ] Coverity complains of a possible NULL dereference: CID 120718 (#1 of 1): Dereference null return value (NULL_RETURNS) 23. dereference: Dereferencing a pointer that might be NULL state->bos when calling msm_gpu_crashstate_get_bo. [show details] 301msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, 302submit->bos[i].iova, submit->bos[i].flags); Fix this by employing the same state->bos NULL check as is used in the next for loop. Cc: Rob Clark Cc: Sean Paul Cc: David Airlie Cc: Daniel Vetter Cc: linux-arm-...@vger.kernel.org Cc: dri-de...@lists.freedesktop.org Cc: freedreno@lists.freedesktop.org Cc: linux-ker...@vger.kernel.org Signed-off-by: Tim Gardner Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210929162554.14295-1-tim.gard...@canonical.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 55d16489d0f3f..90c26da109026 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -376,7 +376,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, state->bos = kcalloc(nr, sizeof(struct msm_gpu_state_bo), GFP_KERNEL); - for (i = 0; i < submit->nr_bos; i++) { + for (i = 0; state->bos && i < submit->nr_bos; i++) { if (should_dump(submit, i)) { msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, submit->bos[i].iova, submit->bos[i].flags); -- 2.33.0
Re: [Freedreno] [PATCH 2/2] drm/msm: Restore error return on invalid fence
On Mon, Nov 15, 2021 at 6:43 AM Akhil P Oommen wrote: > > On 11/12/2021 12:54 AM, Rob Clark wrote: > > From: Rob Clark > > > > When converting to use an idr to map userspace fence seqno values back > > to a dma_fence, we lost the error return when userspace passes seqno > > that is larger than the last submitted fence. Restore this check. > > > > Reported-by: Akhil P Oommen > > Fixes: a61acbbe9cf8 ("drm/msm: Track "seqno" fences by idr") > > Signed-off-by: Rob Clark > > --- > > Note: I will rebase "drm/msm: Handle fence rollover" on top of this, > > to simplify backporting this patch to stable kernels > > > > drivers/gpu/drm/msm/msm_drv.c| 6 ++ > > drivers/gpu/drm/msm/msm_gem_submit.c | 1 + > > drivers/gpu/drm/msm/msm_gpu.h| 3 +++ > > 3 files changed, 10 insertions(+) > > > > diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c > > index cb14d997c174..56500eb5219e 100644 > > --- a/drivers/gpu/drm/msm/msm_drv.c > > +++ b/drivers/gpu/drm/msm/msm_drv.c > > @@ -967,6 +967,12 @@ static int wait_fence(struct msm_gpu_submitqueue > > *queue, uint32_t fence_id, > > struct dma_fence *fence; > > int ret; > > > > + if (fence_id > queue->last_fence) { > > But fence_id can wrap around and then this check won't be valid. that is correct, but see my note about rebasing "drm/msm: Handle fence rollover" on top of this patch, so this patch could be more easily cherry-picked to stable/lts branches BR, -R > -Akhil. > > > + DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of > > %u)\n", > > + fence_id, queue->last_fence); > > + return -EINVAL; > > + } > > + > > /* > >* Map submitqueue scoped "seqno" (which is actually an idr key) > >* back to underlying dma-fence > > diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c > > b/drivers/gpu/drm/msm/msm_gem_submit.c > > index 151d19e4453c..a38f23be497d 100644 > > --- a/drivers/gpu/drm/msm/msm_gem_submit.c > > +++ b/drivers/gpu/drm/msm/msm_gem_submit.c > > @@ -911,6 +911,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void > > *data, > > drm_sched_entity_push_job(&submit->base, queue->entity); > > > > args->fence = submit->fence_id; > > + queue->last_fence = submit->fence_id; > > > > msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs); > > msm_process_post_deps(post_deps, args->nr_out_syncobjs, > > diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h > > index bd4e0024033e..e73a5bb03544 100644 > > --- a/drivers/gpu/drm/msm/msm_gpu.h > > +++ b/drivers/gpu/drm/msm/msm_gpu.h > > @@ -376,6 +376,8 @@ static inline int msm_gpu_convert_priority(struct > > msm_gpu *gpu, int prio, > >* @ring_nr: the ringbuffer used by this submitqueue, which is > > determined > >* by the submitqueue's priority > >* @faults:the number of GPU hangs associated with this submitqueue > > + * @last_fence: the sequence number of the last allocated fence (for error > > + * checking) > >* @ctx: the per-drm_file context associated with the submitqueue > > (ie. > >* which set of pgtables do submits jobs associated with the > >* submitqueue use) > > @@ -391,6 +393,7 @@ struct msm_gpu_submitqueue { > > u32 flags; > > u32 ring_nr; > > int faults; > > + uint32_t last_fence; > > struct msm_file_private *ctx; > > struct list_head node; > > struct idr fence_idr; > > >
Re: [Freedreno] [PATCH v3] arm64: dts: qcom: sc7280: Add Display Port node
On 2021-11-02 16:44, Kuogee Hsieh wrote: From: Kuogee Hsieh Signed-off-by: Kuogee Hsieh --- Anyone has comments on this patch? Changes in v2: -- move fixes of dp_phy reg property to other patch Changes in v3: -- delete "qcom,sc7180-dp" from msm_dp node arch/arm64/boot/dts/qcom/sc7280.dtsi | 89 +++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index fb2f1506..4414abc 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -2709,8 +2709,8 @@ <&gcc GCC_DISP_GPLL0_CLK_SRC>, <&dsi_phy 0>, <&dsi_phy 1>, -<0>, -<0>, +<&dp_phy 0>, +<&dp_phy 1>, <&edp_phy 0>, <&edp_phy 1>; clock-names = "bi_tcxo", @@ -2807,6 +2807,13 @@ remote-endpoint = <&edp_in>; }; }; + + port@2 { +reg = <2>; +dpu_intf0_out: endpoint { + remote-endpoint = <&dp_in>; +}; +}; }; mdp_opp_table: opp-table { @@ -3018,6 +3025,78 @@ status = "disabled"; }; + + msm_dp: displayport-controller@ae9 { + status = "disabled"; + compatible = "qcom,sc7280-dp"; + + reg = <0 0x0ae9 0 0x1400>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, +<&dispcc DISP_CC_MDSS_DP_AUX_CLK>, +<&dispcc DISP_CC_MDSS_DP_LINK_CLK>, +<&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, +<&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + #clock-cells = <1>; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; + assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; + phys = <&dp_phy>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd SC7280_CX>; + + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dp_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + dp_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-16000 { + opp-hz = /bits/ 64 <16000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-27000 { + opp-hz = /bits/ 64 <27000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540
Re: [Freedreno] [PATCH 2/2] drm/msm: Restore error return on invalid fence
On 11/12/2021 12:54 AM, Rob Clark wrote: From: Rob Clark When converting to use an idr to map userspace fence seqno values back to a dma_fence, we lost the error return when userspace passes seqno that is larger than the last submitted fence. Restore this check. Reported-by: Akhil P Oommen Fixes: a61acbbe9cf8 ("drm/msm: Track "seqno" fences by idr") Signed-off-by: Rob Clark --- Note: I will rebase "drm/msm: Handle fence rollover" on top of this, to simplify backporting this patch to stable kernels drivers/gpu/drm/msm/msm_drv.c| 6 ++ drivers/gpu/drm/msm/msm_gem_submit.c | 1 + drivers/gpu/drm/msm/msm_gpu.h| 3 +++ 3 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index cb14d997c174..56500eb5219e 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -967,6 +967,12 @@ static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id, struct dma_fence *fence; int ret; + if (fence_id > queue->last_fence) { But fence_id can wrap around and then this check won't be valid. -Akhil. + DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of %u)\n", + fence_id, queue->last_fence); + return -EINVAL; + } + /* * Map submitqueue scoped "seqno" (which is actually an idr key) * back to underlying dma-fence diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 151d19e4453c..a38f23be497d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -911,6 +911,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, drm_sched_entity_push_job(&submit->base, queue->entity); args->fence = submit->fence_id; + queue->last_fence = submit->fence_id; msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs); msm_process_post_deps(post_deps, args->nr_out_syncobjs, diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index bd4e0024033e..e73a5bb03544 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -376,6 +376,8 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, * @ring_nr: the ringbuffer used by this submitqueue, which is determined * by the submitqueue's priority * @faults:the number of GPU hangs associated with this submitqueue + * @last_fence: the sequence number of the last allocated fence (for error + * checking) * @ctx: the per-drm_file context associated with the submitqueue (ie. * which set of pgtables do submits jobs associated with the * submitqueue use) @@ -391,6 +393,7 @@ struct msm_gpu_submitqueue { u32 flags; u32 ring_nr; int faults; + uint32_t last_fence; struct msm_file_private *ctx; struct list_head node; struct idr fence_idr;