mdp5_encoder.c 13.3 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
 * 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/>.
 */

19 20
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
R
Rob Clark 已提交
21

22
#include "mdp5_kms.h"
R
Rob Clark 已提交
23 24 25 26 27 28 29

static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
{
	struct msm_drm_private *priv = encoder->dev->dev_private;
	return to_mdp5_kms(to_mdp_kms(priv->kms));
}

30
#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
R
Rob Clark 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#include <mach/board.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
	{						\
		.src = MSM_BUS_MASTER_MDP_PORT0,	\
		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
		.ab = (ab_val),				\
		.ib = (ib_val),				\
	}

static struct msm_bus_vectors mdp_bus_vectors[] = {
	MDP_BUS_VECTOR_ENTRY(0, 0),
	MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
};
static struct msm_bus_paths mdp_bus_usecases[] = { {
		.num_paths = 1,
		.vectors = &mdp_bus_vectors[0],
}, {
		.num_paths = 1,
		.vectors = &mdp_bus_vectors[1],
} };
static struct msm_bus_scale_pdata mdp_bus_scale_table = {
	.usecase = mdp_bus_usecases,
	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
	.name = "mdss_mdp",
};

static void bs_init(struct mdp5_encoder *mdp5_encoder)
{
	mdp5_encoder->bsc = msm_bus_scale_register_client(
			&mdp_bus_scale_table);
	DBG("bus scale client: %08x", mdp5_encoder->bsc);
}

static void bs_fini(struct mdp5_encoder *mdp5_encoder)
{
	if (mdp5_encoder->bsc) {
		msm_bus_scale_unregister_client(mdp5_encoder->bsc);
		mdp5_encoder->bsc = 0;
	}
}

static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx)
{
	if (mdp5_encoder->bsc) {
		DBG("set bus scaling: %d", idx);
		/* HACK: scaling down, and then immediately back up
		 * seems to leave things broken (underflow).. so
		 * never disable:
		 */
		idx = 1;
		msm_bus_scale_client_update_request(mdp5_encoder->bsc, idx);
	}
}
#else
static void bs_init(struct mdp5_encoder *mdp5_encoder) {}
static void bs_fini(struct mdp5_encoder *mdp5_encoder) {}
static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) {}
#endif

static void mdp5_encoder_destroy(struct drm_encoder *encoder)
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
	bs_fini(mdp5_encoder);
	drm_encoder_cleanup(encoder);
	kfree(mdp5_encoder);
}

static const struct drm_encoder_funcs mdp5_encoder_funcs = {
	.destroy = mdp5_encoder_destroy,
};

104 105 106
static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder,
				      struct drm_display_mode *mode,
				      struct drm_display_mode *adjusted_mode)
R
Rob Clark 已提交
107 108 109
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
	struct mdp5_kms *mdp5_kms = get_kms(encoder);
110 111
	struct drm_device *dev = encoder->dev;
	struct drm_connector *connector;
112
	int intf = mdp5_encoder->intf->num;
R
Rob Clark 已提交
113 114 115
	uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
	uint32_t display_v_start, display_v_end;
	uint32_t hsync_start_x, hsync_end_x;
116
	uint32_t format = 0x2100;
117
	unsigned long flags;
R
Rob Clark 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130

	mode = adjusted_mode;

	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
			mode->base.id, mode->name,
			mode->vrefresh, mode->clock,
			mode->hdisplay, mode->hsync_start,
			mode->hsync_end, mode->htotal,
			mode->vdisplay, mode->vsync_start,
			mode->vsync_end, mode->vtotal,
			mode->type, mode->flags);

	ctrl_pol = 0;
131 132

	/* DSI controller cannot handle active-low sync signals. */
133
	if (mdp5_encoder->intf->type != INTF_DSI) {
134 135 136 137 138
		if (mode->flags & DRM_MODE_FLAG_NHSYNC)
			ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW;
		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
			ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW;
	}
R
Rob Clark 已提交
139 140 141
	/* probably need to get DATA_EN polarity from panel.. */

	dtv_hsync_skew = 0;  /* get this from panel? */
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

	/* Get color format from panel, default is 8bpc */
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (connector->encoder == encoder) {
			switch (connector->display_info.bpc) {
			case 4:
				format |= 0;
				break;
			case 5:
				format |= 0x15;
				break;
			case 6:
				format |= 0x2A;
				break;
			case 8:
			default:
				format |= 0x3F;
				break;
			}
			break;
		}
	}
R
Rob Clark 已提交
164 165 166 167 168 169 170 171 172

	hsync_start_x = (mode->htotal - mode->hsync_start);
	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;

	vsync_period = mode->vtotal * mode->htotal;
	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;

173 174 175 176 177
	/*
	 * For edp only:
	 * DISPLAY_V_START = (VBP * HCYCLE) + HBP
	 * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
	 */
178
	if (mdp5_encoder->intf->type == INTF_eDP) {
179 180 181 182
		display_v_start += mode->htotal - mode->hsync_start;
		display_v_end -= mode->hsync_start - mode->hdisplay;
	}

183 184
	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);

R
Rob Clark 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf),
			MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) |
			MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal));
	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_PERIOD_F0(intf), vsync_period);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_LEN_F0(intf), vsync_len);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_HCTL(intf),
			MDP5_INTF_DISPLAY_HCTL_START(hsync_start_x) |
			MDP5_INTF_DISPLAY_HCTL_END(hsync_end_x));
	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VSTART_F0(intf), display_v_start);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VEND_F0(intf), display_v_end);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_BORDER_COLOR(intf), 0);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_UNDERFLOW_COLOR(intf), 0xff);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_SKEW(intf), dtv_hsync_skew);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_POLARITY_CTL(intf), ctrl_pol);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_HCTL(intf),
			MDP5_INTF_ACTIVE_HCTL_START(0) |
			MDP5_INTF_ACTIVE_HCTL_END(0));
	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VSTART_F0(intf), 0);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format);
	mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
206 207

	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
208

209
	mdp5_crtc_set_pipeline(encoder->crtc);
R
Rob Clark 已提交
210 211
}

212
static void mdp5_vid_encoder_disable(struct drm_encoder *encoder)
R
Rob Clark 已提交
213
{
214 215
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
	struct mdp5_kms *mdp5_kms = get_kms(encoder);
216
	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
217
	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
218
	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
219 220
	struct mdp5_interface *intf = mdp5_encoder->intf;
	int intfn = mdp5_encoder->intf->num;
221 222 223 224 225
	unsigned long flags;

	if (WARN_ON(!mdp5_encoder->enabled))
		return;

226
	mdp5_ctl_set_encoder_state(ctl, pipeline, false);
227

228
	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
229
	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
230
	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
231
	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
232 233 234 235 236 237 238 239 240

	/*
	 * Wait for a vsync so we know the ENABLE=0 latched before
	 * the (connector) source of the vsync's gets disabled,
	 * otherwise we end up in a funny state if we re-enable
	 * before the disable latches, which results that some of
	 * the settings changes for the new modeset (like new
	 * scanout buffer) don't latch properly..
	 */
241
	mdp_irq_wait(&mdp5_kms->base, intf2vblank(mixer, intf));
242 243 244 245

	bs_set(mdp5_encoder, 0);

	mdp5_encoder->enabled = false;
R
Rob Clark 已提交
246 247
}

248
static void mdp5_vid_encoder_enable(struct drm_encoder *encoder)
R
Rob Clark 已提交
249 250
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
251
	struct mdp5_kms *mdp5_kms = get_kms(encoder);
252
	struct mdp5_ctl *ctl = mdp5_encoder->ctl;
253
	struct mdp5_interface *intf = mdp5_encoder->intf;
254
	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
255
	int intfn = intf->num;
256 257 258 259 260 261 262
	unsigned long flags;

	if (WARN_ON(mdp5_encoder->enabled))
		return;

	bs_set(mdp5_encoder, 1);
	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
263
	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
264
	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
265
	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf));
266

267
	mdp5_ctl_set_encoder_state(ctl, pipeline, true);
268

269
	mdp5_encoder->enabled = true;
R
Rob Clark 已提交
270 271
}

272 273 274 275
static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
				  struct drm_display_mode *mode,
				  struct drm_display_mode *adjusted_mode)
{
276
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
277
	struct mdp5_interface *intf = mdp5_encoder->intf;
278 279 280 281 282

	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
		mdp5_cmd_encoder_mode_set(encoder, mode, adjusted_mode);
	else
		mdp5_vid_encoder_mode_set(encoder, mode, adjusted_mode);
283 284 285 286
}

static void mdp5_encoder_disable(struct drm_encoder *encoder)
{
287
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
288
	struct mdp5_interface *intf = mdp5_encoder->intf;
289 290 291 292 293

	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
		mdp5_cmd_encoder_disable(encoder);
	else
		mdp5_vid_encoder_disable(encoder);
294 295 296 297
}

static void mdp5_encoder_enable(struct drm_encoder *encoder)
{
298
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
299
	struct mdp5_interface *intf = mdp5_encoder->intf;
300 301

	if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
302
		mdp5_cmd_encoder_enable(encoder);
303 304
	else
		mdp5_vid_encoder_enable(encoder);
305 306
}

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
static int mdp5_encoder_atomic_check(struct drm_encoder *encoder,
				     struct drm_crtc_state *crtc_state,
				     struct drm_connector_state *conn_state)
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
	struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc_state);
	struct mdp5_interface *intf = mdp5_encoder->intf;
	struct mdp5_ctl *ctl = mdp5_encoder->ctl;

	mdp5_cstate->ctl = ctl;
	mdp5_cstate->pipeline.intf = intf;

	return 0;
}

R
Rob Clark 已提交
322 323
static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
	.mode_set = mdp5_encoder_mode_set,
324 325
	.disable = mdp5_encoder_disable,
	.enable = mdp5_encoder_enable,
326
	.atomic_check = mdp5_encoder_atomic_check,
R
Rob Clark 已提交
327 328
};

329 330 331 332
int mdp5_encoder_get_linecount(struct drm_encoder *encoder)
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
	struct mdp5_kms *mdp5_kms = get_kms(encoder);
333
	int intf = mdp5_encoder->intf->num;
334 335 336 337 338 339 340 341

	return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
}

u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
	struct mdp5_kms *mdp5_kms = get_kms(encoder);
342
	int intf = mdp5_encoder->intf->num;
343 344 345 346

	return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
}

347 348
int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
				       struct drm_encoder *slave_encoder)
349 350
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
351
	struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
352 353 354 355 356 357 358 359
	struct mdp5_kms *mdp5_kms;
	int intf_num;
	u32 data = 0;

	if (!encoder || !slave_encoder)
		return -EINVAL;

	mdp5_kms = get_kms(encoder);
360
	intf_num = mdp5_encoder->intf->num;
361 362 363 364 365

	/* Switch slave encoder's TimingGen Sync mode,
	 * to use the master's enable signal for the slave encoder.
	 */
	if (intf_num == 1)
366
		data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC;
367
	else if (intf_num == 2)
368
		data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC;
369 370 371 372 373 374
	else
		return -EINVAL;

	/* Make sure clocks are on when connectors calling this function. */
	mdp5_enable(mdp5_kms);
	/* Dumb Panel, Sync mode */
375 376 377
	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
378 379 380

	mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);

381 382 383 384 385
	mdp5_disable(mdp5_kms);

	return 0;
}

386 387 388
void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode)
{
	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
389
	struct mdp5_interface *intf = mdp5_encoder->intf;
390 391 392 393 394 395 396 397 398 399 400 401 402

	/* TODO: Expand this to set writeback modes too */
	if (cmd_mode) {
		WARN_ON(intf->type != INTF_DSI);
		intf->mode = MDP5_INTF_DSI_MODE_COMMAND;
	} else {
		if (intf->type == INTF_DSI)
			intf->mode = MDP5_INTF_DSI_MODE_VIDEO;
		else
			intf->mode = MDP5_INTF_MODE_NONE;
	}
}

R
Rob Clark 已提交
403
/* initialize encoder */
404
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
405 406
				      struct mdp5_interface *intf,
				      struct mdp5_ctl *ctl)
R
Rob Clark 已提交
407 408 409
{
	struct drm_encoder *encoder = NULL;
	struct mdp5_encoder *mdp5_encoder;
410 411
	int enc_type = (intf->type == INTF_DSI) ?
		DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS;
R
Rob Clark 已提交
412 413 414 415 416 417 418 419 420
	int ret;

	mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
	if (!mdp5_encoder) {
		ret = -ENOMEM;
		goto fail;
	}

	encoder = &mdp5_encoder->base;
421
	mdp5_encoder->ctl = ctl;
422
	mdp5_encoder->intf = intf;
R
Rob Clark 已提交
423

424 425
	spin_lock_init(&mdp5_encoder->intf_lock);

426
	drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type, NULL);
427

R
Rob Clark 已提交
428 429 430 431 432 433 434 435 436 437 438 439
	drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);

	bs_init(mdp5_encoder);

	return encoder;

fail:
	if (encoder)
		mdp5_encoder_destroy(encoder);

	return ERR_PTR(ret);
}