brintos

brintos / linux-shallow public Read only

0
0
Text · 38.7 KiB · 9bcae53 Raw
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