xref: /linux/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c (revision db5d28c0bfe566908719bec8e25443aabecbb802)
1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
214be3200SRob Clark /*
314be3200SRob Clark  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
414be3200SRob Clark  * Copyright (C) 2013 Red Hat
514be3200SRob Clark  * Author: Rob Clark <robdclark@gmail.com>
614be3200SRob Clark  */
714be3200SRob Clark 
8feea39a8SSam Ravnborg #include <linux/delay.h>
997f90e1bSGeorgi Djakov #include <linux/interconnect.h>
1014be3200SRob Clark #include <linux/of_irq.h>
1114be3200SRob Clark 
12feea39a8SSam Ravnborg #include <drm/drm_debugfs.h>
13feea39a8SSam Ravnborg #include <drm/drm_drv.h>
14feea39a8SSam Ravnborg #include <drm/drm_file.h>
15feea39a8SSam Ravnborg #include <drm/drm_vblank.h>
16feea39a8SSam Ravnborg 
1714be3200SRob Clark #include "msm_drv.h"
1814be3200SRob Clark #include "msm_gem.h"
1914be3200SRob Clark #include "msm_mmu.h"
2014be3200SRob Clark #include "mdp5_kms.h"
2114be3200SRob Clark 
mdp5_hw_init(struct msm_kms * kms)2214be3200SRob Clark static int mdp5_hw_init(struct msm_kms *kms)
2314be3200SRob Clark {
2414be3200SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
2514be3200SRob Clark 	struct device *dev = &mdp5_kms->pdev->dev;
2614be3200SRob Clark 	unsigned long flags;
2714be3200SRob Clark 
2814be3200SRob Clark 	pm_runtime_get_sync(dev);
2914be3200SRob Clark 
3014be3200SRob Clark 	/* Magic unknown register writes:
3114be3200SRob Clark 	 *
3214be3200SRob Clark 	 *    W VBIF:0x004 00000001      (mdss_mdp.c:839)
3314be3200SRob Clark 	 *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839)
3414be3200SRob Clark 	 *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839)
3514be3200SRob Clark 	 *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839)
3614be3200SRob Clark 	 *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839)
3714be3200SRob Clark 	 *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839)
3814be3200SRob Clark 	 *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839)
3914be3200SRob Clark 	 *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839)
4014be3200SRob Clark 	 *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839)
4114be3200SRob Clark 	 *
4214be3200SRob Clark 	 * Downstream fbdev driver gets these register offsets/values
4314be3200SRob Clark 	 * from DT.. not really sure what these registers are or if
4414be3200SRob Clark 	 * different values for different boards/SoC's, etc.  I guess
4514be3200SRob Clark 	 * they are the golden registers.
4614be3200SRob Clark 	 *
4714be3200SRob Clark 	 * Not setting these does not seem to cause any problem.  But
4814be3200SRob Clark 	 * we may be getting lucky with the bootloader initializing
4914be3200SRob Clark 	 * them for us.  OTOH, if we can always count on the bootloader
5014be3200SRob Clark 	 * setting the golden registers, then perhaps we don't need to
5114be3200SRob Clark 	 * care.
5214be3200SRob Clark 	 */
5314be3200SRob Clark 
5414be3200SRob Clark 	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
5514be3200SRob Clark 	mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
5614be3200SRob Clark 	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
5714be3200SRob Clark 
5814be3200SRob Clark 	mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
5914be3200SRob Clark 
6014be3200SRob Clark 	pm_runtime_put_sync(dev);
6114be3200SRob Clark 
6214be3200SRob Clark 	return 0;
6314be3200SRob Clark }
6414be3200SRob Clark 
658d58ef34SArchit Taneja /* Global/shared object state funcs */
668d58ef34SArchit Taneja 
678d58ef34SArchit Taneja /*
688d58ef34SArchit Taneja  * This is a helper that returns the private state currently in operation.
698d58ef34SArchit Taneja  * Note that this would return the "old_state" if called in the atomic check
708d58ef34SArchit Taneja  * path, and the "new_state" after the atomic swap has been done.
718d58ef34SArchit Taneja  */
728d58ef34SArchit Taneja struct mdp5_global_state *
mdp5_get_existing_global_state(struct mdp5_kms * mdp5_kms)738d58ef34SArchit Taneja mdp5_get_existing_global_state(struct mdp5_kms *mdp5_kms)
748d58ef34SArchit Taneja {
758d58ef34SArchit Taneja 	return to_mdp5_global_state(mdp5_kms->glob_state.state);
768d58ef34SArchit Taneja }
778d58ef34SArchit Taneja 
788d58ef34SArchit Taneja /*
798d58ef34SArchit Taneja  * This acquires the modeset lock set aside for global state, creates
808d58ef34SArchit Taneja  * a new duplicated private object state.
818d58ef34SArchit Taneja  */
mdp5_get_global_state(struct drm_atomic_state * s)828d58ef34SArchit Taneja struct mdp5_global_state *mdp5_get_global_state(struct drm_atomic_state *s)
838d58ef34SArchit Taneja {
848d58ef34SArchit Taneja 	struct msm_drm_private *priv = s->dev->dev_private;
858d58ef34SArchit Taneja 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
868d58ef34SArchit Taneja 	struct drm_private_state *priv_state;
878d58ef34SArchit Taneja 
888d58ef34SArchit Taneja 	priv_state = drm_atomic_get_private_obj_state(s, &mdp5_kms->glob_state);
898d58ef34SArchit Taneja 	if (IS_ERR(priv_state))
908d58ef34SArchit Taneja 		return ERR_CAST(priv_state);
918d58ef34SArchit Taneja 
928d58ef34SArchit Taneja 	return to_mdp5_global_state(priv_state);
938d58ef34SArchit Taneja }
948d58ef34SArchit Taneja 
958d58ef34SArchit Taneja static struct drm_private_state *
mdp5_global_duplicate_state(struct drm_private_obj * obj)968d58ef34SArchit Taneja mdp5_global_duplicate_state(struct drm_private_obj *obj)
978d58ef34SArchit Taneja {
988d58ef34SArchit Taneja 	struct mdp5_global_state *state;
998d58ef34SArchit Taneja 
1008d58ef34SArchit Taneja 	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
1018d58ef34SArchit Taneja 	if (!state)
1028d58ef34SArchit Taneja 		return NULL;
1038d58ef34SArchit Taneja 
1048d58ef34SArchit Taneja 	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
1058d58ef34SArchit Taneja 
1068d58ef34SArchit Taneja 	return &state->base;
1078d58ef34SArchit Taneja }
1088d58ef34SArchit Taneja 
mdp5_global_destroy_state(struct drm_private_obj * obj,struct drm_private_state * state)1098d58ef34SArchit Taneja static void mdp5_global_destroy_state(struct drm_private_obj *obj,
1108d58ef34SArchit Taneja 				      struct drm_private_state *state)
1118d58ef34SArchit Taneja {
1128d58ef34SArchit Taneja 	struct mdp5_global_state *mdp5_state = to_mdp5_global_state(state);
1138d58ef34SArchit Taneja 
1148d58ef34SArchit Taneja 	kfree(mdp5_state);
1158d58ef34SArchit Taneja }
1168d58ef34SArchit Taneja 
mdp5_global_print_state(struct drm_printer * p,const struct drm_private_state * state)117*f9c27e64SDmitry Baryshkov static void mdp5_global_print_state(struct drm_printer *p,
118*f9c27e64SDmitry Baryshkov 				    const struct drm_private_state *state)
119*f9c27e64SDmitry Baryshkov {
120*f9c27e64SDmitry Baryshkov 	struct mdp5_global_state *mdp5_state = to_mdp5_global_state(state);
121*f9c27e64SDmitry Baryshkov 
122*f9c27e64SDmitry Baryshkov 	if (mdp5_state->mdp5_kms->smp)
123*f9c27e64SDmitry Baryshkov 		mdp5_smp_dump(mdp5_state->mdp5_kms->smp, p, mdp5_state);
124*f9c27e64SDmitry Baryshkov }
125*f9c27e64SDmitry Baryshkov 
1268d58ef34SArchit Taneja static const struct drm_private_state_funcs mdp5_global_state_funcs = {
1278d58ef34SArchit Taneja 	.atomic_duplicate_state = mdp5_global_duplicate_state,
1288d58ef34SArchit Taneja 	.atomic_destroy_state = mdp5_global_destroy_state,
129*f9c27e64SDmitry Baryshkov 	.atomic_print_state = mdp5_global_print_state,
1308d58ef34SArchit Taneja };
1318d58ef34SArchit Taneja 
mdp5_global_obj_init(struct mdp5_kms * mdp5_kms)1328d58ef34SArchit Taneja static int mdp5_global_obj_init(struct mdp5_kms *mdp5_kms)
1338d58ef34SArchit Taneja {
1348d58ef34SArchit Taneja 	struct mdp5_global_state *state;
1358d58ef34SArchit Taneja 
1368d58ef34SArchit Taneja 	state = kzalloc(sizeof(*state), GFP_KERNEL);
1378d58ef34SArchit Taneja 	if (!state)
1388d58ef34SArchit Taneja 		return -ENOMEM;
1398d58ef34SArchit Taneja 
1408d58ef34SArchit Taneja 	state->mdp5_kms = mdp5_kms;
1418d58ef34SArchit Taneja 
142b962a120SRob Clark 	drm_atomic_private_obj_init(mdp5_kms->dev, &mdp5_kms->glob_state,
1438d58ef34SArchit Taneja 				    &state->base,
1448d58ef34SArchit Taneja 				    &mdp5_global_state_funcs);
1458d58ef34SArchit Taneja 	return 0;
1468d58ef34SArchit Taneja }
1478d58ef34SArchit Taneja 
mdp5_enable_commit(struct msm_kms * kms)148e35a29d5SRob Clark static void mdp5_enable_commit(struct msm_kms *kms)
149e35a29d5SRob Clark {
150e35a29d5SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
151e35a29d5SRob Clark 	pm_runtime_get_sync(&mdp5_kms->pdev->dev);
152e35a29d5SRob Clark }
153e35a29d5SRob Clark 
mdp5_disable_commit(struct msm_kms * kms)154e35a29d5SRob Clark static void mdp5_disable_commit(struct msm_kms *kms)
155e35a29d5SRob Clark {
156e35a29d5SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
157e35a29d5SRob Clark 	pm_runtime_put_sync(&mdp5_kms->pdev->dev);
158e35a29d5SRob Clark }
159e35a29d5SRob Clark 
mdp5_prepare_commit(struct msm_kms * kms,struct drm_atomic_state * state)16014be3200SRob Clark static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
16114be3200SRob Clark {
16214be3200SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
1637907a0d7SArchit Taneja 	struct mdp5_global_state *global_state;
1647907a0d7SArchit Taneja 
1657907a0d7SArchit Taneja 	global_state = mdp5_get_existing_global_state(mdp5_kms);
16614be3200SRob Clark 
16714be3200SRob Clark 	if (mdp5_kms->smp)
1687907a0d7SArchit Taneja 		mdp5_smp_prepare_commit(mdp5_kms->smp, &global_state->smp);
16914be3200SRob Clark }
17014be3200SRob Clark 
mdp5_flush_commit(struct msm_kms * kms,unsigned crtc_mask)1719f6b6564SRob Clark static void mdp5_flush_commit(struct msm_kms *kms, unsigned crtc_mask)
1729f6b6564SRob Clark {
1739f6b6564SRob Clark 	/* TODO */
1749f6b6564SRob Clark }
1759f6b6564SRob Clark 
mdp5_wait_flush(struct msm_kms * kms,unsigned crtc_mask)176d4d2c604SRob Clark static void mdp5_wait_flush(struct msm_kms *kms, unsigned crtc_mask)
177d4d2c604SRob Clark {
178d4d2c604SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
179d4d2c604SRob Clark 	struct drm_crtc *crtc;
180d4d2c604SRob Clark 
181d4d2c604SRob Clark 	for_each_crtc_mask(mdp5_kms->dev, crtc, crtc_mask)
182d4d2c604SRob Clark 		mdp5_crtc_wait_for_commit_done(crtc);
183d4d2c604SRob Clark }
184d4d2c604SRob Clark 
mdp5_complete_commit(struct msm_kms * kms,unsigned crtc_mask)18580b4b4a7SRob Clark static void mdp5_complete_commit(struct msm_kms *kms, unsigned crtc_mask)
18614be3200SRob Clark {
18714be3200SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
1887907a0d7SArchit Taneja 	struct mdp5_global_state *global_state;
1897907a0d7SArchit Taneja 
1907907a0d7SArchit Taneja 	global_state = mdp5_get_existing_global_state(mdp5_kms);
19114be3200SRob Clark 
19214be3200SRob Clark 	if (mdp5_kms->smp)
1937907a0d7SArchit Taneja 		mdp5_smp_complete_commit(mdp5_kms->smp, &global_state->smp);
19414be3200SRob Clark }
19514be3200SRob Clark 
196c6122688SDmitry Baryshkov static void mdp5_destroy(struct mdp5_kms *mdp5_kms);
1976874f48bSDmitry Baryshkov 
mdp5_kms_destroy(struct msm_kms * kms)19814be3200SRob Clark static void mdp5_kms_destroy(struct msm_kms *kms)
19914be3200SRob Clark {
20014be3200SRob Clark 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
20114be3200SRob Clark 	struct msm_gem_address_space *aspace = kms->aspace;
20214be3200SRob Clark 
20314be3200SRob Clark 	if (aspace) {
20453bf7f7aSDrew Davenport 		aspace->mmu->funcs->detach(aspace->mmu);
20514be3200SRob Clark 		msm_gem_address_space_put(aspace);
20614be3200SRob Clark 	}
207ffe71111SRob Clark 
208ffe71111SRob Clark 	mdp_kms_destroy(&mdp5_kms->base);
209c6122688SDmitry Baryshkov 	mdp5_destroy(mdp5_kms);
21014be3200SRob Clark }
21114be3200SRob Clark 
21214be3200SRob Clark static const struct mdp_kms_funcs kms_funcs = {
21314be3200SRob Clark 	.base = {
21414be3200SRob Clark 		.hw_init         = mdp5_hw_init,
21514be3200SRob Clark 		.irq_preinstall  = mdp5_irq_preinstall,
21614be3200SRob Clark 		.irq_postinstall = mdp5_irq_postinstall,
21714be3200SRob Clark 		.irq_uninstall   = mdp5_irq_uninstall,
21814be3200SRob Clark 		.irq             = mdp5_irq,
21914be3200SRob Clark 		.enable_vblank   = mdp5_enable_vblank,
22014be3200SRob Clark 		.disable_vblank  = mdp5_disable_vblank,
2219f6b6564SRob Clark 		.flush_commit    = mdp5_flush_commit,
222e35a29d5SRob Clark 		.enable_commit   = mdp5_enable_commit,
223e35a29d5SRob Clark 		.disable_commit  = mdp5_disable_commit,
22414be3200SRob Clark 		.prepare_commit  = mdp5_prepare_commit,
225d4d2c604SRob Clark 		.wait_flush      = mdp5_wait_flush,
22614be3200SRob Clark 		.complete_commit = mdp5_complete_commit,
22714be3200SRob Clark 		.destroy         = mdp5_kms_destroy,
22814be3200SRob Clark 	},
22914be3200SRob Clark 	.set_irqmask         = mdp5_set_irqmask,
23014be3200SRob Clark };
23114be3200SRob Clark 
mdp5_disable(struct mdp5_kms * mdp5_kms)232da640b3eSLee Jones static int mdp5_disable(struct mdp5_kms *mdp5_kms)
23314be3200SRob Clark {
23414be3200SRob Clark 	DBG("");
23514be3200SRob Clark 
23614be3200SRob Clark 	mdp5_kms->enable_count--;
23714be3200SRob Clark 	WARN_ON(mdp5_kms->enable_count < 0);
23814be3200SRob Clark 
2391c2a9f25SAngeloGioacchino Del Regno 	clk_disable_unprepare(mdp5_kms->tbu_rt_clk);
2401c2a9f25SAngeloGioacchino Del Regno 	clk_disable_unprepare(mdp5_kms->tbu_clk);
24114be3200SRob Clark 	clk_disable_unprepare(mdp5_kms->ahb_clk);
24214be3200SRob Clark 	clk_disable_unprepare(mdp5_kms->axi_clk);
24314be3200SRob Clark 	clk_disable_unprepare(mdp5_kms->core_clk);
24414be3200SRob Clark 	clk_disable_unprepare(mdp5_kms->lut_clk);
24514be3200SRob Clark 
24614be3200SRob Clark 	return 0;
24714be3200SRob Clark }
24814be3200SRob Clark 
mdp5_enable(struct mdp5_kms * mdp5_kms)249da640b3eSLee Jones static int mdp5_enable(struct mdp5_kms *mdp5_kms)
25014be3200SRob Clark {
25114be3200SRob Clark 	DBG("");
25214be3200SRob Clark 
25314be3200SRob Clark 	mdp5_kms->enable_count++;
25414be3200SRob Clark 
25514be3200SRob Clark 	clk_prepare_enable(mdp5_kms->ahb_clk);
25614be3200SRob Clark 	clk_prepare_enable(mdp5_kms->axi_clk);
25714be3200SRob Clark 	clk_prepare_enable(mdp5_kms->core_clk);
25814be3200SRob Clark 	clk_prepare_enable(mdp5_kms->lut_clk);
2591c2a9f25SAngeloGioacchino Del Regno 	clk_prepare_enable(mdp5_kms->tbu_clk);
2601c2a9f25SAngeloGioacchino Del Regno 	clk_prepare_enable(mdp5_kms->tbu_rt_clk);
26114be3200SRob Clark 
26214be3200SRob Clark 	return 0;
26314be3200SRob Clark }
26414be3200SRob Clark 
construct_encoder(struct mdp5_kms * mdp5_kms,struct mdp5_interface * intf,struct mdp5_ctl * ctl)26514be3200SRob Clark static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
26614be3200SRob Clark 					     struct mdp5_interface *intf,
26714be3200SRob Clark 					     struct mdp5_ctl *ctl)
26814be3200SRob Clark {
26914be3200SRob Clark 	struct drm_device *dev = mdp5_kms->dev;
27014be3200SRob Clark 	struct drm_encoder *encoder;
27114be3200SRob Clark 
27214be3200SRob Clark 	encoder = mdp5_encoder_init(dev, intf, ctl);
27314be3200SRob Clark 	if (IS_ERR(encoder)) {
2746a41da17SMamta Shukla 		DRM_DEV_ERROR(dev->dev, "failed to construct encoder\n");
27514be3200SRob Clark 		return encoder;
27614be3200SRob Clark 	}
27714be3200SRob Clark 
27814be3200SRob Clark 	return encoder;
27914be3200SRob Clark }
28014be3200SRob Clark 
get_dsi_id_from_intf(const struct mdp5_cfg_hw * hw_cfg,int intf_num)28114be3200SRob Clark static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
28214be3200SRob Clark {
28314be3200SRob Clark 	const enum mdp5_intf_type *intfs = hw_cfg->intf.connect;
28414be3200SRob Clark 	const int intf_cnt = ARRAY_SIZE(hw_cfg->intf.connect);
28514be3200SRob Clark 	int id = 0, i;
28614be3200SRob Clark 
28714be3200SRob Clark 	for (i = 0; i < intf_cnt; i++) {
28814be3200SRob Clark 		if (intfs[i] == INTF_DSI) {
28914be3200SRob Clark 			if (intf_num == i)
29014be3200SRob Clark 				return id;
29114be3200SRob Clark 
29214be3200SRob Clark 			id++;
29314be3200SRob Clark 		}
29414be3200SRob Clark 	}
29514be3200SRob Clark 
29614be3200SRob Clark 	return -EINVAL;
29714be3200SRob Clark }
29814be3200SRob Clark 
modeset_init_intf(struct mdp5_kms * mdp5_kms,struct mdp5_interface * intf)29914be3200SRob Clark static int modeset_init_intf(struct mdp5_kms *mdp5_kms,
30014be3200SRob Clark 			     struct mdp5_interface *intf)
30114be3200SRob Clark {
30214be3200SRob Clark 	struct drm_device *dev = mdp5_kms->dev;
30314be3200SRob Clark 	struct msm_drm_private *priv = dev->dev_private;
30414be3200SRob Clark 	struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;
30514be3200SRob Clark 	struct mdp5_ctl *ctl;
30614be3200SRob Clark 	struct drm_encoder *encoder;
30714be3200SRob Clark 	int ret = 0;
30814be3200SRob Clark 
30914be3200SRob Clark 	switch (intf->type) {
31014be3200SRob Clark 	case INTF_eDP:
3119ab3d271SDmitry Baryshkov 		DRM_DEV_INFO(dev->dev, "Skipping eDP interface %d\n", intf->num);
31214be3200SRob Clark 		break;
31314be3200SRob Clark 	case INTF_HDMI:
31414be3200SRob Clark 		if (!priv->hdmi)
31514be3200SRob Clark 			break;
31614be3200SRob Clark 
31714be3200SRob Clark 		ctl = mdp5_ctlm_request(ctlm, intf->num);
31814be3200SRob Clark 		if (!ctl) {
31914be3200SRob Clark 			ret = -EINVAL;
32014be3200SRob Clark 			break;
32114be3200SRob Clark 		}
32214be3200SRob Clark 
32314be3200SRob Clark 		encoder = construct_encoder(mdp5_kms, intf, ctl);
32414be3200SRob Clark 		if (IS_ERR(encoder)) {
32514be3200SRob Clark 			ret = PTR_ERR(encoder);
32614be3200SRob Clark 			break;
32714be3200SRob Clark 		}
32814be3200SRob Clark 
32914be3200SRob Clark 		ret = msm_hdmi_modeset_init(priv->hdmi, dev, encoder);
33014be3200SRob Clark 		break;
33114be3200SRob Clark 	case INTF_DSI:
33214be3200SRob Clark 	{
33314be3200SRob Clark 		const struct mdp5_cfg_hw *hw_cfg =
33414be3200SRob Clark 					mdp5_cfg_get_hw_config(mdp5_kms->cfg);
33514be3200SRob Clark 		int dsi_id = get_dsi_id_from_intf(hw_cfg, intf->num);
33614be3200SRob Clark 
33714be3200SRob Clark 		if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
3386a41da17SMamta Shukla 			DRM_DEV_ERROR(dev->dev, "failed to find dsi from intf %d\n",
33914be3200SRob Clark 				intf->num);
34014be3200SRob Clark 			ret = -EINVAL;
34114be3200SRob Clark 			break;
34214be3200SRob Clark 		}
34314be3200SRob Clark 
34414be3200SRob Clark 		if (!priv->dsi[dsi_id])
34514be3200SRob Clark 			break;
34614be3200SRob Clark 
34714be3200SRob Clark 		ctl = mdp5_ctlm_request(ctlm, intf->num);
34814be3200SRob Clark 		if (!ctl) {
34914be3200SRob Clark 			ret = -EINVAL;
35014be3200SRob Clark 			break;
35114be3200SRob Clark 		}
35214be3200SRob Clark 
35314be3200SRob Clark 		encoder = construct_encoder(mdp5_kms, intf, ctl);
35414be3200SRob Clark 		if (IS_ERR(encoder)) {
35514be3200SRob Clark 			ret = PTR_ERR(encoder);
35614be3200SRob Clark 			break;
35714be3200SRob Clark 		}
35814be3200SRob Clark 
35914be3200SRob Clark 		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
3600f1b69feSDmitry Baryshkov 		if (!ret)
3610f1b69feSDmitry Baryshkov 			mdp5_encoder_set_intf_mode(encoder, msm_dsi_is_cmd_mode(priv->dsi[dsi_id]));
3620f1b69feSDmitry Baryshkov 
36314be3200SRob Clark 		break;
36414be3200SRob Clark 	}
36514be3200SRob Clark 	default:
3666a41da17SMamta Shukla 		DRM_DEV_ERROR(dev->dev, "unknown intf: %d\n", intf->type);
36714be3200SRob Clark 		ret = -EINVAL;
36814be3200SRob Clark 		break;
36914be3200SRob Clark 	}
37014be3200SRob Clark 
37114be3200SRob Clark 	return ret;
37214be3200SRob Clark }
37314be3200SRob Clark 
modeset_init(struct mdp5_kms * mdp5_kms)37414be3200SRob Clark static int modeset_init(struct mdp5_kms *mdp5_kms)
37514be3200SRob Clark {
37614be3200SRob Clark 	struct drm_device *dev = mdp5_kms->dev;
37714be3200SRob Clark 	struct msm_drm_private *priv = dev->dev_private;
37814be3200SRob Clark 	unsigned int num_crtcs;
37914be3200SRob Clark 	int i, ret, pi = 0, ci = 0;
38014be3200SRob Clark 	struct drm_plane *primary[MAX_BASES] = { NULL };
38114be3200SRob Clark 	struct drm_plane *cursor[MAX_BASES] = { NULL };
382fa560afaSDmitry Baryshkov 	struct drm_encoder *encoder;
3830054ac2cSDmitry Baryshkov 	unsigned int num_encoders;
38414be3200SRob Clark 
38514be3200SRob Clark 	/*
38614be3200SRob Clark 	 * Construct encoders and modeset initialize connector devices
38714be3200SRob Clark 	 * for each external display interface.
38814be3200SRob Clark 	 */
38914be3200SRob Clark 	for (i = 0; i < mdp5_kms->num_intfs; i++) {
39014be3200SRob Clark 		ret = modeset_init_intf(mdp5_kms, mdp5_kms->intfs[i]);
39114be3200SRob Clark 		if (ret)
39214be3200SRob Clark 			goto fail;
39314be3200SRob Clark 	}
39414be3200SRob Clark 
3950054ac2cSDmitry Baryshkov 	num_encoders = 0;
3960054ac2cSDmitry Baryshkov 	drm_for_each_encoder(encoder, dev)
3970054ac2cSDmitry Baryshkov 		num_encoders++;
3980054ac2cSDmitry Baryshkov 
39914be3200SRob Clark 	/*
40014be3200SRob Clark 	 * We should ideally have less number of encoders (set up by parsing
40114be3200SRob Clark 	 * the MDP5 interfaces) than the number of layer mixers present in HW,
40214be3200SRob Clark 	 * but let's be safe here anyway
40314be3200SRob Clark 	 */
4040054ac2cSDmitry Baryshkov 	num_crtcs = min(num_encoders, mdp5_kms->num_hwmixers);
40514be3200SRob Clark 
40614be3200SRob Clark 	/*
40714be3200SRob Clark 	 * Construct planes equaling the number of hw pipes, and CRTCs for the
40814be3200SRob Clark 	 * N encoders set up by the driver. The first N planes become primary
40914be3200SRob Clark 	 * planes for the CRTCs, with the remainder as overlay planes:
41014be3200SRob Clark 	 */
41114be3200SRob Clark 	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
41214be3200SRob Clark 		struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
41314be3200SRob Clark 		struct drm_plane *plane;
41414be3200SRob Clark 		enum drm_plane_type type;
41514be3200SRob Clark 
41614be3200SRob Clark 		if (i < num_crtcs)
41714be3200SRob Clark 			type = DRM_PLANE_TYPE_PRIMARY;
41814be3200SRob Clark 		else if (hwpipe->caps & MDP_PIPE_CAP_CURSOR)
41914be3200SRob Clark 			type = DRM_PLANE_TYPE_CURSOR;
42014be3200SRob Clark 		else
42114be3200SRob Clark 			type = DRM_PLANE_TYPE_OVERLAY;
42214be3200SRob Clark 
42314be3200SRob Clark 		plane = mdp5_plane_init(dev, type);
42414be3200SRob Clark 		if (IS_ERR(plane)) {
42514be3200SRob Clark 			ret = PTR_ERR(plane);
4266a41da17SMamta Shukla 			DRM_DEV_ERROR(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
42714be3200SRob Clark 			goto fail;
42814be3200SRob Clark 		}
42914be3200SRob Clark 
43014be3200SRob Clark 		if (type == DRM_PLANE_TYPE_PRIMARY)
43114be3200SRob Clark 			primary[pi++] = plane;
43214be3200SRob Clark 		if (type == DRM_PLANE_TYPE_CURSOR)
43314be3200SRob Clark 			cursor[ci++] = plane;
43414be3200SRob Clark 	}
43514be3200SRob Clark 
43614be3200SRob Clark 	for (i = 0; i < num_crtcs; i++) {
43714be3200SRob Clark 		struct drm_crtc *crtc;
43814be3200SRob Clark 
43914be3200SRob Clark 		crtc  = mdp5_crtc_init(dev, primary[i], cursor[i], i);
44014be3200SRob Clark 		if (IS_ERR(crtc)) {
44114be3200SRob Clark 			ret = PTR_ERR(crtc);
4426a41da17SMamta Shukla 			DRM_DEV_ERROR(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
44314be3200SRob Clark 			goto fail;
44414be3200SRob Clark 		}
445274f1614SDmitry Baryshkov 		priv->num_crtcs++;
44614be3200SRob Clark 	}
44714be3200SRob Clark 
44814be3200SRob Clark 	/*
44914be3200SRob Clark 	 * Now that we know the number of crtcs we've created, set the possible
45014be3200SRob Clark 	 * crtcs for the encoders
45114be3200SRob Clark 	 */
452fa560afaSDmitry Baryshkov 	drm_for_each_encoder(encoder, dev)
45314be3200SRob Clark 		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
45414be3200SRob Clark 
45514be3200SRob Clark 	return 0;
45614be3200SRob Clark 
45714be3200SRob Clark fail:
45814be3200SRob Clark 	return ret;
45914be3200SRob Clark }
46014be3200SRob Clark 
read_mdp_hw_revision(struct mdp5_kms * mdp5_kms,u32 * major,u32 * minor)46114be3200SRob Clark static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,
46214be3200SRob Clark 				 u32 *major, u32 *minor)
46314be3200SRob Clark {
46414be3200SRob Clark 	struct device *dev = &mdp5_kms->pdev->dev;
46514be3200SRob Clark 	u32 version;
46614be3200SRob Clark 
4675d8c0417SDmitry Baryshkov 	pm_runtime_get_sync(dev);
46814be3200SRob Clark 	version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION);
4695d8c0417SDmitry Baryshkov 	pm_runtime_put_sync(dev);
47014be3200SRob Clark 
47114be3200SRob Clark 	*major = FIELD(version, MDP5_HW_VERSION_MAJOR);
47214be3200SRob Clark 	*minor = FIELD(version, MDP5_HW_VERSION_MINOR);
47314be3200SRob Clark 
4746a41da17SMamta Shukla 	DRM_DEV_INFO(dev, "MDP5 version v%d.%d", *major, *minor);
47514be3200SRob Clark }
47614be3200SRob Clark 
get_clk(struct platform_device * pdev,struct clk ** clkp,const char * name,bool mandatory)47714be3200SRob Clark static int get_clk(struct platform_device *pdev, struct clk **clkp,
47814be3200SRob Clark 		const char *name, bool mandatory)
47914be3200SRob Clark {
48014be3200SRob Clark 	struct device *dev = &pdev->dev;
48114be3200SRob Clark 	struct clk *clk = msm_clk_get(pdev, name);
48214be3200SRob Clark 	if (IS_ERR(clk) && mandatory) {
4836a41da17SMamta Shukla 		DRM_DEV_ERROR(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
48414be3200SRob Clark 		return PTR_ERR(clk);
48514be3200SRob Clark 	}
48614be3200SRob Clark 	if (IS_ERR(clk))
48714be3200SRob Clark 		DBG("skipping %s", name);
48814be3200SRob Clark 	else
48914be3200SRob Clark 		*clkp = clk;
49014be3200SRob Clark 
49114be3200SRob Clark 	return 0;
49214be3200SRob Clark }
49314be3200SRob Clark 
4946874f48bSDmitry Baryshkov static int mdp5_init(struct platform_device *pdev, struct drm_device *dev);
4956874f48bSDmitry Baryshkov 
mdp5_kms_init(struct drm_device * dev)4965d44531bSDmitry Baryshkov static int mdp5_kms_init(struct drm_device *dev)
49714be3200SRob Clark {
49814be3200SRob Clark 	struct msm_drm_private *priv = dev->dev_private;
49914be3200SRob Clark 	struct platform_device *pdev;
50014be3200SRob Clark 	struct mdp5_kms *mdp5_kms;
50114be3200SRob Clark 	struct mdp5_cfg *config;
5021f50db2fSDmitry Baryshkov 	struct msm_kms *kms = priv->kms;
50314be3200SRob Clark 	struct msm_gem_address_space *aspace;
5041f50db2fSDmitry Baryshkov 	int i, ret;
50514be3200SRob Clark 
5066874f48bSDmitry Baryshkov 	ret = mdp5_init(to_platform_device(dev->dev), dev);
507c6122688SDmitry Baryshkov 	if (ret)
508c6122688SDmitry Baryshkov 		return ret;
5096874f48bSDmitry Baryshkov 
51014be3200SRob Clark 	mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
5111f50db2fSDmitry Baryshkov 
51214be3200SRob Clark 	pdev = mdp5_kms->pdev;
51314be3200SRob Clark 
514ffe71111SRob Clark 	ret = mdp_kms_init(&mdp5_kms->base, &kms_funcs);
515ffe71111SRob Clark 	if (ret) {
516ffe71111SRob Clark 		DRM_DEV_ERROR(&pdev->dev, "failed to init kms\n");
517ffe71111SRob Clark 		goto fail;
518ffe71111SRob Clark 	}
519ffe71111SRob Clark 
52014be3200SRob Clark 	config = mdp5_cfg_get_config(mdp5_kms->cfg);
52114be3200SRob Clark 
52214be3200SRob Clark 	/* make sure things are off before attaching iommu (bootloader could
52314be3200SRob Clark 	 * have left things on, in which case we'll start getting faults if
52414be3200SRob Clark 	 * we don't disable):
52514be3200SRob Clark 	 */
52614be3200SRob Clark 	pm_runtime_get_sync(&pdev->dev);
52714be3200SRob Clark 	for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
52814be3200SRob Clark 		if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
52914be3200SRob Clark 		    !config->hw->intf.base[i])
53014be3200SRob Clark 			continue;
53114be3200SRob Clark 		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
53214be3200SRob Clark 
53314be3200SRob Clark 		mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
53414be3200SRob Clark 	}
53514be3200SRob Clark 	mdelay(16);
53614be3200SRob Clark 
53740ae54edSDmitry Baryshkov 	aspace = msm_kms_init_aspace(mdp5_kms->dev);
53814be3200SRob Clark 	if (IS_ERR(aspace)) {
53914be3200SRob Clark 		ret = PTR_ERR(aspace);
54014be3200SRob Clark 		goto fail;
54114be3200SRob Clark 	}
54214be3200SRob Clark 
54314be3200SRob Clark 	kms->aspace = aspace;
54414be3200SRob Clark 
54514be3200SRob Clark 	pm_runtime_put_sync(&pdev->dev);
54614be3200SRob Clark 
54714be3200SRob Clark 	ret = modeset_init(mdp5_kms);
54814be3200SRob Clark 	if (ret) {
5496a41da17SMamta Shukla 		DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);
55014be3200SRob Clark 		goto fail;
55114be3200SRob Clark 	}
55214be3200SRob Clark 
55314be3200SRob Clark 	dev->mode_config.min_width = 0;
55414be3200SRob Clark 	dev->mode_config.min_height = 0;
55514be3200SRob Clark 	dev->mode_config.max_width = 0xffff;
55614be3200SRob Clark 	dev->mode_config.max_height = 0xffff;
55714be3200SRob Clark 
5582bab52afSBrian Masney 	dev->max_vblank_count = 0; /* max_vblank_count is set on each CRTC */
55914be3200SRob Clark 	dev->vblank_disable_immediate = true;
56014be3200SRob Clark 
5615d44531bSDmitry Baryshkov 	return 0;
56214be3200SRob Clark fail:
56314be3200SRob Clark 	if (kms)
56414be3200SRob Clark 		mdp5_kms_destroy(kms);
5655d44531bSDmitry Baryshkov 
5665d44531bSDmitry Baryshkov 	return ret;
56714be3200SRob Clark }
56814be3200SRob Clark 
mdp5_destroy(struct mdp5_kms * mdp5_kms)569c6122688SDmitry Baryshkov static void mdp5_destroy(struct mdp5_kms *mdp5_kms)
57014be3200SRob Clark {
57114be3200SRob Clark 	if (mdp5_kms->rpm_enabled)
572c6122688SDmitry Baryshkov 		pm_runtime_disable(&mdp5_kms->pdev->dev);
57314be3200SRob Clark 
5748d58ef34SArchit Taneja 	drm_atomic_private_obj_fini(&mdp5_kms->glob_state);
57514be3200SRob Clark }
57614be3200SRob Clark 
construct_pipes(struct mdp5_kms * mdp5_kms,int cnt,const enum mdp5_pipe * pipes,const uint32_t * offsets,uint32_t caps)57714be3200SRob Clark static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt,
57814be3200SRob Clark 		const enum mdp5_pipe *pipes, const uint32_t *offsets,
57914be3200SRob Clark 		uint32_t caps)
58014be3200SRob Clark {
58114be3200SRob Clark 	struct drm_device *dev = mdp5_kms->dev;
58214be3200SRob Clark 	int i, ret;
58314be3200SRob Clark 
58414be3200SRob Clark 	for (i = 0; i < cnt; i++) {
58514be3200SRob Clark 		struct mdp5_hw_pipe *hwpipe;
58614be3200SRob Clark 
587323e9a18SDmitry Baryshkov 		hwpipe = mdp5_pipe_init(dev, pipes[i], offsets[i], caps);
58814be3200SRob Clark 		if (IS_ERR(hwpipe)) {
58914be3200SRob Clark 			ret = PTR_ERR(hwpipe);
5906a41da17SMamta Shukla 			DRM_DEV_ERROR(dev->dev, "failed to construct pipe for %s (%d)\n",
59114be3200SRob Clark 					pipe2name(pipes[i]), ret);
59214be3200SRob Clark 			return ret;
59314be3200SRob Clark 		}
59414be3200SRob Clark 		hwpipe->idx = mdp5_kms->num_hwpipes;
59514be3200SRob Clark 		mdp5_kms->hwpipes[mdp5_kms->num_hwpipes++] = hwpipe;
59614be3200SRob Clark 	}
59714be3200SRob Clark 
59814be3200SRob Clark 	return 0;
59914be3200SRob Clark }
60014be3200SRob Clark 
hwpipe_init(struct mdp5_kms * mdp5_kms)60114be3200SRob Clark static int hwpipe_init(struct mdp5_kms *mdp5_kms)
60214be3200SRob Clark {
60314be3200SRob Clark 	static const enum mdp5_pipe rgb_planes[] = {
60414be3200SRob Clark 			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
60514be3200SRob Clark 	};
60614be3200SRob Clark 	static const enum mdp5_pipe vig_planes[] = {
60714be3200SRob Clark 			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
60814be3200SRob Clark 	};
60914be3200SRob Clark 	static const enum mdp5_pipe dma_planes[] = {
61014be3200SRob Clark 			SSPP_DMA0, SSPP_DMA1,
61114be3200SRob Clark 	};
61214be3200SRob Clark 	static const enum mdp5_pipe cursor_planes[] = {
61314be3200SRob Clark 			SSPP_CURSOR0, SSPP_CURSOR1,
61414be3200SRob Clark 	};
61514be3200SRob Clark 	const struct mdp5_cfg_hw *hw_cfg;
61614be3200SRob Clark 	int ret;
61714be3200SRob Clark 
61814be3200SRob Clark 	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
61914be3200SRob Clark 
62014be3200SRob Clark 	/* Construct RGB pipes: */
62114be3200SRob Clark 	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_rgb.count, rgb_planes,
62214be3200SRob Clark 			hw_cfg->pipe_rgb.base, hw_cfg->pipe_rgb.caps);
62314be3200SRob Clark 	if (ret)
62414be3200SRob Clark 		return ret;
62514be3200SRob Clark 
62614be3200SRob Clark 	/* Construct video (VIG) pipes: */
62714be3200SRob Clark 	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_vig.count, vig_planes,
62814be3200SRob Clark 			hw_cfg->pipe_vig.base, hw_cfg->pipe_vig.caps);
62914be3200SRob Clark 	if (ret)
63014be3200SRob Clark 		return ret;
63114be3200SRob Clark 
63214be3200SRob Clark 	/* Construct DMA pipes: */
63314be3200SRob Clark 	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_dma.count, dma_planes,
63414be3200SRob Clark 			hw_cfg->pipe_dma.base, hw_cfg->pipe_dma.caps);
63514be3200SRob Clark 	if (ret)
63614be3200SRob Clark 		return ret;
63714be3200SRob Clark 
63814be3200SRob Clark 	/* Construct cursor pipes: */
63914be3200SRob Clark 	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_cursor.count,
64014be3200SRob Clark 			cursor_planes, hw_cfg->pipe_cursor.base,
64114be3200SRob Clark 			hw_cfg->pipe_cursor.caps);
64214be3200SRob Clark 	if (ret)
64314be3200SRob Clark 		return ret;
64414be3200SRob Clark 
64514be3200SRob Clark 	return 0;
64614be3200SRob Clark }
64714be3200SRob Clark 
hwmixer_init(struct mdp5_kms * mdp5_kms)64814be3200SRob Clark static int hwmixer_init(struct mdp5_kms *mdp5_kms)
64914be3200SRob Clark {
65014be3200SRob Clark 	struct drm_device *dev = mdp5_kms->dev;
65114be3200SRob Clark 	const struct mdp5_cfg_hw *hw_cfg;
65214be3200SRob Clark 	int i, ret;
65314be3200SRob Clark 
65414be3200SRob Clark 	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
65514be3200SRob Clark 
65614be3200SRob Clark 	for (i = 0; i < hw_cfg->lm.count; i++) {
65714be3200SRob Clark 		struct mdp5_hw_mixer *mixer;
65814be3200SRob Clark 
6591ad175c2SDmitry Baryshkov 		mixer = mdp5_mixer_init(dev, &hw_cfg->lm.instances[i]);
66014be3200SRob Clark 		if (IS_ERR(mixer)) {
66114be3200SRob Clark 			ret = PTR_ERR(mixer);
6626a41da17SMamta Shukla 			DRM_DEV_ERROR(dev->dev, "failed to construct LM%d (%d)\n",
66314be3200SRob Clark 				i, ret);
66414be3200SRob Clark 			return ret;
66514be3200SRob Clark 		}
66614be3200SRob Clark 
66714be3200SRob Clark 		mixer->idx = mdp5_kms->num_hwmixers;
66814be3200SRob Clark 		mdp5_kms->hwmixers[mdp5_kms->num_hwmixers++] = mixer;
66914be3200SRob Clark 	}
67014be3200SRob Clark 
67114be3200SRob Clark 	return 0;
67214be3200SRob Clark }
67314be3200SRob Clark 
interface_init(struct mdp5_kms * mdp5_kms)67414be3200SRob Clark static int interface_init(struct mdp5_kms *mdp5_kms)
67514be3200SRob Clark {
67614be3200SRob Clark 	struct drm_device *dev = mdp5_kms->dev;
67714be3200SRob Clark 	const struct mdp5_cfg_hw *hw_cfg;
67814be3200SRob Clark 	const enum mdp5_intf_type *intf_types;
67914be3200SRob Clark 	int i;
68014be3200SRob Clark 
68114be3200SRob Clark 	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
68214be3200SRob Clark 	intf_types = hw_cfg->intf.connect;
68314be3200SRob Clark 
68414be3200SRob Clark 	for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
68514be3200SRob Clark 		struct mdp5_interface *intf;
68614be3200SRob Clark 
68714be3200SRob Clark 		if (intf_types[i] == INTF_DISABLED)
68814be3200SRob Clark 			continue;
68914be3200SRob Clark 
6906de8288bSDmitry Baryshkov 		intf = devm_kzalloc(dev->dev, sizeof(*intf), GFP_KERNEL);
69114be3200SRob Clark 		if (!intf) {
6926a41da17SMamta Shukla 			DRM_DEV_ERROR(dev->dev, "failed to construct INTF%d\n", i);
69314be3200SRob Clark 			return -ENOMEM;
69414be3200SRob Clark 		}
69514be3200SRob Clark 
69614be3200SRob Clark 		intf->num = i;
69714be3200SRob Clark 		intf->type = intf_types[i];
69814be3200SRob Clark 		intf->mode = MDP5_INTF_MODE_NONE;
69914be3200SRob Clark 		intf->idx = mdp5_kms->num_intfs;
70014be3200SRob Clark 		mdp5_kms->intfs[mdp5_kms->num_intfs++] = intf;
70114be3200SRob Clark 	}
70214be3200SRob Clark 
70314be3200SRob Clark 	return 0;
70414be3200SRob Clark }
70514be3200SRob Clark 
mdp5_init(struct platform_device * pdev,struct drm_device * dev)70614be3200SRob Clark static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
70714be3200SRob Clark {
70814be3200SRob Clark 	struct msm_drm_private *priv = dev->dev_private;
7091f50db2fSDmitry Baryshkov 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
71014be3200SRob Clark 	struct mdp5_cfg *config;
71114be3200SRob Clark 	u32 major, minor;
71214be3200SRob Clark 	int ret;
71314be3200SRob Clark 
71414be3200SRob Clark 	mdp5_kms->dev = dev;
71514be3200SRob Clark 
7168d58ef34SArchit Taneja 	ret = mdp5_global_obj_init(mdp5_kms);
7178d58ef34SArchit Taneja 	if (ret)
7188d58ef34SArchit Taneja 		goto fail;
7198d58ef34SArchit Taneja 
72014be3200SRob Clark 	/* we need to set a default rate before enabling.  Set a safe
72114be3200SRob Clark 	 * rate first, then figure out hw revision, and then set a
72214be3200SRob Clark 	 * more optimal rate:
72314be3200SRob Clark 	 */
72414be3200SRob Clark 	clk_set_rate(mdp5_kms->core_clk, 200000000);
72514be3200SRob Clark 
7265d8c0417SDmitry Baryshkov 	pm_runtime_enable(&pdev->dev);
7275d8c0417SDmitry Baryshkov 	mdp5_kms->rpm_enabled = true;
7285d8c0417SDmitry Baryshkov 
72914be3200SRob Clark 	read_mdp_hw_revision(mdp5_kms, &major, &minor);
73014be3200SRob Clark 
73114be3200SRob Clark 	mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor);
73214be3200SRob Clark 	if (IS_ERR(mdp5_kms->cfg)) {
73314be3200SRob Clark 		ret = PTR_ERR(mdp5_kms->cfg);
73414be3200SRob Clark 		mdp5_kms->cfg = NULL;
73514be3200SRob Clark 		goto fail;
73614be3200SRob Clark 	}
73714be3200SRob Clark 
73814be3200SRob Clark 	config = mdp5_cfg_get_config(mdp5_kms->cfg);
73914be3200SRob Clark 	mdp5_kms->caps = config->hw->mdp.caps;
74014be3200SRob Clark 
74114be3200SRob Clark 	/* TODO: compute core clock rate at runtime */
74214be3200SRob Clark 	clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk);
74314be3200SRob Clark 
74414be3200SRob Clark 	/*
74514be3200SRob Clark 	 * Some chipsets have a Shared Memory Pool (SMP), while others
74614be3200SRob Clark 	 * have dedicated latency buffering per source pipe instead;
74714be3200SRob Clark 	 * this section initializes the SMP:
74814be3200SRob Clark 	 */
74914be3200SRob Clark 	if (mdp5_kms->caps & MDP_CAP_SMP) {
75014be3200SRob Clark 		mdp5_kms->smp = mdp5_smp_init(mdp5_kms, &config->hw->smp);
75114be3200SRob Clark 		if (IS_ERR(mdp5_kms->smp)) {
75214be3200SRob Clark 			ret = PTR_ERR(mdp5_kms->smp);
75314be3200SRob Clark 			mdp5_kms->smp = NULL;
75414be3200SRob Clark 			goto fail;
75514be3200SRob Clark 		}
75614be3200SRob Clark 	}
75714be3200SRob Clark 
75814be3200SRob Clark 	mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg);
75914be3200SRob Clark 	if (IS_ERR(mdp5_kms->ctlm)) {
76014be3200SRob Clark 		ret = PTR_ERR(mdp5_kms->ctlm);
76114be3200SRob Clark 		mdp5_kms->ctlm = NULL;
76214be3200SRob Clark 		goto fail;
76314be3200SRob Clark 	}
76414be3200SRob Clark 
76514be3200SRob Clark 	ret = hwpipe_init(mdp5_kms);
76614be3200SRob Clark 	if (ret)
76714be3200SRob Clark 		goto fail;
76814be3200SRob Clark 
76914be3200SRob Clark 	ret = hwmixer_init(mdp5_kms);
77014be3200SRob Clark 	if (ret)
77114be3200SRob Clark 		goto fail;
77214be3200SRob Clark 
77314be3200SRob Clark 	ret = interface_init(mdp5_kms);
77414be3200SRob Clark 	if (ret)
77514be3200SRob Clark 		goto fail;
77614be3200SRob Clark 
77714be3200SRob Clark 	return 0;
77814be3200SRob Clark fail:
779c6122688SDmitry Baryshkov 	mdp5_destroy(mdp5_kms);
78014be3200SRob Clark 	return ret;
78114be3200SRob Clark }
78214be3200SRob Clark 
mdp5_setup_interconnect(struct platform_device * pdev)78397f90e1bSGeorgi Djakov static int mdp5_setup_interconnect(struct platform_device *pdev)
78497f90e1bSGeorgi Djakov {
7855ccdcecaSDmitry Baryshkov 	struct icc_path *path0 = msm_icc_get(&pdev->dev, "mdp0-mem");
7865ccdcecaSDmitry Baryshkov 	struct icc_path *path1 = msm_icc_get(&pdev->dev, "mdp1-mem");
7875ccdcecaSDmitry Baryshkov 	struct icc_path *path_rot = msm_icc_get(&pdev->dev, "rotator-mem");
78897f90e1bSGeorgi Djakov 
78997f90e1bSGeorgi Djakov 	if (IS_ERR(path0))
79097f90e1bSGeorgi Djakov 		return PTR_ERR(path0);
79197f90e1bSGeorgi Djakov 
79297f90e1bSGeorgi Djakov 	if (!path0) {
79397f90e1bSGeorgi Djakov 		/* no interconnect support is not necessarily a fatal
79497f90e1bSGeorgi Djakov 		 * condition, the platform may simply not have an
79597f90e1bSGeorgi Djakov 		 * interconnect driver yet.  But warn about it in case
79697f90e1bSGeorgi Djakov 		 * bootloader didn't setup bus clocks high enough for
79797f90e1bSGeorgi Djakov 		 * scanout.
79897f90e1bSGeorgi Djakov 		 */
79997f90e1bSGeorgi Djakov 		dev_warn(&pdev->dev, "No interconnect support may cause display underflows!\n");
80097f90e1bSGeorgi Djakov 		return 0;
80197f90e1bSGeorgi Djakov 	}
80297f90e1bSGeorgi Djakov 
80397f90e1bSGeorgi Djakov 	icc_set_bw(path0, 0, MBps_to_icc(6400));
80497f90e1bSGeorgi Djakov 
80597f90e1bSGeorgi Djakov 	if (!IS_ERR_OR_NULL(path1))
80697f90e1bSGeorgi Djakov 		icc_set_bw(path1, 0, MBps_to_icc(6400));
80797f90e1bSGeorgi Djakov 	if (!IS_ERR_OR_NULL(path_rot))
80897f90e1bSGeorgi Djakov 		icc_set_bw(path_rot, 0, MBps_to_icc(6400));
80997f90e1bSGeorgi Djakov 
81097f90e1bSGeorgi Djakov 	return 0;
81197f90e1bSGeorgi Djakov }
81297f90e1bSGeorgi Djakov 
mdp5_dev_probe(struct platform_device * pdev)81314be3200SRob Clark static int mdp5_dev_probe(struct platform_device *pdev)
81414be3200SRob Clark {
8151f50db2fSDmitry Baryshkov 	struct mdp5_kms *mdp5_kms;
8161f50db2fSDmitry Baryshkov 	int ret, irq;
81797f90e1bSGeorgi Djakov 
81814be3200SRob Clark 	DBG("");
81997f90e1bSGeorgi Djakov 
820b8b12318SDmitry Baryshkov 	if (!msm_disp_drv_should_bind(&pdev->dev, false))
821b8b12318SDmitry Baryshkov 		return -ENODEV;
822b8b12318SDmitry Baryshkov 
8231f50db2fSDmitry Baryshkov 	mdp5_kms = devm_kzalloc(&pdev->dev, sizeof(*mdp5_kms), GFP_KERNEL);
8241f50db2fSDmitry Baryshkov 	if (!mdp5_kms)
8251f50db2fSDmitry Baryshkov 		return -ENOMEM;
8261f50db2fSDmitry Baryshkov 
82797f90e1bSGeorgi Djakov 	ret = mdp5_setup_interconnect(pdev);
82897f90e1bSGeorgi Djakov 	if (ret)
82997f90e1bSGeorgi Djakov 		return ret;
83097f90e1bSGeorgi Djakov 
8311f50db2fSDmitry Baryshkov 	mdp5_kms->pdev = pdev;
8321f50db2fSDmitry Baryshkov 
8331f50db2fSDmitry Baryshkov 	spin_lock_init(&mdp5_kms->resource_lock);
8341f50db2fSDmitry Baryshkov 
8351f50db2fSDmitry Baryshkov 	mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys");
8361f50db2fSDmitry Baryshkov 	if (IS_ERR(mdp5_kms->mmio))
8371f50db2fSDmitry Baryshkov 		return PTR_ERR(mdp5_kms->mmio);
8381f50db2fSDmitry Baryshkov 
8391f50db2fSDmitry Baryshkov 	/* mandatory clocks: */
8401f50db2fSDmitry Baryshkov 	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus", true);
8411f50db2fSDmitry Baryshkov 	if (ret)
8421f50db2fSDmitry Baryshkov 		return ret;
8431f50db2fSDmitry Baryshkov 	ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface", true);
8441f50db2fSDmitry Baryshkov 	if (ret)
8451f50db2fSDmitry Baryshkov 		return ret;
8461f50db2fSDmitry Baryshkov 	ret = get_clk(pdev, &mdp5_kms->core_clk, "core", true);
8471f50db2fSDmitry Baryshkov 	if (ret)
8481f50db2fSDmitry Baryshkov 		return ret;
8491f50db2fSDmitry Baryshkov 	ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync", true);
8501f50db2fSDmitry Baryshkov 	if (ret)
8511f50db2fSDmitry Baryshkov 		return ret;
8521f50db2fSDmitry Baryshkov 
8531f50db2fSDmitry Baryshkov 	/* optional clocks: */
8541f50db2fSDmitry Baryshkov 	get_clk(pdev, &mdp5_kms->lut_clk, "lut", false);
8551f50db2fSDmitry Baryshkov 	get_clk(pdev, &mdp5_kms->tbu_clk, "tbu", false);
8561f50db2fSDmitry Baryshkov 	get_clk(pdev, &mdp5_kms->tbu_rt_clk, "tbu_rt", false);
8571f50db2fSDmitry Baryshkov 
8581f50db2fSDmitry Baryshkov 	irq = platform_get_irq(pdev, 0);
8591f50db2fSDmitry Baryshkov 	if (irq < 0)
8601f50db2fSDmitry Baryshkov 		return dev_err_probe(&pdev->dev, irq, "failed to get irq\n");
8611f50db2fSDmitry Baryshkov 
8621f50db2fSDmitry Baryshkov 	mdp5_kms->base.base.irq = irq;
8631f50db2fSDmitry Baryshkov 
8641f50db2fSDmitry Baryshkov 	return msm_drv_probe(&pdev->dev, mdp5_kms_init, &mdp5_kms->base.base);
86514be3200SRob Clark }
86614be3200SRob Clark 
mdp5_dev_remove(struct platform_device * pdev)86701790d5eSUwe Kleine-König static void mdp5_dev_remove(struct platform_device *pdev)
86814be3200SRob Clark {
86914be3200SRob Clark 	DBG("");
8706874f48bSDmitry Baryshkov 	component_master_del(&pdev->dev, &msm_drm_ops);
87114be3200SRob Clark }
87214be3200SRob Clark 
mdp5_runtime_suspend(struct device * dev)87314be3200SRob Clark static __maybe_unused int mdp5_runtime_suspend(struct device *dev)
87414be3200SRob Clark {
87514be3200SRob Clark 	struct platform_device *pdev = to_platform_device(dev);
876c6122688SDmitry Baryshkov 	struct msm_drm_private *priv = platform_get_drvdata(pdev);
877c6122688SDmitry Baryshkov 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
87814be3200SRob Clark 
87914be3200SRob Clark 	DBG("");
88014be3200SRob Clark 
88114be3200SRob Clark 	return mdp5_disable(mdp5_kms);
88214be3200SRob Clark }
88314be3200SRob Clark 
mdp5_runtime_resume(struct device * dev)88414be3200SRob Clark static __maybe_unused int mdp5_runtime_resume(struct device *dev)
88514be3200SRob Clark {
88614be3200SRob Clark 	struct platform_device *pdev = to_platform_device(dev);
887c6122688SDmitry Baryshkov 	struct msm_drm_private *priv = platform_get_drvdata(pdev);
888c6122688SDmitry Baryshkov 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
88914be3200SRob Clark 
89014be3200SRob Clark 	DBG("");
89114be3200SRob Clark 
89214be3200SRob Clark 	return mdp5_enable(mdp5_kms);
89314be3200SRob Clark }
89414be3200SRob Clark 
89514be3200SRob Clark static const struct dev_pm_ops mdp5_pm_ops = {
89614be3200SRob Clark 	SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL)
897d069ef29SDmitry Baryshkov 	.prepare = msm_kms_pm_prepare,
898d069ef29SDmitry Baryshkov 	.complete = msm_kms_pm_complete,
89914be3200SRob Clark };
90014be3200SRob Clark 
9016874f48bSDmitry Baryshkov static const struct of_device_id mdp5_dt_match[] = {
90214be3200SRob Clark 	{ .compatible = "qcom,mdp5", },
90314be3200SRob Clark 	/* to support downstream DT files */
90414be3200SRob Clark 	{ .compatible = "qcom,mdss_mdp", },
90514be3200SRob Clark 	{}
90614be3200SRob Clark };
90714be3200SRob Clark MODULE_DEVICE_TABLE(of, mdp5_dt_match);
90814be3200SRob Clark 
90914be3200SRob Clark static struct platform_driver mdp5_driver = {
91014be3200SRob Clark 	.probe = mdp5_dev_probe,
91101790d5eSUwe Kleine-König 	.remove_new = mdp5_dev_remove,
912937154e4SDmitry Baryshkov 	.shutdown = msm_kms_shutdown,
91314be3200SRob Clark 	.driver = {
91414be3200SRob Clark 		.name = "msm_mdp",
91514be3200SRob Clark 		.of_match_table = mdp5_dt_match,
91614be3200SRob Clark 		.pm = &mdp5_pm_ops,
91714be3200SRob Clark 	},
91814be3200SRob Clark };
91914be3200SRob Clark 
msm_mdp_register(void)92014be3200SRob Clark void __init msm_mdp_register(void)
92114be3200SRob Clark {
92214be3200SRob Clark 	DBG("");
92314be3200SRob Clark 	platform_driver_register(&mdp5_driver);
92414be3200SRob Clark }
92514be3200SRob Clark 
msm_mdp_unregister(void)92614be3200SRob Clark void __exit msm_mdp_unregister(void)
92714be3200SRob Clark {
92814be3200SRob Clark 	DBG("");
92914be3200SRob Clark 	platform_driver_unregister(&mdp5_driver);
93014be3200SRob Clark }
931