mdp5_kms.c 14.0 KB
Newer Older
R
Rob Clark 已提交
1
/*
2
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
R
Rob Clark 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "msm_drv.h"
#include "msm_mmu.h"
#include "mdp5_kms.h"

24 25 26 27
static const char *iommu_ports[] = {
		"mdp_0",
};

28 29 30 31
static int mdp5_hw_init(struct msm_kms *kms)
{
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
	struct drm_device *dev = mdp5_kms->dev;
32
	unsigned long flags;
33 34 35

	pm_runtime_get_sync(dev->dev);

R
Rob Clark 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	/* Magic unknown register writes:
	 *
	 *    W VBIF:0x004 00000001      (mdss_mdp.c:839)
	 *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839)
	 *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839)
	 *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839)
	 *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839)
	 *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839)
	 *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839)
	 *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839)
	 *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839)
	 *
	 * Downstream fbdev driver gets these register offsets/values
	 * from DT.. not really sure what these registers are or if
	 * different values for different boards/SoC's, etc.  I guess
	 * they are the golden registers.
	 *
	 * Not setting these does not seem to cause any problem.  But
	 * we may be getting lucky with the bootloader initializing
	 * them for us.  OTOH, if we can always count on the bootloader
	 * setting the golden registers, then perhaps we don't need to
	 * care.
	 */

60
	spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
61
	mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), 0);
62
	spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
R
Rob Clark 已提交
63

64
	mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
65

R
Rob Clark 已提交
66 67
	pm_runtime_put_sync(dev->dev);

68
	return 0;
R
Rob Clark 已提交
69 70
}

71 72 73 74 75 76 77 78 79 80 81 82
static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
	mdp5_enable(mdp5_kms);
}

static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
	mdp5_disable(mdp5_kms);
}

R
Rob Clark 已提交
83 84 85 86 87 88
static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
		struct drm_encoder *encoder)
{
	return rate;
}

89 90 91 92 93 94 95 96 97 98 99 100
static int mdp5_set_split_display(struct msm_kms *kms,
		struct drm_encoder *encoder,
		struct drm_encoder *slave_encoder,
		bool is_cmd_mode)
{
	if (is_cmd_mode)
		return mdp5_cmd_encoder_set_split_display(encoder,
							slave_encoder);
	else
		return mdp5_encoder_set_split_display(encoder, slave_encoder);
}

R
Rob Clark 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113
static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
{
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
	struct msm_drm_private *priv = mdp5_kms->dev->dev_private;
	unsigned i;

	for (i = 0; i < priv->num_crtcs; i++)
		mdp5_crtc_cancel_pending_flip(priv->crtcs[i], file);
}

static void mdp5_destroy(struct msm_kms *kms)
{
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
114 115
	struct msm_mmu *mmu = mdp5_kms->mmu;

R
Rob Clark 已提交
116 117
	mdp5_irq_domain_fini(mdp5_kms);

118 119 120 121
	if (mmu) {
		mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
		mmu->funcs->destroy(mmu);
	}
122 123 124 125 126 127 128

	if (mdp5_kms->ctlm)
		mdp5_ctlm_destroy(mdp5_kms->ctlm);
	if (mdp5_kms->smp)
		mdp5_smp_destroy(mdp5_kms->smp);
	if (mdp5_kms->cfg)
		mdp5_cfg_destroy(mdp5_kms->cfg);
129

R
Rob Clark 已提交
130 131 132 133 134 135 136 137 138 139 140 141
	kfree(mdp5_kms);
}

static const struct mdp_kms_funcs kms_funcs = {
	.base = {
		.hw_init         = mdp5_hw_init,
		.irq_preinstall  = mdp5_irq_preinstall,
		.irq_postinstall = mdp5_irq_postinstall,
		.irq_uninstall   = mdp5_irq_uninstall,
		.irq             = mdp5_irq,
		.enable_vblank   = mdp5_enable_vblank,
		.disable_vblank  = mdp5_disable_vblank,
142 143
		.prepare_commit  = mdp5_prepare_commit,
		.complete_commit = mdp5_complete_commit,
R
Rob Clark 已提交
144 145
		.get_format      = mdp_get_format,
		.round_pixclk    = mdp5_round_pixclk,
146
		.set_split_display = mdp5_set_split_display,
R
Rob Clark 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
		.preclose        = mdp5_preclose,
		.destroy         = mdp5_destroy,
	},
	.set_irqmask         = mdp5_set_irqmask,
};

int mdp5_disable(struct mdp5_kms *mdp5_kms)
{
	DBG("");

	clk_disable_unprepare(mdp5_kms->ahb_clk);
	clk_disable_unprepare(mdp5_kms->axi_clk);
	clk_disable_unprepare(mdp5_kms->core_clk);
	clk_disable_unprepare(mdp5_kms->lut_clk);

	return 0;
}

int mdp5_enable(struct mdp5_kms *mdp5_kms)
{
	DBG("");

	clk_prepare_enable(mdp5_kms->ahb_clk);
	clk_prepare_enable(mdp5_kms->axi_clk);
	clk_prepare_enable(mdp5_kms->core_clk);
	clk_prepare_enable(mdp5_kms->lut_clk);

	return 0;
}

177 178 179
static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
		enum mdp5_intf_type intf_type, int intf_num,
		enum mdp5_intf_mode intf_mode)
180 181 182 183 184 185 186
{
	struct drm_device *dev = mdp5_kms->dev;
	struct msm_drm_private *priv = dev->dev_private;
	struct drm_encoder *encoder;
	struct mdp5_interface intf = {
			.num	= intf_num,
			.type	= intf_type,
187
			.mode	= intf_mode,
188 189
	};

190 191 192 193 194 195
	if ((intf_type == INTF_DSI) &&
		(intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
		encoder = mdp5_cmd_encoder_init(dev, &intf);
	else
		encoder = mdp5_encoder_init(dev, &intf);

196
	if (IS_ERR(encoder)) {
197 198
		dev_err(dev->dev, "failed to construct encoder\n");
		return encoder;
199 200 201 202 203
	}

	encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
	priv->encoders[priv->num_encoders++] = encoder;

204 205 206
	return encoder;
}

207 208
static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
{
209 210
	const enum mdp5_intf_type *intfs = hw_cfg->intf.connect;
	const int intf_cnt = ARRAY_SIZE(hw_cfg->intf.connect);
211 212 213 214 215 216 217 218 219 220 221 222 223 224
	int id = 0, i;

	for (i = 0; i < intf_cnt; i++) {
		if (intfs[i] == INTF_DSI) {
			if (intf_num == i)
				return id;

			id++;
		}
	}

	return -EINVAL;
}

225 226 227 228 229 230
static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
{
	struct drm_device *dev = mdp5_kms->dev;
	struct msm_drm_private *priv = dev->dev_private;
	const struct mdp5_cfg_hw *hw_cfg =
					mdp5_cfg_get_hw_config(mdp5_kms->cfg);
231
	enum mdp5_intf_type intf_type = hw_cfg->intf.connect[intf_num];
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
	struct drm_encoder *encoder;
	int ret = 0;

	switch (intf_type) {
	case INTF_DISABLED:
		break;
	case INTF_eDP:
		if (!priv->edp)
			break;

		encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
					MDP5_INTF_MODE_NONE);
		if (IS_ERR(encoder)) {
			ret = PTR_ERR(encoder);
			break;
		}
248 249

		ret = msm_edp_modeset_init(priv->edp, dev, encoder);
250 251 252 253 254 255 256 257 258 259 260 261 262 263
		break;
	case INTF_HDMI:
		if (!priv->hdmi)
			break;

		encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
					MDP5_INTF_MODE_NONE);
		if (IS_ERR(encoder)) {
			ret = PTR_ERR(encoder);
			break;
		}

		ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
		break;
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
	case INTF_DSI:
	{
		int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num);
		struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
		enum mdp5_intf_mode mode;
		int i;

		if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
			dev_err(dev->dev, "failed to find dsi from intf %d\n",
				intf_num);
			ret = -EINVAL;
			break;
		}

		if (!priv->dsi[dsi_id])
			break;

		for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
			mode = (i == MSM_DSI_CMD_ENCODER_ID) ?
				MDP5_INTF_DSI_MODE_COMMAND :
				MDP5_INTF_DSI_MODE_VIDEO;
			dsi_encs[i] = construct_encoder(mdp5_kms, INTF_DSI,
							intf_num, mode);
			if (IS_ERR(dsi_encs)) {
				ret = PTR_ERR(dsi_encs);
				break;
			}
		}

		ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
		break;
	}
296 297 298 299
	default:
		dev_err(dev->dev, "unknown intf: %d\n", intf_type);
		ret = -EINVAL;
		break;
300 301 302 303 304
	}

	return ret;
}

R
Rob Clark 已提交
305 306 307
static int modeset_init(struct mdp5_kms *mdp5_kms)
{
	static const enum mdp5_pipe crtcs[] = {
308
			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
R
Rob Clark 已提交
309
	};
310 311 312
	static const enum mdp5_pipe pub_planes[] = {
			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
	};
R
Rob Clark 已提交
313 314
	struct drm_device *dev = mdp5_kms->dev;
	struct msm_drm_private *priv = dev->dev_private;
315
	const struct mdp5_cfg_hw *hw_cfg;
R
Rob Clark 已提交
316 317
	int i, ret;

318
	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
319

R
Rob Clark 已提交
320 321 322 323 324 325 326
	/* register our interrupt-controller for hdmi/eDP/dsi/etc
	 * to use for irqs routed through mdp:
	 */
	ret = mdp5_irq_domain_init(mdp5_kms);
	if (ret)
		goto fail;

327
	/* construct CRTCs and their private planes: */
328
	for (i = 0; i < hw_cfg->pipe_rgb.count; i++) {
R
Rob Clark 已提交
329 330 331
		struct drm_plane *plane;
		struct drm_crtc *crtc;

332 333
		plane = mdp5_plane_init(dev, crtcs[i], true,
				hw_cfg->pipe_rgb.base[i]);
R
Rob Clark 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
		if (IS_ERR(plane)) {
			ret = PTR_ERR(plane);
			dev_err(dev->dev, "failed to construct plane for %s (%d)\n",
					pipe2name(crtcs[i]), ret);
			goto fail;
		}

		crtc  = mdp5_crtc_init(dev, plane, i);
		if (IS_ERR(crtc)) {
			ret = PTR_ERR(crtc);
			dev_err(dev->dev, "failed to construct crtc for %s (%d)\n",
					pipe2name(crtcs[i]), ret);
			goto fail;
		}
		priv->crtcs[priv->num_crtcs++] = crtc;
	}

351 352 353 354 355 356 357 358 359 360 361 362 363 364
	/* Construct public planes: */
	for (i = 0; i < hw_cfg->pipe_vig.count; i++) {
		struct drm_plane *plane;

		plane = mdp5_plane_init(dev, pub_planes[i], false,
				hw_cfg->pipe_vig.base[i]);
		if (IS_ERR(plane)) {
			ret = PTR_ERR(plane);
			dev_err(dev->dev, "failed to construct %s plane: %d\n",
					pipe2name(pub_planes[i]), ret);
			goto fail;
		}
	}

365 366 367
	/* Construct encoders and modeset initialize connector devices
	 * for each external display interface.
	 */
368
	for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
369
		ret = modeset_init_intf(mdp5_kms, i);
370
		if (ret)
371 372 373
			goto fail;
	}

R
Rob Clark 已提交
374 375 376 377 378 379
	return 0;

fail:
	return ret;
}

380 381 382 383 384 385
static void read_hw_revision(struct mdp5_kms *mdp5_kms,
		uint32_t *major, uint32_t *minor)
{
	uint32_t version;

	mdp5_enable(mdp5_kms);
386
	version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION);
387 388
	mdp5_disable(mdp5_kms);

389 390
	*major = FIELD(version, MDSS_HW_VERSION_MAJOR);
	*minor = FIELD(version, MDSS_HW_VERSION_MINOR);
391 392 393 394

	DBG("MDP5 version v%d.%d", *major, *minor);
}

R
Rob Clark 已提交
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
static int get_clk(struct platform_device *pdev, struct clk **clkp,
		const char *name)
{
	struct device *dev = &pdev->dev;
	struct clk *clk = devm_clk_get(dev, name);
	if (IS_ERR(clk)) {
		dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
		return PTR_ERR(clk);
	}
	*clkp = clk;
	return 0;
}

struct msm_kms *mdp5_kms_init(struct drm_device *dev)
{
	struct platform_device *pdev = dev->platformdev;
411
	struct mdp5_cfg *config;
R
Rob Clark 已提交
412 413 414
	struct mdp5_kms *mdp5_kms;
	struct msm_kms *kms = NULL;
	struct msm_mmu *mmu;
415
	uint32_t major, minor;
416
	int i, ret;
R
Rob Clark 已提交
417 418 419 420 421 422 423 424

	mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL);
	if (!mdp5_kms) {
		dev_err(dev->dev, "failed to allocate kms\n");
		ret = -ENOMEM;
		goto fail;
	}

425 426
	spin_lock_init(&mdp5_kms->resource_lock);

R
Rob Clark 已提交
427 428 429 430 431 432
	mdp_kms_init(&mdp5_kms->base, &kms_funcs);

	kms = &mdp5_kms->base.base;

	mdp5_kms->dev = dev;

433
	/* mdp5_kms->mmio actually represents the MDSS base address */
R
Rob Clark 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
	mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
	if (IS_ERR(mdp5_kms->mmio)) {
		ret = PTR_ERR(mdp5_kms->mmio);
		goto fail;
	}

	mdp5_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF");
	if (IS_ERR(mdp5_kms->vbif)) {
		ret = PTR_ERR(mdp5_kms->vbif);
		goto fail;
	}

	mdp5_kms->vdd = devm_regulator_get(&pdev->dev, "vdd");
	if (IS_ERR(mdp5_kms->vdd)) {
		ret = PTR_ERR(mdp5_kms->vdd);
		goto fail;
	}

	ret = regulator_enable(mdp5_kms->vdd);
	if (ret) {
		dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret);
		goto fail;
	}

R
Rob Clark 已提交
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
	ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk");
	if (ret)
		goto fail;
	ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk");
	if (ret)
		goto fail;
	ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src");
	if (ret)
		goto fail;
	ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk");
	if (ret)
		goto fail;
	ret = get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk");
	if (ret)
		goto fail;
	ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk");
R
Rob Clark 已提交
474 475 476
	if (ret)
		goto fail;

477 478 479 480 481 482
	/* we need to set a default rate before enabling.  Set a safe
	 * rate first, then figure out hw revision, and then set a
	 * more optimal rate:
	 */
	clk_set_rate(mdp5_kms->src_clk, 200000000);

483
	read_hw_revision(mdp5_kms, &major, &minor);
484 485 486 487 488

	mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor);
	if (IS_ERR(mdp5_kms->cfg)) {
		ret = PTR_ERR(mdp5_kms->cfg);
		mdp5_kms->cfg = NULL;
489
		goto fail;
490
	}
491 492

	config = mdp5_cfg_get_config(mdp5_kms->cfg);
493

494
	/* TODO: compute core clock rate at runtime */
495
	clk_set_rate(mdp5_kms->src_clk, config->hw->max_clk);
496

497 498 499 500
	mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp);
	if (IS_ERR(mdp5_kms->smp)) {
		ret = PTR_ERR(mdp5_kms->smp);
		mdp5_kms->smp = NULL;
501 502 503
		goto fail;
	}

504 505 506 507
	mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, config->hw);
	if (IS_ERR(mdp5_kms->ctlm)) {
		ret = PTR_ERR(mdp5_kms->ctlm);
		mdp5_kms->ctlm = NULL;
508 509 510
		goto fail;
	}

R
Rob Clark 已提交
511 512 513 514 515
	/* make sure things are off before attaching iommu (bootloader could
	 * have left things on, in which case we'll start getting faults if
	 * we don't disable):
	 */
	mdp5_enable(mdp5_kms);
516
	for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
517 518
		if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
				!config->hw->intf.base[i])
519
			continue;
520
		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
521
	}
R
Rob Clark 已提交
522 523 524
	mdp5_disable(mdp5_kms);
	mdelay(16);

525 526
	if (config->platform.iommu) {
		mmu = msm_iommu_new(&pdev->dev, config->platform.iommu);
R
Rob Clark 已提交
527 528
		if (IS_ERR(mmu)) {
			ret = PTR_ERR(mmu);
529
			dev_err(dev->dev, "failed to init iommu: %d\n", ret);
R
Rob Clark 已提交
530 531
			goto fail;
		}
532

R
Rob Clark 已提交
533 534
		ret = mmu->funcs->attach(mmu, iommu_ports,
				ARRAY_SIZE(iommu_ports));
535 536 537
		if (ret) {
			dev_err(dev->dev, "failed to attach iommu: %d\n", ret);
			mmu->funcs->destroy(mmu);
R
Rob Clark 已提交
538
			goto fail;
539
		}
R
Rob Clark 已提交
540 541 542 543 544
	} else {
		dev_info(dev->dev, "no iommu, fallback to phys "
				"contig buffers for scanout\n");
		mmu = NULL;
	}
545
	mdp5_kms->mmu = mmu;
R
Rob Clark 已提交
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566

	mdp5_kms->id = msm_register_mmu(dev, mmu);
	if (mdp5_kms->id < 0) {
		ret = mdp5_kms->id;
		dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret);
		goto fail;
	}

	ret = modeset_init(mdp5_kms);
	if (ret) {
		dev_err(dev->dev, "modeset_init failed: %d\n", ret);
		goto fail;
	}

	return kms;

fail:
	if (kms)
		mdp5_destroy(kms);
	return ERR_PTR(ret);
}