diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-common.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-common.yaml index 6b57ce41c95f2221d7bbf2eb76ab05975c6fced0..d0ce85a08b6dc25be6ee80f3132fa66455fe9321 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-common.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-common.yaml @@ -15,6 +15,8 @@ description: properties: "#clock-cells": const: 1 + description: + See include/dt-bindings/clock/qcom,dsi-phy-28nm.h for clock IDs. "#phy-cells": const: 0 diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml index 1ea50a2c7c8e9f420125ad30a80b4ebd05c9367a..59192c59ddb9c126ada43ada1430fa7569651f99 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml @@ -30,10 +30,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -91,9 +95,9 @@ examples: reg = <0x0ae00000 0x1000>; reg-names = "mdss"; - interconnects = <&mmss_noc MASTER_MDP 0 &gem_noc SLAVE_LLCC 0>, - <&mc_virt MASTER_LLCC 0 &mc_virt SLAVE_EBI1 0>; - interconnect-names = "mdp0-mem", "mdp1-mem"; + interconnects = <&mmss_noc MASTER_MDP 0 &mc_virt SLAVE_EBI1 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_DISPLAY_CFG 0>; + interconnect-names = "mdp0-mem", "cpu-cfg"; resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml index 24cece1e888bd35f169dc3764966685de4b6da1d..a1c53e1910330af473a1e6c7827026e0770131ee 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml @@ -29,10 +29,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -75,12 +79,17 @@ examples: #include <dt-bindings/clock/qcom,rpmh.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/power/qcom,rpmhpd.h> + #include <dt-bindings/interconnect/qcom,sm8650-rpmh.h> display-subsystem@ae00000 { compatible = "qcom,sm8650-mdss"; reg = <0x0ae00000 0x1000>; reg-names = "mdss"; + interconnects = <&mmss_noc MASTER_MDP 0 &mc_virt SLAVE_EBI1 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_DISPLAY_CFG 0>; + interconnect-names = "mdp0-mem", "cpu-cfg"; + resets = <&dispcc_core_bcr>; power-domains = <&dispcc_gdsc>; diff --git a/MAINTAINERS b/MAINTAINERS index 43b55429f0fc97e77c4f10428e4419646ecee59c..9f29ec77a654662e56fbcdcf36a8f4617bcb250a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7392,6 +7392,7 @@ T: git https://gitlab.freedesktop.org/drm/msm.git F: Documentation/devicetree/bindings/display/msm/ F: drivers/gpu/drm/ci/xfails/msm* F: drivers/gpu/drm/msm/ +F: include/dt-bindings/clock/qcom,dsi-phy-28nm.h F: include/uapi/drm/msm_drm.h DRM DRIVER FOR NOVATEK NT35510 PANELS diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h index d761ed705bac30d9ffef3c0c9140e5e8a5e930ad..744012892b7c132c68627897dc49ac2da8e24a39 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h @@ -27,6 +27,7 @@ static const struct dpu_mdp_cfg sm6150_mdp = { [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; @@ -162,6 +163,21 @@ static const struct dpu_pingpong_cfg sm6150_pp[] = { }, }; +static const struct dpu_wb_cfg sm6150_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SM8250_MASK, + .format_list = wb2_formats_rgb, + .num_formats = ARRAY_SIZE(wb2_formats_rgb), + .clk_ctrl = DPU_CLK_CTRL_WB2, + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 2160, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + static const struct dpu_intf_cfg sm6150_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -242,6 +258,8 @@ const struct dpu_mdss_cfg dpu_sm6150_cfg = { .dspp = sm6150_dspp, .pingpong_count = ARRAY_SIZE(sm6150_pp), .pingpong = sm6150_pp, + .wb_count = ARRAY_SIZE(sm6150_wb), + .wb = sm6150_wb, .intf_count = ARRAY_SIZE(sm6150_intf), .intf = sm6150_intf, .vbif_count = ARRAY_SIZE(sdm845_vbif), diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index e5dcd41a361f45be20c7d4414de4bf7a42ce3d3b..29485e76f531fad765d586612528cf3f0c9e7a89 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1262,10 +1262,6 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, DRM_DEBUG_ATOMIC("%s: check\n", dpu_crtc->name); - /* force a full mode set if active state changed */ - if (crtc_state->active_changed) - crtc_state->mode_changed = true; - if (cstate->num_mixers) { rc = _dpu_crtc_check_and_setup_lm_bounds(crtc, crtc_state); if (rc) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 48e6e8d74c855b1fcf13c8f42516437039fc27da..1fc220a2ce0d9850a714a906a7b25425ace14a5e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -622,9 +622,9 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc) if (dpu_enc->phys_encs[i]) intf_count++; - /* See dpu_encoder_get_topology, we only support 2:2:1 topology */ - if (dpu_enc->dsc) - num_dsc = 2; + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) + if (dpu_enc->hw_dsc[i]) + num_dsc++; return (num_dsc > 0) && (num_dsc > intf_count); } @@ -649,11 +649,14 @@ struct drm_dsc_config *dpu_encoder_get_dsc_config(struct drm_encoder *drm_enc) static struct msm_display_topology dpu_encoder_get_topology( struct dpu_encoder_virt *dpu_enc, - struct dpu_kms *dpu_kms, struct drm_display_mode *mode, struct drm_crtc_state *crtc_state, - struct drm_dsc_config *dsc) + struct drm_connector_state *conn_state) { + struct msm_drm_private *priv = dpu_enc->base.dev->dev_private; + struct msm_display_info *disp_info = &dpu_enc->disp_info; + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + struct drm_dsc_config *dsc = dpu_encoder_get_dsc_config(&dpu_enc->base); struct msm_display_topology topology = {0}; int i, intf_count = 0; @@ -686,14 +689,38 @@ static struct msm_display_topology dpu_encoder_get_topology( if (dsc) { /* - * In case of Display Stream Compression (DSC), we would use - * 2 DSC encoders, 2 layer mixers and 1 interface - * this is power optimal and can drive up to (including) 4k - * screens + * Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces + * when Display Stream Compression (DSC) is enabled, + * and when enough DSC blocks are available. + * This is power-optimal and can drive up to (including) 4k + * screens. */ - topology.num_dsc = 2; - topology.num_lm = 2; - topology.num_intf = 1; + WARN(topology.num_intf > 2, + "DSC topology cannot support more than 2 interfaces\n"); + if (intf_count >= 2 || dpu_kms->catalog->dsc_count >= 2) { + topology.num_dsc = 2; + topology.num_lm = 2; + } else { + topology.num_dsc = 1; + topology.num_lm = 1; + } + } + + /* + * Use CDM only for writeback or DP at the moment as other interfaces cannot handle it. + * If writeback itself cannot handle cdm for some reason it will fail in its atomic_check() + * earlier. + */ + if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) { + struct drm_framebuffer *fb; + + fb = conn_state->writeback_job->fb; + + if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb))) + topology.needs_cdm = true; + } else if (disp_info->intf_type == INTF_DP) { + if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], mode)) + topology.needs_cdm = true; } return topology; @@ -733,6 +760,34 @@ static void dpu_encoder_assign_crtc_resources(struct dpu_kms *dpu_kms, cstate->num_mixers = num_lm; } +/** + * dpu_encoder_virt_check_mode_changed: check if full modeset is required + * @drm_enc: Pointer to drm encoder structure + * @crtc_state: Corresponding CRTC state to be checked + * @conn_state: Corresponding Connector's state to be checked + * + * Check if the changes in the object properties demand full mode set. + */ +int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + struct msm_display_topology topology; + + DPU_DEBUG_ENC(dpu_enc, "\n"); + + /* Using mode instead of adjusted_mode as it wasn't computed yet */ + topology = dpu_encoder_get_topology(dpu_enc, &crtc_state->mode, crtc_state, conn_state); + + if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm) + crtc_state->mode_changed = true; + else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm) + crtc_state->mode_changed = true; + + return 0; +} + static int dpu_encoder_virt_atomic_check( struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, @@ -743,10 +798,7 @@ static int dpu_encoder_virt_atomic_check( struct dpu_kms *dpu_kms; struct drm_display_mode *adj_mode; struct msm_display_topology topology; - struct msm_display_info *disp_info; struct dpu_global_state *global_state; - struct drm_framebuffer *fb; - struct drm_dsc_config *dsc; int ret = 0; if (!drm_enc || !crtc_state || !conn_state) { @@ -759,7 +811,6 @@ static int dpu_encoder_virt_atomic_check( DPU_DEBUG_ENC(dpu_enc, "\n"); priv = drm_enc->dev->dev_private; - disp_info = &dpu_enc->disp_info; dpu_kms = to_dpu_kms(priv->kms); adj_mode = &crtc_state->adjusted_mode; global_state = dpu_kms_get_global_state(crtc_state->state); @@ -768,37 +819,15 @@ static int dpu_encoder_virt_atomic_check( trace_dpu_enc_atomic_check(DRMID(drm_enc)); - dsc = dpu_encoder_get_dsc_config(drm_enc); - - topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, crtc_state, dsc); - - /* - * Use CDM only for writeback or DP at the moment as other interfaces cannot handle it. - * If writeback itself cannot handle cdm for some reason it will fail in its atomic_check() - * earlier. - */ - if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) { - fb = conn_state->writeback_job->fb; - - if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb))) - topology.needs_cdm = true; - } else if (disp_info->intf_type == INTF_DP) { - if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode)) - topology.needs_cdm = true; - } + topology = dpu_encoder_get_topology(dpu_enc, adj_mode, crtc_state, conn_state); - if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm) - crtc_state->mode_changed = true; - else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm) - crtc_state->mode_changed = true; /* * Release and Allocate resources on every modeset - * Dont allocate when active is false. */ if (drm_atomic_crtc_needs_modeset(crtc_state)) { dpu_rm_release(global_state, drm_enc); - if (!crtc_state->active_changed || crtc_state->enable) + if (crtc_state->enable) ret = dpu_rm_reserve(&dpu_kms->rm, global_state, drm_enc, crtc_state, &topology); if (!ret) @@ -2020,7 +2049,6 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_ctl *ctl, static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, struct drm_dsc_config *dsc) { - /* coding only for 2LM, 2enc, 1 dsc config */ struct dpu_encoder_phys *enc_master = dpu_enc->cur_master; struct dpu_hw_ctl *ctl = enc_master->hw_ctl; struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; @@ -2030,22 +2058,24 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, int dsc_common_mode; int pic_width; u32 initial_lines; + int num_dsc = 0; int i; for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { hw_pp[i] = dpu_enc->hw_pp[i]; hw_dsc[i] = dpu_enc->hw_dsc[i]; - if (!hw_pp[i] || !hw_dsc[i]) { - DPU_ERROR_ENC(dpu_enc, "invalid params for DSC\n"); - return; - } + if (!hw_pp[i] || !hw_dsc[i]) + break; + + num_dsc++; } - dsc_common_mode = 0; pic_width = dsc->pic_width; - dsc_common_mode = DSC_MODE_SPLIT_PANEL; + dsc_common_mode = 0; + if (num_dsc > 1) + dsc_common_mode |= DSC_MODE_SPLIT_PANEL; if (dpu_encoder_use_dsc_merge(enc_master->parent)) dsc_common_mode |= DSC_MODE_MULTIPLEX; if (enc_master->intf_mode == INTF_MODE_VIDEO) @@ -2054,14 +2084,10 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, this_frame_slices = pic_width / dsc->slice_width; intf_ip_w = this_frame_slices * dsc->slice_width; - /* - * dsc merge case: when using 2 encoders for the same stream, - * no. of slices need to be same on both the encoders. - */ - enc_ip_w = intf_ip_w / 2; + enc_ip_w = intf_ip_w / num_dsc; initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w); - for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) + for (i = 0; i < num_dsc; i++) dpu_encoder_dsc_pipe_cfg(ctl, hw_dsc[i], hw_pp[i], dsc, dsc_common_mode, initial_lines); } @@ -2183,8 +2209,8 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) memset(&mixer, 0, sizeof(mixer)); /* reset all mixers for this encoder */ - if (phys_enc->hw_ctl->ops.clear_all_blendstages) - phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl); + if (ctl->ops.clear_all_blendstages) + ctl->ops.clear_all_blendstages(ctl); global_state = dpu_kms_get_existing_global_state(phys_enc->dpu_kms); @@ -2193,12 +2219,12 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) for (i = 0; i < num_lm; i++) { hw_mixer[i] = to_dpu_hw_mixer(hw_lm[i]); - if (phys_enc->hw_ctl->ops.update_pending_flush_mixer) - phys_enc->hw_ctl->ops.update_pending_flush_mixer(ctl, hw_mixer[i]->idx); + if (ctl->ops.update_pending_flush_mixer) + ctl->ops.update_pending_flush_mixer(ctl, hw_mixer[i]->idx); /* clear all blendstages */ - if (phys_enc->hw_ctl->ops.setup_blendstage) - phys_enc->hw_ctl->ops.setup_blendstage(ctl, hw_mixer[i]->idx, NULL); + if (ctl->ops.setup_blendstage) + ctl->ops.setup_blendstage(ctl, hw_mixer[i]->idx, NULL); } } @@ -2250,7 +2276,7 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) dpu_enc = to_dpu_encoder_virt(phys_enc->parent); - phys_enc->hw_ctl->ops.reset(ctl); + ctl->ops.reset(ctl); dpu_encoder_helper_reset_mixers(phys_enc); @@ -2265,8 +2291,8 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, PINGPONG_NONE); /* mark WB flush as pending */ - if (phys_enc->hw_ctl->ops.update_pending_flush_wb) - phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, phys_enc->hw_wb->idx); + if (ctl->ops.update_pending_flush_wb) + ctl->ops.update_pending_flush_wb(ctl, phys_enc->hw_wb->idx); } else { for (i = 0; i < dpu_enc->num_phys_encs; i++) { if (dpu_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk) @@ -2275,8 +2301,8 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) PINGPONG_NONE); /* mark INTF flush as pending */ - if (phys_enc->hw_ctl->ops.update_pending_flush_intf) - phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl, + if (ctl->ops.update_pending_flush_intf) + ctl->ops.update_pending_flush_intf(ctl, dpu_enc->phys_encs[i]->hw_intf->idx); } } @@ -2288,8 +2314,8 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) if (phys_enc->hw_pp && phys_enc->hw_pp->merge_3d) { phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d, BLEND_3D_NONE); - if (phys_enc->hw_ctl->ops.update_pending_flush_merge_3d) - phys_enc->hw_ctl->ops.update_pending_flush_merge_3d(ctl, + if (ctl->ops.update_pending_flush_merge_3d) + ctl->ops.update_pending_flush_merge_3d(ctl, phys_enc->hw_pp->merge_3d->idx); } @@ -2297,9 +2323,9 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) if (phys_enc->hw_cdm->ops.bind_pingpong_blk && phys_enc->hw_pp) phys_enc->hw_cdm->ops.bind_pingpong_blk(phys_enc->hw_cdm, PINGPONG_NONE); - if (phys_enc->hw_ctl->ops.update_pending_flush_cdm) - phys_enc->hw_ctl->ops.update_pending_flush_cdm(phys_enc->hw_ctl, - phys_enc->hw_cdm->idx); + if (ctl->ops.update_pending_flush_cdm) + ctl->ops.update_pending_flush_cdm(ctl, + phys_enc->hw_cdm->idx); } if (dpu_enc->dsc) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 92b5ee390788d16e85e195a664417896a2bf1cae..da133ee4701a329f566f6f9a7255f2f6d050f891 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -88,4 +88,8 @@ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc, bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc); +int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); + #endif /* __DPU_ENCODER_H__ */ 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 e9bbccc44dad8b391cd51daf902307105b2598fc..da9994a79ca293ec0265680c438835742102db2a 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 @@ -5,6 +5,7 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ #include <linux/delay.h> +#include <linux/string_choices.h> #include "dpu_encoder_phys.h" #include "dpu_hw_interrupts.h" #include "dpu_hw_pingpong.h" @@ -261,7 +262,7 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( DRM_DEBUG_KMS("id:%u pp:%d enable=%s/%d\n", DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, - enable ? "true" : "false", refcount); + str_true_false(enable), refcount); if (enable) { if (phys_enc->vblank_refcount == 0) @@ -285,7 +286,7 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( DRM_ERROR("vblank irq err id:%u pp:%d ret:%d, enable %s/%d\n", DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, ret, - enable ? "true" : "false", refcount); + str_true_false(enable), refcount); } return ret; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 97e9cb8c2b099f4757169cadf7e941148d2bfb16..9748d24b3ffde45992d28b697a88db5992b00c69 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -446,6 +446,31 @@ static void dpu_kms_disable_commit(struct msm_kms *kms) pm_runtime_put_sync(&dpu_kms->pdev->dev); } +static int dpu_kms_check_mode_changed(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct drm_crtc_state *new_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *new_conn_state; + int i; + + for_each_new_connector_in_state(state, connector, new_conn_state, i) { + struct drm_encoder *encoder; + + WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc); + + if (!new_conn_state->crtc || !new_conn_state->best_encoder) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + + encoder = new_conn_state->best_encoder; + + dpu_encoder_virt_check_mode_changed(encoder, new_crtc_state, new_conn_state); + } + + return 0; +} + static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask) { struct dpu_kms *dpu_kms = to_dpu_kms(kms); @@ -1062,6 +1087,7 @@ static const struct msm_kms_funcs kms_funcs = { .irq = dpu_core_irq, .enable_commit = dpu_kms_enable_commit, .disable_commit = dpu_kms_disable_commit, + .check_mode_changed = dpu_kms_check_mode_changed, .flush_commit = dpu_kms_flush_commit, .wait_flush = dpu_kms_wait_flush, .complete_commit = dpu_kms_complete_commit, diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c index 666de99a46a5b1fb2511eae4d2b069b6257a07bb..fc183fe37f56a756e0202204dbb8b1feed460240 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c @@ -3,6 +3,7 @@ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. */ +#include <linux/string_choices.h> #include "mdp5_kms.h" #include "mdp5_ctl.h" @@ -233,7 +234,7 @@ int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, return -EINVAL; ctl->encoder_enabled = enabled; - DBG("intf_%d: %s", intf->num, enabled ? "on" : "off"); + DBG("intf_%d: %s", intf->num, str_on_off(enabled)); if (start_signal_needed(ctl, pipeline)) { send_start_signal(ctl); diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 9c463ae2f8fae916661fef1c7e225f55c1026478..d8633a596f8da88cc55f60de80bec8999ffb07c8 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -11,6 +11,7 @@ #include <linux/phy/phy.h> #include <linux/phy/phy-dp.h> #include <linux/pm_opp.h> +#include <linux/string_choices.h> #include <drm/display/drm_dp_helper.h> #include <drm/drm_fixed.h> @@ -1366,9 +1367,9 @@ int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "enable core clocks \n"); drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n", - ctrl->stream_clks_on ? "on" : "off", - ctrl->link_clks_on ? "on" : "off", - ctrl->core_clks_on ? "on" : "off"); + str_on_off(ctrl->stream_clks_on), + str_on_off(ctrl->link_clks_on), + str_on_off(ctrl->core_clks_on)); return 0; } @@ -1385,9 +1386,9 @@ void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "disable core clocks \n"); drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n", - ctrl->stream_clks_on ? "on" : "off", - ctrl->link_clks_on ? "on" : "off", - ctrl->core_clks_on ? "on" : "off"); + str_on_off(ctrl->stream_clks_on), + str_on_off(ctrl->link_clks_on), + str_on_off(ctrl->core_clks_on)); } static int msm_dp_ctrl_link_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl) @@ -1416,9 +1417,9 @@ static int msm_dp_ctrl_link_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "enable link clocks\n"); drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n", - ctrl->stream_clks_on ? "on" : "off", - ctrl->link_clks_on ? "on" : "off", - ctrl->core_clks_on ? "on" : "off"); + str_on_off(ctrl->stream_clks_on), + str_on_off(ctrl->link_clks_on), + str_on_off(ctrl->core_clks_on)); return 0; } @@ -1435,9 +1436,9 @@ static void msm_dp_ctrl_link_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "disabled link clocks\n"); drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n", - ctrl->stream_clks_on ? "on" : "off", - ctrl->link_clks_on ? "on" : "off", - ctrl->core_clks_on ? "on" : "off"); + str_on_off(ctrl->stream_clks_on), + str_on_off(ctrl->link_clks_on), + str_on_off(ctrl->core_clks_on)); } static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 9aa8bbd73d869df7c8929faf8f5dbd1ecf901e2a..bbc47d86ae9e67245c87a8365df366cce0dc529e 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -11,6 +11,7 @@ #include <linux/of_irq.h> #include <linux/phy/phy.h> #include <linux/delay.h> +#include <linux/string_choices.h> #include <drm/display/drm_dp_aux_bus.h> #include <drm/drm_edid.h> @@ -343,8 +344,7 @@ static int msm_dp_display_send_hpd_notification(struct msm_dp_display_private *d { if ((hpd && dp->msm_dp_display.link_ready) || (!hpd && !dp->msm_dp_display.link_ready)) { - drm_dbg_dp(dp->drm_dev, "HPD already %s\n", - (hpd ? "on" : "off")); + drm_dbg_dp(dp->drm_dev, "HPD already %s\n", str_on_off(hpd)); return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 022b3e815cf39e33edc8a54963722d045ac74535..cca57e56c906255a315e759e85a5af5982c80e9c 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -3,6 +3,7 @@ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ +#include <linux/string_choices.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic.h> #include <drm/drm_bridge.h> @@ -25,7 +26,7 @@ static enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge) dp = to_dp_bridge(bridge)->msm_dp_display; drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", - (dp->link_ready) ? "true" : "false"); + str_true_false(dp->link_ready)); return (dp->link_ready) ? connector_status_connected : connector_status_disconnected; @@ -41,7 +42,7 @@ static int msm_dp_bridge_atomic_check(struct drm_bridge *bridge, dp = to_dp_bridge(bridge)->msm_dp_display; drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", - (dp->link_ready) ? "true" : "false"); + str_true_false(dp->link_ready)); /* * There is no protection in the DRM framework to check if the display diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 007311c21fdaa0462b05d53cd8a2aad0269b1727..4d75529c0e858160761f5eb55db65e5d7565c27b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -179,18 +179,18 @@ struct msm_dsi_host { int irq; }; - static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg) { return readl(msm_host->ctrl_base + reg); } + static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data) { writel(data, msm_host->ctrl_base + reg); } -static const struct msm_dsi_cfg_handler *dsi_get_config( - struct msm_dsi_host *msm_host) +static const struct msm_dsi_cfg_handler * +dsi_get_config(struct msm_dsi_host *msm_host) { const struct msm_dsi_cfg_handler *cfg_hnd = NULL; struct device *dev = &msm_host->pdev->dev; @@ -200,7 +200,8 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( ahb_clk = msm_clk_get(msm_host->pdev, "iface"); if (IS_ERR(ahb_clk)) { - pr_err("%s: cannot get interface clock\n", __func__); + dev_err_probe(dev, PTR_ERR(ahb_clk), "%s: cannot get interface clock\n", + __func__); goto exit; } @@ -208,13 +209,13 @@ static const struct msm_dsi_cfg_handler *dsi_get_config( ret = clk_prepare_enable(ahb_clk); if (ret) { - pr_err("%s: unable to enable ahb_clk\n", __func__); + dev_err_probe(dev, ret, "%s: unable to enable ahb_clk\n", __func__); goto runtime_put; } ret = dsi_get_version(msm_host->ctrl_base, &major, &minor); if (ret) { - pr_err("%s: Invalid version\n", __func__); + dev_err_probe(dev, ret, "%s: Invalid version\n", __func__); goto disable_clks; } @@ -281,42 +282,31 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) msm_host->num_bus_clks = cfg->num_bus_clks; ret = devm_clk_bulk_get(&pdev->dev, msm_host->num_bus_clks, msm_host->bus_clks); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get clocks, ret = %d\n", ret); - goto exit; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "Unable to get clocks\n"); /* get link and source clocks */ msm_host->byte_clk = msm_clk_get(pdev, "byte"); - if (IS_ERR(msm_host->byte_clk)) { - ret = PTR_ERR(msm_host->byte_clk); - pr_err("%s: can't find dsi_byte clock. ret=%d\n", - __func__, ret); - msm_host->byte_clk = NULL; - goto exit; - } + if (IS_ERR(msm_host->byte_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(msm_host->byte_clk), + "%s: can't find dsi_byte clock\n", + __func__); msm_host->pixel_clk = msm_clk_get(pdev, "pixel"); - if (IS_ERR(msm_host->pixel_clk)) { - ret = PTR_ERR(msm_host->pixel_clk); - pr_err("%s: can't find dsi_pixel clock. ret=%d\n", - __func__, ret); - msm_host->pixel_clk = NULL; - goto exit; - } + if (IS_ERR(msm_host->pixel_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(msm_host->pixel_clk), + "%s: can't find dsi_pixel clock\n", + __func__); msm_host->esc_clk = msm_clk_get(pdev, "core"); - if (IS_ERR(msm_host->esc_clk)) { - ret = PTR_ERR(msm_host->esc_clk); - pr_err("%s: can't find dsi_esc clock. ret=%d\n", - __func__, ret); - msm_host->esc_clk = NULL; - goto exit; - } + if (IS_ERR(msm_host->esc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(msm_host->esc_clk), + "%s: can't find dsi_esc clock\n", + __func__); if (cfg_hnd->ops->clk_init_ver) ret = cfg_hnd->ops->clk_init_ver(msm_host); -exit: + return ret; } @@ -380,7 +370,6 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) return 0; } - int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) { int ret; @@ -598,7 +587,6 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) DBG("pclk=%lu, bclk=%lu", msm_host->pixel_clk_rate, msm_host->byte_clk_rate); - } int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi) @@ -687,8 +675,8 @@ static inline enum dsi_traffic_mode dsi_get_traffic_mode(const u32 mode_flags) return NON_BURST_SYNCH_EVENT; } -static inline enum dsi_vid_dst_format dsi_get_vid_fmt( - const enum mipi_dsi_pixel_format mipi_fmt) +static inline enum dsi_vid_dst_format +dsi_get_vid_fmt(const enum mipi_dsi_pixel_format mipi_fmt) { switch (mipi_fmt) { case MIPI_DSI_FMT_RGB888: return VID_DST_FORMAT_RGB888; @@ -699,8 +687,8 @@ static inline enum dsi_vid_dst_format dsi_get_vid_fmt( } } -static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt( - const enum mipi_dsi_pixel_format mipi_fmt) +static inline enum dsi_cmd_dst_format +dsi_get_cmd_fmt(const enum mipi_dsi_pixel_format mipi_fmt) { switch (mipi_fmt) { case MIPI_DSI_FMT_RGB888: return CMD_DST_FORMAT_RGB888; @@ -846,7 +834,7 @@ static void dsi_ctrl_enable(struct msm_dsi_host *msm_host, dsi_write(msm_host, REG_DSI_CPHY_MODE_CTRL, BIT(0)); } -static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay) +static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode) { struct drm_dsc_config *dsc = msm_host->dsc; u32 reg, reg_ctrl, reg_ctrl2; @@ -858,7 +846,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod /* first calculate dsc parameters and then program * compress mode registers */ - slice_per_intf = msm_dsc_get_slices_per_intf(dsc, hdisplay); + slice_per_intf = dsc->slice_count; total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf; bytes_per_pkt = dsc->slice_chunk_size; /* * slice_per_pkt; */ @@ -991,7 +979,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) { if (msm_host->dsc) - dsi_update_dsc_timing(msm_host, false, mode->hdisplay); + dsi_update_dsc_timing(msm_host, false); dsi_write(msm_host, REG_DSI_ACTIVE_H, DSI_ACTIVE_H_START(ha_start) | @@ -1012,7 +1000,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) DSI_ACTIVE_VSYNC_VPOS_END(vs_end)); } else { /* command mode */ if (msm_host->dsc) - dsi_update_dsc_timing(msm_host, true, mode->hdisplay); + dsi_update_dsc_timing(msm_host, true); /* image data and 1 byte write_memory_start cmd */ if (!msm_host->dsc) @@ -1292,14 +1280,15 @@ static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg) { u8 *data = msg->rx_buf; + if (data && (msg->rx_len >= 1)) { *data = buf[1]; /* strip out dcs type */ return 1; - } else { - pr_err("%s: read data does not match with rx_buf len %zu\n", - __func__, msg->rx_len); - return -EINVAL; } + + pr_err("%s: read data does not match with rx_buf len %zu\n", + __func__, msg->rx_len); + return -EINVAL; } /* @@ -1308,15 +1297,16 @@ static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg) static int dsi_short_read2_resp(u8 *buf, const struct mipi_dsi_msg *msg) { u8 *data = msg->rx_buf; + if (data && (msg->rx_len >= 2)) { data[0] = buf[1]; /* strip out dcs type */ data[1] = buf[2]; return 2; - } else { - pr_err("%s: read data does not match with rx_buf len %zu\n", - __func__, msg->rx_len); - return -EINVAL; } + + pr_err("%s: read data does not match with rx_buf len %zu\n", + __func__, msg->rx_len); + return -EINVAL; } static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg) @@ -1376,8 +1366,9 @@ static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) ret = -ETIMEDOUT; else ret = len; - } else + } else { ret = len; + } return ret; } @@ -1445,11 +1436,12 @@ static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host, return len; } - /* for video mode, do not send cmds more than - * one pixel line, since it only transmit it - * during BLLP. - */ - /* TODO: if the command is sent in LP mode, the bit rate is only + /* + * for video mode, do not send cmds more than + * one pixel line, since it only transmit it + * during BLLP. + * + * TODO: if the command is sent in LP mode, the bit rate is only * half of esc clk rate. In this case, if the video is already * actively streaming, we need to check more carefully if the * command can be fit into one BLLP. @@ -1767,8 +1759,20 @@ static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc return -EINVAL; } - if (dsc->bits_per_component != 8) { - DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support bits_per_component != 8 yet\n"); + switch (dsc->bits_per_component) { + case 8: + case 10: + case 12: + /* + * Only 8, 10, and 12 bpc are supported for DSC 1.1 block. + * If additional bpc values need to be supported, update + * this quard with the appropriate DSC version verification. + */ + break; + default: + DRM_DEV_ERROR(&msm_host->pdev->dev, + "Unsupported bits_per_component value: %d\n", + dsc->bits_per_component); return -EOPNOTSUPP; } @@ -1779,7 +1783,7 @@ static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc drm_dsc_set_const_params(dsc); drm_dsc_set_rc_buf_thresh(dsc); - /* handle only bpp = bpc = 8, pre-SCR panels */ + /* DPU supports only pre-SCR panels */ ret = drm_dsc_setup_rc_params(dsc, DRM_DSC_1_1_PRE_SCR); if (ret) { DRM_DEV_ERROR(&msm_host->pdev->dev, "could not find DSC RC parameters\n"); @@ -1827,8 +1831,15 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) __func__, ret); goto err; } - if (!ret) + if (!ret) { msm_dsi->te_source = devm_kstrdup(dev, te_source, GFP_KERNEL); + if (!msm_dsi->te_source) { + DRM_DEV_ERROR(dev, "%s: failed to allocate te_source\n", + __func__); + ret = -ENOMEM; + goto err; + } + } ret = 0; if (of_property_present(np, "syscon-sfpb")) { @@ -1874,39 +1885,35 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) int ret; msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); - if (!msm_host) { + if (!msm_host) return -ENOMEM; - } msm_host->pdev = pdev; msm_dsi->host = &msm_host->base; ret = dsi_host_parse_dt(msm_host); - if (ret) { - pr_err("%s: failed to parse dt\n", __func__); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "%s: failed to parse dt\n", + __func__); msm_host->ctrl_base = msm_ioremap_size(pdev, "dsi_ctrl", &msm_host->ctrl_size); - if (IS_ERR(msm_host->ctrl_base)) { - pr_err("%s: unable to map Dsi ctrl base\n", __func__); - return PTR_ERR(msm_host->ctrl_base); - } + if (IS_ERR(msm_host->ctrl_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(msm_host->ctrl_base), + "%s: unable to map Dsi ctrl base\n", __func__); pm_runtime_enable(&pdev->dev); msm_host->cfg_hnd = dsi_get_config(msm_host); - if (!msm_host->cfg_hnd) { - pr_err("%s: get config failed\n", __func__); - return -EINVAL; - } + if (!msm_host->cfg_hnd) + return dev_err_probe(&pdev->dev, -EINVAL, + "%s: get config failed\n", __func__); cfg = msm_host->cfg_hnd->cfg; msm_host->id = dsi_host_get_id(msm_host); - if (msm_host->id < 0) { - pr_err("%s: unable to identify DSI host index\n", __func__); - return msm_host->id; - } + if (msm_host->id < 0) + return dev_err_probe(&pdev->dev, msm_host->id, + "%s: unable to identify DSI host index\n", + __func__); /* fixup base address by io offset */ msm_host->ctrl_base += cfg->io_offset; @@ -1918,42 +1925,32 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) return ret; ret = dsi_clk_init(msm_host); - if (ret) { - pr_err("%s: unable to initialize dsi clks\n", __func__); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "%s: unable to initialize dsi clks\n", __func__); msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL); - if (!msm_host->rx_buf) { - pr_err("%s: alloc rx temp buf failed\n", __func__); + if (!msm_host->rx_buf) return -ENOMEM; - } ret = devm_pm_opp_set_clkname(&pdev->dev, "byte"); if (ret) return ret; /* OPP table is optional */ ret = devm_pm_opp_of_add_table(&pdev->dev); - if (ret && ret != -ENODEV) { - dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - return ret; - } + if (ret && ret != -ENODEV) + return dev_err_probe(&pdev->dev, ret, "invalid OPP table in device tree\n"); msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (!msm_host->irq) { - dev_err(&pdev->dev, "failed to get irq\n"); - return -EINVAL; - } + if (!msm_host->irq) + return dev_err_probe(&pdev->dev, -EINVAL, "failed to get irq\n"); /* do not autoenable, will be enabled later */ ret = devm_request_irq(&pdev->dev, msm_host->irq, dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, "dsi_isr", msm_host); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request IRQ%u: %d\n", - msm_host->irq, ret); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to request IRQ%u\n", + msm_host->irq); init_completion(&msm_host->dma_comp); init_completion(&msm_host->video_comp); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index a210b7c9e5ca281a46fbdb226e25832719a684ea..4fabb01345aa2a6de60bee4dc0dd0b1a4245509c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -74,17 +74,35 @@ static int dsi_mgr_setup_components(int id) int ret; if (!IS_BONDED_DSI()) { + /* + * Set the usecase before calling msm_dsi_host_register(), which would + * already program the PLL source mux based on a default usecase. + */ + msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE); + msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy); + ret = msm_dsi_host_register(msm_dsi->host); if (ret) return ret; - - msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE); - msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy); } else if (other_dsi) { struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ? msm_dsi : other_dsi; struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ? other_dsi : msm_dsi; + + /* + * PLL0 is to drive both DSI link clocks in bonded DSI mode. + * + * Set the usecase before calling msm_dsi_host_register(), which would + * already program the PLL source mux based on a default usecase. + */ + msm_dsi_phy_set_usecase(clk_master_dsi->phy, + MSM_DSI_PHY_MASTER); + msm_dsi_phy_set_usecase(clk_slave_dsi->phy, + MSM_DSI_PHY_SLAVE); + msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy); + msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy); + /* Register slave host first, so that slave DSI device * has a chance to probe, and do not block the master * DSI device's probe. @@ -98,14 +116,6 @@ static int dsi_mgr_setup_components(int id) ret = msm_dsi_host_register(master_link_dsi->host); if (ret) return ret; - - /* PLL0 is to drive both 2 DSI link clocks in bonded DSI mode. */ - msm_dsi_phy_set_usecase(clk_master_dsi->phy, - MSM_DSI_PHY_MASTER); - msm_dsi_phy_set_usecase(clk_slave_dsi->phy, - MSM_DSI_PHY_SLAVE); - msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy); - msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy); } return 0; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 8985818bb2e0934e9084a420c90e2269c2e1c414..1925418d9999a24263d6621299cae78f1fb9455c 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -6,6 +6,7 @@ #ifndef __DSI_PHY_H__ #define __DSI_PHY_H__ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/regulator/consumer.h> @@ -84,9 +85,7 @@ struct msm_dsi_dphy_timing { u8 hs_halfbyte_en_ckln; }; -#define DSI_BYTE_PLL_CLK 0 -#define DSI_PIXEL_PLL_CLK 1 -#define NUM_PROVIDED_CLKS 2 +#define NUM_PROVIDED_CLKS (DSI_PIXEL_PLL_CLK + 1) #define DSI_LANE_MAX 5 diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c index 677c6257181195892fdeb45e262f39c5ac974177..9812b4d69197928ca143e1504c8ee4b4345a232d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -3,6 +3,7 @@ * Copyright (c) 2018, The Linux Foundation */ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/iopoll.h> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index 2c3cbe0f2870e7d68b9563957de8621f7cd36b78..3a1c8ece6657c988cfb0c26af39b5d145bc576f8 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -3,6 +3,7 @@ * Copyright (c) 2016, The Linux Foundation. All rights reserved. */ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c index 1383e3a4e0500178ba2fc7f7af16d5a67b975520..90348a2af3e9dac72924561b23b169a268abc3b0 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -3,6 +3,7 @@ * Copyright (c) 2015, The Linux Foundation. All rights reserved. */ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> #include <linux/clk.h> #include <linux/clk-provider.h> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index 5311ab7f3c7095bada7ccda55b24d62d998d75ce..f3643320ff2f2bae5301bb94f1fe19fa03db584c 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -3,6 +3,7 @@ * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. */ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> #include <linux/clk-provider.h> #include <linux/delay.h> diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 798168180c1ab6c96ec2384f854302720cb27932..a92decbee5b5433853ed973747f7705d9079068d 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -3,6 +3,8 @@ * Copyright (c) 2018, The Linux Foundation */ +#include <dt-bindings/clock/qcom,dsi-phy-28nm.h> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/iopoll.h> @@ -305,7 +307,7 @@ static void dsi_pll_commit(struct dsi_pll_7nm *pll, struct dsi_pll_config *confi writel(pll->phy->cphy_mode ? 0x00 : 0x10, base + REG_DSI_7nm_PHY_PLL_CMODE_1); writel(config->pll_clock_inverters, - base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS); + base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS_1); } static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, @@ -572,11 +574,11 @@ static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy) cached->pll_out_div &= 0x3; cmn_clk_cfg0 = readl(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0); - cached->bit_clk_div = cmn_clk_cfg0 & 0xf; - cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; + cached->bit_clk_div = FIELD_GET(DSI_7nm_PHY_CMN_CLK_CFG0_DIV_CTRL_3_0__MASK, cmn_clk_cfg0); + cached->pix_clk_div = FIELD_GET(DSI_7nm_PHY_CMN_CLK_CFG0_DIV_CTRL_7_4__MASK, cmn_clk_cfg0); cmn_clk_cfg1 = readl(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); - cached->pll_mux = cmn_clk_cfg1 & 0x3; + cached->pll_mux = FIELD_GET(DSI_7nm_PHY_CMN_CLK_CFG1_DSICLK_SEL__MASK, cmn_clk_cfg1); DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", pll_7nm->phy->id, cached->pll_out_div, cached->bit_clk_div, @@ -598,7 +600,8 @@ static int dsi_7nm_pll_restore_state(struct msm_dsi_phy *phy) dsi_pll_cmn_clk_cfg0_write(pll_7nm, DSI_7nm_PHY_CMN_CLK_CFG0_DIV_CTRL_3_0(cached->bit_clk_div) | DSI_7nm_PHY_CMN_CLK_CFG0_DIV_CTRL_7_4(cached->pix_clk_div)); - dsi_pll_cmn_clk_cfg1_update(pll_7nm, 0x3, cached->pll_mux); + dsi_pll_cmn_clk_cfg1_update(pll_7nm, DSI_7nm_PHY_CMN_CLK_CFG1_DSICLK_SEL__MASK, + cached->pll_mux); ret = dsi_pll_7nm_vco_set_rate(phy->vco_hw, pll_7nm->vco_current_rate, @@ -736,11 +739,9 @@ static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm, struct clk_hw **provide * don't register a pclk_mux clock and just use post_out_div instead */ if (pll_7nm->phy->cphy_mode) { - u32 data; - - data = readl(pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); - writel(data | 3, pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); - + dsi_pll_cmn_clk_cfg1_update(pll_7nm, + DSI_7nm_PHY_CMN_CLK_CFG1_DSICLK_SEL__MASK, + DSI_7nm_PHY_CMN_CLK_CFG1_DSICLK_SEL(3)); phy_pll_out_dsi_parent = pll_post_out_div; } else { snprintf(clk_name, sizeof(clk_name), "dsi%d_pclk_mux", pll_7nm->phy->id); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index a7a2384044ffdb13579cc9a10f56f8de9beca761..87a91148a731dc911f30695add4c8f5002770220 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -183,10 +183,16 @@ static unsigned get_crtc_mask(struct drm_atomic_state *state) int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct drm_crtc *crtc; - int i; + int i, ret = 0; + /* + * FIXME: stop setting allow_modeset and move this check to the DPU + * driver. + */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if ((old_crtc_state->ctm && !new_crtc_state->ctm) || @@ -196,6 +202,11 @@ int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) } } + if (kms && kms->funcs && kms->funcs->check_mode_changed) + ret = kms->funcs->check_mode_changed(kms, state); + if (ret) + return ret; + return drm_atomic_helper_check(dev, state); } @@ -221,6 +232,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) kms->funcs->wait_flush(kms, crtc_mask); trace_msm_atomic_wait_flush_finish(crtc_mask); + atomic_set(&kms->fault_snapshot_capture, 0); + /* * Now that there is no in-progress flush, prepare the * current update: diff --git a/drivers/gpu/drm/msm/msm_dsc_helper.h b/drivers/gpu/drm/msm/msm_dsc_helper.h index b9049fe1e2790703a6f42dd7e6cd3fa5eea29389..63f95523b2cbb48f822210ac47cdd3526f231a89 100644 --- a/drivers/gpu/drm/msm/msm_dsc_helper.h +++ b/drivers/gpu/drm/msm/msm_dsc_helper.h @@ -12,17 +12,6 @@ #include <linux/math.h> #include <drm/display/drm_dsc_helper.h> -/** - * msm_dsc_get_slices_per_intf() - calculate number of slices per interface - * @dsc: Pointer to drm dsc config struct - * @intf_width: interface width in pixels - * Returns: Integer representing the number of slices for the given interface - */ -static inline u32 msm_dsc_get_slices_per_intf(const struct drm_dsc_config *dsc, u32 intf_width) -{ - return DIV_ROUND_UP(intf_width, dsc->slice_width); -} - /** * msm_dsc_get_bytes_per_line() - calculate bytes per line * @dsc: Pointer to drm dsc config struct diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 2a94e82316f95c5f9dcc37ef0a4664a29e3492b2..b5d8503d28f9b4b82265af2b3df48994b94ff0fc 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -243,7 +243,7 @@ static const struct iommu_flush_ops tlb_ops = { .tlb_add_page = msm_iommu_tlb_add_page, }; -static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, +static int msm_gpu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *arg); struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) @@ -319,7 +319,7 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) return &pagetable->base; } -static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, +static int msm_gpu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *arg) { struct msm_iommu *iommu = arg; @@ -343,6 +343,17 @@ static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, return 0; } +static int msm_disp_fault_handler(struct iommu_domain *domain, struct device *dev, + unsigned long iova, int flags, void *arg) +{ + struct msm_iommu *iommu = arg; + + if (iommu->base.handler) + return iommu->base.handler(iommu->base.arg, iova, flags, NULL); + + return -ENOSYS; +} + static void msm_iommu_resume_translation(struct msm_mmu *mmu) { struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(mmu->dev); @@ -437,6 +448,21 @@ struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks) return &iommu->base; } +struct msm_mmu *msm_iommu_disp_new(struct device *dev, unsigned long quirks) +{ + struct msm_iommu *iommu; + struct msm_mmu *mmu; + + mmu = msm_iommu_new(dev, quirks); + if (IS_ERR_OR_NULL(mmu)) + return mmu; + + iommu = to_msm_iommu(mmu); + iommu_set_fault_handler(iommu->domain, msm_disp_fault_handler, iommu); + + return mmu; +} + struct msm_mmu *msm_iommu_gpu_new(struct device *dev, struct msm_gpu *gpu, unsigned long quirks) { struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev); @@ -448,7 +474,7 @@ struct msm_mmu *msm_iommu_gpu_new(struct device *dev, struct msm_gpu *gpu, unsig return mmu; iommu = to_msm_iommu(mmu); - iommu_set_fault_handler(iommu->domain, msm_fault_handler, iommu); + iommu_set_fault_handler(iommu->domain, msm_gpu_fault_handler, iommu); /* Enable stall on iommu fault: */ if (adreno_smmu->set_stall) diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c index 38965e12a6bfc9fafd534e9920c549ba094c3506..b877278888e6228a84773e0dd6c4fc8ce24b2de6 100644 --- a/drivers/gpu/drm/msm/msm_kms.c +++ b/drivers/gpu/drm/msm/msm_kms.c @@ -164,12 +164,26 @@ void msm_crtc_disable_vblank(struct drm_crtc *crtc) vblank_ctrl_queue_work(priv, crtc, false); } +static int msm_kms_fault_handler(void *arg, unsigned long iova, int flags, void *data) +{ + struct msm_kms *kms = arg; + + if (atomic_read(&kms->fault_snapshot_capture) == 0) { + msm_disp_snapshot_state(kms->dev); + atomic_inc(&kms->fault_snapshot_capture); + } + + return -ENOSYS; +} + struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) { struct msm_gem_address_space *aspace; struct msm_mmu *mmu; struct device *mdp_dev = dev->dev; struct device *mdss_dev = mdp_dev->parent; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; struct device *iommu_dev; /* @@ -181,7 +195,7 @@ struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) else iommu_dev = mdss_dev; - mmu = msm_iommu_new(iommu_dev, 0); + mmu = msm_iommu_disp_new(iommu_dev, 0); if (IS_ERR(mmu)) return ERR_CAST(mmu); @@ -197,6 +211,8 @@ struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) mmu->funcs->destroy(mmu); } + msm_mmu_set_fault_handler(aspace->mmu, kms, msm_kms_fault_handler); + return aspace; } diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index e60162744c669773b6e5aef824a173647626ab4e..43b58d052ee6aae0ce34d09c88e1e1c34f9c52ef 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -59,6 +59,13 @@ struct msm_kms_funcs { void (*enable_commit)(struct msm_kms *kms); void (*disable_commit)(struct msm_kms *kms); + /** + * @check_mode_changed: + * + * Verify if the commit requires a full modeset on one of CRTCs. + */ + int (*check_mode_changed)(struct msm_kms *kms, struct drm_atomic_state *state); + /** * Prepare for atomic commit. This is called after any previous * (async or otherwise) commit has completed. @@ -128,6 +135,9 @@ struct msm_kms { int irq; bool irq_requested; + /* rate limit the snapshot capture to once per attach */ + atomic_t fault_snapshot_capture; + /* mapper-id used to request GEM buffer mapped for scanout: */ struct msm_gem_address_space *aspace; diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 88af4f490881f2a6789ae2d03e1c02d10046331a..730458d08d6b0ddf16358eb12d7a991fe39fe77e 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -42,6 +42,7 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks); struct msm_mmu *msm_iommu_gpu_new(struct device *dev, struct msm_gpu *gpu, unsigned long quirks); +struct msm_mmu *msm_iommu_disp_new(struct device *dev, unsigned long quirks); static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg, int (*handler)(void *arg, unsigned long iova, int flags, void *data)) diff --git a/drivers/gpu/drm/msm/registers/display/dsi_phy_7nm.xml b/drivers/gpu/drm/msm/registers/display/dsi_phy_7nm.xml index 35f7f40e405b7dd9687725eae754522a7136725e..d2c8c46bb04159da6e539bfe80a4b5dc9ffdf367 100644 --- a/drivers/gpu/drm/msm/registers/display/dsi_phy_7nm.xml +++ b/drivers/gpu/drm/msm/registers/display/dsi_phy_7nm.xml @@ -17,6 +17,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> <bitfield name="CLK_EN" pos="5" type="boolean"/> <bitfield name="CLK_EN_SEL" pos="4" type="boolean"/> <bitfield name="BITCLK_SEL" low="2" high="3" type="uint"/> + <bitfield name="DSICLK_SEL" low="0" high="1" type="uint"/> </reg32> <reg32 offset="0x00018" name="GLBL_CTRL"/> <reg32 offset="0x0001c" name="RBUF_CTRL"/> diff --git a/include/dt-bindings/clock/qcom,dsi-phy-28nm.h b/include/dt-bindings/clock/qcom,dsi-phy-28nm.h new file mode 100644 index 0000000000000000000000000000000000000000..ab94d58377a1c6aae740bef75c866e8ce5d93260 --- /dev/null +++ b/include/dt-bindings/clock/qcom,dsi-phy-28nm.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef _DT_BINDINGS_CLK_QCOM_DSI_PHY_28NM_H +#define _DT_BINDINGS_CLK_QCOM_DSI_PHY_28NM_H + +#define DSI_BYTE_PLL_CLK 0 +#define DSI_PIXEL_PLL_CLK 1 + +#endif