brintos

brintos / linux-shallow public Read only

0
0
Text · 22.8 KiB · 374704c Raw
931 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.4 * Copyright (C) 2013 Red Hat5 * Author: Rob Clark <robdclark@gmail.com>6 */7 8#include <linux/delay.h>9#include <linux/interconnect.h>10#include <linux/of_irq.h>11 12#include <drm/drm_debugfs.h>13#include <drm/drm_drv.h>14#include <drm/drm_file.h>15#include <drm/drm_vblank.h>16 17#include "msm_drv.h"18#include "msm_gem.h"19#include "msm_mmu.h"20#include "mdp5_kms.h"21 22static int mdp5_hw_init(struct msm_kms *kms)23{24	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));25	struct device *dev = &mdp5_kms->pdev->dev;26	unsigned long flags;27 28	pm_runtime_get_sync(dev);29 30	/* Magic unknown register writes:31	 *32	 *    W VBIF:0x004 00000001      (mdss_mdp.c:839)33	 *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839)34	 *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839)35	 *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839)36	 *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839)37	 *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839)38	 *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839)39	 *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839)40	 *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839)41	 *42	 * Downstream fbdev driver gets these register offsets/values43	 * from DT.. not really sure what these registers are or if44	 * different values for different boards/SoC's, etc.  I guess45	 * they are the golden registers.46	 *47	 * Not setting these does not seem to cause any problem.  But48	 * we may be getting lucky with the bootloader initializing49	 * them for us.  OTOH, if we can always count on the bootloader50	 * setting the golden registers, then perhaps we don't need to51	 * care.52	 */53 54	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);55	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);56	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);57 58	mdp5_ctlm_hw_reset(mdp5_kms->ctlm);59 60	pm_runtime_put_sync(dev);61 62	return 0;63}64 65/* Global/shared object state funcs */66 67/*68 * This is a helper that returns the private state currently in operation.69 * Note that this would return the "old_state" if called in the atomic check70 * path, and the "new_state" after the atomic swap has been done.71 */72struct mdp5_global_state *73mdp5_get_existing_global_state(struct mdp5_kms *mdp5_kms)74{75	return to_mdp5_global_state(mdp5_kms->glob_state.state);76}77 78/*79 * This acquires the modeset lock set aside for global state, creates80 * a new duplicated private object state.81 */82struct mdp5_global_state *mdp5_get_global_state(struct drm_atomic_state *s)83{84	struct msm_drm_private *priv = s->dev->dev_private;85	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));86	struct drm_private_state *priv_state;87 88	priv_state = drm_atomic_get_private_obj_state(s, &mdp5_kms->glob_state);89	if (IS_ERR(priv_state))90		return ERR_CAST(priv_state);91 92	return to_mdp5_global_state(priv_state);93}94 95static struct drm_private_state *96mdp5_global_duplicate_state(struct drm_private_obj *obj)97{98	struct mdp5_global_state *state;99 100	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);101	if (!state)102		return NULL;103 104	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);105 106	return &state->base;107}108 109static void mdp5_global_destroy_state(struct drm_private_obj *obj,110				      struct drm_private_state *state)111{112	struct mdp5_global_state *mdp5_state = to_mdp5_global_state(state);113 114	kfree(mdp5_state);115}116 117static void mdp5_global_print_state(struct drm_printer *p,118				    const struct drm_private_state *state)119{120	struct mdp5_global_state *mdp5_state = to_mdp5_global_state(state);121 122	if (mdp5_state->mdp5_kms->smp)123		mdp5_smp_dump(mdp5_state->mdp5_kms->smp, p, mdp5_state);124}125 126static const struct drm_private_state_funcs mdp5_global_state_funcs = {127	.atomic_duplicate_state = mdp5_global_duplicate_state,128	.atomic_destroy_state = mdp5_global_destroy_state,129	.atomic_print_state = mdp5_global_print_state,130};131 132static int mdp5_global_obj_init(struct mdp5_kms *mdp5_kms)133{134	struct mdp5_global_state *state;135 136	state = kzalloc(sizeof(*state), GFP_KERNEL);137	if (!state)138		return -ENOMEM;139 140	state->mdp5_kms = mdp5_kms;141 142	drm_atomic_private_obj_init(mdp5_kms->dev, &mdp5_kms->glob_state,143				    &state->base,144				    &mdp5_global_state_funcs);145	return 0;146}147 148static void mdp5_enable_commit(struct msm_kms *kms)149{150	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));151	pm_runtime_get_sync(&mdp5_kms->pdev->dev);152}153 154static void mdp5_disable_commit(struct msm_kms *kms)155{156	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));157	pm_runtime_put_sync(&mdp5_kms->pdev->dev);158}159 160static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)161{162	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));163	struct mdp5_global_state *global_state;164 165	global_state = mdp5_get_existing_global_state(mdp5_kms);166 167	if (mdp5_kms->smp)168		mdp5_smp_prepare_commit(mdp5_kms->smp, &global_state->smp);169}170 171static void mdp5_flush_commit(struct msm_kms *kms, unsigned crtc_mask)172{173	/* TODO */174}175 176static void mdp5_wait_flush(struct msm_kms *kms, unsigned crtc_mask)177{178	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));179	struct drm_crtc *crtc;180 181	for_each_crtc_mask(mdp5_kms->dev, crtc, crtc_mask)182		mdp5_crtc_wait_for_commit_done(crtc);183}184 185static void mdp5_complete_commit(struct msm_kms *kms, unsigned crtc_mask)186{187	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));188	struct mdp5_global_state *global_state;189 190	global_state = mdp5_get_existing_global_state(mdp5_kms);191 192	if (mdp5_kms->smp)193		mdp5_smp_complete_commit(mdp5_kms->smp, &global_state->smp);194}195 196static void mdp5_destroy(struct mdp5_kms *mdp5_kms);197 198static void mdp5_kms_destroy(struct msm_kms *kms)199{200	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));201	struct msm_gem_address_space *aspace = kms->aspace;202 203	if (aspace) {204		aspace->mmu->funcs->detach(aspace->mmu);205		msm_gem_address_space_put(aspace);206	}207 208	mdp_kms_destroy(&mdp5_kms->base);209	mdp5_destroy(mdp5_kms);210}211 212static const struct mdp_kms_funcs kms_funcs = {213	.base = {214		.hw_init         = mdp5_hw_init,215		.irq_preinstall  = mdp5_irq_preinstall,216		.irq_postinstall = mdp5_irq_postinstall,217		.irq_uninstall   = mdp5_irq_uninstall,218		.irq             = mdp5_irq,219		.enable_vblank   = mdp5_enable_vblank,220		.disable_vblank  = mdp5_disable_vblank,221		.flush_commit    = mdp5_flush_commit,222		.enable_commit   = mdp5_enable_commit,223		.disable_commit  = mdp5_disable_commit,224		.prepare_commit  = mdp5_prepare_commit,225		.wait_flush      = mdp5_wait_flush,226		.complete_commit = mdp5_complete_commit,227		.destroy         = mdp5_kms_destroy,228	},229	.set_irqmask         = mdp5_set_irqmask,230};231 232static int mdp5_disable(struct mdp5_kms *mdp5_kms)233{234	DBG("");235 236	mdp5_kms->enable_count--;237	WARN_ON(mdp5_kms->enable_count < 0);238 239	clk_disable_unprepare(mdp5_kms->tbu_rt_clk);240	clk_disable_unprepare(mdp5_kms->tbu_clk);241	clk_disable_unprepare(mdp5_kms->ahb_clk);242	clk_disable_unprepare(mdp5_kms->axi_clk);243	clk_disable_unprepare(mdp5_kms->core_clk);244	clk_disable_unprepare(mdp5_kms->lut_clk);245 246	return 0;247}248 249static int mdp5_enable(struct mdp5_kms *mdp5_kms)250{251	DBG("");252 253	mdp5_kms->enable_count++;254 255	clk_prepare_enable(mdp5_kms->ahb_clk);256	clk_prepare_enable(mdp5_kms->axi_clk);257	clk_prepare_enable(mdp5_kms->core_clk);258	clk_prepare_enable(mdp5_kms->lut_clk);259	clk_prepare_enable(mdp5_kms->tbu_clk);260	clk_prepare_enable(mdp5_kms->tbu_rt_clk);261 262	return 0;263}264 265static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,266					     struct mdp5_interface *intf,267					     struct mdp5_ctl *ctl)268{269	struct drm_device *dev = mdp5_kms->dev;270	struct drm_encoder *encoder;271 272	encoder = mdp5_encoder_init(dev, intf, ctl);273	if (IS_ERR(encoder)) {274		DRM_DEV_ERROR(dev->dev, "failed to construct encoder\n");275		return encoder;276	}277 278	return encoder;279}280 281static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)282{283	const enum mdp5_intf_type *intfs = hw_cfg->intf.connect;284	const int intf_cnt = ARRAY_SIZE(hw_cfg->intf.connect);285	int id = 0, i;286 287	for (i = 0; i < intf_cnt; i++) {288		if (intfs[i] == INTF_DSI) {289			if (intf_num == i)290				return id;291 292			id++;293		}294	}295 296	return -EINVAL;297}298 299static int modeset_init_intf(struct mdp5_kms *mdp5_kms,300			     struct mdp5_interface *intf)301{302	struct drm_device *dev = mdp5_kms->dev;303	struct msm_drm_private *priv = dev->dev_private;304	struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;305	struct mdp5_ctl *ctl;306	struct drm_encoder *encoder;307	int ret = 0;308 309	switch (intf->type) {310	case INTF_eDP:311		DRM_DEV_INFO(dev->dev, "Skipping eDP interface %d\n", intf->num);312		break;313	case INTF_HDMI:314		if (!priv->hdmi)315			break;316 317		ctl = mdp5_ctlm_request(ctlm, intf->num);318		if (!ctl) {319			ret = -EINVAL;320			break;321		}322 323		encoder = construct_encoder(mdp5_kms, intf, ctl);324		if (IS_ERR(encoder)) {325			ret = PTR_ERR(encoder);326			break;327		}328 329		ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);330		break;331	case INTF_DSI:332	{333		const struct mdp5_cfg_hw *hw_cfg =334					mdp5_cfg_get_hw_config(mdp5_kms->cfg);335		int dsi_id = get_dsi_id_from_intf(hw_cfg, intf->num);336 337		if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {338			DRM_DEV_ERROR(dev->dev, "failed to find dsi from intf %d\n",339				intf->num);340			ret = -EINVAL;341			break;342		}343 344		if (!priv->dsi[dsi_id])345			break;346 347		ctl = mdp5_ctlm_request(ctlm, intf->num);348		if (!ctl) {349			ret = -EINVAL;350			break;351		}352 353		encoder = construct_encoder(mdp5_kms, intf, ctl);354		if (IS_ERR(encoder)) {355			ret = PTR_ERR(encoder);356			break;357		}358 359		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);360		if (!ret)361			mdp5_encoder_set_intf_mode(encoder, msm_dsi_is_cmd_mode(priv->dsi[dsi_id]));362 363		break;364	}365	default:366		DRM_DEV_ERROR(dev->dev, "unknown intf: %d\n", intf->type);367		ret = -EINVAL;368		break;369	}370 371	return ret;372}373 374static int modeset_init(struct mdp5_kms *mdp5_kms)375{376	struct drm_device *dev = mdp5_kms->dev;377	struct msm_drm_private *priv = dev->dev_private;378	unsigned int num_crtcs;379	int i, ret, pi = 0, ci = 0;380	struct drm_plane *primary[MAX_BASES] = { NULL };381	struct drm_plane *cursor[MAX_BASES] = { NULL };382	struct drm_encoder *encoder;383	unsigned int num_encoders;384 385	/*386	 * Construct encoders and modeset initialize connector devices387	 * for each external display interface.388	 */389	for (i = 0; i < mdp5_kms->num_intfs; i++) {390		ret = modeset_init_intf(mdp5_kms, mdp5_kms->intfs[i]);391		if (ret)392			goto fail;393	}394 395	num_encoders = 0;396	drm_for_each_encoder(encoder, dev)397		num_encoders++;398 399	/*400	 * We should ideally have less number of encoders (set up by parsing401	 * the MDP5 interfaces) than the number of layer mixers present in HW,402	 * but let's be safe here anyway403	 */404	num_crtcs = min(num_encoders, mdp5_kms->num_hwmixers);405 406	/*407	 * Construct planes equaling the number of hw pipes, and CRTCs for the408	 * N encoders set up by the driver. The first N planes become primary409	 * planes for the CRTCs, with the remainder as overlay planes:410	 */411	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {412		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];413		struct drm_plane *plane;414		enum drm_plane_type type;415 416		if (i < num_crtcs)417			type = DRM_PLANE_TYPE_PRIMARY;418		else if (hwpipe->caps & MDP_PIPE_CAP_CURSOR)419			type = DRM_PLANE_TYPE_CURSOR;420		else421			type = DRM_PLANE_TYPE_OVERLAY;422 423		plane = mdp5_plane_init(dev, type);424		if (IS_ERR(plane)) {425			ret = PTR_ERR(plane);426			DRM_DEV_ERROR(dev->dev, "failed to construct plane %d (%d)\n", i, ret);427			goto fail;428		}429 430		if (type == DRM_PLANE_TYPE_PRIMARY)431			primary[pi++] = plane;432		if (type == DRM_PLANE_TYPE_CURSOR)433			cursor[ci++] = plane;434	}435 436	for (i = 0; i < num_crtcs; i++) {437		struct drm_crtc *crtc;438 439		crtc  = mdp5_crtc_init(dev, primary[i], cursor[i], i);440		if (IS_ERR(crtc)) {441			ret = PTR_ERR(crtc);442			DRM_DEV_ERROR(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);443			goto fail;444		}445		priv->num_crtcs++;446	}447 448	/*449	 * Now that we know the number of crtcs we've created, set the possible450	 * crtcs for the encoders451	 */452	drm_for_each_encoder(encoder, dev)453		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;454 455	return 0;456 457fail:458	return ret;459}460 461static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,462				 u32 *major, u32 *minor)463{464	struct device *dev = &mdp5_kms->pdev->dev;465	u32 version;466 467	pm_runtime_get_sync(dev);468	version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION);469	pm_runtime_put_sync(dev);470 471	*major = FIELD(version, MDP5_HW_VERSION_MAJOR);472	*minor = FIELD(version, MDP5_HW_VERSION_MINOR);473 474	DRM_DEV_INFO(dev, "MDP5 version v%d.%d", *major, *minor);475}476 477static int get_clk(struct platform_device *pdev, struct clk **clkp,478		const char *name, bool mandatory)479{480	struct device *dev = &pdev->dev;481	struct clk *clk = msm_clk_get(pdev, name);482	if (IS_ERR(clk) && mandatory) {483		DRM_DEV_ERROR(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));484		return PTR_ERR(clk);485	}486	if (IS_ERR(clk))487		DBG("skipping %s", name);488	else489		*clkp = clk;490 491	return 0;492}493 494static int mdp5_init(struct platform_device *pdev, struct drm_device *dev);495 496static int mdp5_kms_init(struct drm_device *dev)497{498	struct msm_drm_private *priv = dev->dev_private;499	struct platform_device *pdev;500	struct mdp5_kms *mdp5_kms;501	struct mdp5_cfg *config;502	struct msm_kms *kms = priv->kms;503	struct msm_gem_address_space *aspace;504	int i, ret;505 506	ret = mdp5_init(to_platform_device(dev->dev), dev);507	if (ret)508		return ret;509 510	mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));511 512	pdev = mdp5_kms->pdev;513 514	ret = mdp_kms_init(&mdp5_kms->base, &kms_funcs);515	if (ret) {516		DRM_DEV_ERROR(&pdev->dev, "failed to init kms\n");517		goto fail;518	}519 520	config = mdp5_cfg_get_config(mdp5_kms->cfg);521 522	/* make sure things are off before attaching iommu (bootloader could523	 * have left things on, in which case we'll start getting faults if524	 * we don't disable):525	 */526	pm_runtime_get_sync(&pdev->dev);527	for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {528		if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||529		    !config->hw->intf.base[i])530			continue;531		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);532 533		mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);534	}535	mdelay(16);536 537	aspace = msm_kms_init_aspace(mdp5_kms->dev);538	if (IS_ERR(aspace)) {539		ret = PTR_ERR(aspace);540		goto fail;541	}542 543	kms->aspace = aspace;544 545	pm_runtime_put_sync(&pdev->dev);546 547	ret = modeset_init(mdp5_kms);548	if (ret) {549		DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);550		goto fail;551	}552 553	dev->mode_config.min_width = 0;554	dev->mode_config.min_height = 0;555	dev->mode_config.max_width = 0xffff;556	dev->mode_config.max_height = 0xffff;557 558	dev->max_vblank_count = 0; /* max_vblank_count is set on each CRTC */559	dev->vblank_disable_immediate = true;560 561	return 0;562fail:563	if (kms)564		mdp5_kms_destroy(kms);565 566	return ret;567}568 569static void mdp5_destroy(struct mdp5_kms *mdp5_kms)570{571	if (mdp5_kms->rpm_enabled)572		pm_runtime_disable(&mdp5_kms->pdev->dev);573 574	drm_atomic_private_obj_fini(&mdp5_kms->glob_state);575}576 577static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt,578		const enum mdp5_pipe *pipes, const uint32_t *offsets,579		uint32_t caps)580{581	struct drm_device *dev = mdp5_kms->dev;582	int i, ret;583 584	for (i = 0; i < cnt; i++) {585		struct mdp5_hw_pipe *hwpipe;586 587		hwpipe = mdp5_pipe_init(dev, pipes[i], offsets[i], caps);588		if (IS_ERR(hwpipe)) {589			ret = PTR_ERR(hwpipe);590			DRM_DEV_ERROR(dev->dev, "failed to construct pipe for %s (%d)\n",591					pipe2name(pipes[i]), ret);592			return ret;593		}594		hwpipe->idx = mdp5_kms->num_hwpipes;595		mdp5_kms->hwpipes[mdp5_kms->num_hwpipes++] = hwpipe;596	}597 598	return 0;599}600 601static int hwpipe_init(struct mdp5_kms *mdp5_kms)602{603	static const enum mdp5_pipe rgb_planes[] = {604			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,605	};606	static const enum mdp5_pipe vig_planes[] = {607			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,608	};609	static const enum mdp5_pipe dma_planes[] = {610			SSPP_DMA0, SSPP_DMA1,611	};612	static const enum mdp5_pipe cursor_planes[] = {613			SSPP_CURSOR0, SSPP_CURSOR1,614	};615	const struct mdp5_cfg_hw *hw_cfg;616	int ret;617 618	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);619 620	/* Construct RGB pipes: */621	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_rgb.count, rgb_planes,622			hw_cfg->pipe_rgb.base, hw_cfg->pipe_rgb.caps);623	if (ret)624		return ret;625 626	/* Construct video (VIG) pipes: */627	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_vig.count, vig_planes,628			hw_cfg->pipe_vig.base, hw_cfg->pipe_vig.caps);629	if (ret)630		return ret;631 632	/* Construct DMA pipes: */633	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_dma.count, dma_planes,634			hw_cfg->pipe_dma.base, hw_cfg->pipe_dma.caps);635	if (ret)636		return ret;637 638	/* Construct cursor pipes: */639	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_cursor.count,640			cursor_planes, hw_cfg->pipe_cursor.base,641			hw_cfg->pipe_cursor.caps);642	if (ret)643		return ret;644 645	return 0;646}647 648static int hwmixer_init(struct mdp5_kms *mdp5_kms)649{650	struct drm_device *dev = mdp5_kms->dev;651	const struct mdp5_cfg_hw *hw_cfg;652	int i, ret;653 654	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);655 656	for (i = 0; i < hw_cfg->lm.count; i++) {657		struct mdp5_hw_mixer *mixer;658 659		mixer = mdp5_mixer_init(dev, &hw_cfg->lm.instances[i]);660		if (IS_ERR(mixer)) {661			ret = PTR_ERR(mixer);662			DRM_DEV_ERROR(dev->dev, "failed to construct LM%d (%d)\n",663				i, ret);664			return ret;665		}666 667		mixer->idx = mdp5_kms->num_hwmixers;668		mdp5_kms->hwmixers[mdp5_kms->num_hwmixers++] = mixer;669	}670 671	return 0;672}673 674static int interface_init(struct mdp5_kms *mdp5_kms)675{676	struct drm_device *dev = mdp5_kms->dev;677	const struct mdp5_cfg_hw *hw_cfg;678	const enum mdp5_intf_type *intf_types;679	int i;680 681	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);682	intf_types = hw_cfg->intf.connect;683 684	for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {685		struct mdp5_interface *intf;686 687		if (intf_types[i] == INTF_DISABLED)688			continue;689 690		intf = devm_kzalloc(dev->dev, sizeof(*intf), GFP_KERNEL);691		if (!intf) {692			DRM_DEV_ERROR(dev->dev, "failed to construct INTF%d\n", i);693			return -ENOMEM;694		}695 696		intf->num = i;697		intf->type = intf_types[i];698		intf->mode = MDP5_INTF_MODE_NONE;699		intf->idx = mdp5_kms->num_intfs;700		mdp5_kms->intfs[mdp5_kms->num_intfs++] = intf;701	}702 703	return 0;704}705 706static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)707{708	struct msm_drm_private *priv = dev->dev_private;709	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));710	struct mdp5_cfg *config;711	u32 major, minor;712	int ret;713 714	mdp5_kms->dev = dev;715 716	ret = mdp5_global_obj_init(mdp5_kms);717	if (ret)718		goto fail;719 720	/* we need to set a default rate before enabling.  Set a safe721	 * rate first, then figure out hw revision, and then set a722	 * more optimal rate:723	 */724	clk_set_rate(mdp5_kms->core_clk, 200000000);725 726	pm_runtime_enable(&pdev->dev);727	mdp5_kms->rpm_enabled = true;728 729	read_mdp_hw_revision(mdp5_kms, &major, &minor);730 731	mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor);732	if (IS_ERR(mdp5_kms->cfg)) {733		ret = PTR_ERR(mdp5_kms->cfg);734		mdp5_kms->cfg = NULL;735		goto fail;736	}737 738	config = mdp5_cfg_get_config(mdp5_kms->cfg);739	mdp5_kms->caps = config->hw->mdp.caps;740 741	/* TODO: compute core clock rate at runtime */742	clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk);743 744	/*745	 * Some chipsets have a Shared Memory Pool (SMP), while others746	 * have dedicated latency buffering per source pipe instead;747	 * this section initializes the SMP:748	 */749	if (mdp5_kms->caps & MDP_CAP_SMP) {750		mdp5_kms->smp = mdp5_smp_init(mdp5_kms, &config->hw->smp);751		if (IS_ERR(mdp5_kms->smp)) {752			ret = PTR_ERR(mdp5_kms->smp);753			mdp5_kms->smp = NULL;754			goto fail;755		}756	}757 758	mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg);759	if (IS_ERR(mdp5_kms->ctlm)) {760		ret = PTR_ERR(mdp5_kms->ctlm);761		mdp5_kms->ctlm = NULL;762		goto fail;763	}764 765	ret = hwpipe_init(mdp5_kms);766	if (ret)767		goto fail;768 769	ret = hwmixer_init(mdp5_kms);770	if (ret)771		goto fail;772 773	ret = interface_init(mdp5_kms);774	if (ret)775		goto fail;776 777	return 0;778fail:779	mdp5_destroy(mdp5_kms);780	return ret;781}782 783static int mdp5_setup_interconnect(struct platform_device *pdev)784{785	struct icc_path *path0 = msm_icc_get(&pdev->dev, "mdp0-mem");786	struct icc_path *path1 = msm_icc_get(&pdev->dev, "mdp1-mem");787	struct icc_path *path_rot = msm_icc_get(&pdev->dev, "rotator-mem");788 789	if (IS_ERR(path0))790		return PTR_ERR(path0);791 792	if (!path0) {793		/* no interconnect support is not necessarily a fatal794		 * condition, the platform may simply not have an795		 * interconnect driver yet.  But warn about it in case796		 * bootloader didn't setup bus clocks high enough for797		 * scanout.798		 */799		dev_warn(&pdev->dev, "No interconnect support may cause display underflows!\n");800		return 0;801	}802 803	icc_set_bw(path0, 0, MBps_to_icc(6400));804 805	if (!IS_ERR_OR_NULL(path1))806		icc_set_bw(path1, 0, MBps_to_icc(6400));807	if (!IS_ERR_OR_NULL(path_rot))808		icc_set_bw(path_rot, 0, MBps_to_icc(6400));809 810	return 0;811}812 813static int mdp5_dev_probe(struct platform_device *pdev)814{815	struct mdp5_kms *mdp5_kms;816	int ret, irq;817 818	DBG("");819 820	if (!msm_disp_drv_should_bind(&pdev->dev, false))821		return -ENODEV;822 823	mdp5_kms = devm_kzalloc(&pdev->dev, sizeof(*mdp5_kms), GFP_KERNEL);824	if (!mdp5_kms)825		return -ENOMEM;826 827	ret = mdp5_setup_interconnect(pdev);828	if (ret)829		return ret;830 831	mdp5_kms->pdev = pdev;832 833	spin_lock_init(&mdp5_kms->resource_lock);834 835	mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys");836	if (IS_ERR(mdp5_kms->mmio))837		return PTR_ERR(mdp5_kms->mmio);838 839	/* mandatory clocks: */840	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus", true);841	if (ret)842		return ret;843	ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface", true);844	if (ret)845		return ret;846	ret = get_clk(pdev, &mdp5_kms->core_clk, "core", true);847	if (ret)848		return ret;849	ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync", true);850	if (ret)851		return ret;852 853	/* optional clocks: */854	get_clk(pdev, &mdp5_kms->lut_clk, "lut", false);855	get_clk(pdev, &mdp5_kms->tbu_clk, "tbu", false);856	get_clk(pdev, &mdp5_kms->tbu_rt_clk, "tbu_rt", false);857 858	irq = platform_get_irq(pdev, 0);859	if (irq < 0)860		return dev_err_probe(&pdev->dev, irq, "failed to get irq\n");861 862	mdp5_kms->base.base.irq = irq;863 864	return msm_drv_probe(&pdev->dev, mdp5_kms_init, &mdp5_kms->base.base);865}866 867static void mdp5_dev_remove(struct platform_device *pdev)868{869	DBG("");870	component_master_del(&pdev->dev, &msm_drm_ops);871}872 873static __maybe_unused int mdp5_runtime_suspend(struct device *dev)874{875	struct platform_device *pdev = to_platform_device(dev);876	struct msm_drm_private *priv = platform_get_drvdata(pdev);877	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));878 879	DBG("");880 881	return mdp5_disable(mdp5_kms);882}883 884static __maybe_unused int mdp5_runtime_resume(struct device *dev)885{886	struct platform_device *pdev = to_platform_device(dev);887	struct msm_drm_private *priv = platform_get_drvdata(pdev);888	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));889 890	DBG("");891 892	return mdp5_enable(mdp5_kms);893}894 895static const struct dev_pm_ops mdp5_pm_ops = {896	SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL)897	.prepare = msm_kms_pm_prepare,898	.complete = msm_kms_pm_complete,899};900 901static const struct of_device_id mdp5_dt_match[] = {902	{ .compatible = "qcom,mdp5", },903	/* to support downstream DT files */904	{ .compatible = "qcom,mdss_mdp", },905	{}906};907MODULE_DEVICE_TABLE(of, mdp5_dt_match);908 909static struct platform_driver mdp5_driver = {910	.probe = mdp5_dev_probe,911	.remove_new = mdp5_dev_remove,912	.shutdown = msm_kms_shutdown,913	.driver = {914		.name = "msm_mdp",915		.of_match_table = mdp5_dt_match,916		.pm = &mdp5_pm_ops,917	},918};919 920void __init msm_mdp_register(void)921{922	DBG("");923	platform_driver_register(&mdp5_driver);924}925 926void __exit msm_mdp_unregister(void)927{928	DBG("");929	platform_driver_unregister(&mdp5_driver);930}931