diff options
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c')
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 542 |
1 files changed, 351 insertions, 191 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index aa6ba2cf4b84..f4c9767c418d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2013 Red Hat * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. * * Author: Rob Clark <robdclark@gmail.com> */ @@ -20,9 +20,10 @@ #include <drm/drm_vblank.h> #include <drm/drm_writeback.h> +#include <linux/soc/qcom/ubwc.h> + #include "msm_drv.h" #include "msm_mmu.h" -#include "msm_mdss.h" #include "msm_gem.h" #include "disp/msm_disp_snapshot.h" @@ -51,6 +52,9 @@ #define DPU_DEBUGFS_DIR "msm_dpu" #define DPU_DEBUGFS_HWMASKNAME "hw_log_mask" +bool dpu_use_virtual_planes; +module_param(dpu_use_virtual_planes, bool, 0); + static int dpu_kms_hw_init(struct msm_kms *kms); static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms); @@ -230,6 +234,21 @@ static int dpu_regset32_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(dpu_regset32); +/** + * dpu_debugfs_create_regset32 - Create register read back file for debugfs + * + * This function is almost identical to the standard debugfs_create_regset32() + * function, with the main difference being that a list of register + * names/offsets do not need to be provided. The 'read' function simply outputs + * sequential register values over a specified range. + * + * @name: File name within debugfs + * @mode: File mode within debugfs + * @parent: Parent directory entry within debugfs, can be NULL + * @offset: sub-block offset + * @length: sub-block length, in bytes + * @dpu_kms: pointer to dpu kms structure + */ void dpu_debugfs_create_regset32(const char *name, umode_t mode, void *parent, uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms) @@ -274,9 +293,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) struct dpu_kms *dpu_kms = to_dpu_kms(kms); void *p = dpu_hw_util_get_log_mask_ptr(); struct dentry *entry; - struct drm_device *dev; - struct msm_drm_private *priv; - int i; if (!p) return -EINVAL; @@ -285,9 +301,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) if (minor->type != DRM_MINOR_PRIMARY) return 0; - dev = dpu_kms->dev; - priv = dev->dev_private; - entry = debugfs_create_dir("debug", minor->debugfs_root); debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, entry, p); @@ -297,11 +310,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) dpu_debugfs_core_irq_init(dpu_kms, entry); dpu_debugfs_sspp_init(dpu_kms, entry); - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { - if (priv->dp[i]) - msm_dp_debugfs_init(priv->dp[i], minor); - } - return dpu_core_perf_debugfs_init(dpu_kms, entry); } #endif @@ -328,11 +336,6 @@ struct dpu_global_state *dpu_kms_get_global_state(struct drm_atomic_state *s) struct msm_drm_private *priv = s->dev->dev_private; struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct drm_private_state *priv_state; - int ret; - - ret = drm_modeset_lock(&dpu_kms->global_state_lock, s->acquire_ctx); - if (ret) - return ERR_PTR(ret); priv_state = drm_atomic_get_private_obj_state(s, &dpu_kms->global_state); @@ -364,17 +367,24 @@ static void dpu_kms_global_destroy_state(struct drm_private_obj *obj, kfree(dpu_state); } +static void dpu_kms_global_print_state(struct drm_printer *p, + const struct drm_private_state *state) +{ + const struct dpu_global_state *global_state = to_dpu_global_state(state); + + dpu_rm_print_state(p, global_state); +} + static const struct drm_private_state_funcs dpu_kms_global_state_funcs = { .atomic_duplicate_state = dpu_kms_global_duplicate_state, .atomic_destroy_state = dpu_kms_global_destroy_state, + .atomic_print_state = dpu_kms_global_print_state, }; static int dpu_kms_global_obj_init(struct dpu_kms *dpu_kms) { struct dpu_global_state *state; - drm_modeset_lock_init(&dpu_kms->global_state_lock); - state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; @@ -382,15 +392,22 @@ static int dpu_kms_global_obj_init(struct dpu_kms *dpu_kms) drm_atomic_private_obj_init(dpu_kms->dev, &dpu_kms->global_state, &state->base, &dpu_kms_global_state_funcs); + + state->rm = &dpu_kms->rm; + return 0; } +static void dpu_kms_global_obj_fini(struct dpu_kms *dpu_kms) +{ + drm_atomic_private_obj_fini(&dpu_kms->global_state); +} + static int dpu_kms_parse_data_bus_icc_path(struct dpu_kms *dpu_kms) { struct icc_path *path0; struct icc_path *path1; - struct drm_device *dev = dpu_kms->dev; - struct device *dpu_dev = dev->dev; + struct device *dpu_dev = &dpu_kms->pdev->dev; path0 = msm_icc_get(dpu_dev, "mdp0-mem"); path1 = msm_icc_get(dpu_dev, "mdp1-mem"); @@ -430,6 +447,19 @@ 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_crtc_state *old_crtc_state; + struct drm_crtc *crtc; + int i; + + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) + dpu_crtc_check_mode_changed(old_crtc_state, new_crtc_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); @@ -490,7 +520,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms, * mode panels. This may be a no-op for command mode panels. */ trace_dpu_kms_wait_for_commit_done(DRMID(crtc)); - ret = dpu_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE); + ret = dpu_encoder_wait_for_commit_done(encoder); if (ret && ret != -EWOULDBLOCK) { DPU_ERROR("wait for commit done returned %d\n", ret); break; @@ -507,6 +537,44 @@ static void dpu_kms_wait_flush(struct msm_kms *kms, unsigned crtc_mask) dpu_kms_wait_for_commit_done(kms, crtc); } +static const char *dpu_vsync_sources[] = { + [DPU_VSYNC_SOURCE_GPIO_0] = "mdp_vsync_p", + [DPU_VSYNC_SOURCE_GPIO_1] = "mdp_vsync_s", + [DPU_VSYNC_SOURCE_GPIO_2] = "mdp_vsync_e", + [DPU_VSYNC_SOURCE_INTF_0] = "mdp_intf0", + [DPU_VSYNC_SOURCE_INTF_1] = "mdp_intf1", + [DPU_VSYNC_SOURCE_INTF_2] = "mdp_intf2", + [DPU_VSYNC_SOURCE_INTF_3] = "mdp_intf3", + [DPU_VSYNC_SOURCE_WD_TIMER_0] = "timer0", + [DPU_VSYNC_SOURCE_WD_TIMER_1] = "timer1", + [DPU_VSYNC_SOURCE_WD_TIMER_2] = "timer2", + [DPU_VSYNC_SOURCE_WD_TIMER_3] = "timer3", + [DPU_VSYNC_SOURCE_WD_TIMER_4] = "timer4", +}; + +static int dpu_kms_dsi_set_te_source(struct msm_display_info *info, + struct msm_dsi *dsi) +{ + const char *te_source = msm_dsi_get_te_source(dsi); + int i; + + if (!te_source) { + info->vsync_source = DPU_VSYNC_SOURCE_GPIO_0; + return 0; + } + + /* we can not use match_string since dpu_vsync_sources is a sparse array */ + for (i = 0; i < ARRAY_SIZE(dpu_vsync_sources); i++) { + if (dpu_vsync_sources[i] && + !strcmp(dpu_vsync_sources[i], te_source)) { + info->vsync_source = i; + return 0; + } + } + + return -EINVAL; +} + static int _dpu_kms_initialize_dsi(struct drm_device *dev, struct msm_drm_private *priv, struct dpu_kms *dpu_kms) @@ -515,7 +583,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, struct msm_display_info info; int i, rc = 0; - if (!(priv->dsi[0] || priv->dsi[1])) + if (!(priv->kms->dsi[0] || priv->kms->dsi[1])) return rc; /* @@ -526,24 +594,30 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, * * TODO: Support swapping DSI0 and DSI1 in the bonded setup. */ - for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { + for (i = 0; i < ARRAY_SIZE(priv->kms->dsi); i++) { int other = (i + 1) % 2; - if (!priv->dsi[i]) + if (!priv->kms->dsi[i]) continue; - if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && - !msm_dsi_is_master_dsi(priv->dsi[i])) + if (msm_dsi_is_bonded_dsi(priv->kms->dsi[i]) && + !msm_dsi_is_master_dsi(priv->kms->dsi[i])) continue; memset(&info, 0, sizeof(info)); info.intf_type = INTF_DSI; info.h_tile_instance[info.num_of_h_tiles++] = i; - if (msm_dsi_is_bonded_dsi(priv->dsi[i])) + if (msm_dsi_is_bonded_dsi(priv->kms->dsi[i])) info.h_tile_instance[info.num_of_h_tiles++] = other; - info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]); + info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->kms->dsi[i]); + + rc = dpu_kms_dsi_set_te_source(&info, priv->kms->dsi[i]); + if (rc) { + DPU_ERROR("failed to identify TE source for dsi display\n"); + return rc; + } encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI, &info); if (IS_ERR(encoder)) { @@ -551,15 +625,15 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, return PTR_ERR(encoder); } - rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder); + rc = msm_dsi_modeset_init(priv->kms->dsi[i], dev, encoder); if (rc) { DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n", i, rc); break; } - if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) { - rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder); + if (msm_dsi_is_bonded_dsi(priv->kms->dsi[i]) && priv->kms->dsi[other]) { + rc = msm_dsi_modeset_init(priv->kms->dsi[other], dev, encoder); if (rc) { DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n", other, rc); @@ -577,11 +651,12 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, { struct drm_encoder *encoder = NULL; struct msm_display_info info; + bool yuv_supported; int rc; int i; - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { - if (!priv->dp[i]) + for (i = 0; i < ARRAY_SIZE(priv->kms->dp); i++) { + if (!priv->kms->dp[i]) continue; memset(&info, 0, sizeof(info)); @@ -595,10 +670,10 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, return PTR_ERR(encoder); } - rc = msm_dp_modeset_init(priv->dp[i], dev, encoder); + yuv_supported = !!dpu_kms->catalog->cdm; + rc = msm_dp_modeset_init(priv->kms->dp[i], dev, encoder, yuv_supported); if (rc) { DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); - drm_encoder_cleanup(encoder); return rc; } } @@ -614,7 +689,7 @@ static int _dpu_kms_initialize_hdmi(struct drm_device *dev, struct msm_display_info info; int rc; - if (!priv->hdmi) + if (!priv->kms->hdmi) return 0; memset(&info, 0, sizeof(info)); @@ -628,10 +703,9 @@ static int _dpu_kms_initialize_hdmi(struct drm_device *dev, return PTR_ERR(encoder); } - rc = msm_hdmi_modeset_init(priv->hdmi, dev, encoder); + rc = msm_hdmi_modeset_init(priv->kms->hdmi, dev, encoder); if (rc) { DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); - drm_encoder_cleanup(encoder); return rc; } @@ -644,26 +718,28 @@ static int _dpu_kms_initialize_writeback(struct drm_device *dev, { struct drm_encoder *encoder = NULL; struct msm_display_info info; + const enum dpu_wb wb_idx = WB_2; + u32 maxlinewidth; int rc; memset(&info, 0, sizeof(info)); info.num_of_h_tiles = 1; /* use only WB idx 2 instance for DPU */ - info.h_tile_instance[0] = WB_2; + info.h_tile_instance[0] = wb_idx; info.intf_type = INTF_WB; + maxlinewidth = dpu_rm_get_wb(&dpu_kms->rm, info.h_tile_instance[0])->caps->maxlinewidth; + encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL, &info); if (IS_ERR(encoder)) { DPU_ERROR("encoder init failed for dsi display\n"); return PTR_ERR(encoder); } - rc = dpu_writeback_init(dev, encoder, wb_formats, - n_formats); + rc = dpu_writeback_init(dev, encoder, wb_formats, n_formats, maxlinewidth); if (rc) { DPU_ERROR("dpu_writeback_init, rc = %d\n", rc); - drm_encoder_cleanup(encoder); return rc; } @@ -749,8 +825,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) return ret; num_encoders = 0; - drm_for_each_encoder(encoder, dev) + drm_for_each_encoder(encoder, dev) { num_encoders++; + if (catalog->cwb_count > 0) + encoder->possible_clones = dpu_encoder_get_clones(encoder); + } max_crtc_count = min(catalog->mixer_count, num_encoders); @@ -770,8 +849,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) type, catalog->sspp[i].features, catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR)); - plane = dpu_plane_init(dev, catalog->sspp[i].id, type, - (1UL << max_crtc_count) - 1); + if (dpu_use_virtual_planes) + plane = dpu_plane_init_virtual(dev, type, (1UL << max_crtc_count) - 1); + else + plane = dpu_plane_init(dev, catalog->sspp[i].id, type, + (1UL << max_crtc_count) - 1); if (IS_ERR(plane)) { DPU_ERROR("dpu_plane_init failed\n"); ret = PTR_ERR(plane); @@ -793,12 +875,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) ret = PTR_ERR(crtc); return ret; } - priv->num_crtcs++; } /* All CRTCs are compatible with all encoders */ drm_for_each_encoder(encoder, dev) - encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; + encoder->possible_crtcs = (1 << dev->mode_config.num_crtc) - 1; return 0; } @@ -807,43 +888,20 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) { int i; - if (dpu_kms->hw_intr) - dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; /* safe to call these more than once during shutdown */ _dpu_kms_mmu_destroy(dpu_kms); - if (dpu_kms->catalog) { - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - if (dpu_kms->hw_vbif[i]) { - dpu_hw_vbif_destroy(dpu_kms->hw_vbif[i]); - dpu_kms->hw_vbif[i] = NULL; - } - } + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + dpu_kms->hw_vbif[i] = NULL; } - if (dpu_kms->rm_init) - dpu_rm_destroy(&dpu_kms->rm); - dpu_kms->rm_init = false; + dpu_kms_global_obj_fini(dpu_kms); dpu_kms->catalog = NULL; - if (dpu_kms->vbif[VBIF_NRT]) - devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_NRT]); - dpu_kms->vbif[VBIF_NRT] = NULL; - - if (dpu_kms->vbif[VBIF_RT]) - devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]); - dpu_kms->vbif[VBIF_RT] = NULL; - - if (dpu_kms->hw_mdp) - dpu_hw_mdp_destroy(dpu_kms->hw_mdp); dpu_kms->hw_mdp = NULL; - - if (dpu_kms->mmio) - devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->mmio); - dpu_kms->mmio = NULL; } static void dpu_kms_destroy(struct msm_kms *kms) @@ -869,7 +927,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) { struct msm_drm_private *priv; struct dpu_kms *dpu_kms = to_dpu_kms(kms); - int i; if (!dpu_kms || !dpu_kms->dev) return -EINVAL; @@ -878,9 +935,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) if (!priv) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) - msm_dp_irq_postinstall(priv->dp[i]); - return 0; } @@ -900,12 +954,14 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k /* dump CTL sub-blocks HW regs info */ for (i = 0; i < cat->ctl_count; i++) msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len, - dpu_kms->mmio + cat->ctl[i].base, cat->ctl[i].name); + dpu_kms->mmio + cat->ctl[i].base, "%s", + cat->ctl[i].name); /* dump DSPP sub-blocks HW regs info */ for (i = 0; i < cat->dspp_count; i++) { base = dpu_kms->mmio + cat->dspp[i].base; - msm_disp_snapshot_add_block(disp_state, cat->dspp[i].len, base, cat->dspp[i].name); + msm_disp_snapshot_add_block(disp_state, cat->dspp[i].len, base, + "%s", cat->dspp[i].name); if (cat->dspp[i].sblk && cat->dspp[i].sblk->pcc.len > 0) msm_disp_snapshot_add_block(disp_state, cat->dspp[i].sblk->pcc.len, @@ -917,13 +973,14 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k /* dump INTF sub-blocks HW regs info */ for (i = 0; i < cat->intf_count; i++) msm_disp_snapshot_add_block(disp_state, cat->intf[i].len, - dpu_kms->mmio + cat->intf[i].base, cat->intf[i].name); + dpu_kms->mmio + cat->intf[i].base, "%s", + cat->intf[i].name); /* dump PP sub-blocks HW regs info */ for (i = 0; i < cat->pingpong_count; i++) { base = dpu_kms->mmio + cat->pingpong[i].base; msm_disp_snapshot_add_block(disp_state, cat->pingpong[i].len, base, - cat->pingpong[i].name); + "%s", cat->pingpong[i].name); /* TE2 sub-block has length of 0, so will not print it */ @@ -937,7 +994,8 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k /* dump SSPP sub-blocks HW regs info */ for (i = 0; i < cat->sspp_count; i++) { base = dpu_kms->mmio + cat->sspp[i].base; - msm_disp_snapshot_add_block(disp_state, cat->sspp[i].len, base, cat->sspp[i].name); + msm_disp_snapshot_add_block(disp_state, cat->sspp[i].len, base, + "%s", cat->sspp[i].name); if (cat->sspp[i].sblk && cat->sspp[i].sblk->scaler_blk.len > 0) msm_disp_snapshot_add_block(disp_state, cat->sspp[i].sblk->scaler_blk.len, @@ -955,14 +1013,16 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k /* dump LM sub-blocks HW regs info */ for (i = 0; i < cat->mixer_count; i++) msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len, - dpu_kms->mmio + cat->mixer[i].base, cat->mixer[i].name); + dpu_kms->mmio + cat->mixer[i].base, + "%s", cat->mixer[i].name); /* dump WB sub-blocks HW regs info */ for (i = 0; i < cat->wb_count; i++) msm_disp_snapshot_add_block(disp_state, cat->wb[i].len, - dpu_kms->mmio + cat->wb[i].base, cat->wb[i].name); + dpu_kms->mmio + cat->wb[i].base, "%s", + cat->wb[i].name); - if (cat->mdp[0].features & BIT(DPU_MDP_PERIPH_0_REMOVED)) { + if (dpu_kms->catalog->mdss_ver->core_major_ver >= 8) { msm_disp_snapshot_add_block(disp_state, MDP_PERIPH_TOP0, dpu_kms->mmio + cat->mdp[0].base, "top"); msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len - MDP_PERIPH_TOP0_END, @@ -972,12 +1032,18 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k dpu_kms->mmio + cat->mdp[0].base, "top"); } + /* dump CWB sub-blocks HW regs info */ + for (i = 0; i < cat->cwb_count; i++) + msm_disp_snapshot_add_block(disp_state, cat->cwb[i].len, + dpu_kms->mmio + cat->cwb[i].base, cat->cwb[i].name); + /* dump DSC sub-blocks HW regs info */ for (i = 0; i < cat->dsc_count; i++) { base = dpu_kms->mmio + cat->dsc[i].base; - msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len, base, cat->dsc[i].name); + msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len, base, + "%s", cat->dsc[i].name); - if (cat->dsc[i].features & BIT(DPU_DSC_HW_REV_1_2)) { + if (cat->mdss_ver->core_major_ver >= 7) { struct dpu_dsc_blk enc = cat->dsc[i].sblk->enc; struct dpu_dsc_blk ctl = cat->dsc[i].sblk->ctl; @@ -988,6 +1054,19 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k } } + if (cat->cdm) + msm_disp_snapshot_add_block(disp_state, cat->cdm->len, + dpu_kms->mmio + cat->cdm->base, + "%s", cat->cdm->name); + + for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { + const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; + + msm_disp_snapshot_add_block(disp_state, vbif->len, + dpu_kms->vbif[vbif->id] + vbif->base, + "%s", vbif->name); + } + pm_runtime_put_sync(&dpu_kms->pdev->dev); } @@ -999,13 +1078,12 @@ 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, .enable_vblank = dpu_kms_enable_vblank, .disable_vblank = dpu_kms_disable_vblank, - .check_modified_format = dpu_format_check_modified_format, - .get_format = dpu_get_msm_format, .destroy = dpu_kms_destroy, .snapshot = dpu_kms_mdp_snapshot, #ifdef CONFIG_DEBUG_FS @@ -1017,30 +1095,37 @@ static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms) { struct msm_mmu *mmu; - if (!dpu_kms->base.aspace) + if (!dpu_kms->base.vm) return; - mmu = dpu_kms->base.aspace->mmu; + mmu = to_msm_vm(dpu_kms->base.vm)->mmu; mmu->funcs->detach(mmu); - msm_gem_address_space_put(dpu_kms->base.aspace); + drm_gpuvm_put(dpu_kms->base.vm); - dpu_kms->base.aspace = NULL; + dpu_kms->base.vm = NULL; } static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) { - struct msm_gem_address_space *aspace; + struct drm_gpuvm *vm; - aspace = msm_kms_init_aspace(dpu_kms->dev); - if (IS_ERR(aspace)) - return PTR_ERR(aspace); + vm = msm_kms_init_vm(dpu_kms->dev, dpu_kms->dev->dev->parent); + if (IS_ERR(vm)) + return PTR_ERR(vm); - dpu_kms->base.aspace = aspace; + dpu_kms->base.vm = vm; return 0; } +/** + * dpu_kms_get_clk_rate() - get the clock rate + * @dpu_kms: pointer to dpu_kms structure + * @clock_name: clock name to get the rate + * + * Return: current clock rate + */ unsigned long dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name) { struct clk *clk; @@ -1079,30 +1164,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) atomic_set(&dpu_kms->bandwidth_ref, 0); - dpu_kms->mmio = msm_ioremap(dpu_kms->pdev, "mdp"); - if (IS_ERR(dpu_kms->mmio)) { - rc = PTR_ERR(dpu_kms->mmio); - DPU_ERROR("mdp register memory map failed: %d\n", rc); - dpu_kms->mmio = NULL; - goto error; - } - DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio); - - dpu_kms->vbif[VBIF_RT] = msm_ioremap(dpu_kms->pdev, "vbif"); - if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { - rc = PTR_ERR(dpu_kms->vbif[VBIF_RT]); - DPU_ERROR("vbif register memory map failed: %d\n", rc); - dpu_kms->vbif[VBIF_RT] = NULL; - goto error; - } - dpu_kms->vbif[VBIF_NRT] = msm_ioremap_quiet(dpu_kms->pdev, "vbif_nrt"); - if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) { - dpu_kms->vbif[VBIF_NRT] = NULL; - DPU_DEBUG("VBIF NRT is not defined"); - } - - dpu_kms_parse_data_bus_icc_path(dpu_kms); - rc = pm_runtime_resume_and_get(&dpu_kms->pdev->dev); if (rc < 0) goto error; @@ -1115,7 +1176,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) if (!dpu_kms->catalog) { DPU_ERROR("device config not known!\n"); rc = -EINVAL; - goto power_error; + goto err_pm_put; } /* @@ -1125,49 +1186,48 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = _dpu_kms_mmu_init(dpu_kms); if (rc) { DPU_ERROR("dpu_kms_mmu_init failed: %d\n", rc); - goto power_error; + goto err_pm_put; } - dpu_kms->mdss = msm_mdss_get_mdss_data(dpu_kms->pdev->dev.parent); + dpu_kms->mdss = qcom_ubwc_config_get_data(); if (IS_ERR(dpu_kms->mdss)) { rc = PTR_ERR(dpu_kms->mdss); - DPU_ERROR("failed to get MDSS data: %d\n", rc); - goto power_error; + DPU_ERROR("failed to get UBWC config data: %d\n", rc); + goto err_pm_put; } if (!dpu_kms->mdss) { rc = -EINVAL; DPU_ERROR("NULL MDSS data\n"); - goto power_error; + goto err_pm_put; } - rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); + rc = dpu_rm_init(dev, &dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); if (rc) { DPU_ERROR("rm init failed: %d\n", rc); - goto power_error; + goto err_pm_put; } - dpu_kms->rm_init = true; - - dpu_kms->hw_mdp = dpu_hw_mdptop_init(dpu_kms->catalog->mdp, + dpu_kms->hw_mdp = dpu_hw_mdptop_init(dev, + dpu_kms->catalog->mdp, dpu_kms->mmio, - dpu_kms->catalog); + dpu_kms->catalog->mdss_ver); if (IS_ERR(dpu_kms->hw_mdp)) { rc = PTR_ERR(dpu_kms->hw_mdp); DPU_ERROR("failed to get hw_mdp: %d\n", rc); dpu_kms->hw_mdp = NULL; - goto power_error; + goto err_pm_put; } for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { struct dpu_hw_vbif *hw; const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; - hw = dpu_hw_vbif_init(vbif, dpu_kms->vbif[vbif->id]); + hw = dpu_hw_vbif_init(dev, vbif, dpu_kms->vbif[vbif->id]); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed to init vbif %d: %d\n", vbif->id, rc); - goto power_error; + goto err_pm_put; } dpu_kms->hw_vbif[vbif->id] = hw; @@ -1183,27 +1243,32 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = dpu_core_perf_init(&dpu_kms->perf, dpu_kms->catalog->perf, max_core_clk_rate); if (rc) { DPU_ERROR("failed to init perf %d\n", rc); - goto perf_err; + goto err_pm_put; } - dpu_kms->hw_intr = dpu_hw_intr_init(dpu_kms->mmio, dpu_kms->catalog); - if (IS_ERR_OR_NULL(dpu_kms->hw_intr)) { + /* + * We need to program DP <-> PHY relationship only for SC8180X since it + * has fewer DP controllers than DP PHYs. + * If any other platform requires the same kind of programming, or if + * the INTF <->DP relationship isn't static anymore, this needs to be + * configured through the DT. + */ + if (of_device_is_compatible(dpu_kms->pdev->dev.of_node, "qcom,sc8180x-dpu")) + dpu_kms->hw_mdp->ops.dp_phy_intf_sel(dpu_kms->hw_mdp, (unsigned int[]){ 1, 2, }); + + dpu_kms->hw_intr = dpu_hw_intr_init(dev, dpu_kms->mmio, dpu_kms->catalog); + if (IS_ERR(dpu_kms->hw_intr)) { rc = PTR_ERR(dpu_kms->hw_intr); DPU_ERROR("hw_intr init failed: %d\n", rc); dpu_kms->hw_intr = NULL; - goto hw_intr_init_err; + goto err_pm_put; } dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; - /* - * max crtc width is equal to the max mixer width * 2 and max height is - * is 4K - */ - dev->mode_config.max_width = - dpu_kms->catalog->caps->max_mixer_width * 2; - dev->mode_config.max_height = 4096; + dev->mode_config.max_width = DPU_MAX_IMG_WIDTH; + dev->mode_config.max_height = DPU_MAX_IMG_HEIGHT; dev->max_vblank_count = 0xffffffff; /* Disable vblank irqs aggressively for power-saving */ @@ -1216,7 +1281,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = _dpu_kms_drm_obj_init(dpu_kms); if (rc) { DPU_ERROR("modeset init failed: %d\n", rc); - goto drm_obj_init_err; + goto err_pm_put; } dpu_vbif_init_memtypes(dpu_kms); @@ -1225,10 +1290,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) return 0; -drm_obj_init_err: -hw_intr_init_err: -perf_err: -power_error: +err_pm_put: pm_runtime_put_sync(&dpu_kms->pdev->dev); error: _dpu_kms_hw_destroy(dpu_kms); @@ -1241,33 +1303,11 @@ static int dpu_kms_init(struct drm_device *ddev) struct msm_drm_private *priv = ddev->dev_private; struct device *dev = ddev->dev; struct platform_device *pdev = to_platform_device(dev); - struct dpu_kms *dpu_kms; - int irq; + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct dev_pm_opp *opp; int ret = 0; unsigned long max_freq = ULONG_MAX; - dpu_kms = devm_kzalloc(&pdev->dev, sizeof(*dpu_kms), GFP_KERNEL); - if (!dpu_kms) - return -ENOMEM; - - ret = devm_pm_opp_set_clkname(dev, "core"); - if (ret) - return ret; - /* OPP table is optional */ - ret = devm_pm_opp_of_add_table(dev); - if (ret && ret != -ENODEV) { - dev_err(dev, "invalid OPP table in device tree\n"); - return ret; - } - - ret = devm_clk_bulk_get_all(&pdev->dev, &dpu_kms->clocks); - if (ret < 0) { - DPU_ERROR("failed to parse clocks, ret=%d\n", ret); - return ret; - } - dpu_kms->num_clocks = ret; - opp = dev_pm_opp_find_freq_floor(dev, &max_freq); if (!IS_ERR(opp)) dev_pm_opp_put(opp); @@ -1280,33 +1320,138 @@ static int dpu_kms_init(struct drm_device *ddev) return ret; } dpu_kms->dev = ddev; - dpu_kms->pdev = pdev; pm_runtime_enable(&pdev->dev); dpu_kms->rpm_enabled = true; - priv->kms = &dpu_kms->base; + return 0; +} - irq = irq_of_parse_and_map(dpu_kms->pdev->dev.of_node, 0); - if (!irq) { - DPU_ERROR("failed to get irq\n"); +static int dpu_kms_mmap_mdp5(struct dpu_kms *dpu_kms) +{ + struct platform_device *pdev = dpu_kms->pdev; + struct platform_device *mdss_dev; + int ret; + + if (!dev_is_platform(dpu_kms->pdev->dev.parent)) return -EINVAL; + + mdss_dev = to_platform_device(dpu_kms->pdev->dev.parent); + + dpu_kms->mmio = msm_ioremap(pdev, "mdp_phys"); + if (IS_ERR(dpu_kms->mmio)) { + ret = PTR_ERR(dpu_kms->mmio); + DPU_ERROR("mdp register memory map failed: %d\n", ret); + dpu_kms->mmio = NULL; + return ret; + } + DRM_DEBUG("mapped dpu address space @%p\n", dpu_kms->mmio); + + dpu_kms->vbif[VBIF_RT] = msm_ioremap_mdss(mdss_dev, + dpu_kms->pdev, + "vbif_phys"); + if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { + ret = PTR_ERR(dpu_kms->vbif[VBIF_RT]); + DPU_ERROR("vbif register memory map failed: %d\n", ret); + dpu_kms->vbif[VBIF_RT] = NULL; + return ret; + } + + dpu_kms->vbif[VBIF_NRT] = msm_ioremap_mdss(mdss_dev, + dpu_kms->pdev, + "vbif_nrt_phys"); + if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) { + dpu_kms->vbif[VBIF_NRT] = NULL; + DPU_DEBUG("VBIF NRT is not defined"); + } + + return 0; +} + +static int dpu_kms_mmap_dpu(struct dpu_kms *dpu_kms) +{ + struct platform_device *pdev = dpu_kms->pdev; + int ret; + + dpu_kms->mmio = msm_ioremap(pdev, "mdp"); + if (IS_ERR(dpu_kms->mmio)) { + ret = PTR_ERR(dpu_kms->mmio); + DPU_ERROR("mdp register memory map failed: %d\n", ret); + dpu_kms->mmio = NULL; + return ret; + } + DRM_DEBUG("mapped dpu address space @%p\n", dpu_kms->mmio); + + dpu_kms->vbif[VBIF_RT] = msm_ioremap(pdev, "vbif"); + if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { + ret = PTR_ERR(dpu_kms->vbif[VBIF_RT]); + DPU_ERROR("vbif register memory map failed: %d\n", ret); + dpu_kms->vbif[VBIF_RT] = NULL; + return ret; + } + + dpu_kms->vbif[VBIF_NRT] = msm_ioremap_quiet(pdev, "vbif_nrt"); + if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) { + dpu_kms->vbif[VBIF_NRT] = NULL; + DPU_DEBUG("VBIF NRT is not defined"); } - dpu_kms->base.irq = irq; return 0; } static int dpu_dev_probe(struct platform_device *pdev) { - return msm_drv_probe(&pdev->dev, dpu_kms_init); + struct device *dev = &pdev->dev; + struct dpu_kms *dpu_kms; + int irq; + int ret = 0; + + if (!msm_disp_drv_should_bind(&pdev->dev, true)) + return -ENODEV; + + dpu_kms = devm_kzalloc(dev, sizeof(*dpu_kms), GFP_KERNEL); + if (!dpu_kms) + return -ENOMEM; + + dpu_kms->pdev = pdev; + + ret = devm_pm_opp_set_clkname(dev, "core"); + if (ret) + return ret; + /* OPP table is optional */ + ret = devm_pm_opp_of_add_table(dev); + if (ret && ret != -ENODEV) + return dev_err_probe(dev, ret, "invalid OPP table in device tree\n"); + + ret = devm_clk_bulk_get_all(&pdev->dev, &dpu_kms->clocks); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to parse clocks\n"); + + dpu_kms->num_clocks = ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get irq\n"); + + dpu_kms->base.irq = irq; + + if (of_device_is_compatible(dpu_kms->pdev->dev.of_node, "qcom,mdp5")) + ret = dpu_kms_mmap_mdp5(dpu_kms); + else + ret = dpu_kms_mmap_dpu(dpu_kms); + if (ret) + return ret; + + ret = dpu_kms_parse_data_bus_icc_path(dpu_kms); + if (ret) + return ret; + + return msm_drv_probe(&pdev->dev, dpu_kms_init, &dpu_kms->base); } -static int dpu_dev_remove(struct platform_device *pdev) +static void dpu_dev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); - - return 0; } static int __maybe_unused dpu_runtime_suspend(struct device *dev) @@ -1355,13 +1500,23 @@ static const struct dev_pm_ops dpu_pm_ops = { SET_RUNTIME_PM_OPS(dpu_runtime_suspend, dpu_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) - .prepare = msm_pm_prepare, - .complete = msm_pm_complete, + .prepare = msm_kms_pm_prepare, + .complete = msm_kms_pm_complete, }; static const struct of_device_id dpu_dt_match[] = { + { .compatible = "qcom,glymur-dpu", .data = &dpu_glymur_cfg, }, + { .compatible = "qcom,msm8917-mdp5", .data = &dpu_msm8917_cfg, }, + { .compatible = "qcom,msm8937-mdp5", .data = &dpu_msm8937_cfg, }, + { .compatible = "qcom,msm8953-mdp5", .data = &dpu_msm8953_cfg, }, + { .compatible = "qcom,msm8996-mdp5", .data = &dpu_msm8996_cfg, }, { .compatible = "qcom,msm8998-dpu", .data = &dpu_msm8998_cfg, }, { .compatible = "qcom,qcm2290-dpu", .data = &dpu_qcm2290_cfg, }, + { .compatible = "qcom,sa8775p-dpu", .data = &dpu_sa8775p_cfg, }, + { .compatible = "qcom,sar2130p-dpu", .data = &dpu_sar2130p_cfg, }, + { .compatible = "qcom,sdm630-mdp5", .data = &dpu_sdm630_cfg, }, + { .compatible = "qcom,sdm660-mdp5", .data = &dpu_sdm660_cfg, }, + { .compatible = "qcom,sdm670-dpu", .data = &dpu_sdm670_cfg, }, { .compatible = "qcom,sdm845-dpu", .data = &dpu_sdm845_cfg, }, { .compatible = "qcom,sc7180-dpu", .data = &dpu_sc7180_cfg, }, { .compatible = "qcom,sc7280-dpu", .data = &dpu_sc7280_cfg, }, @@ -1369,13 +1524,18 @@ static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sc8280xp-dpu", .data = &dpu_sc8280xp_cfg, }, { .compatible = "qcom,sm6115-dpu", .data = &dpu_sm6115_cfg, }, { .compatible = "qcom,sm6125-dpu", .data = &dpu_sm6125_cfg, }, + { .compatible = "qcom,sm6150-dpu", .data = &dpu_sm6150_cfg, }, { .compatible = "qcom,sm6350-dpu", .data = &dpu_sm6350_cfg, }, { .compatible = "qcom,sm6375-dpu", .data = &dpu_sm6375_cfg, }, + { .compatible = "qcom,sm7150-dpu", .data = &dpu_sm7150_cfg, }, { .compatible = "qcom,sm8150-dpu", .data = &dpu_sm8150_cfg, }, { .compatible = "qcom,sm8250-dpu", .data = &dpu_sm8250_cfg, }, { .compatible = "qcom,sm8350-dpu", .data = &dpu_sm8350_cfg, }, { .compatible = "qcom,sm8450-dpu", .data = &dpu_sm8450_cfg, }, { .compatible = "qcom,sm8550-dpu", .data = &dpu_sm8550_cfg, }, + { .compatible = "qcom,sm8650-dpu", .data = &dpu_sm8650_cfg, }, + { .compatible = "qcom,sm8750-dpu", .data = &dpu_sm8750_cfg, }, + { .compatible = "qcom,x1e80100-dpu", .data = &dpu_x1e80100_cfg, }, {} }; MODULE_DEVICE_TABLE(of, dpu_dt_match); @@ -1383,7 +1543,7 @@ MODULE_DEVICE_TABLE(of, dpu_dt_match); static struct platform_driver dpu_driver = { .probe = dpu_dev_probe, .remove = dpu_dev_remove, - .shutdown = msm_drv_shutdown, + .shutdown = msm_kms_shutdown, .driver = { .name = "msm_dpu", .of_match_table = dpu_dt_match, |
