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 | 245 |
1 files changed, 131 insertions, 114 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index e29796c4f27b..bce47647d891 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * 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. + * * Author: Rob Clark <robdclark@gmail.com> */ @@ -15,6 +17,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_file.h> #include <drm/drm_vblank.h> +#include <drm/drm_writeback.h> #include "msm_drv.h" #include "msm_mmu.h" @@ -29,6 +32,7 @@ #include "dpu_kms.h" #include "dpu_plane.h" #include "dpu_vbif.h" +#include "dpu_writeback.h" #define CREATE_TRACE_POINTS #include "dpu_trace.h" @@ -380,9 +384,13 @@ 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 *mdss_dev = dpu_dev->parent; - path0 = of_icc_get(dev->dev, "mdp0-mem"); - path1 = of_icc_get(dev->dev, "mdp1-mem"); + /* Interconnects are a part of MDSS device tree binding, not the + * MDP/DPU device. */ + path0 = of_icc_get(mdss_dev, "mdp0-mem"); + path1 = of_icc_get(mdss_dev, "mdp1-mem"); if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); @@ -565,8 +573,6 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, return PTR_ERR(encoder); } - priv->encoders[priv->num_encoders++] = encoder; - memset(&info, 0, sizeof(info)); info.intf_type = encoder->encoder_type; @@ -582,6 +588,8 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, MSM_DISPLAY_CAP_CMD_MODE : MSM_DISPLAY_CAP_VID_MODE; + info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]); + if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) { rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder); if (rc) { @@ -629,8 +637,6 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, return rc; } - priv->encoders[priv->num_encoders++] = encoder; - info.num_of_h_tiles = 1; info.h_tile_instance[0] = i; info.capabilities = MSM_DISPLAY_CAP_VID_MODE; @@ -646,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, return 0; } +static int _dpu_kms_initialize_writeback(struct drm_device *dev, + struct msm_drm_private *priv, struct dpu_kms *dpu_kms, + const u32 *wb_formats, int n_formats) +{ + struct drm_encoder *encoder = NULL; + struct msm_display_info info; + int rc; + + encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL); + if (IS_ERR(encoder)) { + DPU_ERROR("encoder init failed for dsi display\n"); + return PTR_ERR(encoder); + } + + memset(&info, 0, sizeof(info)); + + rc = dpu_writeback_init(dev, encoder, wb_formats, + n_formats); + if (rc) { + DPU_ERROR("dpu_writeback_init, rc = %d\n", rc); + drm_encoder_cleanup(encoder); + return rc; + } + + info.num_of_h_tiles = 1; + /* use only WB idx 2 instance for DPU */ + info.h_tile_instance[0] = WB_2; + info.intf_type = encoder->encoder_type; + + rc = dpu_encoder_setup(dev, encoder, &info); + if (rc) { + DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n", + encoder->base.id, rc); + return rc; + } + + return 0; +} + /** * _dpu_kms_setup_displays - create encoders, bridges and connectors * for underlying displays @@ -659,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev, struct dpu_kms *dpu_kms) { int rc = 0; + int i; rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms); if (rc) { @@ -672,39 +718,33 @@ static int _dpu_kms_setup_displays(struct drm_device *dev, return rc; } - return rc; -} - -static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms) -{ - struct msm_drm_private *priv; - int i; - - priv = dpu_kms->dev->dev_private; - - for (i = 0; i < priv->num_crtcs; i++) - priv->crtcs[i]->funcs->destroy(priv->crtcs[i]); - priv->num_crtcs = 0; - - for (i = 0; i < priv->num_planes; i++) - priv->planes[i]->funcs->destroy(priv->planes[i]); - priv->num_planes = 0; - - for (i = 0; i < priv->num_connectors; i++) - priv->connectors[i]->funcs->destroy(priv->connectors[i]); - priv->num_connectors = 0; + /* Since WB isn't a driver check the catalog before initializing */ + if (dpu_kms->catalog->wb_count) { + for (i = 0; i < dpu_kms->catalog->wb_count; i++) { + if (dpu_kms->catalog->wb[i].id == WB_2) { + rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms, + dpu_kms->catalog->wb[i].format_list, + dpu_kms->catalog->wb[i].num_formats); + if (rc) { + DPU_ERROR("initialize_WB failed, rc = %d\n", rc); + return rc; + } + } + } + } - for (i = 0; i < priv->num_encoders; i++) - priv->encoders[i]->funcs->destroy(priv->encoders[i]); - priv->num_encoders = 0; + return rc; } +#define MAX_PLANES 20 static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) { struct drm_device *dev; struct drm_plane *primary_planes[MAX_PLANES], *plane; struct drm_plane *cursor_planes[MAX_PLANES] = { NULL }; struct drm_crtc *crtc; + struct drm_encoder *encoder; + unsigned int num_encoders; struct msm_drm_private *priv; struct dpu_mdss_cfg *catalog; @@ -721,9 +761,13 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) */ ret = _dpu_kms_setup_displays(dev, priv, dpu_kms); if (ret) - goto fail; + return ret; + + num_encoders = 0; + drm_for_each_encoder(encoder, dev) + num_encoders++; - max_crtc_count = min(catalog->mixer_count, priv->num_encoders); + max_crtc_count = min(catalog->mixer_count, num_encoders); /* Create the planes, keeping track of one primary/cursor per crtc */ for (i = 0; i < catalog->sspp_count; i++) { @@ -746,9 +790,8 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) if (IS_ERR(plane)) { DPU_ERROR("dpu_plane_init failed\n"); ret = PTR_ERR(plane); - goto fail; + return ret; } - priv->planes[priv->num_planes++] = plane; if (type == DRM_PLANE_TYPE_CURSOR) cursor_planes[cursor_planes_idx++] = plane; @@ -763,19 +806,16 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) crtc = dpu_crtc_init(dev, primary_planes[i], cursor_planes[i]); if (IS_ERR(crtc)) { ret = PTR_ERR(crtc); - goto fail; + return ret; } priv->crtcs[priv->num_crtcs++] = crtc; } /* All CRTCs are compatible with all encoders */ - for (i = 0; i < priv->num_encoders; i++) - priv->encoders[i]->possible_crtcs = (1 << priv->num_crtcs) - 1; + drm_for_each_encoder(encoder, dev) + encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; return 0; -fail: - _dpu_kms_drm_obj_destroy(dpu_kms); - return ret; } static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) @@ -793,8 +833,10 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { u32 vbif_idx = dpu_kms->catalog->vbif[i].id; - if ((vbif_idx < VBIF_MAX) && dpu_kms->hw_vbif[vbif_idx]) + if ((vbif_idx < VBIF_MAX) && dpu_kms->hw_vbif[vbif_idx]) { dpu_hw_vbif_destroy(dpu_kms->hw_vbif[vbif_idx]); + dpu_kms->hw_vbif[vbif_idx] = NULL; + } } } @@ -837,20 +879,9 @@ static void dpu_kms_destroy(struct msm_kms *kms) _dpu_kms_hw_destroy(dpu_kms); msm_kms_destroy(&dpu_kms->base); -} -static irqreturn_t dpu_irq(struct msm_kms *kms) -{ - struct dpu_kms *dpu_kms = to_dpu_kms(kms); - - return dpu_core_irq(dpu_kms); -} - -static void dpu_irq_preinstall(struct msm_kms *kms) -{ - struct dpu_kms *dpu_kms = to_dpu_kms(kms); - - dpu_core_irq_preinstall(dpu_kms); + if (dpu_kms->rpm_enabled) + pm_runtime_disable(&dpu_kms->pdev->dev); } static int dpu_irq_postinstall(struct msm_kms *kms) @@ -872,13 +903,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) return 0; } -static void dpu_irq_uninstall(struct msm_kms *kms) -{ - struct dpu_kms *dpu_kms = to_dpu_kms(kms); - - dpu_core_irq_uninstall(dpu_kms); -} - static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_kms *kms) { int i; @@ -923,6 +947,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len, dpu_kms->mmio + cat->mixer[i].base, "lm_%d", i); + /* 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, "wb_%d", i); + msm_disp_snapshot_add_block(disp_state, top->hw.length, dpu_kms->mmio + top->hw.blk_off, "top"); @@ -931,10 +960,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k static const struct msm_kms_funcs kms_funcs = { .hw_init = dpu_kms_hw_init, - .irq_preinstall = dpu_irq_preinstall, + .irq_preinstall = dpu_core_irq_preinstall, .irq_postinstall = dpu_irq_postinstall, - .irq_uninstall = dpu_irq_uninstall, - .irq = dpu_irq, + .irq_uninstall = dpu_core_irq_uninstall, + .irq = dpu_core_irq, .enable_commit = dpu_kms_enable_commit, .disable_commit = dpu_kms_disable_commit, .vsync_time = dpu_kms_vsync_time, @@ -973,12 +1002,16 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) struct iommu_domain *domain; struct msm_gem_address_space *aspace; struct msm_mmu *mmu; + struct device *dpu_dev = dpu_kms->dev->dev; + struct device *mdss_dev = dpu_dev->parent; domain = iommu_domain_alloc(&platform_bus_type); if (!domain) return 0; - mmu = msm_iommu_new(dpu_kms->dev->dev, domain); + /* IOMMUs are a part of MDSS device tree binding, not the + * MDP/DPU device. */ + mmu = msm_iommu_new(mdss_dev, domain); if (IS_ERR(mmu)) { iommu_domain_free(domain); return PTR_ERR(mmu); @@ -1056,7 +1089,9 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dpu_kms_parse_data_bus_icc_path(dpu_kms); - pm_runtime_get_sync(&dpu_kms->pdev->dev); + rc = pm_runtime_resume_and_get(&dpu_kms->pdev->dev); + if (rc < 0) + goto error; dpu_kms->core_rev = readl_relaxed(dpu_kms->mmio + 0x0); @@ -1172,37 +1207,16 @@ error: return rc; } -struct msm_kms *dpu_kms_init(struct drm_device *dev) -{ - struct msm_drm_private *priv; - struct dpu_kms *dpu_kms; - int irq; - - if (!dev) { - DPU_ERROR("drm device node invalid\n"); - return ERR_PTR(-EINVAL); - } - - priv = dev->dev_private; - dpu_kms = to_dpu_kms(priv->kms); - - irq = irq_of_parse_and_map(dpu_kms->pdev->dev.of_node, 0); - if (irq < 0) { - DPU_ERROR("failed to get irq: %d\n", irq); - return ERR_PTR(irq); - } - dpu_kms->base.irq = irq; - - return &dpu_kms->base; -} - -static int dpu_bind(struct device *dev, struct device *master, void *data) +static int dpu_kms_init(struct drm_device *ddev) { - struct msm_drm_private *priv = dev_get_drvdata(master); + struct msm_drm_private *priv = ddev->dev_private; + struct device *dev = ddev->dev; struct platform_device *pdev = to_platform_device(dev); - struct drm_device *ddev = priv->dev; struct dpu_kms *dpu_kms; + int irq; + 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) @@ -1225,7 +1239,11 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) } dpu_kms->num_clocks = ret; - platform_set_drvdata(pdev, dpu_kms); + opp = dev_pm_opp_find_freq_floor(dev, &max_freq); + if (!IS_ERR(opp)) + dev_pm_opp_put(opp); + + dev_pm_opp_set_rate(dev, max_freq); ret = msm_kms_init(&dpu_kms->base, &kms_funcs); if (ret) { @@ -1240,31 +1258,25 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) priv->kms = &dpu_kms->base; - return ret; -} - -static void dpu_unbind(struct device *dev, struct device *master, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + irq = irq_of_parse_and_map(dpu_kms->pdev->dev.of_node, 0); + if (!irq) { + DPU_ERROR("failed to get irq\n"); + return -EINVAL; + } + dpu_kms->base.irq = irq; - if (dpu_kms->rpm_enabled) - pm_runtime_disable(&pdev->dev); + return 0; } -static const struct component_ops dpu_ops = { - .bind = dpu_bind, - .unbind = dpu_unbind, -}; - static int dpu_dev_probe(struct platform_device *pdev) { - return component_add(&pdev->dev, &dpu_ops); + return msm_drv_probe(&pdev->dev, dpu_kms_init); } static int dpu_dev_remove(struct platform_device *pdev) { - component_del(&pdev->dev, &dpu_ops); + component_master_del(&pdev->dev, &msm_drm_ops); + return 0; } @@ -1272,7 +1284,8 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) { int i; struct platform_device *pdev = to_platform_device(dev); - struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); /* Drop the performance state vote */ dev_pm_opp_set_rate(dev, 0); @@ -1288,7 +1301,8 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) { int rc = -1; struct platform_device *pdev = to_platform_device(dev); - struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct drm_encoder *encoder; struct drm_device *ddev; int i; @@ -1318,9 +1332,11 @@ 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, }; -const struct of_device_id dpu_dt_match[] = { +static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,msm8998-dpu", }, { .compatible = "qcom,qcm2290-dpu", }, { .compatible = "qcom,sdm845-dpu", }, @@ -1336,6 +1352,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, .driver = { .name = "msm_dpu", .of_match_table = dpu_dt_match, |