1494 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 Red Hat4 * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.5 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.6 *7 * Author: Rob Clark <robdclark@gmail.com>8 */9 10#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__11 12#include <linux/debugfs.h>13#include <linux/dma-buf.h>14#include <linux/of_irq.h>15#include <linux/pm_opp.h>16 17#include <drm/drm_crtc.h>18#include <drm/drm_file.h>19#include <drm/drm_framebuffer.h>20#include <drm/drm_vblank.h>21#include <drm/drm_writeback.h>22 23#include "msm_drv.h"24#include "msm_mmu.h"25#include "msm_mdss.h"26#include "msm_gem.h"27#include "disp/msm_disp_snapshot.h"28 29#include "dpu_core_irq.h"30#include "dpu_crtc.h"31#include "dpu_encoder.h"32#include "dpu_formats.h"33#include "dpu_hw_vbif.h"34#include "dpu_kms.h"35#include "dpu_plane.h"36#include "dpu_vbif.h"37#include "dpu_writeback.h"38 39#define CREATE_TRACE_POINTS40#include "dpu_trace.h"41 42/*43 * To enable overall DRM driver logging44 * # echo 0x2 > /sys/module/drm/parameters/debug45 *46 * To enable DRM driver h/w logging47 * # echo <mask> > /sys/kernel/debug/dri/0/debug/hw_log_mask48 *49 * See dpu_hw_mdss.h for h/w logging mask definitions (search for DPU_DBG_MASK_)50 */51#define DPU_DEBUGFS_DIR "msm_dpu"52#define DPU_DEBUGFS_HWMASKNAME "hw_log_mask"53 54static int dpu_kms_hw_init(struct msm_kms *kms);55static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms);56 57#ifdef CONFIG_DEBUG_FS58static int _dpu_danger_signal_status(struct seq_file *s,59 bool danger_status)60{61 struct dpu_danger_safe_status status;62 struct dpu_kms *kms = s->private;63 int i;64 65 if (!kms->hw_mdp) {66 DPU_ERROR("invalid arg(s)\n");67 return 0;68 }69 70 memset(&status, 0, sizeof(struct dpu_danger_safe_status));71 72 pm_runtime_get_sync(&kms->pdev->dev);73 if (danger_status) {74 seq_puts(s, "\nDanger signal status:\n");75 if (kms->hw_mdp->ops.get_danger_status)76 kms->hw_mdp->ops.get_danger_status(kms->hw_mdp,77 &status);78 } else {79 seq_puts(s, "\nSafe signal status:\n");80 if (kms->hw_mdp->ops.get_safe_status)81 kms->hw_mdp->ops.get_safe_status(kms->hw_mdp,82 &status);83 }84 pm_runtime_put_sync(&kms->pdev->dev);85 86 seq_printf(s, "MDP : 0x%x\n", status.mdp);87 88 for (i = SSPP_VIG0; i < SSPP_MAX; i++)89 seq_printf(s, "SSPP%d : 0x%x \n", i - SSPP_VIG0,90 status.sspp[i]);91 seq_puts(s, "\n");92 93 return 0;94}95 96static int dpu_debugfs_danger_stats_show(struct seq_file *s, void *v)97{98 return _dpu_danger_signal_status(s, true);99}100DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_danger_stats);101 102static int dpu_debugfs_safe_stats_show(struct seq_file *s, void *v)103{104 return _dpu_danger_signal_status(s, false);105}106DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_safe_stats);107 108static ssize_t _dpu_plane_danger_read(struct file *file,109 char __user *buff, size_t count, loff_t *ppos)110{111 struct dpu_kms *kms = file->private_data;112 int len;113 char buf[40];114 115 len = scnprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);116 117 return simple_read_from_buffer(buff, count, ppos, buf, len);118}119 120static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable)121{122 struct drm_plane *plane;123 124 drm_for_each_plane(plane, kms->dev) {125 if (plane->fb && plane->state) {126 dpu_plane_danger_signal_ctrl(plane, enable);127 DPU_DEBUG("plane:%d img:%dx%d ",128 plane->base.id, plane->fb->width,129 plane->fb->height);130 DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",131 plane->state->src_x >> 16,132 plane->state->src_y >> 16,133 plane->state->src_w >> 16,134 plane->state->src_h >> 16,135 plane->state->crtc_x, plane->state->crtc_y,136 plane->state->crtc_w, plane->state->crtc_h);137 } else {138 DPU_DEBUG("Inactive plane:%d\n", plane->base.id);139 }140 }141}142 143static ssize_t _dpu_plane_danger_write(struct file *file,144 const char __user *user_buf, size_t count, loff_t *ppos)145{146 struct dpu_kms *kms = file->private_data;147 int disable_panic;148 int ret;149 150 ret = kstrtouint_from_user(user_buf, count, 0, &disable_panic);151 if (ret)152 return ret;153 154 if (disable_panic) {155 /* Disable panic signal for all active pipes */156 DPU_DEBUG("Disabling danger:\n");157 _dpu_plane_set_danger_state(kms, false);158 kms->has_danger_ctrl = false;159 } else {160 /* Enable panic signal for all active pipes */161 DPU_DEBUG("Enabling danger:\n");162 kms->has_danger_ctrl = true;163 _dpu_plane_set_danger_state(kms, true);164 }165 166 return count;167}168 169static const struct file_operations dpu_plane_danger_enable = {170 .open = simple_open,171 .read = _dpu_plane_danger_read,172 .write = _dpu_plane_danger_write,173};174 175static void dpu_debugfs_danger_init(struct dpu_kms *dpu_kms,176 struct dentry *parent)177{178 struct dentry *entry = debugfs_create_dir("danger", parent);179 180 debugfs_create_file("danger_status", 0600, entry,181 dpu_kms, &dpu_debugfs_danger_stats_fops);182 debugfs_create_file("safe_status", 0600, entry,183 dpu_kms, &dpu_debugfs_safe_stats_fops);184 debugfs_create_file("disable_danger", 0600, entry,185 dpu_kms, &dpu_plane_danger_enable);186 187}188 189/*190 * Companion structure for dpu_debugfs_create_regset32.191 */192struct dpu_debugfs_regset32 {193 uint32_t offset;194 uint32_t blk_len;195 struct dpu_kms *dpu_kms;196};197 198static int dpu_regset32_show(struct seq_file *s, void *data)199{200 struct dpu_debugfs_regset32 *regset = s->private;201 struct dpu_kms *dpu_kms = regset->dpu_kms;202 void __iomem *base;203 uint32_t i, addr;204 205 if (!dpu_kms->mmio)206 return 0;207 208 base = dpu_kms->mmio + regset->offset;209 210 /* insert padding spaces, if needed */211 if (regset->offset & 0xF) {212 seq_printf(s, "[%x]", regset->offset & ~0xF);213 for (i = 0; i < (regset->offset & 0xF); i += 4)214 seq_puts(s, " ");215 }216 217 pm_runtime_get_sync(&dpu_kms->pdev->dev);218 219 /* main register output */220 for (i = 0; i < regset->blk_len; i += 4) {221 addr = regset->offset + i;222 if ((addr & 0xF) == 0x0)223 seq_printf(s, i ? "\n[%x]" : "[%x]", addr);224 seq_printf(s, " %08x", readl_relaxed(base + i));225 }226 seq_puts(s, "\n");227 pm_runtime_put_sync(&dpu_kms->pdev->dev);228 229 return 0;230}231DEFINE_SHOW_ATTRIBUTE(dpu_regset32);232 233void dpu_debugfs_create_regset32(const char *name, umode_t mode,234 void *parent,235 uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms)236{237 struct dpu_debugfs_regset32 *regset;238 239 if (WARN_ON(!name || !dpu_kms || !length))240 return;241 242 regset = devm_kzalloc(&dpu_kms->pdev->dev, sizeof(*regset), GFP_KERNEL);243 if (!regset)244 return;245 246 /* make sure offset is a multiple of 4 */247 regset->offset = round_down(offset, 4);248 regset->blk_len = length;249 regset->dpu_kms = dpu_kms;250 251 debugfs_create_file(name, mode, parent, regset, &dpu_regset32_fops);252}253 254static void dpu_debugfs_sspp_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)255{256 struct dentry *entry = debugfs_create_dir("sspp", debugfs_root);257 int i;258 259 if (IS_ERR(entry))260 return;261 262 for (i = SSPP_NONE; i < SSPP_MAX; i++) {263 struct dpu_hw_sspp *hw = dpu_rm_get_sspp(&dpu_kms->rm, i);264 265 if (!hw)266 continue;267 268 _dpu_hw_sspp_init_debugfs(hw, dpu_kms, entry);269 }270}271 272static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor)273{274 struct dpu_kms *dpu_kms = to_dpu_kms(kms);275 void *p = dpu_hw_util_get_log_mask_ptr();276 struct dentry *entry;277 278 if (!p)279 return -EINVAL;280 281 /* Only create a set of debugfs for the primary node, ignore render nodes */282 if (minor->type != DRM_MINOR_PRIMARY)283 return 0;284 285 entry = debugfs_create_dir("debug", minor->debugfs_root);286 287 debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, entry, p);288 289 dpu_debugfs_danger_init(dpu_kms, entry);290 dpu_debugfs_vbif_init(dpu_kms, entry);291 dpu_debugfs_core_irq_init(dpu_kms, entry);292 dpu_debugfs_sspp_init(dpu_kms, entry);293 294 return dpu_core_perf_debugfs_init(dpu_kms, entry);295}296#endif297 298/* Global/shared object state funcs */299 300/*301 * This is a helper that returns the private state currently in operation.302 * Note that this would return the "old_state" if called in the atomic check303 * path, and the "new_state" after the atomic swap has been done.304 */305struct dpu_global_state *306dpu_kms_get_existing_global_state(struct dpu_kms *dpu_kms)307{308 return to_dpu_global_state(dpu_kms->global_state.state);309}310 311/*312 * This acquires the modeset lock set aside for global state, creates313 * a new duplicated private object state.314 */315struct dpu_global_state *dpu_kms_get_global_state(struct drm_atomic_state *s)316{317 struct msm_drm_private *priv = s->dev->dev_private;318 struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms);319 struct drm_private_state *priv_state;320 321 priv_state = drm_atomic_get_private_obj_state(s,322 &dpu_kms->global_state);323 if (IS_ERR(priv_state))324 return ERR_CAST(priv_state);325 326 return to_dpu_global_state(priv_state);327}328 329static struct drm_private_state *330dpu_kms_global_duplicate_state(struct drm_private_obj *obj)331{332 struct dpu_global_state *state;333 334 state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);335 if (!state)336 return NULL;337 338 __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);339 340 return &state->base;341}342 343static void dpu_kms_global_destroy_state(struct drm_private_obj *obj,344 struct drm_private_state *state)345{346 struct dpu_global_state *dpu_state = to_dpu_global_state(state);347 348 kfree(dpu_state);349}350 351static void dpu_kms_global_print_state(struct drm_printer *p,352 const struct drm_private_state *state)353{354 const struct dpu_global_state *global_state = to_dpu_global_state(state);355 356 dpu_rm_print_state(p, global_state);357}358 359static const struct drm_private_state_funcs dpu_kms_global_state_funcs = {360 .atomic_duplicate_state = dpu_kms_global_duplicate_state,361 .atomic_destroy_state = dpu_kms_global_destroy_state,362 .atomic_print_state = dpu_kms_global_print_state,363};364 365static int dpu_kms_global_obj_init(struct dpu_kms *dpu_kms)366{367 struct dpu_global_state *state;368 369 state = kzalloc(sizeof(*state), GFP_KERNEL);370 if (!state)371 return -ENOMEM;372 373 drm_atomic_private_obj_init(dpu_kms->dev, &dpu_kms->global_state,374 &state->base,375 &dpu_kms_global_state_funcs);376 377 state->rm = &dpu_kms->rm;378 379 return 0;380}381 382static void dpu_kms_global_obj_fini(struct dpu_kms *dpu_kms)383{384 drm_atomic_private_obj_fini(&dpu_kms->global_state);385}386 387static int dpu_kms_parse_data_bus_icc_path(struct dpu_kms *dpu_kms)388{389 struct icc_path *path0;390 struct icc_path *path1;391 struct device *dpu_dev = &dpu_kms->pdev->dev;392 393 path0 = msm_icc_get(dpu_dev, "mdp0-mem");394 path1 = msm_icc_get(dpu_dev, "mdp1-mem");395 396 if (IS_ERR_OR_NULL(path0))397 return PTR_ERR_OR_ZERO(path0);398 399 dpu_kms->path[0] = path0;400 dpu_kms->num_paths = 1;401 402 if (!IS_ERR_OR_NULL(path1)) {403 dpu_kms->path[1] = path1;404 dpu_kms->num_paths++;405 }406 return 0;407}408 409static int dpu_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)410{411 return dpu_crtc_vblank(crtc, true);412}413 414static void dpu_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)415{416 dpu_crtc_vblank(crtc, false);417}418 419static void dpu_kms_enable_commit(struct msm_kms *kms)420{421 struct dpu_kms *dpu_kms = to_dpu_kms(kms);422 pm_runtime_get_sync(&dpu_kms->pdev->dev);423}424 425static void dpu_kms_disable_commit(struct msm_kms *kms)426{427 struct dpu_kms *dpu_kms = to_dpu_kms(kms);428 pm_runtime_put_sync(&dpu_kms->pdev->dev);429}430 431static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask)432{433 struct dpu_kms *dpu_kms = to_dpu_kms(kms);434 struct drm_crtc *crtc;435 436 for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) {437 if (!crtc->state->active)438 continue;439 440 trace_dpu_kms_commit(DRMID(crtc));441 dpu_crtc_commit_kickoff(crtc);442 }443}444 445static void dpu_kms_complete_commit(struct msm_kms *kms, unsigned crtc_mask)446{447 struct dpu_kms *dpu_kms = to_dpu_kms(kms);448 struct drm_crtc *crtc;449 450 DPU_ATRACE_BEGIN("kms_complete_commit");451 452 for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask)453 dpu_crtc_complete_commit(crtc);454 455 DPU_ATRACE_END("kms_complete_commit");456}457 458static void dpu_kms_wait_for_commit_done(struct msm_kms *kms,459 struct drm_crtc *crtc)460{461 struct drm_encoder *encoder;462 struct drm_device *dev;463 int ret;464 465 if (!kms || !crtc || !crtc->state) {466 DPU_ERROR("invalid params\n");467 return;468 }469 470 dev = crtc->dev;471 472 if (!crtc->state->enable) {473 DPU_DEBUG("[crtc:%d] not enable\n", crtc->base.id);474 return;475 }476 477 if (!drm_atomic_crtc_effectively_active(crtc->state)) {478 DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);479 return;480 }481 482 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {483 if (encoder->crtc != crtc)484 continue;485 /*486 * Wait for post-flush if necessary to delay before487 * plane_cleanup. For example, wait for vsync in case of video488 * mode panels. This may be a no-op for command mode panels.489 */490 trace_dpu_kms_wait_for_commit_done(DRMID(crtc));491 ret = dpu_encoder_wait_for_commit_done(encoder);492 if (ret && ret != -EWOULDBLOCK) {493 DPU_ERROR("wait for commit done returned %d\n", ret);494 break;495 }496 }497}498 499static void dpu_kms_wait_flush(struct msm_kms *kms, unsigned crtc_mask)500{501 struct dpu_kms *dpu_kms = to_dpu_kms(kms);502 struct drm_crtc *crtc;503 504 for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask)505 dpu_kms_wait_for_commit_done(kms, crtc);506}507 508static const char *dpu_vsync_sources[] = {509 [DPU_VSYNC_SOURCE_GPIO_0] = "mdp_vsync_p",510 [DPU_VSYNC_SOURCE_GPIO_1] = "mdp_vsync_s",511 [DPU_VSYNC_SOURCE_GPIO_2] = "mdp_vsync_e",512 [DPU_VSYNC_SOURCE_INTF_0] = "mdp_intf0",513 [DPU_VSYNC_SOURCE_INTF_1] = "mdp_intf1",514 [DPU_VSYNC_SOURCE_INTF_2] = "mdp_intf2",515 [DPU_VSYNC_SOURCE_INTF_3] = "mdp_intf3",516 [DPU_VSYNC_SOURCE_WD_TIMER_0] = "timer0",517 [DPU_VSYNC_SOURCE_WD_TIMER_1] = "timer1",518 [DPU_VSYNC_SOURCE_WD_TIMER_2] = "timer2",519 [DPU_VSYNC_SOURCE_WD_TIMER_3] = "timer3",520 [DPU_VSYNC_SOURCE_WD_TIMER_4] = "timer4",521};522 523static int dpu_kms_dsi_set_te_source(struct msm_display_info *info,524 struct msm_dsi *dsi)525{526 const char *te_source = msm_dsi_get_te_source(dsi);527 int i;528 529 if (!te_source) {530 info->vsync_source = DPU_VSYNC_SOURCE_GPIO_0;531 return 0;532 }533 534 /* we can not use match_string since dpu_vsync_sources is a sparse array */535 for (i = 0; i < ARRAY_SIZE(dpu_vsync_sources); i++) {536 if (dpu_vsync_sources[i] &&537 !strcmp(dpu_vsync_sources[i], te_source)) {538 info->vsync_source = i;539 return 0;540 }541 }542 543 return -EINVAL;544}545 546static int _dpu_kms_initialize_dsi(struct drm_device *dev,547 struct msm_drm_private *priv,548 struct dpu_kms *dpu_kms)549{550 struct drm_encoder *encoder = NULL;551 struct msm_display_info info;552 int i, rc = 0;553 554 if (!(priv->dsi[0] || priv->dsi[1]))555 return rc;556 557 /*558 * We support following confiurations:559 * - Single DSI host (dsi0 or dsi1)560 * - Two independent DSI hosts561 * - Bonded DSI0 and DSI1 hosts562 *563 * TODO: Support swapping DSI0 and DSI1 in the bonded setup.564 */565 for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) {566 int other = (i + 1) % 2;567 568 if (!priv->dsi[i])569 continue;570 571 if (msm_dsi_is_bonded_dsi(priv->dsi[i]) &&572 !msm_dsi_is_master_dsi(priv->dsi[i]))573 continue;574 575 memset(&info, 0, sizeof(info));576 info.intf_type = INTF_DSI;577 578 info.h_tile_instance[info.num_of_h_tiles++] = i;579 if (msm_dsi_is_bonded_dsi(priv->dsi[i]))580 info.h_tile_instance[info.num_of_h_tiles++] = other;581 582 info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);583 584 rc = dpu_kms_dsi_set_te_source(&info, priv->dsi[i]);585 if (rc) {586 DPU_ERROR("failed to identify TE source for dsi display\n");587 return rc;588 }589 590 encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI, &info);591 if (IS_ERR(encoder)) {592 DPU_ERROR("encoder init failed for dsi display\n");593 return PTR_ERR(encoder);594 }595 596 rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder);597 if (rc) {598 DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n",599 i, rc);600 break;601 }602 603 if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) {604 rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder);605 if (rc) {606 DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n",607 other, rc);608 break;609 }610 }611 }612 613 return rc;614}615 616static int _dpu_kms_initialize_displayport(struct drm_device *dev,617 struct msm_drm_private *priv,618 struct dpu_kms *dpu_kms)619{620 struct drm_encoder *encoder = NULL;621 struct msm_display_info info;622 bool yuv_supported;623 int rc;624 int i;625 626 for (i = 0; i < ARRAY_SIZE(priv->dp); i++) {627 if (!priv->dp[i])628 continue;629 630 memset(&info, 0, sizeof(info));631 info.num_of_h_tiles = 1;632 info.h_tile_instance[0] = i;633 info.intf_type = INTF_DP;634 635 encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_TMDS, &info);636 if (IS_ERR(encoder)) {637 DPU_ERROR("encoder init failed for dsi display\n");638 return PTR_ERR(encoder);639 }640 641 yuv_supported = !!dpu_kms->catalog->cdm;642 rc = msm_dp_modeset_init(priv->dp[i], dev, encoder, yuv_supported);643 if (rc) {644 DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);645 return rc;646 }647 }648 649 return 0;650}651 652static int _dpu_kms_initialize_hdmi(struct drm_device *dev,653 struct msm_drm_private *priv,654 struct dpu_kms *dpu_kms)655{656 struct drm_encoder *encoder = NULL;657 struct msm_display_info info;658 int rc;659 660 if (!priv->hdmi)661 return 0;662 663 memset(&info, 0, sizeof(info));664 info.num_of_h_tiles = 1;665 info.h_tile_instance[0] = 0;666 info.intf_type = INTF_HDMI;667 668 encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_TMDS, &info);669 if (IS_ERR(encoder)) {670 DPU_ERROR("encoder init failed for HDMI display\n");671 return PTR_ERR(encoder);672 }673 674 rc = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);675 if (rc) {676 DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);677 return rc;678 }679 680 return 0;681}682 683static int _dpu_kms_initialize_writeback(struct drm_device *dev,684 struct msm_drm_private *priv, struct dpu_kms *dpu_kms,685 const u32 *wb_formats, int n_formats)686{687 struct drm_encoder *encoder = NULL;688 struct msm_display_info info;689 const enum dpu_wb wb_idx = WB_2;690 u32 maxlinewidth;691 int rc;692 693 memset(&info, 0, sizeof(info));694 695 info.num_of_h_tiles = 1;696 /* use only WB idx 2 instance for DPU */697 info.h_tile_instance[0] = wb_idx;698 info.intf_type = INTF_WB;699 700 maxlinewidth = dpu_rm_get_wb(&dpu_kms->rm, info.h_tile_instance[0])->caps->maxlinewidth;701 702 encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL, &info);703 if (IS_ERR(encoder)) {704 DPU_ERROR("encoder init failed for dsi display\n");705 return PTR_ERR(encoder);706 }707 708 rc = dpu_writeback_init(dev, encoder, wb_formats, n_formats, maxlinewidth);709 if (rc) {710 DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);711 return rc;712 }713 714 return 0;715}716 717/**718 * _dpu_kms_setup_displays - create encoders, bridges and connectors719 * for underlying displays720 * @dev: Pointer to drm device structure721 * @priv: Pointer to private drm device data722 * @dpu_kms: Pointer to dpu kms structure723 * Returns: Zero on success724 */725static int _dpu_kms_setup_displays(struct drm_device *dev,726 struct msm_drm_private *priv,727 struct dpu_kms *dpu_kms)728{729 int rc = 0;730 int i;731 732 rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);733 if (rc) {734 DPU_ERROR("initialize_dsi failed, rc = %d\n", rc);735 return rc;736 }737 738 rc = _dpu_kms_initialize_displayport(dev, priv, dpu_kms);739 if (rc) {740 DPU_ERROR("initialize_DP failed, rc = %d\n", rc);741 return rc;742 }743 744 rc = _dpu_kms_initialize_hdmi(dev, priv, dpu_kms);745 if (rc) {746 DPU_ERROR("initialize HDMI failed, rc = %d\n", rc);747 return rc;748 }749 750 /* Since WB isn't a driver check the catalog before initializing */751 if (dpu_kms->catalog->wb_count) {752 for (i = 0; i < dpu_kms->catalog->wb_count; i++) {753 if (dpu_kms->catalog->wb[i].id == WB_2) {754 rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,755 dpu_kms->catalog->wb[i].format_list,756 dpu_kms->catalog->wb[i].num_formats);757 if (rc) {758 DPU_ERROR("initialize_WB failed, rc = %d\n", rc);759 return rc;760 }761 }762 }763 }764 765 return rc;766}767 768#define MAX_PLANES 20769static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)770{771 struct drm_device *dev;772 struct drm_plane *primary_planes[MAX_PLANES], *plane;773 struct drm_plane *cursor_planes[MAX_PLANES] = { NULL };774 struct drm_crtc *crtc;775 struct drm_encoder *encoder;776 unsigned int num_encoders;777 778 struct msm_drm_private *priv;779 const struct dpu_mdss_cfg *catalog;780 781 int primary_planes_idx = 0, cursor_planes_idx = 0, i, ret;782 int max_crtc_count;783 dev = dpu_kms->dev;784 priv = dev->dev_private;785 catalog = dpu_kms->catalog;786 787 /*788 * Create encoder and query display drivers to create789 * bridges and connectors790 */791 ret = _dpu_kms_setup_displays(dev, priv, dpu_kms);792 if (ret)793 return ret;794 795 num_encoders = 0;796 drm_for_each_encoder(encoder, dev)797 num_encoders++;798 799 max_crtc_count = min(catalog->mixer_count, num_encoders);800 801 /* Create the planes, keeping track of one primary/cursor per crtc */802 for (i = 0; i < catalog->sspp_count; i++) {803 enum drm_plane_type type;804 805 if ((catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR))806 && cursor_planes_idx < max_crtc_count)807 type = DRM_PLANE_TYPE_CURSOR;808 else if (primary_planes_idx < max_crtc_count)809 type = DRM_PLANE_TYPE_PRIMARY;810 else811 type = DRM_PLANE_TYPE_OVERLAY;812 813 DPU_DEBUG("Create plane type %d with features %lx (cur %lx)\n",814 type, catalog->sspp[i].features,815 catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR));816 817 plane = dpu_plane_init(dev, catalog->sspp[i].id, type,818 (1UL << max_crtc_count) - 1);819 if (IS_ERR(plane)) {820 DPU_ERROR("dpu_plane_init failed\n");821 ret = PTR_ERR(plane);822 return ret;823 }824 825 if (type == DRM_PLANE_TYPE_CURSOR)826 cursor_planes[cursor_planes_idx++] = plane;827 else if (type == DRM_PLANE_TYPE_PRIMARY)828 primary_planes[primary_planes_idx++] = plane;829 }830 831 max_crtc_count = min(max_crtc_count, primary_planes_idx);832 833 /* Create one CRTC per encoder */834 for (i = 0; i < max_crtc_count; i++) {835 crtc = dpu_crtc_init(dev, primary_planes[i], cursor_planes[i]);836 if (IS_ERR(crtc)) {837 ret = PTR_ERR(crtc);838 return ret;839 }840 priv->num_crtcs++;841 }842 843 /* All CRTCs are compatible with all encoders */844 drm_for_each_encoder(encoder, dev)845 encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;846 847 return 0;848}849 850static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms)851{852 int i;853 854 dpu_kms->hw_intr = NULL;855 856 /* safe to call these more than once during shutdown */857 _dpu_kms_mmu_destroy(dpu_kms);858 859 for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {860 dpu_kms->hw_vbif[i] = NULL;861 }862 863 dpu_kms_global_obj_fini(dpu_kms);864 865 dpu_kms->catalog = NULL;866 867 dpu_kms->hw_mdp = NULL;868}869 870static void dpu_kms_destroy(struct msm_kms *kms)871{872 struct dpu_kms *dpu_kms;873 874 if (!kms) {875 DPU_ERROR("invalid kms\n");876 return;877 }878 879 dpu_kms = to_dpu_kms(kms);880 881 _dpu_kms_hw_destroy(dpu_kms);882 883 msm_kms_destroy(&dpu_kms->base);884 885 if (dpu_kms->rpm_enabled)886 pm_runtime_disable(&dpu_kms->pdev->dev);887}888 889static int dpu_irq_postinstall(struct msm_kms *kms)890{891 struct msm_drm_private *priv;892 struct dpu_kms *dpu_kms = to_dpu_kms(kms);893 894 if (!dpu_kms || !dpu_kms->dev)895 return -EINVAL;896 897 priv = dpu_kms->dev->dev_private;898 if (!priv)899 return -EINVAL;900 901 return 0;902}903 904static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_kms *kms)905{906 int i;907 struct dpu_kms *dpu_kms;908 const struct dpu_mdss_cfg *cat;909 void __iomem *base;910 911 dpu_kms = to_dpu_kms(kms);912 913 cat = dpu_kms->catalog;914 915 pm_runtime_get_sync(&dpu_kms->pdev->dev);916 917 /* dump CTL sub-blocks HW regs info */918 for (i = 0; i < cat->ctl_count; i++)919 msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len,920 dpu_kms->mmio + cat->ctl[i].base, cat->ctl[i].name);921 922 /* dump DSPP sub-blocks HW regs info */923 for (i = 0; i < cat->dspp_count; i++) {924 base = dpu_kms->mmio + cat->dspp[i].base;925 msm_disp_snapshot_add_block(disp_state, cat->dspp[i].len, base, cat->dspp[i].name);926 927 if (cat->dspp[i].sblk && cat->dspp[i].sblk->pcc.len > 0)928 msm_disp_snapshot_add_block(disp_state, cat->dspp[i].sblk->pcc.len,929 base + cat->dspp[i].sblk->pcc.base, "%s_%s",930 cat->dspp[i].name,931 cat->dspp[i].sblk->pcc.name);932 }933 934 /* dump INTF sub-blocks HW regs info */935 for (i = 0; i < cat->intf_count; i++)936 msm_disp_snapshot_add_block(disp_state, cat->intf[i].len,937 dpu_kms->mmio + cat->intf[i].base, cat->intf[i].name);938 939 /* dump PP sub-blocks HW regs info */940 for (i = 0; i < cat->pingpong_count; i++) {941 base = dpu_kms->mmio + cat->pingpong[i].base;942 msm_disp_snapshot_add_block(disp_state, cat->pingpong[i].len, base,943 cat->pingpong[i].name);944 945 /* TE2 sub-block has length of 0, so will not print it */946 947 if (cat->pingpong[i].sblk && cat->pingpong[i].sblk->dither.len > 0)948 msm_disp_snapshot_add_block(disp_state, cat->pingpong[i].sblk->dither.len,949 base + cat->pingpong[i].sblk->dither.base,950 "%s_%s", cat->pingpong[i].name,951 cat->pingpong[i].sblk->dither.name);952 }953 954 /* dump SSPP sub-blocks HW regs info */955 for (i = 0; i < cat->sspp_count; i++) {956 base = dpu_kms->mmio + cat->sspp[i].base;957 msm_disp_snapshot_add_block(disp_state, cat->sspp[i].len, base, cat->sspp[i].name);958 959 if (cat->sspp[i].sblk && cat->sspp[i].sblk->scaler_blk.len > 0)960 msm_disp_snapshot_add_block(disp_state, cat->sspp[i].sblk->scaler_blk.len,961 base + cat->sspp[i].sblk->scaler_blk.base,962 "%s_%s", cat->sspp[i].name,963 cat->sspp[i].sblk->scaler_blk.name);964 965 if (cat->sspp[i].sblk && cat->sspp[i].sblk->csc_blk.len > 0)966 msm_disp_snapshot_add_block(disp_state, cat->sspp[i].sblk->csc_blk.len,967 base + cat->sspp[i].sblk->csc_blk.base,968 "%s_%s", cat->sspp[i].name,969 cat->sspp[i].sblk->csc_blk.name);970 }971 972 /* dump LM sub-blocks HW regs info */973 for (i = 0; i < cat->mixer_count; i++)974 msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len,975 dpu_kms->mmio + cat->mixer[i].base, cat->mixer[i].name);976 977 /* dump WB sub-blocks HW regs info */978 for (i = 0; i < cat->wb_count; i++)979 msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,980 dpu_kms->mmio + cat->wb[i].base, cat->wb[i].name);981 982 if (cat->mdp[0].features & BIT(DPU_MDP_PERIPH_0_REMOVED)) {983 msm_disp_snapshot_add_block(disp_state, MDP_PERIPH_TOP0,984 dpu_kms->mmio + cat->mdp[0].base, "top");985 msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len - MDP_PERIPH_TOP0_END,986 dpu_kms->mmio + cat->mdp[0].base + MDP_PERIPH_TOP0_END, "top_2");987 } else {988 msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len,989 dpu_kms->mmio + cat->mdp[0].base, "top");990 }991 992 /* dump DSC sub-blocks HW regs info */993 for (i = 0; i < cat->dsc_count; i++) {994 base = dpu_kms->mmio + cat->dsc[i].base;995 msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len, base, cat->dsc[i].name);996 997 if (cat->dsc[i].features & BIT(DPU_DSC_HW_REV_1_2)) {998 struct dpu_dsc_blk enc = cat->dsc[i].sblk->enc;999 struct dpu_dsc_blk ctl = cat->dsc[i].sblk->ctl;1000 1001 msm_disp_snapshot_add_block(disp_state, enc.len, base + enc.base, "%s_%s",1002 cat->dsc[i].name, enc.name);1003 msm_disp_snapshot_add_block(disp_state, ctl.len, base + ctl.base, "%s_%s",1004 cat->dsc[i].name, ctl.name);1005 }1006 }1007 1008 if (cat->cdm)1009 msm_disp_snapshot_add_block(disp_state, cat->cdm->len,1010 dpu_kms->mmio + cat->cdm->base, cat->cdm->name);1011 1012 pm_runtime_put_sync(&dpu_kms->pdev->dev);1013}1014 1015static const struct msm_kms_funcs kms_funcs = {1016 .hw_init = dpu_kms_hw_init,1017 .irq_preinstall = dpu_core_irq_preinstall,1018 .irq_postinstall = dpu_irq_postinstall,1019 .irq_uninstall = dpu_core_irq_uninstall,1020 .irq = dpu_core_irq,1021 .enable_commit = dpu_kms_enable_commit,1022 .disable_commit = dpu_kms_disable_commit,1023 .flush_commit = dpu_kms_flush_commit,1024 .wait_flush = dpu_kms_wait_flush,1025 .complete_commit = dpu_kms_complete_commit,1026 .enable_vblank = dpu_kms_enable_vblank,1027 .disable_vblank = dpu_kms_disable_vblank,1028 .check_modified_format = dpu_format_check_modified_format,1029 .destroy = dpu_kms_destroy,1030 .snapshot = dpu_kms_mdp_snapshot,1031#ifdef CONFIG_DEBUG_FS1032 .debugfs_init = dpu_kms_debugfs_init,1033#endif1034};1035 1036static void _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms)1037{1038 struct msm_mmu *mmu;1039 1040 if (!dpu_kms->base.aspace)1041 return;1042 1043 mmu = dpu_kms->base.aspace->mmu;1044 1045 mmu->funcs->detach(mmu);1046 msm_gem_address_space_put(dpu_kms->base.aspace);1047 1048 dpu_kms->base.aspace = NULL;1049}1050 1051static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms)1052{1053 struct msm_gem_address_space *aspace;1054 1055 aspace = msm_kms_init_aspace(dpu_kms->dev);1056 if (IS_ERR(aspace))1057 return PTR_ERR(aspace);1058 1059 dpu_kms->base.aspace = aspace;1060 1061 return 0;1062}1063 1064unsigned long dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name)1065{1066 struct clk *clk;1067 1068 clk = msm_clk_bulk_get_clock(dpu_kms->clocks, dpu_kms->num_clocks, clock_name);1069 if (!clk)1070 return 0;1071 1072 return clk_get_rate(clk);1073}1074 1075#define DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE 4125000001076 1077static int dpu_kms_hw_init(struct msm_kms *kms)1078{1079 struct dpu_kms *dpu_kms;1080 struct drm_device *dev;1081 int i, rc = -EINVAL;1082 unsigned long max_core_clk_rate;1083 u32 core_rev;1084 1085 if (!kms) {1086 DPU_ERROR("invalid kms\n");1087 return rc;1088 }1089 1090 dpu_kms = to_dpu_kms(kms);1091 dev = dpu_kms->dev;1092 1093 dev->mode_config.cursor_width = 512;1094 dev->mode_config.cursor_height = 512;1095 1096 rc = dpu_kms_global_obj_init(dpu_kms);1097 if (rc)1098 return rc;1099 1100 atomic_set(&dpu_kms->bandwidth_ref, 0);1101 1102 rc = pm_runtime_resume_and_get(&dpu_kms->pdev->dev);1103 if (rc < 0)1104 goto error;1105 1106 core_rev = readl_relaxed(dpu_kms->mmio + 0x0);1107 1108 pr_info("dpu hardware revision:0x%x\n", core_rev);1109 1110 dpu_kms->catalog = of_device_get_match_data(dev->dev);1111 if (!dpu_kms->catalog) {1112 DPU_ERROR("device config not known!\n");1113 rc = -EINVAL;1114 goto err_pm_put;1115 }1116 1117 /*1118 * Now we need to read the HW catalog and initialize resources such as1119 * clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc1120 */1121 rc = _dpu_kms_mmu_init(dpu_kms);1122 if (rc) {1123 DPU_ERROR("dpu_kms_mmu_init failed: %d\n", rc);1124 goto err_pm_put;1125 }1126 1127 dpu_kms->mdss = msm_mdss_get_mdss_data(dpu_kms->pdev->dev.parent);1128 if (IS_ERR(dpu_kms->mdss)) {1129 rc = PTR_ERR(dpu_kms->mdss);1130 DPU_ERROR("failed to get MDSS data: %d\n", rc);1131 goto err_pm_put;1132 }1133 1134 if (!dpu_kms->mdss) {1135 rc = -EINVAL;1136 DPU_ERROR("NULL MDSS data\n");1137 goto err_pm_put;1138 }1139 1140 rc = dpu_rm_init(dev, &dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio);1141 if (rc) {1142 DPU_ERROR("rm init failed: %d\n", rc);1143 goto err_pm_put;1144 }1145 1146 dpu_kms->hw_mdp = dpu_hw_mdptop_init(dev,1147 dpu_kms->catalog->mdp,1148 dpu_kms->mmio,1149 dpu_kms->catalog->mdss_ver);1150 if (IS_ERR(dpu_kms->hw_mdp)) {1151 rc = PTR_ERR(dpu_kms->hw_mdp);1152 DPU_ERROR("failed to get hw_mdp: %d\n", rc);1153 dpu_kms->hw_mdp = NULL;1154 goto err_pm_put;1155 }1156 1157 for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {1158 struct dpu_hw_vbif *hw;1159 const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i];1160 1161 hw = dpu_hw_vbif_init(dev, vbif, dpu_kms->vbif[vbif->id]);1162 if (IS_ERR(hw)) {1163 rc = PTR_ERR(hw);1164 DPU_ERROR("failed to init vbif %d: %d\n", vbif->id, rc);1165 goto err_pm_put;1166 }1167 1168 dpu_kms->hw_vbif[vbif->id] = hw;1169 }1170 1171 /* TODO: use the same max_freq as in dpu_kms_hw_init */1172 max_core_clk_rate = dpu_kms_get_clk_rate(dpu_kms, "core");1173 if (!max_core_clk_rate) {1174 DPU_DEBUG("max core clk rate not determined, using default\n");1175 max_core_clk_rate = DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE;1176 }1177 1178 rc = dpu_core_perf_init(&dpu_kms->perf, dpu_kms->catalog->perf, max_core_clk_rate);1179 if (rc) {1180 DPU_ERROR("failed to init perf %d\n", rc);1181 goto err_pm_put;1182 }1183 1184 /*1185 * We need to program DP <-> PHY relationship only for SC8180X since it1186 * has fewer DP controllers than DP PHYs.1187 * If any other platform requires the same kind of programming, or if1188 * the INTF <->DP relationship isn't static anymore, this needs to be1189 * configured through the DT.1190 */1191 if (of_device_is_compatible(dpu_kms->pdev->dev.of_node, "qcom,sc8180x-dpu"))1192 dpu_kms->hw_mdp->ops.dp_phy_intf_sel(dpu_kms->hw_mdp, (unsigned int[]){ 1, 2, });1193 1194 dpu_kms->hw_intr = dpu_hw_intr_init(dev, dpu_kms->mmio, dpu_kms->catalog);1195 if (IS_ERR(dpu_kms->hw_intr)) {1196 rc = PTR_ERR(dpu_kms->hw_intr);1197 DPU_ERROR("hw_intr init failed: %d\n", rc);1198 dpu_kms->hw_intr = NULL;1199 goto err_pm_put;1200 }1201 1202 dev->mode_config.min_width = 0;1203 dev->mode_config.min_height = 0;1204 1205 /*1206 * max crtc width is equal to the max mixer width * 2 and max height is1207 * is 4K1208 */1209 dev->mode_config.max_width =1210 dpu_kms->catalog->caps->max_mixer_width * 2;1211 dev->mode_config.max_height = 4096;1212 1213 dev->max_vblank_count = 0xffffffff;1214 /* Disable vblank irqs aggressively for power-saving */1215 dev->vblank_disable_immediate = true;1216 1217 /*1218 * _dpu_kms_drm_obj_init should create the DRM related objects1219 * i.e. CRTCs, planes, encoders, connectors and so forth1220 */1221 rc = _dpu_kms_drm_obj_init(dpu_kms);1222 if (rc) {1223 DPU_ERROR("modeset init failed: %d\n", rc);1224 goto err_pm_put;1225 }1226 1227 dpu_vbif_init_memtypes(dpu_kms);1228 1229 pm_runtime_put_sync(&dpu_kms->pdev->dev);1230 1231 return 0;1232 1233err_pm_put:1234 pm_runtime_put_sync(&dpu_kms->pdev->dev);1235error:1236 _dpu_kms_hw_destroy(dpu_kms);1237 1238 return rc;1239}1240 1241static int dpu_kms_init(struct drm_device *ddev)1242{1243 struct msm_drm_private *priv = ddev->dev_private;1244 struct device *dev = ddev->dev;1245 struct platform_device *pdev = to_platform_device(dev);1246 struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms);1247 struct dev_pm_opp *opp;1248 int ret = 0;1249 unsigned long max_freq = ULONG_MAX;1250 1251 opp = dev_pm_opp_find_freq_floor(dev, &max_freq);1252 if (!IS_ERR(opp))1253 dev_pm_opp_put(opp);1254 1255 dev_pm_opp_set_rate(dev, max_freq);1256 1257 ret = msm_kms_init(&dpu_kms->base, &kms_funcs);1258 if (ret) {1259 DPU_ERROR("failed to init kms, ret=%d\n", ret);1260 return ret;1261 }1262 dpu_kms->dev = ddev;1263 1264 pm_runtime_enable(&pdev->dev);1265 dpu_kms->rpm_enabled = true;1266 1267 return 0;1268}1269 1270static int dpu_kms_mmap_mdp5(struct dpu_kms *dpu_kms)1271{1272 struct platform_device *pdev = dpu_kms->pdev;1273 struct platform_device *mdss_dev;1274 int ret;1275 1276 if (!dev_is_platform(dpu_kms->pdev->dev.parent))1277 return -EINVAL;1278 1279 mdss_dev = to_platform_device(dpu_kms->pdev->dev.parent);1280 1281 dpu_kms->mmio = msm_ioremap(pdev, "mdp_phys");1282 if (IS_ERR(dpu_kms->mmio)) {1283 ret = PTR_ERR(dpu_kms->mmio);1284 DPU_ERROR("mdp register memory map failed: %d\n", ret);1285 dpu_kms->mmio = NULL;1286 return ret;1287 }1288 DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio);1289 1290 dpu_kms->vbif[VBIF_RT] = msm_ioremap_mdss(mdss_dev,1291 dpu_kms->pdev,1292 "vbif_phys");1293 if (IS_ERR(dpu_kms->vbif[VBIF_RT])) {1294 ret = PTR_ERR(dpu_kms->vbif[VBIF_RT]);1295 DPU_ERROR("vbif register memory map failed: %d\n", ret);1296 dpu_kms->vbif[VBIF_RT] = NULL;1297 return ret;1298 }1299 1300 dpu_kms->vbif[VBIF_NRT] = msm_ioremap_mdss(mdss_dev,1301 dpu_kms->pdev,1302 "vbif_nrt_phys");1303 if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) {1304 dpu_kms->vbif[VBIF_NRT] = NULL;1305 DPU_DEBUG("VBIF NRT is not defined");1306 }1307 1308 return 0;1309}1310 1311static int dpu_kms_mmap_dpu(struct dpu_kms *dpu_kms)1312{1313 struct platform_device *pdev = dpu_kms->pdev;1314 int ret;1315 1316 dpu_kms->mmio = msm_ioremap(pdev, "mdp");1317 if (IS_ERR(dpu_kms->mmio)) {1318 ret = PTR_ERR(dpu_kms->mmio);1319 DPU_ERROR("mdp register memory map failed: %d\n", ret);1320 dpu_kms->mmio = NULL;1321 return ret;1322 }1323 DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio);1324 1325 dpu_kms->vbif[VBIF_RT] = msm_ioremap(pdev, "vbif");1326 if (IS_ERR(dpu_kms->vbif[VBIF_RT])) {1327 ret = PTR_ERR(dpu_kms->vbif[VBIF_RT]);1328 DPU_ERROR("vbif register memory map failed: %d\n", ret);1329 dpu_kms->vbif[VBIF_RT] = NULL;1330 return ret;1331 }1332 1333 dpu_kms->vbif[VBIF_NRT] = msm_ioremap_quiet(pdev, "vbif_nrt");1334 if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) {1335 dpu_kms->vbif[VBIF_NRT] = NULL;1336 DPU_DEBUG("VBIF NRT is not defined");1337 }1338 1339 return 0;1340}1341 1342static int dpu_dev_probe(struct platform_device *pdev)1343{1344 struct device *dev = &pdev->dev;1345 struct dpu_kms *dpu_kms;1346 int irq;1347 int ret = 0;1348 1349 if (!msm_disp_drv_should_bind(&pdev->dev, true))1350 return -ENODEV;1351 1352 dpu_kms = devm_kzalloc(dev, sizeof(*dpu_kms), GFP_KERNEL);1353 if (!dpu_kms)1354 return -ENOMEM;1355 1356 dpu_kms->pdev = pdev;1357 1358 ret = devm_pm_opp_set_clkname(dev, "core");1359 if (ret)1360 return ret;1361 /* OPP table is optional */1362 ret = devm_pm_opp_of_add_table(dev);1363 if (ret && ret != -ENODEV)1364 return dev_err_probe(dev, ret, "invalid OPP table in device tree\n");1365 1366 ret = devm_clk_bulk_get_all(&pdev->dev, &dpu_kms->clocks);1367 if (ret < 0)1368 return dev_err_probe(dev, ret, "failed to parse clocks\n");1369 1370 dpu_kms->num_clocks = ret;1371 1372 irq = platform_get_irq(pdev, 0);1373 if (irq < 0)1374 return dev_err_probe(dev, irq, "failed to get irq\n");1375 1376 dpu_kms->base.irq = irq;1377 1378 if (of_device_is_compatible(dpu_kms->pdev->dev.of_node, "qcom,mdp5"))1379 ret = dpu_kms_mmap_mdp5(dpu_kms);1380 else1381 ret = dpu_kms_mmap_dpu(dpu_kms);1382 if (ret)1383 return ret;1384 1385 ret = dpu_kms_parse_data_bus_icc_path(dpu_kms);1386 if (ret)1387 return ret;1388 1389 return msm_drv_probe(&pdev->dev, dpu_kms_init, &dpu_kms->base);1390}1391 1392static void dpu_dev_remove(struct platform_device *pdev)1393{1394 component_master_del(&pdev->dev, &msm_drm_ops);1395}1396 1397static int __maybe_unused dpu_runtime_suspend(struct device *dev)1398{1399 int i;1400 struct platform_device *pdev = to_platform_device(dev);1401 struct msm_drm_private *priv = platform_get_drvdata(pdev);1402 struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms);1403 1404 /* Drop the performance state vote */1405 dev_pm_opp_set_rate(dev, 0);1406 clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks);1407 1408 for (i = 0; i < dpu_kms->num_paths; i++)1409 icc_set_bw(dpu_kms->path[i], 0, 0);1410 1411 return 0;1412}1413 1414static int __maybe_unused dpu_runtime_resume(struct device *dev)1415{1416 int rc = -1;1417 struct platform_device *pdev = to_platform_device(dev);1418 struct msm_drm_private *priv = platform_get_drvdata(pdev);1419 struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms);1420 struct drm_encoder *encoder;1421 struct drm_device *ddev;1422 1423 ddev = dpu_kms->dev;1424 1425 rc = clk_bulk_prepare_enable(dpu_kms->num_clocks, dpu_kms->clocks);1426 if (rc) {1427 DPU_ERROR("clock enable failed rc:%d\n", rc);1428 return rc;1429 }1430 1431 dpu_vbif_init_memtypes(dpu_kms);1432 1433 drm_for_each_encoder(encoder, ddev)1434 dpu_encoder_virt_runtime_resume(encoder);1435 1436 return rc;1437}1438 1439static const struct dev_pm_ops dpu_pm_ops = {1440 SET_RUNTIME_PM_OPS(dpu_runtime_suspend, dpu_runtime_resume, NULL)1441 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,1442 pm_runtime_force_resume)1443 .prepare = msm_kms_pm_prepare,1444 .complete = msm_kms_pm_complete,1445};1446 1447static const struct of_device_id dpu_dt_match[] = {1448 { .compatible = "qcom,msm8998-dpu", .data = &dpu_msm8998_cfg, },1449 { .compatible = "qcom,qcm2290-dpu", .data = &dpu_qcm2290_cfg, },1450 { .compatible = "qcom,sdm630-mdp5", .data = &dpu_sdm630_cfg, },1451 { .compatible = "qcom,sdm660-mdp5", .data = &dpu_sdm660_cfg, },1452 { .compatible = "qcom,sdm670-dpu", .data = &dpu_sdm670_cfg, },1453 { .compatible = "qcom,sdm845-dpu", .data = &dpu_sdm845_cfg, },1454 { .compatible = "qcom,sc7180-dpu", .data = &dpu_sc7180_cfg, },1455 { .compatible = "qcom,sc7280-dpu", .data = &dpu_sc7280_cfg, },1456 { .compatible = "qcom,sc8180x-dpu", .data = &dpu_sc8180x_cfg, },1457 { .compatible = "qcom,sc8280xp-dpu", .data = &dpu_sc8280xp_cfg, },1458 { .compatible = "qcom,sm6115-dpu", .data = &dpu_sm6115_cfg, },1459 { .compatible = "qcom,sm6125-dpu", .data = &dpu_sm6125_cfg, },1460 { .compatible = "qcom,sm6350-dpu", .data = &dpu_sm6350_cfg, },1461 { .compatible = "qcom,sm6375-dpu", .data = &dpu_sm6375_cfg, },1462 { .compatible = "qcom,sm7150-dpu", .data = &dpu_sm7150_cfg, },1463 { .compatible = "qcom,sm8150-dpu", .data = &dpu_sm8150_cfg, },1464 { .compatible = "qcom,sm8250-dpu", .data = &dpu_sm8250_cfg, },1465 { .compatible = "qcom,sm8350-dpu", .data = &dpu_sm8350_cfg, },1466 { .compatible = "qcom,sm8450-dpu", .data = &dpu_sm8450_cfg, },1467 { .compatible = "qcom,sm8550-dpu", .data = &dpu_sm8550_cfg, },1468 { .compatible = "qcom,sm8650-dpu", .data = &dpu_sm8650_cfg, },1469 { .compatible = "qcom,x1e80100-dpu", .data = &dpu_x1e80100_cfg, },1470 {}1471};1472MODULE_DEVICE_TABLE(of, dpu_dt_match);1473 1474static struct platform_driver dpu_driver = {1475 .probe = dpu_dev_probe,1476 .remove_new = dpu_dev_remove,1477 .shutdown = msm_kms_shutdown,1478 .driver = {1479 .name = "msm_dpu",1480 .of_match_table = dpu_dt_match,1481 .pm = &dpu_pm_ops,1482 },1483};1484 1485void __init msm_dpu_register(void)1486{1487 platform_driver_register(&dpu_driver);1488}1489 1490void __exit msm_dpu_unregister(void)1491{1492 platform_driver_unregister(&dpu_driver);1493}1494